diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2019-12-05 15:11:01 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2019-12-05 15:11:01 +0900 |
commit | 3fdc3e5ee96dca5b11d1694975a65200787eab86 (patch) | |
tree | 5c1733853892b8397d67706fa453a9bd978d2102 /boost/asio | |
parent | 88e602c57797660ebe0f9e15dbd64c1ff16dead3 (diff) | |
download | boost-3fdc3e5ee96dca5b11d1694975a65200787eab86.tar.gz boost-3fdc3e5ee96dca5b11d1694975a65200787eab86.tar.bz2 boost-3fdc3e5ee96dca5b11d1694975a65200787eab86.zip |
Imported Upstream version 1.66.0upstream/1.66.0
Diffstat (limited to 'boost/asio')
374 files changed, 32894 insertions, 12780 deletions
diff --git a/boost/asio/associated_allocator.hpp b/boost/asio/associated_allocator.hpp new file mode 100644 index 0000000000..b9ef5a452f --- /dev/null +++ b/boost/asio/associated_allocator.hpp @@ -0,0 +1,133 @@ +// +// associated_allocator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_ASSOCIATED_ALLOCATOR_HPP +#define BOOST_ASIO_ASSOCIATED_ALLOCATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <memory> +#include <boost/asio/detail/type_traits.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +template <typename> +struct associated_allocator_check +{ + typedef void type; +}; + +template <typename T, typename E, typename = void> +struct associated_allocator_impl +{ + typedef E type; + + static type get(const T&, const E& e) BOOST_ASIO_NOEXCEPT + { + return e; + } +}; + +template <typename T, typename E> +struct associated_allocator_impl<T, E, + typename associated_allocator_check<typename T::allocator_type>::type> +{ + typedef typename T::allocator_type type; + + static type get(const T& t, const E&) BOOST_ASIO_NOEXCEPT + { + return t.get_allocator(); + } +}; + +} // namespace detail + +/// Traits type used to obtain the allocator associated with an object. +/** + * A program may specialise this traits type if the @c T template parameter in + * the specialisation is a user-defined type. The template parameter @c + * Allocator shall be a type meeting the Allocator requirements. + * + * Specialisations shall meet the following requirements, where @c t is a const + * reference to an object of type @c T, and @c a is an object of type @c + * Allocator. + * + * @li Provide a nested typedef @c type that identifies a type meeting the + * Allocator requirements. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t) and with return type @c type. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t,a) and with return type @c type. + */ +template <typename T, typename Allocator = std::allocator<void> > +struct associated_allocator +{ + /// If @c T has a nested type @c allocator_type, <tt>T::allocator_type</tt>. + /// Otherwise @c Allocator. +#if defined(GENERATING_DOCUMENTATION) + typedef see_below type; +#else // defined(GENERATING_DOCUMENTATION) + typedef typename detail::associated_allocator_impl<T, Allocator>::type type; +#endif // defined(GENERATING_DOCUMENTATION) + + /// If @c T has a nested type @c allocator_type, returns + /// <tt>t.get_allocator()</tt>. Otherwise returns @c a. + static type get(const T& t, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return detail::associated_allocator_impl<T, Allocator>::get(t, a); + } +}; + +/// Helper function to obtain an object's associated allocator. +/** + * @returns <tt>associated_allocator<T>::get(t)</tt> + */ +template <typename T> +inline typename associated_allocator<T>::type +get_associated_allocator(const T& t) BOOST_ASIO_NOEXCEPT +{ + return associated_allocator<T>::get(t); +} + +/// Helper function to obtain an object's associated allocator. +/** + * @returns <tt>associated_allocator<T, Allocator>::get(t, a)</tt> + */ +template <typename T, typename Allocator> +inline typename associated_allocator<T, Allocator>::type +get_associated_allocator(const T& t, const Allocator& a) BOOST_ASIO_NOEXCEPT +{ + return associated_allocator<T, Allocator>::get(t, a); +} + +#if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) + +template <typename T, typename Allocator = std::allocator<void> > +using associated_allocator_t + = typename associated_allocator<T, Allocator>::type; + +#endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_ASSOCIATED_ALLOCATOR_HPP diff --git a/boost/asio/associated_executor.hpp b/boost/asio/associated_executor.hpp new file mode 100644 index 0000000000..d0347afcfa --- /dev/null +++ b/boost/asio/associated_executor.hpp @@ -0,0 +1,151 @@ +// +// associated_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_ASSOCIATED_EXECUTOR_HPP +#define BOOST_ASIO_ASSOCIATED_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/type_traits.hpp> +#include <boost/asio/is_executor.hpp> +#include <boost/asio/system_executor.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +template <typename> +struct associated_executor_check +{ + typedef void type; +}; + +template <typename T, typename E, typename = void> +struct associated_executor_impl +{ + typedef E type; + + static type get(const T&, const E& e) BOOST_ASIO_NOEXCEPT + { + return e; + } +}; + +template <typename T, typename E> +struct associated_executor_impl<T, E, + typename associated_executor_check<typename T::executor_type>::type> +{ + typedef typename T::executor_type type; + + static type get(const T& t, const E&) BOOST_ASIO_NOEXCEPT + { + return t.get_executor(); + } +}; + +} // namespace detail + +/// Traits type used to obtain the executor associated with an object. +/** + * A program may specialise this traits type if the @c T template parameter in + * the specialisation is a user-defined type. The template parameter @c + * Executor shall be a type meeting the Executor requirements. + * + * Specialisations shall meet the following requirements, where @c t is a const + * reference to an object of type @c T, and @c e is an object of type @c + * Executor. + * + * @li Provide a nested typedef @c type that identifies a type meeting the + * Executor requirements. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t) and with return type @c type. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t,e) and with return type @c type. + */ +template <typename T, typename Executor = system_executor> +struct associated_executor +{ + /// If @c T has a nested type @c executor_type, <tt>T::executor_type</tt>. + /// Otherwise @c Executor. +#if defined(GENERATING_DOCUMENTATION) + typedef see_below type; +#else // defined(GENERATING_DOCUMENTATION) + typedef typename detail::associated_executor_impl<T, Executor>::type type; +#endif // defined(GENERATING_DOCUMENTATION) + + /// If @c T has a nested type @c executor_type, returns + /// <tt>t.get_executor()</tt>. Otherwise returns @c ex. + static type get(const T& t, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return detail::associated_executor_impl<T, Executor>::get(t, ex); + } +}; + +/// Helper function to obtain an object's associated executor. +/** + * @returns <tt>associated_executor<T>::get(t)</tt> + */ +template <typename T> +inline typename associated_executor<T>::type +get_associated_executor(const T& t) BOOST_ASIO_NOEXCEPT +{ + return associated_executor<T>::get(t); +} + +/// Helper function to obtain an object's associated executor. +/** + * @returns <tt>associated_executor<T, Executor>::get(t, ex)</tt> + */ +template <typename T, typename Executor> +inline typename associated_executor<T, Executor>::type +get_associated_executor(const T& t, const Executor& ex, + typename enable_if<is_executor< + Executor>::value>::type* = 0) BOOST_ASIO_NOEXCEPT +{ + return associated_executor<T, Executor>::get(t, ex); +} + +/// Helper function to obtain an object's associated executor. +/** + * @returns <tt>associated_executor<T, typename + * ExecutionContext::executor_type>::get(t, ctx.get_executor())</tt> + */ +template <typename T, typename ExecutionContext> +inline typename associated_executor<T, + typename ExecutionContext::executor_type>::type +get_associated_executor(const T& t, ExecutionContext& ctx, + typename enable_if<is_convertible<ExecutionContext&, + execution_context&>::value>::type* = 0) BOOST_ASIO_NOEXCEPT +{ + return associated_executor<T, + typename ExecutionContext::executor_type>::get(t, ctx.get_executor()); +} + +#if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) + +template <typename T, typename Executor = system_executor> +using associated_executor_t = typename associated_executor<T, Executor>::type; + +#endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_ASSOCIATED_EXECUTOR_HPP diff --git a/boost/asio/async_result.hpp b/boost/asio/async_result.hpp index 6290b8462a..f49f2eb2e0 100644 --- a/boost/asio/async_result.hpp +++ b/boost/asio/async_result.hpp @@ -16,6 +16,7 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/type_traits.hpp> #include <boost/asio/handler_type.hpp> #include <boost/asio/detail/push_options.hpp> @@ -25,10 +26,93 @@ namespace asio { /// An interface for customising the behaviour of an initiating function. /** + * The async_result traits class is used for determining: + * + * @li the concrete completion handler type to be called at the end of the + * asynchronous operation; + * + * @li the initiating function return type; and + * + * @li how the return value of the initiating function is obtained. + * + * The trait allows the handler and return types to be determined at the point + * where the specific completion handler signature is known. + * + * This template may be specialised for user-defined completion token types. + * The primary template assumes that the CompletionToken is the completion + * handler. + */ +#if defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) +template <typename CompletionToken, typename Signature> +#else // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) +template <typename CompletionToken, typename Signature = void> +#endif // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) +class async_result +{ +public: +#if defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + /// The concrete completion handler type for the specific signature. + typedef CompletionToken completion_handler_type; + + /// The return type of the initiating function. + typedef void return_type; +#else // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + // For backward compatibility, determine the concrete completion handler type + // by using the legacy handler_type trait. + typedef typename handler_type<CompletionToken, Signature>::type + completion_handler_type; + + // For backward compatibility, determine the initiating function return type + // using the legacy single-parameter version of async_result. + typedef typename async_result<completion_handler_type>::type return_type; +#endif // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + + /// Construct an async result from a given handler. + /** + * When using a specalised async_result, the constructor has an opportunity + * to initialise some state associated with the completion handler, which is + * then returned from the initiating function. + */ + explicit async_result(completion_handler_type& h) +#if defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + // No data members to initialise. +#else // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + : legacy_result_(h) +#endif // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + { + (void)h; + } + + /// Obtain the value to be returned from the initiating function. + return_type get() + { +#if defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + // Nothing to do. +#else // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + return legacy_result_.get(); +#endif // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + } + +private: + async_result(const async_result&) BOOST_ASIO_DELETED; + async_result& operator=(const async_result&) BOOST_ASIO_DELETED; + +#if defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + // No data members. +#else // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + async_result<completion_handler_type> legacy_result_; +#endif // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) +}; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +/// (Deprecated: Use two-parameter version of async_result.) An interface for +/// customising the behaviour of an initiating function. +/** * This template may be specialised for user-defined handler types. */ template <typename Handler> -class async_result +class async_result<Handler> { public: /// The return type of the initiating function. @@ -50,29 +134,65 @@ public: } }; -namespace detail { +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) -// Helper template to deduce the true type of a handler, capture a local copy -// of the handler, and then create an async_result for the handler. -template <typename Handler, typename Signature> -struct async_result_init +/// Helper template to deduce the handler type from a CompletionToken, capture +/// a local copy of the handler, and then create an async_result for the +/// handler. +template <typename CompletionToken, typename Signature> +struct async_completion { - explicit async_result_init(BOOST_ASIO_MOVE_ARG(Handler) orig_handler) - : handler(BOOST_ASIO_MOVE_CAST(Handler)(orig_handler)), - result(handler) + /// The real handler type to be used for the asynchronous operation. + typedef typename boost::asio::async_result< + typename decay<CompletionToken>::type, + Signature>::completion_handler_type completion_handler_type; + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Constructor. + /** + * The constructor creates the concrete completion handler and makes the link + * between the handler and the asynchronous result. + */ + explicit async_completion(CompletionToken& token) + : completion_handler(static_cast<typename conditional< + is_same<CompletionToken, completion_handler_type>::value, + completion_handler_type&, CompletionToken&&>::type>(token)), + result(completion_handler) + { + } +#else // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + explicit async_completion(typename decay<CompletionToken>::type& token) + : completion_handler(token), + result(completion_handler) { } - typename handler_type<Handler, Signature>::type handler; - async_result<typename handler_type<Handler, Signature>::type> result; + explicit async_completion(const typename decay<CompletionToken>::type& token) + : completion_handler(token), + result(completion_handler) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// A copy of, or reference to, a real handler object. +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + typename conditional< + is_same<CompletionToken, completion_handler_type>::value, + completion_handler_type&, completion_handler_type>::type completion_handler; +#else // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + completion_handler_type completion_handler; +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// The result of the asynchronous operation's initiating function. + async_result<typename decay<CompletionToken>::type, Signature> result; }; -template <typename Handler, typename Signature> -struct async_result_type_helper +namespace detail { + +template <typename CompletionToken, typename Signature> +struct async_result_helper + : async_result<typename decay<CompletionToken>::type, Signature> { - typedef typename async_result< - typename handler_type<Handler, Signature>::type - >::type type; }; } // namespace detail @@ -82,15 +202,22 @@ struct async_result_type_helper #include <boost/asio/detail/pop_options.hpp> #if defined(GENERATING_DOCUMENTATION) -# define BOOST_ASIO_INITFN_RESULT_TYPE(h, sig) \ +# define BOOST_ASIO_INITFN_RESULT_TYPE(ct, sig) \ void_or_deduced #elif defined(_MSC_VER) && (_MSC_VER < 1500) -# define BOOST_ASIO_INITFN_RESULT_TYPE(h, sig) \ - typename ::boost::asio::detail::async_result_type_helper<h, sig>::type +# define BOOST_ASIO_INITFN_RESULT_TYPE(ct, sig) \ + typename ::boost::asio::detail::async_result_helper< \ + ct, sig>::return_type +#define BOOST_ASIO_HANDLER_TYPE(ct, sig) \ + typename ::boost::asio::detail::async_result_helper< \ + ct, sig>::completion_handler_type #else -# define BOOST_ASIO_INITFN_RESULT_TYPE(h, sig) \ +# define BOOST_ASIO_INITFN_RESULT_TYPE(ct, sig) \ + typename ::boost::asio::async_result< \ + typename ::boost::asio::decay<ct>::type, sig>::return_type +#define BOOST_ASIO_HANDLER_TYPE(ct, sig) \ typename ::boost::asio::async_result< \ - typename ::boost::asio::handler_type<h, sig>::type>::type + typename ::boost::asio::decay<ct>::type, sig>::completion_handler_type #endif #endif // BOOST_ASIO_ASYNC_RESULT_HPP diff --git a/boost/asio/basic_datagram_socket.hpp b/boost/asio/basic_datagram_socket.hpp index 22801ee081..c2aa00bf48 100644 --- a/boost/asio/basic_datagram_socket.hpp +++ b/boost/asio/basic_datagram_socket.hpp @@ -18,12 +18,15 @@ #include <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/basic_socket.hpp> -#include <boost/asio/datagram_socket_service.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/datagram_socket_service.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #include <boost/asio/detail/push_options.hpp> namespace boost { @@ -38,18 +41,19 @@ namespace asio { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template <typename Protocol, - typename DatagramSocketService = datagram_socket_service<Protocol> > +template <typename Protocol + BOOST_ASIO_SVC_TPARAM_DEF1(= datagram_socket_service<Protocol>)> class basic_datagram_socket - : public basic_socket<Protocol, DatagramSocketService> + : public basic_socket<Protocol BOOST_ASIO_SVC_TARG> { public: - /// (Deprecated: Use native_handle_type.) The native representation of a - /// socket. - typedef typename DatagramSocketService::native_handle_type native_type; - /// The native representation of a socket. - typedef typename DatagramSocketService::native_handle_type native_handle_type; +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef typename basic_socket< + Protocol BOOST_ASIO_SVC_TARG>::native_handle_type native_handle_type; +#endif /// The protocol type. typedef Protocol protocol_type; @@ -62,12 +66,12 @@ public: * This constructor creates a datagram socket without opening it. The open() * function must be called before data can be sent or received on the socket. * - * @param io_service The io_service object that the datagram socket will use + * @param io_context The io_context object that the datagram socket will use * to dispatch handlers for any asynchronous operations performed on the * socket. */ - explicit basic_datagram_socket(boost::asio::io_service& io_service) - : basic_socket<Protocol, DatagramSocketService>(io_service) + explicit basic_datagram_socket(boost::asio::io_context& io_context) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(io_context) { } @@ -75,7 +79,7 @@ public: /** * This constructor creates and opens a datagram socket. * - * @param io_service The io_service object that the datagram socket will use + * @param io_context The io_context object that the datagram socket will use * to dispatch handlers for any asynchronous operations performed on the * socket. * @@ -83,9 +87,9 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_datagram_socket(boost::asio::io_service& io_service, + basic_datagram_socket(boost::asio::io_context& io_context, const protocol_type& protocol) - : basic_socket<Protocol, DatagramSocketService>(io_service, protocol) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(io_context, protocol) { } @@ -96,7 +100,7 @@ public: * to the specified endpoint on the local machine. The protocol used is the * protocol associated with the given endpoint. * - * @param io_service The io_service object that the datagram socket will use + * @param io_context The io_context object that the datagram socket will use * to dispatch handlers for any asynchronous operations performed on the * socket. * @@ -105,9 +109,9 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_datagram_socket(boost::asio::io_service& io_service, + basic_datagram_socket(boost::asio::io_context& io_context, const endpoint_type& endpoint) - : basic_socket<Protocol, DatagramSocketService>(io_service, endpoint) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(io_context, endpoint) { } @@ -116,7 +120,7 @@ public: * This constructor creates a datagram socket object to hold an existing * native socket. * - * @param io_service The io_service object that the datagram socket will use + * @param io_context The io_context object that the datagram socket will use * to dispatch handlers for any asynchronous operations performed on the * socket. * @@ -126,10 +130,10 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_datagram_socket(boost::asio::io_service& io_service, + basic_datagram_socket(boost::asio::io_context& io_context, const protocol_type& protocol, const native_handle_type& native_socket) - : basic_socket<Protocol, DatagramSocketService>( - io_service, protocol, native_socket) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>( + io_context, protocol, native_socket) { } @@ -142,11 +146,10 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_datagram_socket(io_service&) constructor. + * constructed using the @c basic_datagram_socket(io_context&) constructor. */ basic_datagram_socket(basic_datagram_socket&& other) - : basic_socket<Protocol, DatagramSocketService>( - BOOST_ASIO_MOVE_CAST(basic_datagram_socket)(other)) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(std::move(other)) { } @@ -159,12 +162,11 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_datagram_socket(io_service&) constructor. + * constructed using the @c basic_datagram_socket(io_context&) constructor. */ basic_datagram_socket& operator=(basic_datagram_socket&& other) { - basic_socket<Protocol, DatagramSocketService>::operator=( - BOOST_ASIO_MOVE_CAST(basic_datagram_socket)(other)); + basic_socket<Protocol BOOST_ASIO_SVC_TARG>::operator=(std::move(other)); return *this; } @@ -177,15 +179,13 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_datagram_socket(io_service&) constructor. + * constructed using the @c basic_datagram_socket(io_context&) constructor. */ - template <typename Protocol1, typename DatagramSocketService1> + template <typename Protocol1 BOOST_ASIO_SVC_TPARAM1> basic_datagram_socket( - basic_datagram_socket<Protocol1, DatagramSocketService1>&& other, + basic_datagram_socket<Protocol1 BOOST_ASIO_SVC_TARG1>&& other, typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0) - : basic_socket<Protocol, DatagramSocketService>( - BOOST_ASIO_MOVE_CAST2(basic_datagram_socket< - Protocol1, DatagramSocketService1>)(other)) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(std::move(other)) { } @@ -199,20 +199,27 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_datagram_socket(io_service&) constructor. + * constructed using the @c basic_datagram_socket(io_context&) constructor. */ - template <typename Protocol1, typename DatagramSocketService1> + template <typename Protocol1 BOOST_ASIO_SVC_TPARAM1> typename enable_if<is_convertible<Protocol1, Protocol>::value, basic_datagram_socket>::type& operator=( - basic_datagram_socket<Protocol1, DatagramSocketService1>&& other) + basic_datagram_socket<Protocol1 BOOST_ASIO_SVC_TARG1>&& other) { - basic_socket<Protocol, DatagramSocketService>::operator=( - BOOST_ASIO_MOVE_CAST2(basic_datagram_socket< - Protocol1, DatagramSocketService1>)(other)); + basic_socket<Protocol BOOST_ASIO_SVC_TARG>::operator=(std::move(other)); return *this; } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Destroys the socket. + /** + * This function destroys the socket, cancelling any outstanding asynchronous + * operations associated with the socket as if by calling @c cancel. + */ + ~basic_datagram_socket() + { + } + /// Send some data on a connected socket. /** * This function is used to send data on the datagram socket. The function @@ -318,7 +325,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The async_send operation can only be used with a connected socket. * Use the async_send_to function to send data on an unconnected datagram @@ -343,8 +350,18 @@ public: // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_send(this->get_implementation(), buffers, 0, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_send(this->get_implementation(), + buffers, 0, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Start an asynchronous send on a connected socket. @@ -369,7 +386,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The async_send operation can only be used with a connected socket. * Use the async_send_to function to send data on an unconnected datagram @@ -386,8 +403,18 @@ public: // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_send(this->get_implementation(), buffers, flags, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_send(this->get_implementation(), + buffers, flags, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Send a datagram to the specified endpoint. @@ -501,7 +528,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * To send a single data buffer use the @ref buffer function as follows: @@ -526,9 +553,20 @@ public: // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_send_to( this->get_implementation(), buffers, destination, 0, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_send_to( + this->get_implementation(), buffers, destination, 0, + init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Start an asynchronous send. @@ -556,7 +594,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). */ template <typename ConstBufferSequence, typename WriteHandler> BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, @@ -569,9 +607,20 @@ public: // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_send_to( this->get_implementation(), buffers, destination, flags, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_send_to( + this->get_implementation(), buffers, destination, flags, + init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Receive some data on a connected socket. @@ -683,7 +732,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The async_receive operation can only be used with a connected socket. * Use the async_receive_from function to receive data on an unconnected @@ -709,8 +758,18 @@ public: // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_receive(this->get_implementation(), buffers, 0, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_receive(this->get_implementation(), + buffers, 0, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Start an asynchronous receive on a connected socket. @@ -735,7 +794,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The async_receive operation can only be used with a connected socket. * Use the async_receive_from function to receive data on an unconnected @@ -752,8 +811,18 @@ public: // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_receive(this->get_implementation(), buffers, flags, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_receive(this->get_implementation(), + buffers, flags, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Receive a datagram with the endpoint of the sender. @@ -870,7 +939,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * To receive into a single data buffer use the @ref buffer function as @@ -892,9 +961,20 @@ public: // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_receive_from( this->get_implementation(), buffers, sender_endpoint, 0, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_receive_from( + this->get_implementation(), buffers, sender_endpoint, 0, + init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Start an asynchronous receive. @@ -924,7 +1004,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). */ template <typename MutableBufferSequence, typename ReadHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, @@ -937,9 +1017,20 @@ public: // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_receive_from( this->get_implementation(), buffers, sender_endpoint, flags, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_receive_from( + this->get_implementation(), buffers, sender_endpoint, flags, + init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } }; diff --git a/boost/asio/basic_deadline_timer.hpp b/boost/asio/basic_deadline_timer.hpp index 930370046b..f7179a853e 100644 --- a/boost/asio/basic_deadline_timer.hpp +++ b/boost/asio/basic_deadline_timer.hpp @@ -22,10 +22,17 @@ #include <cstddef> #include <boost/asio/basic_io_object.hpp> -#include <boost/asio/deadline_timer_service.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> +#include <boost/asio/time_traits.hpp> + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/deadline_timer_service.hpp> +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/detail/deadline_timer_service.hpp> +# define BOOST_ASIO_SVC_T detail::deadline_timer_service<TimeTraits> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) #include <boost/asio/detail/push_options.hpp> @@ -51,7 +58,7 @@ namespace asio { * Performing a blocking wait: * @code * // Construct a timer without setting an expiry time. - * boost::asio::deadline_timer timer(io_service); + * boost::asio::deadline_timer timer(io_context); * * // Set an expiry time relative to now. * timer.expires_from_now(boost::posix_time::seconds(5)); @@ -74,7 +81,7 @@ namespace asio { * ... * * // Construct a timer with an absolute expiry time. - * boost::asio::deadline_timer timer(io_service, + * boost::asio::deadline_timer timer(io_context, * boost::posix_time::time_from_string("2005-12-07 23:59:59.000")); * * // Start an asynchronous wait. @@ -121,12 +128,15 @@ namespace asio { * it contains the value boost::asio::error::operation_aborted. */ template <typename Time, - typename TimeTraits = boost::asio::time_traits<Time>, - typename TimerService = deadline_timer_service<Time, TimeTraits> > + typename TimeTraits = boost::asio::time_traits<Time> + BOOST_ASIO_SVC_TPARAM_DEF2(= deadline_timer_service<Time, TimeTraits>)> class basic_deadline_timer - : public basic_io_object<TimerService> + : BOOST_ASIO_SVC_ACCESS basic_io_object<BOOST_ASIO_SVC_T> { public: + /// The type of the executor associated with the object. + typedef io_context::executor_type executor_type; + /// The time traits type. typedef TimeTraits traits_type; @@ -142,11 +152,11 @@ public: * expires_at() or expires_from_now() functions must be called to set an * expiry time before the timer can be waited on. * - * @param io_service The io_service object that the timer will use to dispatch + * @param io_context The io_context object that the timer will use to dispatch * handlers for any asynchronous operations performed on the timer. */ - explicit basic_deadline_timer(boost::asio::io_service& io_service) - : basic_io_object<TimerService>(io_service) + explicit basic_deadline_timer(boost::asio::io_context& io_context) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) { } @@ -154,18 +164,18 @@ public: /** * This constructor creates a timer and sets the expiry time. * - * @param io_service The io_service object that the timer will use to dispatch + * @param io_context The io_context object that the timer will use to dispatch * handlers for any asynchronous operations performed on the timer. * * @param expiry_time The expiry time to be used for the timer, expressed * as an absolute time. */ - basic_deadline_timer(boost::asio::io_service& io_service, + basic_deadline_timer(boost::asio::io_context& io_context, const time_type& expiry_time) - : basic_io_object<TimerService>(io_service) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) { boost::system::error_code ec; - this->service.expires_at(this->implementation, expiry_time, ec); + this->get_service().expires_at(this->get_implementation(), expiry_time, ec); boost::asio::detail::throw_error(ec, "expires_at"); } @@ -173,21 +183,105 @@ public: /** * This constructor creates a timer and sets the expiry time. * - * @param io_service The io_service object that the timer will use to dispatch + * @param io_context The io_context object that the timer will use to dispatch * handlers for any asynchronous operations performed on the timer. * * @param expiry_time The expiry time to be used for the timer, relative to * now. */ - basic_deadline_timer(boost::asio::io_service& io_service, + basic_deadline_timer(boost::asio::io_context& io_context, const duration_type& expiry_time) - : basic_io_object<TimerService>(io_service) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) { boost::system::error_code ec; - this->service.expires_from_now(this->implementation, expiry_time, ec); + this->get_service().expires_from_now( + this->get_implementation(), expiry_time, ec); boost::asio::detail::throw_error(ec, "expires_from_now"); } +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_deadline_timer from another. + /** + * This constructor moves a timer from one object to another. + * + * @param other The other basic_deadline_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_deadline_timer(io_context&) constructor. + */ + basic_deadline_timer(basic_deadline_timer&& other) + : basic_io_object<BOOST_ASIO_SVC_T>(std::move(other)) + { + } + + /// Move-assign a basic_deadline_timer from another. + /** + * This assignment operator moves a timer from one object to another. Cancels + * any outstanding asynchronous operations associated with the target object. + * + * @param other The other basic_deadline_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_deadline_timer(io_context&) constructor. + */ + basic_deadline_timer& operator=(basic_deadline_timer&& other) + { + basic_io_object<BOOST_ASIO_SVC_T>::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the timer. + /** + * This function destroys the timer, cancelling any outstanding asynchronous + * wait operations associated with the timer as if by calling @c cancel. + */ + ~basic_deadline_timer() + { + } + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + // These functions are provided by basic_io_object<>. +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_context() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_service() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_service(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_executor(); + } +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + /// Cancel any asynchronous operations that are waiting on the timer. /** * This function forces the completion of any pending asynchronous wait @@ -213,7 +307,7 @@ public: std::size_t cancel() { boost::system::error_code ec; - std::size_t s = this->service.cancel(this->implementation, ec); + std::size_t s = this->get_service().cancel(this->get_implementation(), ec); boost::asio::detail::throw_error(ec, "cancel"); return s; } @@ -242,7 +336,7 @@ public: */ std::size_t cancel(boost::system::error_code& ec) { - return this->service.cancel(this->implementation, ec); + return this->get_service().cancel(this->get_implementation(), ec); } /// Cancels one asynchronous operation that is waiting on the timer. @@ -272,7 +366,8 @@ public: std::size_t cancel_one() { boost::system::error_code ec; - std::size_t s = this->service.cancel_one(this->implementation, ec); + std::size_t s = this->get_service().cancel_one( + this->get_implementation(), ec); boost::asio::detail::throw_error(ec, "cancel_one"); return s; } @@ -303,7 +398,7 @@ public: */ std::size_t cancel_one(boost::system::error_code& ec) { - return this->service.cancel_one(this->implementation, ec); + return this->get_service().cancel_one(this->get_implementation(), ec); } /// Get the timer's expiry time as an absolute time. @@ -313,7 +408,7 @@ public: */ time_type expires_at() const { - return this->service.expires_at(this->implementation); + return this->get_service().expires_at(this->get_implementation()); } /// Set the timer's expiry time as an absolute time. @@ -341,8 +436,8 @@ public: std::size_t expires_at(const time_type& expiry_time) { boost::system::error_code ec; - std::size_t s = this->service.expires_at( - this->implementation, expiry_time, ec); + std::size_t s = this->get_service().expires_at( + this->get_implementation(), expiry_time, ec); boost::asio::detail::throw_error(ec, "expires_at"); return s; } @@ -372,7 +467,8 @@ public: std::size_t expires_at(const time_type& expiry_time, boost::system::error_code& ec) { - return this->service.expires_at(this->implementation, expiry_time, ec); + return this->get_service().expires_at( + this->get_implementation(), expiry_time, ec); } /// Get the timer's expiry time relative to now. @@ -382,7 +478,7 @@ public: */ duration_type expires_from_now() const { - return this->service.expires_from_now(this->implementation); + return this->get_service().expires_from_now(this->get_implementation()); } /// Set the timer's expiry time relative to now. @@ -410,8 +506,8 @@ public: std::size_t expires_from_now(const duration_type& expiry_time) { boost::system::error_code ec; - std::size_t s = this->service.expires_from_now( - this->implementation, expiry_time, ec); + std::size_t s = this->get_service().expires_from_now( + this->get_implementation(), expiry_time, ec); boost::asio::detail::throw_error(ec, "expires_from_now"); return s; } @@ -441,8 +537,8 @@ public: std::size_t expires_from_now(const duration_type& expiry_time, boost::system::error_code& ec) { - return this->service.expires_from_now( - this->implementation, expiry_time, ec); + return this->get_service().expires_from_now( + this->get_implementation(), expiry_time, ec); } /// Perform a blocking wait on the timer. @@ -455,7 +551,7 @@ public: void wait() { boost::system::error_code ec; - this->service.wait(this->implementation, ec); + this->get_service().wait(this->get_implementation(), ec); boost::asio::detail::throw_error(ec, "wait"); } @@ -468,7 +564,7 @@ public: */ void wait(boost::system::error_code& ec) { - this->service.wait(this->implementation, ec); + this->get_service().wait(this->get_implementation(), ec); } /// Start an asynchronous wait on the timer. @@ -493,7 +589,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). */ template <typename WaitHandler> BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, @@ -504,8 +600,18 @@ public: // not meet the documented type requirements for a WaitHandler. BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; - return this->service.async_wait(this->implementation, +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + return this->get_service().async_wait(this->get_implementation(), BOOST_ASIO_MOVE_CAST(WaitHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<WaitHandler, + void (boost::system::error_code)> init(handler); + + this->get_service().async_wait(this->get_implementation(), + init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } }; @@ -514,6 +620,10 @@ public: #include <boost/asio/detail/pop_options.hpp> +#if !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# undef BOOST_ASIO_SVC_T +#endif // !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) // || defined(GENERATING_DOCUMENTATION) diff --git a/boost/asio/basic_io_object.hpp b/boost/asio/basic_io_object.hpp index d490a161f6..87653b5c53 100644 --- a/boost/asio/basic_io_object.hpp +++ b/boost/asio/basic_io_object.hpp @@ -16,7 +16,7 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -68,17 +68,43 @@ public: /// The underlying implementation type of I/O object. typedef typename service_type::implementation_type implementation_type; - /// Get the io_service associated with the object. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. /** - * This function may be used to obtain the io_service object that the I/O + * This function may be used to obtain the io_context object that the I/O * object uses to dispatch handlers for asynchronous operations. * - * @return A reference to the io_service object that the I/O object will use + * @return A reference to the io_context object that the I/O object will use * to dispatch handlers. Ownership is not transferred to the caller. */ - boost::asio::io_service& get_io_service() + boost::asio::io_context& get_io_context() { - return service.get_io_service(); + return service_.get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_service() + { + return service_.get_io_context(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// The type of the executor associated with the object. + typedef boost::asio::io_context::executor_type executor_type; + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return service_.get_io_context().get_executor(); } protected: @@ -87,10 +113,10 @@ protected: * Performs: * @code get_service().construct(get_implementation()); @endcode */ - explicit basic_io_object(boost::asio::io_service& io_service) - : service(boost::asio::use_service<IoObjectService>(io_service)) + explicit basic_io_object(boost::asio::io_context& io_context) + : service_(boost::asio::use_service<IoObjectService>(io_context)) { - service.construct(implementation); + service_.construct(implementation_); } #if defined(GENERATING_DOCUMENTATION) @@ -127,47 +153,42 @@ protected: */ ~basic_io_object() { - service.destroy(implementation); + service_.destroy(implementation_); } /// Get the service associated with the I/O object. service_type& get_service() { - return service; + return service_; } /// Get the service associated with the I/O object. const service_type& get_service() const { - return service; + return service_; } - /// (Deprecated: Use get_service().) The service associated with the I/O - /// object. - /** - * @note Available only for services that do not support movability. - */ - service_type& service; - /// Get the underlying implementation of the I/O object. implementation_type& get_implementation() { - return implementation; + return implementation_; } /// Get the underlying implementation of the I/O object. const implementation_type& get_implementation() const { - return implementation; + return implementation_; } - /// (Deprecated: Use get_implementation().) The underlying implementation of - /// the I/O object. - implementation_type implementation; - private: basic_io_object(const basic_io_object&); basic_io_object& operator=(const basic_io_object&); + + // The service associated with the I/O object. + service_type& service_; + + /// The underlying implementation of the I/O object. + implementation_type implementation_; }; #if defined(BOOST_ASIO_HAS_MOVE) @@ -179,43 +200,57 @@ public: typedef IoObjectService service_type; typedef typename service_type::implementation_type implementation_type; - boost::asio::io_service& get_io_service() +#if !defined(BOOST_ASIO_NO_DEPRECATED) + boost::asio::io_context& get_io_context() + { + return service_->get_io_context(); + } + + boost::asio::io_context& get_io_service() { - return service_->get_io_service(); + return service_->get_io_context(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + typedef boost::asio::io_context::executor_type executor_type; + + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return service_->get_io_context().get_executor(); } protected: - explicit basic_io_object(boost::asio::io_service& io_service) - : service_(&boost::asio::use_service<IoObjectService>(io_service)) + explicit basic_io_object(boost::asio::io_context& io_context) + : service_(&boost::asio::use_service<IoObjectService>(io_context)) { - service_->construct(implementation); + service_->construct(implementation_); } basic_io_object(basic_io_object&& other) : service_(&other.get_service()) { - service_->move_construct(implementation, other.implementation); + service_->move_construct(implementation_, other.implementation_); } template <typename IoObjectService1> basic_io_object(IoObjectService1& other_service, typename IoObjectService1::implementation_type& other_implementation) : service_(&boost::asio::use_service<IoObjectService>( - other_service.get_io_service())) + other_service.get_io_context())) { - service_->converting_move_construct(implementation, + service_->converting_move_construct(implementation_, other_service, other_implementation); } ~basic_io_object() { - service_->destroy(implementation); + service_->destroy(implementation_); } basic_io_object& operator=(basic_io_object&& other) { - service_->move_assign(implementation, - *other.service_, other.implementation); + service_->move_assign(implementation_, + *other.service_, other.implementation_); service_ = other.service_; return *this; } @@ -232,21 +267,20 @@ protected: implementation_type& get_implementation() { - return implementation; + return implementation_; } const implementation_type& get_implementation() const { - return implementation; + return implementation_; } - implementation_type implementation; - private: basic_io_object(const basic_io_object&); void operator=(const basic_io_object&); IoObjectService* service_; + implementation_type implementation_; }; #endif // defined(BOOST_ASIO_HAS_MOVE) diff --git a/boost/asio/basic_raw_socket.hpp b/boost/asio/basic_raw_socket.hpp index 85f8f42642..09058de224 100644 --- a/boost/asio/basic_raw_socket.hpp +++ b/boost/asio/basic_raw_socket.hpp @@ -22,7 +22,10 @@ #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/raw_socket_service.hpp> + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/raw_socket_service.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) #include <boost/asio/detail/push_options.hpp> @@ -38,18 +41,19 @@ namespace asio { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template <typename Protocol, - typename RawSocketService = raw_socket_service<Protocol> > +template <typename Protocol + BOOST_ASIO_SVC_TPARAM_DEF1(= raw_socket_service<Protocol>)> class basic_raw_socket - : public basic_socket<Protocol, RawSocketService> + : public basic_socket<Protocol BOOST_ASIO_SVC_TARG> { public: - /// (Deprecated: Use native_handle_type.) The native representation of a - /// socket. - typedef typename RawSocketService::native_handle_type native_type; - /// The native representation of a socket. - typedef typename RawSocketService::native_handle_type native_handle_type; +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef typename basic_socket< + Protocol BOOST_ASIO_SVC_TARG>::native_handle_type native_handle_type; +#endif /// The protocol type. typedef Protocol protocol_type; @@ -62,12 +66,12 @@ public: * This constructor creates a raw socket without opening it. The open() * function must be called before data can be sent or received on the socket. * - * @param io_service The io_service object that the raw socket will use + * @param io_context The io_context object that the raw socket will use * to dispatch handlers for any asynchronous operations performed on the * socket. */ - explicit basic_raw_socket(boost::asio::io_service& io_service) - : basic_socket<Protocol, RawSocketService>(io_service) + explicit basic_raw_socket(boost::asio::io_context& io_context) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(io_context) { } @@ -75,7 +79,7 @@ public: /** * This constructor creates and opens a raw socket. * - * @param io_service The io_service object that the raw socket will use + * @param io_context The io_context object that the raw socket will use * to dispatch handlers for any asynchronous operations performed on the * socket. * @@ -83,9 +87,9 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_raw_socket(boost::asio::io_service& io_service, + basic_raw_socket(boost::asio::io_context& io_context, const protocol_type& protocol) - : basic_socket<Protocol, RawSocketService>(io_service, protocol) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(io_context, protocol) { } @@ -96,7 +100,7 @@ public: * to the specified endpoint on the local machine. The protocol used is the * protocol associated with the given endpoint. * - * @param io_service The io_service object that the raw socket will use + * @param io_context The io_context object that the raw socket will use * to dispatch handlers for any asynchronous operations performed on the * socket. * @@ -105,9 +109,9 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_raw_socket(boost::asio::io_service& io_service, + basic_raw_socket(boost::asio::io_context& io_context, const endpoint_type& endpoint) - : basic_socket<Protocol, RawSocketService>(io_service, endpoint) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(io_context, endpoint) { } @@ -116,7 +120,7 @@ public: * This constructor creates a raw socket object to hold an existing * native socket. * - * @param io_service The io_service object that the raw socket will use + * @param io_context The io_context object that the raw socket will use * to dispatch handlers for any asynchronous operations performed on the * socket. * @@ -126,10 +130,10 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_raw_socket(boost::asio::io_service& io_service, + basic_raw_socket(boost::asio::io_context& io_context, const protocol_type& protocol, const native_handle_type& native_socket) - : basic_socket<Protocol, RawSocketService>( - io_service, protocol, native_socket) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>( + io_context, protocol, native_socket) { } @@ -142,11 +146,10 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_raw_socket(io_service&) constructor. + * constructed using the @c basic_raw_socket(io_context&) constructor. */ basic_raw_socket(basic_raw_socket&& other) - : basic_socket<Protocol, RawSocketService>( - BOOST_ASIO_MOVE_CAST(basic_raw_socket)(other)) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(std::move(other)) { } @@ -158,12 +161,11 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_raw_socket(io_service&) constructor. + * constructed using the @c basic_raw_socket(io_context&) constructor. */ basic_raw_socket& operator=(basic_raw_socket&& other) { - basic_socket<Protocol, RawSocketService>::operator=( - BOOST_ASIO_MOVE_CAST(basic_raw_socket)(other)); + basic_socket<Protocol BOOST_ASIO_SVC_TARG>::operator=(std::move(other)); return *this; } @@ -175,14 +177,12 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_raw_socket(io_service&) constructor. + * constructed using the @c basic_raw_socket(io_context&) constructor. */ - template <typename Protocol1, typename RawSocketService1> - basic_raw_socket(basic_raw_socket<Protocol1, RawSocketService1>&& other, + template <typename Protocol1 BOOST_ASIO_SVC_TPARAM1> + basic_raw_socket(basic_raw_socket<Protocol1 BOOST_ASIO_SVC_TARG1>&& other, typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0) - : basic_socket<Protocol, RawSocketService>( - BOOST_ASIO_MOVE_CAST2(basic_raw_socket< - Protocol1, RawSocketService1>)(other)) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(std::move(other)) { } @@ -194,20 +194,27 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_raw_socket(io_service&) constructor. + * constructed using the @c basic_raw_socket(io_context&) constructor. */ - template <typename Protocol1, typename RawSocketService1> + template <typename Protocol1 BOOST_ASIO_SVC_TPARAM1> typename enable_if<is_convertible<Protocol1, Protocol>::value, basic_raw_socket>::type& operator=( - basic_raw_socket<Protocol1, RawSocketService1>&& other) + basic_raw_socket<Protocol1 BOOST_ASIO_SVC_TARG1>&& other) { - basic_socket<Protocol, RawSocketService>::operator=( - BOOST_ASIO_MOVE_CAST2(basic_raw_socket< - Protocol1, RawSocketService1>)(other)); + basic_socket<Protocol BOOST_ASIO_SVC_TARG>::operator=(std::move(other)); return *this; } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Destroys the socket. + /** + * This function destroys the socket, cancelling any outstanding asynchronous + * operations associated with the socket as if by calling @c cancel. + */ + ~basic_raw_socket() + { + } + /// Send some data on a connected socket. /** * This function is used to send data on the raw socket. The function call @@ -310,7 +317,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The async_send operation can only be used with a connected socket. * Use the async_send_to function to send data on an unconnected raw @@ -335,8 +342,18 @@ public: // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_send(this->get_implementation(), buffers, 0, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_send(this->get_implementation(), + buffers, 0, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Start an asynchronous send on a connected socket. @@ -361,7 +378,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The async_send operation can only be used with a connected socket. * Use the async_send_to function to send data on an unconnected raw @@ -378,8 +395,18 @@ public: // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_send(this->get_implementation(), buffers, flags, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_send(this->get_implementation(), + buffers, flags, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Send raw data to the specified endpoint. @@ -493,7 +520,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * To send a single data buffer use the @ref buffer function as follows: @@ -518,8 +545,18 @@ public: // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_send_to(this->get_implementation(), buffers, destination, 0, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_send_to(this->get_implementation(), + buffers, destination, 0, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Start an asynchronous send. @@ -547,7 +584,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). */ template <typename ConstBufferSequence, typename WriteHandler> BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, @@ -560,9 +597,20 @@ public: // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_send_to( this->get_implementation(), buffers, destination, flags, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_send_to( + this->get_implementation(), buffers, destination, flags, + init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Receive some data on a connected socket. @@ -674,7 +722,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The async_receive operation can only be used with a connected socket. * Use the async_receive_from function to receive data on an unconnected @@ -700,8 +748,18 @@ public: // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_receive(this->get_implementation(), buffers, 0, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_receive(this->get_implementation(), + buffers, 0, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Start an asynchronous receive on a connected socket. @@ -726,7 +784,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The async_receive operation can only be used with a connected socket. * Use the async_receive_from function to receive data on an unconnected @@ -743,8 +801,18 @@ public: // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_receive(this->get_implementation(), buffers, flags, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_receive(this->get_implementation(), + buffers, flags, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Receive raw data with the endpoint of the sender. @@ -861,7 +929,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * To receive into a single data buffer use the @ref buffer function as @@ -883,9 +951,20 @@ public: // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_receive_from( this->get_implementation(), buffers, sender_endpoint, 0, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_receive_from( + this->get_implementation(), buffers, sender_endpoint, 0, + init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Start an asynchronous receive. @@ -915,7 +994,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). */ template <typename MutableBufferSequence, typename ReadHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, @@ -928,9 +1007,20 @@ public: // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_receive_from( this->get_implementation(), buffers, sender_endpoint, flags, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_receive_from( + this->get_implementation(), buffers, sender_endpoint, flags, + init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } }; diff --git a/boost/asio/basic_seq_packet_socket.hpp b/boost/asio/basic_seq_packet_socket.hpp index c8e43f77d6..a48a5b847e 100644 --- a/boost/asio/basic_seq_packet_socket.hpp +++ b/boost/asio/basic_seq_packet_socket.hpp @@ -21,7 +21,10 @@ #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/seq_packet_socket_service.hpp> + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/seq_packet_socket_service.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) #include <boost/asio/detail/push_options.hpp> @@ -37,19 +40,19 @@ namespace asio { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template <typename Protocol, - typename SeqPacketSocketService = seq_packet_socket_service<Protocol> > +template <typename Protocol + BOOST_ASIO_SVC_TPARAM_DEF1(= seq_packet_socket_service<Protocol>)> class basic_seq_packet_socket - : public basic_socket<Protocol, SeqPacketSocketService> + : public basic_socket<Protocol BOOST_ASIO_SVC_TARG> { public: - /// (Deprecated: Use native_handle_type.) The native representation of a - /// socket. - typedef typename SeqPacketSocketService::native_handle_type native_type; - /// The native representation of a socket. - typedef typename SeqPacketSocketService::native_handle_type - native_handle_type; +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef typename basic_socket< + Protocol BOOST_ASIO_SVC_TARG>::native_handle_type native_handle_type; +#endif /// The protocol type. typedef Protocol protocol_type; @@ -63,12 +66,12 @@ public: * socket needs to be opened and then connected or accepted before data can * be sent or received on it. * - * @param io_service The io_service object that the sequenced packet socket + * @param io_context The io_context object that the sequenced packet socket * will use to dispatch handlers for any asynchronous operations performed on * the socket. */ - explicit basic_seq_packet_socket(boost::asio::io_service& io_service) - : basic_socket<Protocol, SeqPacketSocketService>(io_service) + explicit basic_seq_packet_socket(boost::asio::io_context& io_context) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(io_context) { } @@ -78,7 +81,7 @@ public: * needs to be connected or accepted before data can be sent or received on * it. * - * @param io_service The io_service object that the sequenced packet socket + * @param io_context The io_context object that the sequenced packet socket * will use to dispatch handlers for any asynchronous operations performed on * the socket. * @@ -86,9 +89,9 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_seq_packet_socket(boost::asio::io_service& io_service, + basic_seq_packet_socket(boost::asio::io_context& io_context, const protocol_type& protocol) - : basic_socket<Protocol, SeqPacketSocketService>(io_service, protocol) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(io_context, protocol) { } @@ -99,7 +102,7 @@ public: * it bound to the specified endpoint on the local machine. The protocol used * is the protocol associated with the given endpoint. * - * @param io_service The io_service object that the sequenced packet socket + * @param io_context The io_context object that the sequenced packet socket * will use to dispatch handlers for any asynchronous operations performed on * the socket. * @@ -108,9 +111,9 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_seq_packet_socket(boost::asio::io_service& io_service, + basic_seq_packet_socket(boost::asio::io_context& io_context, const endpoint_type& endpoint) - : basic_socket<Protocol, SeqPacketSocketService>(io_service, endpoint) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(io_context, endpoint) { } @@ -119,7 +122,7 @@ public: * This constructor creates a sequenced packet socket object to hold an * existing native socket. * - * @param io_service The io_service object that the sequenced packet socket + * @param io_context The io_context object that the sequenced packet socket * will use to dispatch handlers for any asynchronous operations performed on * the socket. * @@ -129,10 +132,10 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_seq_packet_socket(boost::asio::io_service& io_service, + basic_seq_packet_socket(boost::asio::io_context& io_context, const protocol_type& protocol, const native_handle_type& native_socket) - : basic_socket<Protocol, SeqPacketSocketService>( - io_service, protocol, native_socket) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>( + io_context, protocol, native_socket) { } @@ -146,11 +149,10 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_seq_packet_socket(io_service&) constructor. + * constructed using the @c basic_seq_packet_socket(io_context&) constructor. */ basic_seq_packet_socket(basic_seq_packet_socket&& other) - : basic_socket<Protocol, SeqPacketSocketService>( - BOOST_ASIO_MOVE_CAST(basic_seq_packet_socket)(other)) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(std::move(other)) { } @@ -163,12 +165,11 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_seq_packet_socket(io_service&) constructor. + * constructed using the @c basic_seq_packet_socket(io_context&) constructor. */ basic_seq_packet_socket& operator=(basic_seq_packet_socket&& other) { - basic_socket<Protocol, SeqPacketSocketService>::operator=( - BOOST_ASIO_MOVE_CAST(basic_seq_packet_socket)(other)); + basic_socket<Protocol BOOST_ASIO_SVC_TARG>::operator=(std::move(other)); return *this; } @@ -182,15 +183,13 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_seq_packet_socket(io_service&) constructor. + * constructed using the @c basic_seq_packet_socket(io_context&) constructor. */ - template <typename Protocol1, typename SeqPacketSocketService1> + template <typename Protocol1 BOOST_ASIO_SVC_TPARAM1> basic_seq_packet_socket( - basic_seq_packet_socket<Protocol1, SeqPacketSocketService1>&& other, + basic_seq_packet_socket<Protocol1 BOOST_ASIO_SVC_TARG1>&& other, typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0) - : basic_socket<Protocol, SeqPacketSocketService>( - BOOST_ASIO_MOVE_CAST2(basic_seq_packet_socket< - Protocol1, SeqPacketSocketService1>)(other)) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(std::move(other)) { } @@ -204,20 +203,27 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_seq_packet_socket(io_service&) constructor. + * constructed using the @c basic_seq_packet_socket(io_context&) constructor. */ - template <typename Protocol1, typename SeqPacketSocketService1> + template <typename Protocol1 BOOST_ASIO_SVC_TPARAM1> typename enable_if<is_convertible<Protocol1, Protocol>::value, basic_seq_packet_socket>::type& operator=( - basic_seq_packet_socket<Protocol1, SeqPacketSocketService1>&& other) + basic_seq_packet_socket<Protocol1 BOOST_ASIO_SVC_TARG1>&& other) { - basic_socket<Protocol, SeqPacketSocketService>::operator=( - BOOST_ASIO_MOVE_CAST2(basic_seq_packet_socket< - Protocol1, SeqPacketSocketService1>)(other)); + basic_socket<Protocol BOOST_ASIO_SVC_TARG>::operator=(std::move(other)); return *this; } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Destroys the socket. + /** + * This function destroys the socket, cancelling any outstanding asynchronous + * operations associated with the socket as if by calling @c cancel. + */ + ~basic_seq_packet_socket() + { + } + /// Send some data on the socket. /** * This function is used to send data on the sequenced packet socket. The @@ -300,7 +306,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * To send a single data buffer use the @ref buffer function as follows: @@ -322,8 +328,18 @@ public: // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_send(this->get_implementation(), buffers, flags, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_send(this->get_implementation(), + buffers, flags, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Receive some data on the socket. @@ -360,8 +376,13 @@ public: socket_base::message_flags& out_flags) { boost::system::error_code ec; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) std::size_t s = this->get_service().receive( this->get_implementation(), buffers, 0, out_flags, ec); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + std::size_t s = this->get_service().receive_with_flags( + this->get_implementation(), buffers, 0, out_flags, ec); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) boost::asio::detail::throw_error(ec, "receive"); return s; } @@ -407,8 +428,13 @@ public: socket_base::message_flags& out_flags) { boost::system::error_code ec; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) std::size_t s = this->get_service().receive( this->get_implementation(), buffers, in_flags, out_flags, ec); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + std::size_t s = this->get_service().receive_with_flags( + this->get_implementation(), buffers, in_flags, out_flags, ec); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) boost::asio::detail::throw_error(ec, "receive"); return s; } @@ -441,8 +467,13 @@ public: socket_base::message_flags in_flags, socket_base::message_flags& out_flags, boost::system::error_code& ec) { +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().receive(this->get_implementation(), buffers, in_flags, out_flags, ec); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + return this->get_service().receive_with_flags(this->get_implementation(), + buffers, in_flags, out_flags, ec); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Start an asynchronous receive. @@ -471,7 +502,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * To receive into a single data buffer use the @ref buffer function as @@ -494,9 +525,20 @@ public: // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_receive( this->get_implementation(), buffers, 0, out_flags, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_receive_with_flags( + this->get_implementation(), buffers, 0, out_flags, + init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Start an asynchronous receive. @@ -527,7 +569,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * To receive into a single data buffer use the @ref buffer function as @@ -553,9 +595,20 @@ public: // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_receive( this->get_implementation(), buffers, in_flags, out_flags, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_receive_with_flags( + this->get_implementation(), buffers, in_flags, out_flags, + init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } }; diff --git a/boost/asio/basic_serial_port.hpp b/boost/asio/basic_serial_port.hpp index bfc78afaf6..af2193f7cb 100644 --- a/boost/asio/basic_serial_port.hpp +++ b/boost/asio/basic_serial_port.hpp @@ -18,6 +18,8 @@ #include <boost/asio/detail/config.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) @@ -49,10 +51,6 @@ class basic_serial_port public serial_port_base { public: - /// (Deprecated: Use native_handle_type.) The native representation of a - /// serial port. - typedef typename SerialPortService::native_handle_type native_type; - /// The native representation of a serial port. typedef typename SerialPortService::native_handle_type native_handle_type; @@ -63,11 +61,11 @@ public: /** * This constructor creates a serial port without opening it. * - * @param io_service The io_service object that the serial port will use to + * @param io_context The io_context object that the serial port will use to * dispatch handlers for any asynchronous operations performed on the port. */ - explicit basic_serial_port(boost::asio::io_service& io_service) - : basic_io_object<SerialPortService>(io_service) + explicit basic_serial_port(boost::asio::io_context& io_context) + : basic_io_object<SerialPortService>(io_context) { } @@ -76,15 +74,15 @@ public: * This constructor creates and opens a serial port for the specified device * name. * - * @param io_service The io_service object that the serial port will use to + * @param io_context The io_context object that the serial port will use to * dispatch handlers for any asynchronous operations performed on the port. * * @param device The platform-specific device name for this serial * port. */ - explicit basic_serial_port(boost::asio::io_service& io_service, + explicit basic_serial_port(boost::asio::io_context& io_context, const char* device) - : basic_io_object<SerialPortService>(io_service) + : basic_io_object<SerialPortService>(io_context) { boost::system::error_code ec; this->get_service().open(this->get_implementation(), device, ec); @@ -96,15 +94,15 @@ public: * This constructor creates and opens a serial port for the specified device * name. * - * @param io_service The io_service object that the serial port will use to + * @param io_context The io_context object that the serial port will use to * dispatch handlers for any asynchronous operations performed on the port. * * @param device The platform-specific device name for this serial * port. */ - explicit basic_serial_port(boost::asio::io_service& io_service, + explicit basic_serial_port(boost::asio::io_context& io_context, const std::string& device) - : basic_io_object<SerialPortService>(io_service) + : basic_io_object<SerialPortService>(io_context) { boost::system::error_code ec; this->get_service().open(this->get_implementation(), device, ec); @@ -116,16 +114,16 @@ public: * This constructor creates a serial port object to hold an existing native * serial port. * - * @param io_service The io_service object that the serial port will use to + * @param io_context The io_context object that the serial port will use to * dispatch handlers for any asynchronous operations performed on the port. * * @param native_serial_port A native serial port. * * @throws boost::system::system_error Thrown on failure. */ - basic_serial_port(boost::asio::io_service& io_service, + basic_serial_port(boost::asio::io_context& io_context, const native_handle_type& native_serial_port) - : basic_io_object<SerialPortService>(io_service) + : basic_io_object<SerialPortService>(io_context) { boost::system::error_code ec; this->get_service().assign(this->get_implementation(), @@ -142,7 +140,7 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_serial_port(io_service&) constructor. + * constructed using the @c basic_serial_port(io_context&) constructor. */ basic_serial_port(basic_serial_port&& other) : basic_io_object<SerialPortService>( @@ -158,7 +156,7 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_serial_port(io_service&) constructor. + * constructed using the @c basic_serial_port(io_context&) constructor. */ basic_serial_port& operator=(basic_serial_port&& other) { @@ -220,10 +218,11 @@ public: * * @param ec Set the indicate what error occurred, if any. */ - boost::system::error_code open(const std::string& device, + BOOST_ASIO_SYNC_OP_VOID open(const std::string& device, boost::system::error_code& ec) { - return this->get_service().open(this->get_implementation(), device, ec); + this->get_service().open(this->get_implementation(), device, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Assign an existing native serial port to the serial port. @@ -250,11 +249,12 @@ public: * * @param ec Set to indicate what error occurred, if any. */ - boost::system::error_code assign(const native_handle_type& native_serial_port, + BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& native_serial_port, boost::system::error_code& ec) { - return this->get_service().assign(this->get_implementation(), + this->get_service().assign(this->get_implementation(), native_serial_port, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the serial port is open. @@ -286,21 +286,10 @@ public: * * @param ec Set to indicate what error occurred, if any. */ - boost::system::error_code close(boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) { - return this->get_service().close(this->get_implementation(), ec); - } - - /// (Deprecated: Use native_handle().) Get the native serial port - /// representation. - /** - * This function may be used to obtain the underlying representation of the - * serial port. This is intended to allow access to native serial port - * functionality that is not otherwise provided. - */ - native_type native() - { - return this->get_service().native_handle(this->get_implementation()); + this->get_service().close(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get the native serial port representation. @@ -337,9 +326,10 @@ public: * * @param ec Set to indicate what error occurred, if any. */ - boost::system::error_code cancel(boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) { - return this->get_service().cancel(this->get_implementation(), ec); + this->get_service().cancel(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Send a break sequence to the serial port. @@ -363,9 +353,10 @@ public: * * @param ec Set to indicate what error occurred, if any. */ - boost::system::error_code send_break(boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID send_break(boost::system::error_code& ec) { - return this->get_service().send_break(this->get_implementation(), ec); + this->get_service().send_break(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Set an option on the serial port. @@ -407,11 +398,11 @@ public: * boost::asio::serial_port_base::character_size */ template <typename SettableSerialPortOption> - boost::system::error_code set_option(const SettableSerialPortOption& option, + BOOST_ASIO_SYNC_OP_VOID set_option(const SettableSerialPortOption& option, boost::system::error_code& ec) { - return this->get_service().set_option( - this->get_implementation(), option, ec); + this->get_service().set_option(this->get_implementation(), option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get an option from the serial port. @@ -455,11 +446,11 @@ public: * boost::asio::serial_port_base::character_size */ template <typename GettableSerialPortOption> - boost::system::error_code get_option(GettableSerialPortOption& option, + BOOST_ASIO_SYNC_OP_VOID get_option(GettableSerialPortOption& option, boost::system::error_code& ec) { - return this->get_service().get_option( - this->get_implementation(), option, ec); + this->get_service().get_option(this->get_implementation(), option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Write some data to the serial port. @@ -543,7 +534,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The write operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all @@ -655,7 +646,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The read operation may not read all of the requested number of bytes. * Consider using the @ref async_read function if you need to ensure that the @@ -694,4 +685,6 @@ public: #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_BASIC_SERIAL_PORT_HPP diff --git a/boost/asio/basic_signal_set.hpp b/boost/asio/basic_signal_set.hpp index 608bc0a6d8..3c00fa6e26 100644 --- a/boost/asio/basic_signal_set.hpp +++ b/boost/asio/basic_signal_set.hpp @@ -17,6 +17,8 @@ #include <boost/asio/detail/config.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #include <boost/asio/basic_io_object.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/throw_error.hpp> @@ -55,7 +57,7 @@ namespace asio { * ... * * // Construct a signal set registered for process termination. - * boost::asio::signal_set signals(io_service, SIGINT, SIGTERM); + * boost::asio::signal_set signals(io_context, SIGINT, SIGTERM); * * // Start an asynchronous wait for one of the signals to occur. * signals.async_wait(handler); @@ -99,11 +101,11 @@ public: /** * This constructor creates a signal set without registering for any signals. * - * @param io_service The io_service object that the signal set will use to + * @param io_context The io_context object that the signal set will use to * dispatch handlers for any asynchronous operations performed on the set. */ - explicit basic_signal_set(boost::asio::io_service& io_service) - : basic_io_object<SignalSetService>(io_service) + explicit basic_signal_set(boost::asio::io_context& io_context) + : basic_io_object<SignalSetService>(io_context) { } @@ -111,20 +113,20 @@ public: /** * This constructor creates a signal set and registers for one signal. * - * @param io_service The io_service object that the signal set will use to + * @param io_context The io_context object that the signal set will use to * dispatch handlers for any asynchronous operations performed on the set. * * @param signal_number_1 The signal number to be added. * * @note This constructor is equivalent to performing: - * @code boost::asio::signal_set signals(io_service); + * @code boost::asio::signal_set signals(io_context); * signals.add(signal_number_1); @endcode */ - basic_signal_set(boost::asio::io_service& io_service, int signal_number_1) - : basic_io_object<SignalSetService>(io_service) + basic_signal_set(boost::asio::io_context& io_context, int signal_number_1) + : basic_io_object<SignalSetService>(io_context) { boost::system::error_code ec; - this->service.add(this->implementation, signal_number_1, ec); + this->get_service().add(this->get_implementation(), signal_number_1, ec); boost::asio::detail::throw_error(ec, "add"); } @@ -132,7 +134,7 @@ public: /** * This constructor creates a signal set and registers for two signals. * - * @param io_service The io_service object that the signal set will use to + * @param io_context The io_context object that the signal set will use to * dispatch handlers for any asynchronous operations performed on the set. * * @param signal_number_1 The first signal number to be added. @@ -140,18 +142,18 @@ public: * @param signal_number_2 The second signal number to be added. * * @note This constructor is equivalent to performing: - * @code boost::asio::signal_set signals(io_service); + * @code boost::asio::signal_set signals(io_context); * signals.add(signal_number_1); * signals.add(signal_number_2); @endcode */ - basic_signal_set(boost::asio::io_service& io_service, int signal_number_1, + basic_signal_set(boost::asio::io_context& io_context, int signal_number_1, int signal_number_2) - : basic_io_object<SignalSetService>(io_service) + : basic_io_object<SignalSetService>(io_context) { boost::system::error_code ec; - this->service.add(this->implementation, signal_number_1, ec); + this->get_service().add(this->get_implementation(), signal_number_1, ec); boost::asio::detail::throw_error(ec, "add"); - this->service.add(this->implementation, signal_number_2, ec); + this->get_service().add(this->get_implementation(), signal_number_2, ec); boost::asio::detail::throw_error(ec, "add"); } @@ -159,7 +161,7 @@ public: /** * This constructor creates a signal set and registers for three signals. * - * @param io_service The io_service object that the signal set will use to + * @param io_context The io_context object that the signal set will use to * dispatch handlers for any asynchronous operations performed on the set. * * @param signal_number_1 The first signal number to be added. @@ -169,21 +171,21 @@ public: * @param signal_number_3 The third signal number to be added. * * @note This constructor is equivalent to performing: - * @code boost::asio::signal_set signals(io_service); + * @code boost::asio::signal_set signals(io_context); * signals.add(signal_number_1); * signals.add(signal_number_2); * signals.add(signal_number_3); @endcode */ - basic_signal_set(boost::asio::io_service& io_service, int signal_number_1, + basic_signal_set(boost::asio::io_context& io_context, int signal_number_1, int signal_number_2, int signal_number_3) - : basic_io_object<SignalSetService>(io_service) + : basic_io_object<SignalSetService>(io_context) { boost::system::error_code ec; - this->service.add(this->implementation, signal_number_1, ec); + this->get_service().add(this->get_implementation(), signal_number_1, ec); boost::asio::detail::throw_error(ec, "add"); - this->service.add(this->implementation, signal_number_2, ec); + this->get_service().add(this->get_implementation(), signal_number_2, ec); boost::asio::detail::throw_error(ec, "add"); - this->service.add(this->implementation, signal_number_3, ec); + this->get_service().add(this->get_implementation(), signal_number_3, ec); boost::asio::detail::throw_error(ec, "add"); } @@ -199,7 +201,7 @@ public: void add(int signal_number) { boost::system::error_code ec; - this->service.add(this->implementation, signal_number, ec); + this->get_service().add(this->get_implementation(), signal_number, ec); boost::asio::detail::throw_error(ec, "add"); } @@ -212,10 +214,10 @@ public: * * @param ec Set to indicate what error occurred, if any. */ - boost::system::error_code add(int signal_number, - boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID add(int signal_number, boost::system::error_code& ec) { - return this->service.add(this->implementation, signal_number, ec); + this->get_service().add(this->get_implementation(), signal_number, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Remove a signal from a signal_set. @@ -233,7 +235,7 @@ public: void remove(int signal_number) { boost::system::error_code ec; - this->service.remove(this->implementation, signal_number, ec); + this->get_service().remove(this->get_implementation(), signal_number, ec); boost::asio::detail::throw_error(ec, "remove"); } @@ -249,10 +251,11 @@ public: * @note Removes any notifications that have been queued for the specified * signal number. */ - boost::system::error_code remove(int signal_number, + BOOST_ASIO_SYNC_OP_VOID remove(int signal_number, boost::system::error_code& ec) { - return this->service.remove(this->implementation, signal_number, ec); + this->get_service().remove(this->get_implementation(), signal_number, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Remove all signals from a signal_set. @@ -267,7 +270,7 @@ public: void clear() { boost::system::error_code ec; - this->service.clear(this->implementation, ec); + this->get_service().clear(this->get_implementation(), ec); boost::asio::detail::throw_error(ec, "clear"); } @@ -280,9 +283,10 @@ public: * * @note Removes all queued notifications. */ - boost::system::error_code clear(boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID clear(boost::system::error_code& ec) { - return this->service.clear(this->implementation, ec); + this->get_service().clear(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Cancel all operations associated with the signal set. @@ -309,7 +313,7 @@ public: void cancel() { boost::system::error_code ec; - this->service.cancel(this->implementation, ec); + this->get_service().cancel(this->get_implementation(), ec); boost::asio::detail::throw_error(ec, "cancel"); } @@ -334,9 +338,10 @@ public: * These handlers can no longer be cancelled, and therefore are passed an * error code that indicates the successful completion of the wait operation. */ - boost::system::error_code cancel(boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) { - return this->service.cancel(this->implementation, ec); + this->get_service().cancel(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Start an asynchronous operation to wait for a signal to be delivered. @@ -362,7 +367,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). */ template <typename SignalHandler> BOOST_ASIO_INITFN_RESULT_TYPE(SignalHandler, @@ -373,7 +378,7 @@ public: // not meet the documented type requirements for a SignalHandler. BOOST_ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check; - return this->service.async_wait(this->implementation, + return this->get_service().async_wait(this->get_implementation(), BOOST_ASIO_MOVE_CAST(SignalHandler)(handler)); } }; @@ -383,4 +388,6 @@ public: #include <boost/asio/detail/pop_options.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_BASIC_SIGNAL_SET_HPP diff --git a/boost/asio/basic_socket.hpp b/boost/asio/basic_socket.hpp index 777f6a9ce1..cf51470690 100644 --- a/boost/asio/basic_socket.hpp +++ b/boost/asio/basic_socket.hpp @@ -22,8 +22,26 @@ #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> +#include <boost/asio/post.hpp> #include <boost/asio/socket_base.hpp> +#if defined(BOOST_ASIO_HAS_MOVE) +# include <utility> +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#if !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include <boost/asio/detail/winrt_ssocket_service.hpp> +# define BOOST_ASIO_SVC_T detail::winrt_ssocket_service<Protocol> +# elif defined(BOOST_ASIO_HAS_IOCP) +# include <boost/asio/detail/win_iocp_socket_service.hpp> +# define BOOST_ASIO_SVC_T detail::win_iocp_socket_service<Protocol> +# else +# include <boost/asio/detail/reactive_socket_service.hpp> +# define BOOST_ASIO_SVC_T detail::reactive_socket_service<Protocol> +# endif +#endif // !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #include <boost/asio/detail/push_options.hpp> namespace boost { @@ -38,18 +56,21 @@ namespace asio { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template <typename Protocol, typename SocketService> +template <typename Protocol BOOST_ASIO_SVC_TPARAM> class basic_socket - : public basic_io_object<SocketService>, + : BOOST_ASIO_SVC_ACCESS basic_io_object<BOOST_ASIO_SVC_T>, public socket_base { public: - /// (Deprecated: Use native_handle_type.) The native representation of a - /// socket. - typedef typename SocketService::native_handle_type native_type; + /// The type of the executor associated with the object. + typedef io_context::executor_type executor_type; /// The native representation of a socket. - typedef typename SocketService::native_handle_type native_handle_type; +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef typename BOOST_ASIO_SVC_T::native_handle_type native_handle_type; +#endif /// The protocol type. typedef Protocol protocol_type; @@ -57,18 +78,20 @@ public: /// The endpoint type. typedef typename Protocol::endpoint endpoint_type; +#if !defined(BOOST_ASIO_NO_EXTENSIONS) /// A basic_socket is always the lowest layer. - typedef basic_socket<Protocol, SocketService> lowest_layer_type; + typedef basic_socket<Protocol BOOST_ASIO_SVC_TARG> lowest_layer_type; +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) /// Construct a basic_socket without opening it. /** * This constructor creates a socket without opening it. * - * @param io_service The io_service object that the socket will use to + * @param io_context The io_context object that the socket will use to * dispatch handlers for any asynchronous operations performed on the socket. */ - explicit basic_socket(boost::asio::io_service& io_service) - : basic_io_object<SocketService>(io_service) + explicit basic_socket(boost::asio::io_context& io_context) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) { } @@ -76,16 +99,16 @@ public: /** * This constructor creates and opens a socket. * - * @param io_service The io_service object that the socket will use to + * @param io_context The io_context object that the socket will use to * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. * * @throws boost::system::system_error Thrown on failure. */ - basic_socket(boost::asio::io_service& io_service, + basic_socket(boost::asio::io_context& io_context, const protocol_type& protocol) - : basic_io_object<SocketService>(io_service) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) { boost::system::error_code ec; this->get_service().open(this->get_implementation(), protocol, ec); @@ -99,7 +122,7 @@ public: * specified endpoint on the local machine. The protocol used is the protocol * associated with the given endpoint. * - * @param io_service The io_service object that the socket will use to + * @param io_context The io_context object that the socket will use to * dispatch handlers for any asynchronous operations performed on the socket. * * @param endpoint An endpoint on the local machine to which the socket will @@ -107,9 +130,9 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_socket(boost::asio::io_service& io_service, + basic_socket(boost::asio::io_context& io_context, const endpoint_type& endpoint) - : basic_io_object<SocketService>(io_service) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) { boost::system::error_code ec; const protocol_type protocol = endpoint.protocol(); @@ -123,7 +146,7 @@ public: /** * This constructor creates a socket object to hold an existing native socket. * - * @param io_service The io_service object that the socket will use to + * @param io_context The io_context object that the socket will use to * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. @@ -132,9 +155,9 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_socket(boost::asio::io_service& io_service, + basic_socket(boost::asio::io_context& io_context, const protocol_type& protocol, const native_handle_type& native_socket) - : basic_io_object<SocketService>(io_service) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) { boost::system::error_code ec; this->get_service().assign(this->get_implementation(), @@ -151,11 +174,10 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket(io_service&) constructor. + * constructed using the @c basic_socket(io_context&) constructor. */ basic_socket(basic_socket&& other) - : basic_io_object<SocketService>( - BOOST_ASIO_MOVE_CAST(basic_socket)(other)) + : basic_io_object<BOOST_ASIO_SVC_T>(std::move(other)) { } @@ -167,17 +189,16 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket(io_service&) constructor. + * constructed using the @c basic_socket(io_context&) constructor. */ basic_socket& operator=(basic_socket&& other) { - basic_io_object<SocketService>::operator=( - BOOST_ASIO_MOVE_CAST(basic_socket)(other)); + basic_io_object<BOOST_ASIO_SVC_T>::operator=(std::move(other)); return *this; } // All sockets have access to each other's implementations. - template <typename Protocol1, typename SocketService1> + template <typename Protocol1 BOOST_ASIO_SVC_TPARAM1> friend class basic_socket; /// Move-construct a basic_socket from a socket of another protocol type. @@ -188,12 +209,12 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket(io_service&) constructor. + * constructed using the @c basic_socket(io_context&) constructor. */ - template <typename Protocol1, typename SocketService1> - basic_socket(basic_socket<Protocol1, SocketService1>&& other, + template <typename Protocol1 BOOST_ASIO_SVC_TPARAM1> + basic_socket(basic_socket<Protocol1 BOOST_ASIO_SVC_TARG1>&& other, typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0) - : basic_io_object<SocketService>( + : basic_io_object<BOOST_ASIO_SVC_T>( other.get_service(), other.get_implementation()) { } @@ -206,21 +227,60 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket(io_service&) constructor. + * constructed using the @c basic_socket(io_context&) constructor. */ - template <typename Protocol1, typename SocketService1> + template <typename Protocol1 BOOST_ASIO_SVC_TPARAM1> typename enable_if<is_convertible<Protocol1, Protocol>::value, basic_socket>::type& operator=( - basic_socket<Protocol1, SocketService1>&& other) + basic_socket<Protocol1 BOOST_ASIO_SVC_TARG1>&& other) { - basic_socket tmp(BOOST_ASIO_MOVE_CAST2(basic_socket< - Protocol1, SocketService1>)(other)); - basic_io_object<SocketService>::operator=( - BOOST_ASIO_MOVE_CAST(basic_socket)(tmp)); + basic_socket tmp(std::move(other)); + basic_io_object<BOOST_ASIO_SVC_T>::operator=(std::move(tmp)); return *this; } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + // These functions are provided by basic_io_object<>. +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_context() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_service() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_service(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_executor(); + } +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) /// Get a reference to the lowest layer. /** * This function returns a reference to the lowest layer in a stack of @@ -248,6 +308,7 @@ public: { return *this; } +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) /// Open the socket using the specified protocol. /** @@ -259,7 +320,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * socket.open(boost::asio::ip::tcp::v4()); * @endcode */ @@ -280,7 +341,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * boost::system::error_code ec; * socket.open(boost::asio::ip::tcp::v4(), ec); * if (ec) @@ -289,10 +350,11 @@ public: * } * @endcode */ - boost::system::error_code open(const protocol_type& protocol, + BOOST_ASIO_SYNC_OP_VOID open(const protocol_type& protocol, boost::system::error_code& ec) { - return this->get_service().open(this->get_implementation(), protocol, ec); + this->get_service().open(this->get_implementation(), protocol, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Assign an existing native socket to the socket. @@ -324,11 +386,12 @@ public: * * @param ec Set to indicate what error occurred, if any. */ - boost::system::error_code assign(const protocol_type& protocol, + BOOST_ASIO_SYNC_OP_VOID assign(const protocol_type& protocol, const native_handle_type& native_socket, boost::system::error_code& ec) { - return this->get_service().assign(this->get_implementation(), + this->get_service().assign(this->get_implementation(), protocol, native_socket, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the socket is open. @@ -367,7 +430,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::system::error_code ec; * socket.close(ec); @@ -380,20 +443,62 @@ public: * @note For portable behaviour with respect to graceful closure of a * connected socket, call shutdown() before closing the socket. */ - boost::system::error_code close(boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) { - return this->get_service().close(this->get_implementation(), ec); + this->get_service().close(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } - /// (Deprecated: Use native_handle().) Get the native socket representation. + /// Release ownership of the underlying native socket. /** - * This function may be used to obtain the underlying representation of the - * socket. This is intended to allow access to native socket functionality - * that is not otherwise provided. + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the boost::asio::error::operation_aborted error. Ownership + * of the native socket is then transferred to the caller. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with boost::asio::error::operation_not_supported on + * these platforms. + */ +#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release() + { + boost::system::error_code ec; + native_handle_type s = this->get_service().release( + this->get_implementation(), ec); + boost::asio::detail::throw_error(ec, "release"); + return s; + } + + /// Release ownership of the underlying native socket. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the boost::asio::error::operation_aborted error. Ownership + * of the native socket is then transferred to the caller. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with boost::asio::error::operation_not_supported on + * these platforms. */ - native_type native() +#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release(boost::system::error_code& ec) { - return this->get_service().native_handle(this->get_implementation()); + return this->get_service().release(this->get_implementation(), ec); } /// Get the native socket representation. @@ -496,9 +601,10 @@ public: "operation_not_supported when used on Windows XP, Windows Server 2003, " "or earlier. Consult documentation for details.")) #endif - boost::system::error_code cancel(boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) { - return this->get_service().cancel(this->get_implementation(), ec); + this->get_service().cancel(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the socket is at the out-of-band data mark. @@ -580,7 +686,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * socket.open(boost::asio::ip::tcp::v4()); * socket.bind(boost::asio::ip::tcp::endpoint( * boost::asio::ip::tcp::v4(), 12345)); @@ -605,7 +711,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * socket.open(boost::asio::ip::tcp::v4()); * boost::system::error_code ec; * socket.bind(boost::asio::ip::tcp::endpoint( @@ -616,10 +722,11 @@ public: * } * @endcode */ - boost::system::error_code bind(const endpoint_type& endpoint, + BOOST_ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint, boost::system::error_code& ec) { - return this->get_service().bind(this->get_implementation(), endpoint, ec); + this->get_service().bind(this->get_implementation(), endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Connect the socket to the specified endpoint. @@ -639,7 +746,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * boost::asio::ip::tcp::endpoint endpoint( * boost::asio::ip::address::from_string("1.2.3.4"), 12345); * socket.connect(endpoint); @@ -675,7 +782,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * boost::asio::ip::tcp::endpoint endpoint( * boost::asio::ip::address::from_string("1.2.3.4"), 12345); * boost::system::error_code ec; @@ -686,20 +793,21 @@ public: * } * @endcode */ - boost::system::error_code connect(const endpoint_type& peer_endpoint, + BOOST_ASIO_SYNC_OP_VOID connect(const endpoint_type& peer_endpoint, boost::system::error_code& ec) { if (!is_open()) { - if (this->get_service().open(this->get_implementation(), - peer_endpoint.protocol(), ec)) + this->get_service().open(this->get_implementation(), + peer_endpoint.protocol(), ec); + if (ec) { - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } - return this->get_service().connect( - this->get_implementation(), peer_endpoint, ec); + this->get_service().connect(this->get_implementation(), peer_endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Start an asynchronous connect. @@ -723,7 +831,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * @code @@ -737,7 +845,7 @@ public: * * ... * - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * boost::asio::ip::tcp::endpoint endpoint( * boost::asio::ip::address::from_string("1.2.3.4"), 12345); * socket.async_connect(endpoint, connect_handler); @@ -757,24 +865,34 @@ public: { boost::system::error_code ec; const protocol_type protocol = peer_endpoint.protocol(); - if (this->get_service().open(this->get_implementation(), protocol, ec)) + this->get_service().open(this->get_implementation(), protocol, ec); + if (ec) { - detail::async_result_init< - ConnectHandler, void (boost::system::error_code)> init( - BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler)); + async_completion<ConnectHandler, + void (boost::system::error_code)> init(handler); - this->get_io_service().post( + boost::asio::post(this->get_executor(), boost::asio::detail::bind_handler( BOOST_ASIO_MOVE_CAST(BOOST_ASIO_HANDLER_TYPE( ConnectHandler, void (boost::system::error_code)))( - init.handler), ec)); + init.completion_handler), ec)); return init.result.get(); } } +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_connect(this->get_implementation(), peer_endpoint, BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<ConnectHandler, + void (boost::system::error_code)> init(handler); + + this->get_service().async_connect( + this->get_implementation(), peer_endpoint, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Set an option on the socket. @@ -805,7 +923,7 @@ public: * @par Example * Setting the IPPROTO_TCP/TCP_NODELAY option: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::ip::tcp::no_delay option(true); * socket.set_option(option); @@ -847,7 +965,7 @@ public: * @par Example * Setting the IPPROTO_TCP/TCP_NODELAY option: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::ip::tcp::no_delay option(true); * boost::system::error_code ec; @@ -859,11 +977,11 @@ public: * @endcode */ template <typename SettableSocketOption> - boost::system::error_code set_option(const SettableSocketOption& option, + BOOST_ASIO_SYNC_OP_VOID set_option(const SettableSocketOption& option, boost::system::error_code& ec) { - return this->get_service().set_option( - this->get_implementation(), option, ec); + this->get_service().set_option(this->get_implementation(), option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get an option from the socket. @@ -894,7 +1012,7 @@ public: * @par Example * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::ip::tcp::socket::keep_alive option; * socket.get_option(option); @@ -937,7 +1055,7 @@ public: * @par Example * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::ip::tcp::socket::keep_alive option; * boost::system::error_code ec; @@ -950,11 +1068,11 @@ public: * @endcode */ template <typename GettableSocketOption> - boost::system::error_code get_option(GettableSocketOption& option, + BOOST_ASIO_SYNC_OP_VOID get_option(GettableSocketOption& option, boost::system::error_code& ec) const { - return this->get_service().get_option( - this->get_implementation(), option, ec); + this->get_service().get_option(this->get_implementation(), option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Perform an IO control command on the socket. @@ -972,7 +1090,7 @@ public: * @par Example * Getting the number of bytes ready to read: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::ip::tcp::socket::bytes_readable command; * socket.io_control(command); @@ -1002,7 +1120,7 @@ public: * @par Example * Getting the number of bytes ready to read: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::ip::tcp::socket::bytes_readable command; * boost::system::error_code ec; @@ -1015,11 +1133,11 @@ public: * @endcode */ template <typename IoControlCommand> - boost::system::error_code io_control(IoControlCommand& command, + BOOST_ASIO_SYNC_OP_VOID io_control(IoControlCommand& command, boost::system::error_code& ec) { - return this->get_service().io_control( - this->get_implementation(), command, ec); + this->get_service().io_control(this->get_implementation(), command, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the socket. @@ -1071,11 +1189,11 @@ public: * operations. Asynchronous operations will never fail with the error * boost::asio::error::would_block. */ - boost::system::error_code non_blocking( + BOOST_ASIO_SYNC_OP_VOID non_blocking( bool mode, boost::system::error_code& ec) { - return this->get_service().non_blocking( - this->get_implementation(), mode, ec); + this->get_service().non_blocking(this->get_implementation(), mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the native socket implementation. @@ -1135,7 +1253,7 @@ public: * || ec == boost::asio::error::try_again) * { * // We have to wait for the socket to become ready again. - * sock_.async_write_some(boost::asio::null_buffers(), *this); + * sock_.async_wait(tcp::socket::wait_write, *this); * return; * } * @@ -1159,7 +1277,7 @@ public: * void async_sendfile(tcp::socket& sock, int fd, Handler h) * { * sendfile_op<Handler> op = { sock, fd, h, 0, 0 }; - * sock.async_write_some(boost::asio::null_buffers(), op); + * sock.async_wait(tcp::socket::wait_write, op); * } @endcode */ bool native_non_blocking() const @@ -1225,7 +1343,7 @@ public: * || ec == boost::asio::error::try_again) * { * // We have to wait for the socket to become ready again. - * sock_.async_write_some(boost::asio::null_buffers(), *this); + * sock_.async_wait(tcp::socket::wait_write, *this); * return; * } * @@ -1249,7 +1367,7 @@ public: * void async_sendfile(tcp::socket& sock, int fd, Handler h) * { * sendfile_op<Handler> op = { sock, fd, h, 0, 0 }; - * sock.async_write_some(boost::asio::null_buffers(), op); + * sock.async_wait(tcp::socket::wait_write, op); * } @endcode */ void native_non_blocking(bool mode) @@ -1318,7 +1436,7 @@ public: * || ec == boost::asio::error::try_again) * { * // We have to wait for the socket to become ready again. - * sock_.async_write_some(boost::asio::null_buffers(), *this); + * sock_.async_wait(tcp::socket::wait_write, *this); * return; * } * @@ -1342,14 +1460,15 @@ public: * void async_sendfile(tcp::socket& sock, int fd, Handler h) * { * sendfile_op<Handler> op = { sock, fd, h, 0, 0 }; - * sock.async_write_some(boost::asio::null_buffers(), op); + * sock.async_wait(tcp::socket::wait_write, op); * } @endcode */ - boost::system::error_code native_non_blocking( + BOOST_ASIO_SYNC_OP_VOID native_non_blocking( bool mode, boost::system::error_code& ec) { - return this->get_service().native_non_blocking( + this->get_service().native_non_blocking( this->get_implementation(), mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get the local endpoint of the socket. @@ -1362,7 +1481,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::ip::tcp::endpoint endpoint = socket.local_endpoint(); * @endcode @@ -1387,7 +1506,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::system::error_code ec; * boost::asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec); @@ -1412,7 +1531,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(); * @endcode @@ -1437,7 +1556,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::system::error_code ec; * boost::asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec); @@ -1464,7 +1583,7 @@ public: * @par Example * Shutting down the send side of the socket: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send); * @endcode @@ -1488,7 +1607,7 @@ public: * @par Example * Shutting down the send side of the socket: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::system::error_code ec; * socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec); @@ -1498,17 +1617,134 @@ public: * } * @endcode */ - boost::system::error_code shutdown(shutdown_type what, + BOOST_ASIO_SYNC_OP_VOID shutdown(shutdown_type what, boost::system::error_code& ec) { - return this->get_service().shutdown(this->get_implementation(), what, ec); + this->get_service().shutdown(this->get_implementation(), what, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Wait for the socket to become ready to read, ready to write, or to have + /// pending error conditions. + /** + * This function is used to perform a blocking wait for a socket to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired socket state. + * + * @par Example + * Waiting for a socket to become readable. + * @code + * boost::asio::ip::tcp::socket socket(io_context); + * ... + * socket.wait(boost::asio::ip::tcp::socket::wait_read); + * @endcode + */ + void wait(wait_type w) + { + boost::system::error_code ec; + this->get_service().wait(this->get_implementation(), w, ec); + boost::asio::detail::throw_error(ec, "wait"); + } + + /// Wait for the socket to become ready to read, ready to write, or to have + /// pending error conditions. + /** + * This function is used to perform a blocking wait for a socket to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired socket state. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * Waiting for a socket to become readable. + * @code + * boost::asio::ip::tcp::socket socket(io_context); + * ... + * boost::system::error_code ec; + * socket.wait(boost::asio::ip::tcp::socket::wait_read, ec); + * @endcode + */ + BOOST_ASIO_SYNC_OP_VOID wait(wait_type w, boost::system::error_code& ec) + { + this->get_service().wait(this->get_implementation(), w, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Asynchronously wait for the socket to become ready to read, ready to + /// write, or to have pending error conditions. + /** + * This function is used to perform an asynchronous wait for a socket to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired socket state. + * + * @param handler The handler to be called when the wait operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error // Result of operation + * ); @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 + * boost::asio::io_context::post(). + * + * @par Example + * @code + * void wait_handler(const boost::system::error_code& error) + * { + * if (!error) + * { + * // Wait succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::socket socket(io_context); + * ... + * socket.async_wait(boost::asio::ip::tcp::socket::wait_read, wait_handler); + * @endcode + */ + template <typename WaitHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(wait_type w, BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WaitHandler. + BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + return this->get_service().async_wait(this->get_implementation(), + w, BOOST_ASIO_MOVE_CAST(WaitHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<WaitHandler, + void (boost::system::error_code)> init(handler); + + this->get_service().async_wait(this->get_implementation(), + w, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } protected: /// Protected destructor to prevent deletion through this type. + /** + * This function destroys the socket, cancelling any outstanding asynchronous + * operations associated with the socket as if by calling @c cancel. + */ ~basic_socket() { } + +private: + // Disallow copying and assignment. + basic_socket(const basic_socket&) BOOST_ASIO_DELETED; + basic_socket& operator=(const basic_socket&) BOOST_ASIO_DELETED; }; } // namespace asio @@ -1516,4 +1752,8 @@ protected: #include <boost/asio/detail/pop_options.hpp> +#if !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# undef BOOST_ASIO_SVC_T +#endif // !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_BASIC_SOCKET_HPP diff --git a/boost/asio/basic_socket_acceptor.hpp b/boost/asio/basic_socket_acceptor.hpp index f1d2b8e7a6..3cbfa5081d 100644 --- a/boost/asio/basic_socket_acceptor.hpp +++ b/boost/asio/basic_socket_acceptor.hpp @@ -22,9 +22,27 @@ #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/socket_acceptor_service.hpp> #include <boost/asio/socket_base.hpp> +#if defined(BOOST_ASIO_HAS_MOVE) +# include <utility> +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/socket_acceptor_service.hpp> +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include <boost/asio/detail/null_socket_service.hpp> +# define BOOST_ASIO_SVC_T detail::null_socket_service<Protocol> +# elif defined(BOOST_ASIO_HAS_IOCP) +# include <boost/asio/detail/win_iocp_socket_service.hpp> +# define BOOST_ASIO_SVC_T detail::win_iocp_socket_service<Protocol> +# else +# include <boost/asio/detail/reactive_socket_service.hpp> +# define BOOST_ASIO_SVC_T detail::reactive_socket_service<Protocol> +# endif +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #include <boost/asio/detail/push_options.hpp> namespace boost { @@ -42,7 +60,7 @@ namespace asio { * @par Example * Opening a socket acceptor with the SO_REUSEADDR option enabled: * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port); * acceptor.open(endpoint.protocol()); * acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); @@ -50,19 +68,22 @@ namespace asio { * acceptor.listen(); * @endcode */ -template <typename Protocol, - typename SocketAcceptorService = socket_acceptor_service<Protocol> > +template <typename Protocol + BOOST_ASIO_SVC_TPARAM_DEF1(= socket_acceptor_service<Protocol>)> class basic_socket_acceptor - : public basic_io_object<SocketAcceptorService>, + : BOOST_ASIO_SVC_ACCESS basic_io_object<BOOST_ASIO_SVC_T>, public socket_base { public: - /// (Deprecated: Use native_handle_type.) The native representation of an - /// acceptor. - typedef typename SocketAcceptorService::native_handle_type native_type; + /// The type of the executor associated with the object. + typedef io_context::executor_type executor_type; /// The native representation of an acceptor. - typedef typename SocketAcceptorService::native_handle_type native_handle_type; +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef typename BOOST_ASIO_SVC_T::native_handle_type native_handle_type; +#endif /// The protocol type. typedef Protocol protocol_type; @@ -76,12 +97,12 @@ public: * connections. The open() function must be called before the acceptor can * accept new socket connections. * - * @param io_service The io_service object that the acceptor will use to + * @param io_context The io_context object that the acceptor will use to * dispatch handlers for any asynchronous operations performed on the * acceptor. */ - explicit basic_socket_acceptor(boost::asio::io_service& io_service) - : basic_io_object<SocketAcceptorService>(io_service) + explicit basic_socket_acceptor(boost::asio::io_context& io_context) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) { } @@ -89,7 +110,7 @@ public: /** * This constructor creates an acceptor and automatically opens it. * - * @param io_service The io_service object that the acceptor will use to + * @param io_context The io_context object that the acceptor will use to * dispatch handlers for any asynchronous operations performed on the * acceptor. * @@ -97,9 +118,9 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_socket_acceptor(boost::asio::io_service& io_service, + basic_socket_acceptor(boost::asio::io_context& io_context, const protocol_type& protocol) - : basic_io_object<SocketAcceptorService>(io_service) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) { boost::system::error_code ec; this->get_service().open(this->get_implementation(), protocol, ec); @@ -111,7 +132,7 @@ public: * This constructor creates an acceptor and automatically opens it to listen * for new connections on the specified endpoint. * - * @param io_service The io_service object that the acceptor will use to + * @param io_context The io_context object that the acceptor will use to * dispatch handlers for any asynchronous operations performed on the * acceptor. * @@ -125,7 +146,7 @@ public: * * @note This constructor is equivalent to the following code: * @code - * basic_socket_acceptor<Protocol> acceptor(io_service); + * basic_socket_acceptor<Protocol> acceptor(io_context); * acceptor.open(endpoint.protocol()); * if (reuse_addr) * acceptor.set_option(socket_base::reuse_address(true)); @@ -133,9 +154,9 @@ public: * acceptor.listen(listen_backlog); * @endcode */ - basic_socket_acceptor(boost::asio::io_service& io_service, + basic_socket_acceptor(boost::asio::io_context& io_context, const endpoint_type& endpoint, bool reuse_addr = true) - : basic_io_object<SocketAcceptorService>(io_service) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) { boost::system::error_code ec; const protocol_type protocol = endpoint.protocol(); @@ -150,7 +171,7 @@ public: this->get_service().bind(this->get_implementation(), endpoint, ec); boost::asio::detail::throw_error(ec, "bind"); this->get_service().listen(this->get_implementation(), - socket_base::max_connections, ec); + socket_base::max_listen_connections, ec); boost::asio::detail::throw_error(ec, "listen"); } @@ -159,7 +180,7 @@ public: * This constructor creates an acceptor object to hold an existing native * acceptor. * - * @param io_service The io_service object that the acceptor will use to + * @param io_context The io_context object that the acceptor will use to * dispatch handlers for any asynchronous operations performed on the * acceptor. * @@ -169,9 +190,9 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_socket_acceptor(boost::asio::io_service& io_service, + basic_socket_acceptor(boost::asio::io_context& io_context, const protocol_type& protocol, const native_handle_type& native_acceptor) - : basic_io_object<SocketAcceptorService>(io_service) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) { boost::system::error_code ec; this->get_service().assign(this->get_implementation(), @@ -188,11 +209,10 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket_acceptor(io_service&) constructor. + * constructed using the @c basic_socket_acceptor(io_context&) constructor. */ basic_socket_acceptor(basic_socket_acceptor&& other) - : basic_io_object<SocketAcceptorService>( - BOOST_ASIO_MOVE_CAST(basic_socket_acceptor)(other)) + : basic_io_object<BOOST_ASIO_SVC_T>(std::move(other)) { } @@ -204,17 +224,16 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket_acceptor(io_service&) constructor. + * constructed using the @c basic_socket_acceptor(io_context&) constructor. */ basic_socket_acceptor& operator=(basic_socket_acceptor&& other) { - basic_io_object<SocketAcceptorService>::operator=( - BOOST_ASIO_MOVE_CAST(basic_socket_acceptor)(other)); + basic_io_object<BOOST_ASIO_SVC_T>::operator=(std::move(other)); return *this; } // All socket acceptors have access to each other's implementations. - template <typename Protocol1, typename SocketAcceptorService1> + template <typename Protocol1 BOOST_ASIO_SVC_TPARAM1> friend class basic_socket_acceptor; /// Move-construct a basic_socket_acceptor from an acceptor of another @@ -226,13 +245,13 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket(io_service&) constructor. + * constructed using the @c basic_socket(io_context&) constructor. */ - template <typename Protocol1, typename SocketAcceptorService1> + template <typename Protocol1 BOOST_ASIO_SVC_TPARAM1> basic_socket_acceptor( - basic_socket_acceptor<Protocol1, SocketAcceptorService1>&& other, + basic_socket_acceptor<Protocol1 BOOST_ASIO_SVC_TARG1>&& other, typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0) - : basic_io_object<SocketAcceptorService>( + : basic_io_object<BOOST_ASIO_SVC_T>( other.get_service(), other.get_implementation()) { } @@ -246,21 +265,69 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_socket(io_service&) constructor. + * constructed using the @c basic_socket(io_context&) constructor. */ - template <typename Protocol1, typename SocketAcceptorService1> + template <typename Protocol1 BOOST_ASIO_SVC_TPARAM1> typename enable_if<is_convertible<Protocol1, Protocol>::value, basic_socket_acceptor>::type& operator=( - basic_socket_acceptor<Protocol1, SocketAcceptorService1>&& other) + basic_socket_acceptor<Protocol1 BOOST_ASIO_SVC_TARG1>&& other) { - basic_socket_acceptor tmp(BOOST_ASIO_MOVE_CAST2(basic_socket_acceptor< - Protocol1, SocketAcceptorService1>)(other)); - basic_io_object<SocketAcceptorService>::operator=( - BOOST_ASIO_MOVE_CAST(basic_socket_acceptor)(tmp)); + basic_socket_acceptor tmp(std::move(other)); + basic_io_object<BOOST_ASIO_SVC_T>::operator=(std::move(tmp)); return *this; } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Destroys the acceptor. + /** + * This function destroys the acceptor, cancelling any outstanding + * asynchronous operations associated with the acceptor as if by calling + * @c cancel. + */ + ~basic_socket_acceptor() + { + } + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + // These functions are provided by basic_io_object<>. +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_context() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_service() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_service(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_executor(); + } +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + /// Open the acceptor using the specified protocol. /** * This function opens the socket acceptor so that it will use the specified @@ -272,7 +339,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * acceptor.open(boost::asio::ip::tcp::v4()); * @endcode */ @@ -294,7 +361,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * boost::system::error_code ec; * acceptor.open(boost::asio::ip::tcp::v4(), ec); * if (ec) @@ -303,10 +370,11 @@ public: * } * @endcode */ - boost::system::error_code open(const protocol_type& protocol, + BOOST_ASIO_SYNC_OP_VOID open(const protocol_type& protocol, boost::system::error_code& ec) { - return this->get_service().open(this->get_implementation(), protocol, ec); + this->get_service().open(this->get_implementation(), protocol, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Assigns an existing native acceptor to the acceptor. @@ -338,11 +406,12 @@ public: * * @param ec Set to indicate what error occurred, if any. */ - boost::system::error_code assign(const protocol_type& protocol, + BOOST_ASIO_SYNC_OP_VOID assign(const protocol_type& protocol, const native_handle_type& native_acceptor, boost::system::error_code& ec) { - return this->get_service().assign(this->get_implementation(), + this->get_service().assign(this->get_implementation(), protocol, native_acceptor, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the acceptor is open. @@ -363,7 +432,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 12345); * acceptor.open(endpoint.protocol()); * acceptor.bind(endpoint); @@ -388,7 +457,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 12345); * acceptor.open(endpoint.protocol()); * boost::system::error_code ec; @@ -399,10 +468,11 @@ public: * } * @endcode */ - boost::system::error_code bind(const endpoint_type& endpoint, + BOOST_ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint, boost::system::error_code& ec) { - return this->get_service().bind(this->get_implementation(), endpoint, ec); + this->get_service().bind(this->get_implementation(), endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Place the acceptor into the state where it will listen for new @@ -415,7 +485,7 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - void listen(int backlog = socket_base::max_connections) + void listen(int backlog = socket_base::max_listen_connections) { boost::system::error_code ec; this->get_service().listen(this->get_implementation(), backlog, ec); @@ -434,19 +504,20 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... * boost::system::error_code ec; - * acceptor.listen(boost::asio::socket_base::max_connections, ec); + * acceptor.listen(boost::asio::socket_base::max_listen_connections, ec); * if (ec) * { * // An error occurred. * } * @endcode */ - boost::system::error_code listen(int backlog, boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID listen(int backlog, boost::system::error_code& ec) { - return this->get_service().listen(this->get_implementation(), backlog, ec); + this->get_service().listen(this->get_implementation(), backlog, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Close the acceptor. @@ -478,7 +549,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... * boost::system::error_code ec; * acceptor.close(ec); @@ -488,20 +559,62 @@ public: * } * @endcode */ - boost::system::error_code close(boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) { - return this->get_service().close(this->get_implementation(), ec); + this->get_service().close(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } - /// (Deprecated: Use native_handle().) Get the native acceptor representation. + /// Release ownership of the underlying native acceptor. /** - * This function may be used to obtain the underlying representation of the - * acceptor. This is intended to allow access to native acceptor functionality - * that is not otherwise provided. + * This function causes all outstanding asynchronous accept operations to + * finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. Ownership of the + * native acceptor is then transferred to the caller. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with boost::asio::error::operation_not_supported on + * these platforms. */ - native_type native() +#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release() { - return this->get_service().native_handle(this->get_implementation()); + boost::system::error_code ec; + native_handle_type s = this->get_service().release( + this->get_implementation(), ec); + boost::asio::detail::throw_error(ec, "release"); + return s; + } + + /// Release ownership of the underlying native acceptor. + /** + * This function causes all outstanding asynchronous accept operations to + * finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. Ownership of the + * native acceptor is then transferred to the caller. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with boost::asio::error::operation_not_supported on + * these platforms. + */ +#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release(boost::system::error_code& ec) + { + return this->get_service().release(this->get_implementation(), ec); } /// Get the native acceptor representation. @@ -538,9 +651,10 @@ public: * * @param ec Set to indicate what error occurred, if any. */ - boost::system::error_code cancel(boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) { - return this->get_service().cancel(this->get_implementation(), ec); + this->get_service().cancel(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Set an option on the acceptor. @@ -558,7 +672,7 @@ public: * @par Example * Setting the SOL_SOCKET/SO_REUSEADDR option: * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... * boost::asio::ip::tcp::acceptor::reuse_address option(true); * acceptor.set_option(option); @@ -587,7 +701,7 @@ public: * @par Example * Setting the SOL_SOCKET/SO_REUSEADDR option: * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... * boost::asio::ip::tcp::acceptor::reuse_address option(true); * boost::system::error_code ec; @@ -599,11 +713,11 @@ public: * @endcode */ template <typename SettableSocketOption> - boost::system::error_code set_option(const SettableSocketOption& option, + BOOST_ASIO_SYNC_OP_VOID set_option(const SettableSocketOption& option, boost::system::error_code& ec) { - return this->get_service().set_option( - this->get_implementation(), option, ec); + this->get_service().set_option(this->get_implementation(), option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get an option from the acceptor. @@ -621,7 +735,7 @@ public: * @par Example * Getting the value of the SOL_SOCKET/SO_REUSEADDR option: * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... * boost::asio::ip::tcp::acceptor::reuse_address option; * acceptor.get_option(option); @@ -651,7 +765,7 @@ public: * @par Example * Getting the value of the SOL_SOCKET/SO_REUSEADDR option: * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... * boost::asio::ip::tcp::acceptor::reuse_address option; * boost::system::error_code ec; @@ -664,11 +778,11 @@ public: * @endcode */ template <typename GettableSocketOption> - boost::system::error_code get_option(GettableSocketOption& option, + BOOST_ASIO_SYNC_OP_VOID get_option(GettableSocketOption& option, boost::system::error_code& ec) { - return this->get_service().get_option( - this->get_implementation(), option, ec); + this->get_service().get_option(this->get_implementation(), option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Perform an IO control command on the acceptor. @@ -685,7 +799,7 @@ public: * @par Example * Getting the number of bytes ready to read: * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... * boost::asio::ip::tcp::acceptor::non_blocking_io command(true); * socket.io_control(command); @@ -713,7 +827,7 @@ public: * @par Example * Getting the number of bytes ready to read: * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... * boost::asio::ip::tcp::acceptor::non_blocking_io command(true); * boost::system::error_code ec; @@ -725,11 +839,11 @@ public: * @endcode */ template <typename IoControlCommand> - boost::system::error_code io_control(IoControlCommand& command, + BOOST_ASIO_SYNC_OP_VOID io_control(IoControlCommand& command, boost::system::error_code& ec) { - return this->get_service().io_control( - this->get_implementation(), command, ec); + this->get_service().io_control(this->get_implementation(), command, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the acceptor. @@ -781,11 +895,11 @@ public: * operations. Asynchronous operations will never fail with the error * boost::asio::error::would_block. */ - boost::system::error_code non_blocking( + BOOST_ASIO_SYNC_OP_VOID non_blocking( bool mode, boost::system::error_code& ec) { - return this->get_service().non_blocking( - this->get_implementation(), mode, ec); + this->get_service().non_blocking(this->get_implementation(), mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the native acceptor implementation. @@ -845,11 +959,12 @@ public: * function fails with boost::asio::error::invalid_argument, as the * combination does not make sense. */ - boost::system::error_code native_non_blocking( + BOOST_ASIO_SYNC_OP_VOID native_non_blocking( bool mode, boost::system::error_code& ec) { - return this->get_service().native_non_blocking( + this->get_service().native_non_blocking( this->get_implementation(), mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get the local endpoint of the acceptor. @@ -862,7 +977,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... * boost::asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(); * @endcode @@ -888,7 +1003,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... * boost::system::error_code ec; * boost::asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(ec); @@ -903,6 +1018,116 @@ public: return this->get_service().local_endpoint(this->get_implementation(), ec); } + /// Wait for the acceptor to become ready to read, ready to write, or to have + /// pending error conditions. + /** + * This function is used to perform a blocking wait for an acceptor to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired acceptor state. + * + * @par Example + * Waiting for an acceptor to become readable. + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_context); + * ... + * acceptor.wait(boost::asio::ip::tcp::acceptor::wait_read); + * @endcode + */ + void wait(wait_type w) + { + boost::system::error_code ec; + this->get_service().wait(this->get_implementation(), w, ec); + boost::asio::detail::throw_error(ec, "wait"); + } + + /// Wait for the acceptor to become ready to read, ready to write, or to have + /// pending error conditions. + /** + * This function is used to perform a blocking wait for an acceptor to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired acceptor state. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * Waiting for an acceptor to become readable. + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_context); + * ... + * boost::system::error_code ec; + * acceptor.wait(boost::asio::ip::tcp::acceptor::wait_read, ec); + * @endcode + */ + BOOST_ASIO_SYNC_OP_VOID wait(wait_type w, boost::system::error_code& ec) + { + this->get_service().wait(this->get_implementation(), w, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Asynchronously wait for the acceptor to become ready to read, ready to + /// write, or to have pending error conditions. + /** + * This function is used to perform an asynchronous wait for an acceptor to + * enter a ready to read, write or error condition state. + * + * @param w Specifies the desired acceptor state. + * + * @param handler The handler to be called when the wait operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error // Result of operation + * ); @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 + * boost::asio::io_context::post(). + * + * @par Example + * @code + * void wait_handler(const boost::system::error_code& error) + * { + * if (!error) + * { + * // Wait succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::acceptor acceptor(io_context); + * ... + * acceptor.async_wait( + * boost::asio::ip::tcp::acceptor::wait_read, + * wait_handler); + * @endcode + */ + template <typename WaitHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(wait_type w, BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WaitHandler. + BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + return this->get_service().async_wait(this->get_implementation(), + w, BOOST_ASIO_MOVE_CAST(WaitHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<WaitHandler, + void (boost::system::error_code)> init(handler); + + this->get_service().async_wait(this->get_implementation(), + w, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + } + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) /// Accept a new connection. /** * This function is used to accept a new connection from a peer into the @@ -915,15 +1140,21 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * acceptor.accept(socket); * @endcode */ +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) template <typename Protocol1, typename SocketService> void accept(basic_socket<Protocol1, SocketService>& peer, typename enable_if<is_convertible<Protocol, Protocol1>::value>::type* = 0) +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + template <typename Protocol1> + void accept(basic_socket<Protocol1>& peer, + typename enable_if<is_convertible<Protocol, Protocol1>::value>::type* = 0) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) { boost::system::error_code ec; this->get_service().accept(this->get_implementation(), @@ -943,9 +1174,9 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... - * boost::asio::ip::tcp::soocket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * boost::system::error_code ec; * acceptor.accept(socket, ec); * if (ec) @@ -954,14 +1185,22 @@ public: * } * @endcode */ +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) template <typename Protocol1, typename SocketService> - boost::system::error_code accept( + BOOST_ASIO_SYNC_OP_VOID accept( basic_socket<Protocol1, SocketService>& peer, boost::system::error_code& ec, typename enable_if<is_convertible<Protocol, Protocol1>::value>::type* = 0) +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + template <typename Protocol1> + BOOST_ASIO_SYNC_OP_VOID accept( + basic_socket<Protocol1>& peer, boost::system::error_code& ec, + typename enable_if<is_convertible<Protocol, Protocol1>::value>::type* = 0) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) { - return this->get_service().accept(this->get_implementation(), + this->get_service().accept(this->get_implementation(), peer, static_cast<endpoint_type*>(0), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Start an asynchronous accept. @@ -982,7 +1221,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * @code @@ -996,26 +1235,45 @@ public: * * ... * - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * acceptor.async_accept(socket, accept_handler); * @endcode */ +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) template <typename Protocol1, typename SocketService, typename AcceptHandler> BOOST_ASIO_INITFN_RESULT_TYPE(AcceptHandler, void (boost::system::error_code)) async_accept(basic_socket<Protocol1, SocketService>& peer, BOOST_ASIO_MOVE_ARG(AcceptHandler) handler, typename enable_if<is_convertible<Protocol, Protocol1>::value>::type* = 0) +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + template <typename Protocol1, typename AcceptHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(AcceptHandler, + void (boost::system::error_code)) + async_accept(basic_socket<Protocol1>& peer, + BOOST_ASIO_MOVE_ARG(AcceptHandler) handler, + typename enable_if<is_convertible<Protocol, Protocol1>::value>::type* = 0) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a AcceptHandler. BOOST_ASIO_ACCEPT_HANDLER_CHECK(AcceptHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_accept(this->get_implementation(), peer, static_cast<endpoint_type*>(0), BOOST_ASIO_MOVE_CAST(AcceptHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<AcceptHandler, + void (boost::system::error_code)> init(handler); + + this->get_service().async_accept(this->get_implementation(), + peer, static_cast<endpoint_type*>(0), init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Accept a new connection and obtain the endpoint of the peer @@ -1034,16 +1292,20 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * boost::asio::ip::tcp::endpoint endpoint; * acceptor.accept(socket, endpoint); * @endcode */ +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) template <typename SocketService> void accept(basic_socket<protocol_type, SocketService>& peer, endpoint_type& peer_endpoint) +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + void accept(basic_socket<protocol_type>& peer, endpoint_type& peer_endpoint) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) { boost::system::error_code ec; this->get_service().accept(this->get_implementation(), @@ -1067,9 +1329,9 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * boost::asio::ip::tcp::endpoint endpoint; * boost::system::error_code ec; * acceptor.accept(socket, endpoint, ec); @@ -1079,13 +1341,19 @@ public: * } * @endcode */ +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) template <typename SocketService> - boost::system::error_code accept( + BOOST_ASIO_SYNC_OP_VOID accept( basic_socket<protocol_type, SocketService>& peer, endpoint_type& peer_endpoint, boost::system::error_code& ec) +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + BOOST_ASIO_SYNC_OP_VOID accept(basic_socket<protocol_type>& peer, + endpoint_type& peer_endpoint, boost::system::error_code& ec) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) { - return this->get_service().accept( + this->get_service().accept( this->get_implementation(), peer, &peer_endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Start an asynchronous accept. @@ -1112,21 +1380,600 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). */ +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) template <typename SocketService, typename AcceptHandler> BOOST_ASIO_INITFN_RESULT_TYPE(AcceptHandler, void (boost::system::error_code)) async_accept(basic_socket<protocol_type, SocketService>& peer, endpoint_type& peer_endpoint, BOOST_ASIO_MOVE_ARG(AcceptHandler) handler) +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + template <typename AcceptHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(AcceptHandler, + void (boost::system::error_code)) + async_accept(basic_socket<protocol_type>& peer, + endpoint_type& peer_endpoint, BOOST_ASIO_MOVE_ARG(AcceptHandler) handler) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a AcceptHandler. BOOST_ASIO_ACCEPT_HANDLER_CHECK(AcceptHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_accept(this->get_implementation(), peer, &peer_endpoint, BOOST_ASIO_MOVE_CAST(AcceptHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<AcceptHandler, + void (boost::system::error_code)> init(handler); + + this->get_service().async_accept(this->get_implementation(), + peer, &peer_endpoint, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + } +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +#if defined(BOOST_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 boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_context); + * ... + * boost::asio::ip::tcp::socket socket(acceptor.accept()); + * @endcode + */ + typename Protocol::socket accept() + { + boost::system::error_code ec; + typename Protocol::socket peer( + this->get_service().accept( + this->get_implementation(), 0, 0, ec)); + boost::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 + * boost::asio::ip::tcp::acceptor acceptor(io_context); + * ... + * boost::asio::ip::tcp::socket socket(acceptor.accept(ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + typename Protocol::socket accept(boost::system::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 boost::system::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 + * boost::asio::io_context::post(). + * + * @par Example + * @code + * void accept_handler(const boost::system::error_code& error, + * boost::asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::acceptor acceptor(io_context); + * ... + * acceptor.async_accept(accept_handler); + * @endcode + */ + template <typename MoveAcceptHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + void (boost::system::error_code, typename Protocol::socket)) + async_accept(BOOST_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. + BOOST_ASIO_MOVE_ACCEPT_HANDLER_CHECK(MoveAcceptHandler, + handler, typename Protocol::socket) type_check; + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + return this->get_service().async_accept( + this->get_implementation(), static_cast<boost::asio::io_context*>(0), + static_cast<endpoint_type*>(0), + BOOST_ASIO_MOVE_CAST(MoveAcceptHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<MoveAcceptHandler, + void (boost::system::error_code, + typename Protocol::socket)> init(handler); + + this->get_service().async_accept( + this->get_implementation(), static_cast<boost::asio::io_context*>(0), + static_cast<endpoint_type*>(0), init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + } + + /// 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 io_context The io_context object to be used for the newly accepted + * socket. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_context); + * ... + * boost::asio::ip::tcp::socket socket(acceptor.accept()); + * @endcode + */ + typename Protocol::socket accept(boost::asio::io_context& io_context) + { + boost::system::error_code ec; + typename Protocol::socket peer( + this->get_service().accept(this->get_implementation(), + &io_context, static_cast<endpoint_type*>(0), ec)); + boost::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 io_context The io_context object to be used for the newly accepted + * socket. + * + * @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 + * boost::asio::ip::tcp::acceptor acceptor(io_context); + * ... + * boost::asio::ip::tcp::socket socket(acceptor.accept(io_context2, ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + typename Protocol::socket accept( + boost::asio::io_context& io_context, boost::system::error_code& ec) + { + return this->get_service().accept(this->get_implementation(), + &io_context, static_cast<endpoint_type*>(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 io_context The io_context object to be used for the newly accepted + * socket. + * + * @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 boost::system::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 + * boost::asio::io_context::post(). + * + * @par Example + * @code + * void accept_handler(const boost::system::error_code& error, + * boost::asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::acceptor acceptor(io_context); + * ... + * acceptor.async_accept(io_context2, accept_handler); + * @endcode + */ + template <typename MoveAcceptHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + void (boost::system::error_code, typename Protocol::socket)) + async_accept(boost::asio::io_context& io_context, + BOOST_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. + BOOST_ASIO_MOVE_ACCEPT_HANDLER_CHECK(MoveAcceptHandler, + handler, typename Protocol::socket) type_check; + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + return this->get_service().async_accept(this->get_implementation(), + &io_context, static_cast<endpoint_type*>(0), + BOOST_ASIO_MOVE_CAST(MoveAcceptHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<MoveAcceptHandler, + void (boost::system::error_code, + typename Protocol::socket)> init(handler); + + this->get_service().async_accept(this->get_implementation(), + &io_context, static_cast<endpoint_type*>(0), init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + } + + /// 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 peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint; + * boost::asio::ip::tcp::socket socket(acceptor.accept(endpoint)); + * @endcode + */ + typename Protocol::socket accept(endpoint_type& peer_endpoint) + { + boost::system::error_code ec; + typename Protocol::socket peer( + this->get_service().accept(this->get_implementation(), + static_cast<boost::asio::io_context*>(0), &peer_endpoint, ec)); + boost::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 peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @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 + * boost::asio::ip::tcp::acceptor acceptor(io_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint; + * boost::asio::ip::tcp::socket socket(acceptor.accept(endpoint, ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + typename Protocol::socket accept( + endpoint_type& peer_endpoint, boost::system::error_code& ec) + { + return this->get_service().accept(this->get_implementation(), + static_cast<boost::asio::io_context*>(0), &peer_endpoint, 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 peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. Ownership of the peer_endpoint object is + * retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @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 boost::system::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 + * boost::asio::io_context::post(). + * + * @par Example + * @code + * void accept_handler(const boost::system::error_code& error, + * boost::asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::acceptor acceptor(io_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint; + * acceptor.async_accept(endpoint, accept_handler); + * @endcode + */ + template <typename MoveAcceptHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + void (boost::system::error_code, typename Protocol::socket)) + async_accept(endpoint_type& peer_endpoint, + BOOST_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. + BOOST_ASIO_MOVE_ACCEPT_HANDLER_CHECK(MoveAcceptHandler, + handler, typename Protocol::socket) type_check; + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + return this->get_service().async_accept(this->get_implementation(), + static_cast<boost::asio::io_context*>(0), &peer_endpoint, + BOOST_ASIO_MOVE_CAST(MoveAcceptHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<MoveAcceptHandler, + void (boost::system::error_code, + typename Protocol::socket)> init(handler); + + this->get_service().async_accept(this->get_implementation(), + static_cast<boost::asio::io_context*>(0), &peer_endpoint, + init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + } + + /// 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 io_context The io_context object to be used for the newly accepted + * socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint; + * boost::asio::ip::tcp::socket socket( + * acceptor.accept(io_context2, endpoint)); + * @endcode + */ + typename Protocol::socket accept( + boost::asio::io_context& io_context, endpoint_type& peer_endpoint) + { + boost::system::error_code ec; + typename Protocol::socket peer( + this->get_service().accept(this->get_implementation(), + &io_context, &peer_endpoint, ec)); + boost::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 io_context The io_context object to be used for the newly accepted + * socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @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 + * boost::asio::ip::tcp::acceptor acceptor(io_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint; + * boost::asio::ip::tcp::socket socket( + * acceptor.accept(io_context2, endpoint, ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + typename Protocol::socket accept(boost::asio::io_context& io_context, + endpoint_type& peer_endpoint, boost::system::error_code& ec) + { + return this->get_service().accept(this->get_implementation(), + &io_context, &peer_endpoint, 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 io_context The io_context object to be used for the newly accepted + * socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. Ownership of the peer_endpoint object is + * retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @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 boost::system::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 + * boost::asio::io_context::post(). + * + * @par Example + * @code + * void accept_handler(const boost::system::error_code& error, + * boost::asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::acceptor acceptor(io_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint; + * acceptor.async_accept(io_context2, endpoint, accept_handler); + * @endcode + */ + template <typename MoveAcceptHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + void (boost::system::error_code, typename Protocol::socket)) + async_accept(boost::asio::io_context& io_context, + endpoint_type& peer_endpoint, + BOOST_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. + BOOST_ASIO_MOVE_ACCEPT_HANDLER_CHECK(MoveAcceptHandler, + handler, typename Protocol::socket) type_check; + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + return this->get_service().async_accept( + this->get_implementation(), &io_context, &peer_endpoint, + BOOST_ASIO_MOVE_CAST(MoveAcceptHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<MoveAcceptHandler, + void (boost::system::error_code, + typename Protocol::socket)> init(handler); + + this->get_service().async_accept(this->get_implementation(), + &io_context, &peer_endpoint, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) }; } // namespace asio @@ -1134,4 +1981,8 @@ public: #include <boost/asio/detail/pop_options.hpp> +#if !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# undef BOOST_ASIO_SVC_T +#endif // !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_HPP diff --git a/boost/asio/basic_socket_iostream.hpp b/boost/asio/basic_socket_iostream.hpp index 6ed71f7b68..a5f8e0223a 100644 --- a/boost/asio/basic_socket_iostream.hpp +++ b/boost/asio/basic_socket_iostream.hpp @@ -22,7 +22,10 @@ #include <istream> #include <ostream> #include <boost/asio/basic_socket_streambuf.hpp> -#include <boost/asio/stream_socket_service.hpp> + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/stream_socket_service.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) #if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) @@ -33,8 +36,8 @@ // explicit basic_socket_iostream(T1 x1, ..., Tn xn) // : std::basic_iostream<char>( // &this->detail::socket_iostream_base< -// Protocol, StreamSocketService, Time, -// TimeTraits, TimerService>::streambuf_) +// Protocol BOOST_ASIO_SVC_TARG, Clock, +// WaitTraits BOOST_ASIO_SVC_TARG1>::streambuf_) // { // if (rdbuf()->connect(x1, ..., xn) == 0) // this->setstate(std::ios_base::failbit); @@ -43,14 +46,14 @@ # define BOOST_ASIO_PRIVATE_CTR_DEF(n) \ template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ - explicit basic_socket_iostream(BOOST_ASIO_VARIADIC_PARAMS(n)) \ + explicit basic_socket_iostream(BOOST_ASIO_VARIADIC_BYVAL_PARAMS(n)) \ : std::basic_iostream<char>( \ &this->detail::socket_iostream_base< \ - Protocol, StreamSocketService, Time, \ - TimeTraits, TimerService>::streambuf_) \ + Protocol BOOST_ASIO_SVC_TARG, Clock, \ + WaitTraits BOOST_ASIO_SVC_TARG1>::streambuf_) \ { \ this->setf(std::ios_base::unitbuf); \ - if (rdbuf()->connect(BOOST_ASIO_VARIADIC_ARGS(n)) == 0) \ + if (rdbuf()->connect(BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \ this->setstate(std::ios_base::failbit); \ } \ /**/ @@ -66,9 +69,9 @@ # define BOOST_ASIO_PRIVATE_CONNECT_DEF(n) \ template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ - void connect(BOOST_ASIO_VARIADIC_PARAMS(n)) \ + void connect(BOOST_ASIO_VARIADIC_BYVAL_PARAMS(n)) \ { \ - if (rdbuf()->connect(BOOST_ASIO_VARIADIC_ARGS(n)) == 0) \ + if (rdbuf()->connect(BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \ this->setstate(std::ios_base::failbit); \ } \ /**/ @@ -83,69 +86,163 @@ namespace detail { // A separate base class is used to ensure that the streambuf is initialised // prior to the basic_socket_iostream's basic_iostream base class. -template <typename Protocol, typename StreamSocketService, - typename Time, typename TimeTraits, typename TimerService> +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename Clock, typename WaitTraits BOOST_ASIO_SVC_TPARAM1> class socket_iostream_base { protected: - basic_socket_streambuf<Protocol, StreamSocketService, - Time, TimeTraits, TimerService> streambuf_; + socket_iostream_base() + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + socket_iostream_base(socket_iostream_base&& other) + : streambuf_(std::move(other.streambuf_)) + { + } + + socket_iostream_base(basic_stream_socket<Protocol> s) + : streambuf_(std::move(s)) + { + } + + socket_iostream_base& operator=(socket_iostream_base&& other) + { + streambuf_ = std::move(other.streambuf_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + basic_socket_streambuf<Protocol BOOST_ASIO_SVC_TARG, + Clock, WaitTraits BOOST_ASIO_SVC_TARG1> streambuf_; }; -} +} // namespace detail -/// Iostream interface for a socket. -template <typename Protocol, - typename StreamSocketService = stream_socket_service<Protocol>, -#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ - || defined(GENERATING_DOCUMENTATION) - typename Time = boost::posix_time::ptime, - typename TimeTraits = boost::asio::time_traits<Time>, - typename TimerService = deadline_timer_service<Time, TimeTraits> > +#if !defined(BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL) +#define BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename Protocol + BOOST_ASIO_SVC_TPARAM_DEF1(= stream_socket_service<Protocol>), +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + typename Clock = boost::posix_time::ptime, + typename WaitTraits = time_traits<Clock> + BOOST_ASIO_SVC_TPARAM1_DEF2(= deadline_timer_service<Clock, WaitTraits>)> #else - typename Time = steady_timer::clock_type, - typename TimeTraits = steady_timer::traits_type, - typename TimerService = steady_timer::service_type> + typename Clock = chrono::steady_clock, + typename WaitTraits = wait_traits<Clock> + BOOST_ASIO_SVC_TPARAM1_DEF1(= steady_timer::service_type)> #endif +class basic_socket_iostream; + +#endif // !defined(BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL) + +/// Iostream interface for a socket. +#if defined(GENERATING_DOCUMENTATION) +template <typename Protocol, + typename Clock = chrono::steady_clock, + typename WaitTraits = wait_traits<Clock> > +#else // defined(GENERATING_DOCUMENTATION) +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename Clock, typename WaitTraits BOOST_ASIO_SVC_TPARAM1> +#endif // defined(GENERATING_DOCUMENTATION) class basic_socket_iostream - : private detail::socket_iostream_base<Protocol, - StreamSocketService, Time, TimeTraits, TimerService>, + : private detail::socket_iostream_base<Protocol + BOOST_ASIO_SVC_TARG, Clock, WaitTraits BOOST_ASIO_SVC_TARG1>, public std::basic_iostream<char> { private: // These typedefs are intended keep this class's implementation independent - // of whether it's using Boost.DateTime, Boost.Chrono or std::chrono. + // of whether it's using Boost.DateClock, Boost.Chrono or std::chrono. #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) - typedef TimeTraits traits_helper; + typedef WaitTraits traits_helper; #else - typedef detail::chrono_time_traits<Time, TimeTraits> traits_helper; + typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper; #endif public: + /// The protocol type. + typedef Protocol protocol_type; + /// The endpoint type. typedef typename Protocol::endpoint endpoint_type; + /// The clock type. + typedef Clock clock_type; + #if defined(GENERATING_DOCUMENTATION) + /// (Deprecated: Use time_point.) The time type. + typedef typename WaitTraits::time_type time_type; + /// The time type. - typedef typename TimeTraits::time_type time_type; + typedef typename WaitTraits::time_point time_point; + + /// (Deprecated: Use duration.) The duration type. + typedef typename WaitTraits::duration_type duration_type; /// The duration type. - typedef typename TimeTraits::duration_type duration_type; + typedef typename WaitTraits::duration duration; #else +# if !defined(BOOST_ASIO_NO_DEPRECATED) typedef typename traits_helper::time_type time_type; typedef typename traits_helper::duration_type duration_type; +# endif // !defined(BOOST_ASIO_NO_DEPRECATED) + typedef typename traits_helper::time_type time_point; + typedef typename traits_helper::duration_type duration; #endif /// Construct a basic_socket_iostream without establishing a connection. basic_socket_iostream() : std::basic_iostream<char>( &this->detail::socket_iostream_base< - Protocol, StreamSocketService, Time, - TimeTraits, TimerService>::streambuf_) + Protocol BOOST_ASIO_SVC_TARG, Clock, + WaitTraits BOOST_ASIO_SVC_TARG1>::streambuf_) + { + this->setf(std::ios_base::unitbuf); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Construct a basic_socket_iostream from the supplied socket. + explicit basic_socket_iostream(basic_stream_socket<protocol_type> s) + : detail::socket_iostream_base< + Protocol BOOST_ASIO_SVC_TARG, Clock, + WaitTraits BOOST_ASIO_SVC_TARG1>(std::move(s)), + std::basic_iostream<char>( + &this->detail::socket_iostream_base< + Protocol BOOST_ASIO_SVC_TARG, Clock, + WaitTraits BOOST_ASIO_SVC_TARG1>::streambuf_) { this->setf(std::ios_base::unitbuf); } +#if defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) \ + || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_socket_iostream from another. + basic_socket_iostream(basic_socket_iostream&& other) + : detail::socket_iostream_base< + Protocol BOOST_ASIO_SVC_TARG, Clock, + WaitTraits BOOST_ASIO_SVC_TARG1>(std::move(other)), + std::basic_iostream<char>(std::move(other)) + { + this->set_rdbuf(&this->detail::socket_iostream_base< + Protocol BOOST_ASIO_SVC_TARG, Clock, + WaitTraits BOOST_ASIO_SVC_TARG1>::streambuf_); + } + + /// Move-assign a basic_socket_iostream from another. + basic_socket_iostream& operator=(basic_socket_iostream&& other) + { + std::basic_iostream<char>::operator=(std::move(other)); + detail::socket_iostream_base< + Protocol BOOST_ASIO_SVC_TARG, Clock, + WaitTraits BOOST_ASIO_SVC_TARG1>::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) + // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + #if defined(GENERATING_DOCUMENTATION) /// Establish a connection to an endpoint corresponding to a resolver query. /** @@ -160,8 +257,8 @@ public: explicit basic_socket_iostream(T... x) : std::basic_iostream<char>( &this->detail::socket_iostream_base< - Protocol, StreamSocketService, Time, - TimeTraits, TimerService>::streambuf_) + Protocol BOOST_ASIO_SVC_TARG, Clock, + WaitTraits BOOST_ASIO_SVC_TARG1>::streambuf_) { this->setf(std::ios_base::unitbuf); if (rdbuf()->connect(x...) == 0) @@ -199,14 +296,20 @@ public: } /// Return a pointer to the underlying streambuf. - basic_socket_streambuf<Protocol, StreamSocketService, - Time, TimeTraits, TimerService>* rdbuf() const + basic_socket_streambuf<Protocol BOOST_ASIO_SVC_TARG, + Clock, WaitTraits BOOST_ASIO_SVC_TARG1>* rdbuf() const { - return const_cast<basic_socket_streambuf<Protocol, StreamSocketService, - Time, TimeTraits, TimerService>*>( + return const_cast<basic_socket_streambuf<Protocol BOOST_ASIO_SVC_TARG, + Clock, WaitTraits BOOST_ASIO_SVC_TARG1>*>( &this->detail::socket_iostream_base< - Protocol, StreamSocketService, Time, - TimeTraits, TimerService>::streambuf_); + Protocol BOOST_ASIO_SVC_TARG, Clock, + WaitTraits BOOST_ASIO_SVC_TARG1>::streambuf_); + } + + /// Get a reference to the underlying socket. + basic_socket<Protocol BOOST_ASIO_SVC_TARG>& socket() + { + return rdbuf()->socket(); } /// Get the last error associated with the stream. @@ -223,17 +326,29 @@ public: */ const boost::system::error_code& error() const { - return rdbuf()->puberror(); + return rdbuf()->error(); } - /// Get the stream's expiry time as an absolute time. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the stream's expiry time as an absolute + /// time. /** * @return An absolute time value representing the stream's expiry time. */ - time_type expires_at() const + time_point expires_at() const { return rdbuf()->expires_at(); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the stream's expiry time as an absolute time. + /** + * @return An absolute time value representing the stream's expiry time. + */ + time_point expiry() const + { + return rdbuf()->expiry(); + } /// Set the stream's expiry time as an absolute time. /** @@ -244,21 +359,37 @@ public: * * @param expiry_time The expiry time to be used for the stream. */ - void expires_at(const time_type& expiry_time) + void expires_at(const time_point& expiry_time) { rdbuf()->expires_at(expiry_time); } - /// Get the timer's expiry time relative to now. + /// Set the stream's expiry time relative to now. + /** + * This function sets the expiry time associated with the stream. Stream + * operations performed after this time (where the operations cannot be + * completed using the internal buffers) will fail with the error + * boost::asio::error::operation_aborted. + * + * @param expiry_time The expiry time to be used for the timer. + */ + void expires_after(const duration& expiry_time) + { + rdbuf()->expires_after(expiry_time); + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the stream's expiry time relative to now. /** * @return A relative time value representing the stream's expiry time. */ - duration_type expires_from_now() const + duration expires_from_now() const { return rdbuf()->expires_from_now(); } - /// Set the stream's expiry time relative to now. + /// (Deprecated: Use expires_after().) Set the stream's expiry time relative + /// to now. /** * This function sets the expiry time associated with the stream. Stream * operations performed after this time (where the operations cannot be @@ -267,10 +398,17 @@ public: * * @param expiry_time The expiry time to be used for the timer. */ - void expires_from_now(const duration_type& expiry_time) + void expires_from_now(const duration& expiry_time) { rdbuf()->expires_from_now(expiry_time); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +private: + // Disallow copying and assignment. + basic_socket_iostream(const basic_socket_iostream&) BOOST_ASIO_DELETED; + basic_socket_iostream& operator=( + const basic_socket_iostream&) BOOST_ASIO_DELETED; }; } // namespace asio diff --git a/boost/asio/basic_socket_streambuf.hpp b/boost/asio/basic_socket_streambuf.hpp index 922b005d88..352225b876 100644 --- a/boost/asio/basic_socket_streambuf.hpp +++ b/boost/asio/basic_socket_streambuf.hpp @@ -20,15 +20,24 @@ #if !defined(BOOST_ASIO_NO_IOSTREAM) #include <streambuf> +#include <vector> #include <boost/asio/basic_socket.hpp> -#include <boost/asio/deadline_timer_service.hpp> -#include <boost/asio/detail/array.hpp> +#include <boost/asio/basic_stream_socket.hpp> +#include <boost/asio/detail/buffer_sequence_adapter.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/throw_error.hpp> -#include <boost/asio/io_service.hpp> -#include <boost/asio/stream_socket_service.hpp> +#include <boost/asio/io_context.hpp> + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/stream_socket_service.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) -# include <boost/asio/deadline_timer.hpp> +# if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/deadline_timer_service.hpp> +# else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/detail/deadline_timer_service.hpp> +# endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) #else # include <boost/asio/steady_timer.hpp> #endif @@ -39,113 +48,214 @@ // A macro that should expand to: // template <typename T1, ..., typename Tn> -// basic_socket_streambuf<Protocol, StreamSocketService, -// Time, TimeTraits, TimerService>* connect( -// T1 x1, ..., Tn xn) +// basic_socket_streambuf* connect(T1 x1, ..., Tn xn) // { // init_buffers(); -// this->basic_socket<Protocol, StreamSocketService>::close(ec_); // typedef typename Protocol::resolver resolver_type; -// typedef typename resolver_type::query resolver_query; -// resolver_query query(x1, ..., xn); -// resolve_and_connect(query); +// resolver_type resolver(socket().get_executor().context()); +// connect_to_endpoints( +// resolver.resolve(x1, ..., xn, ec_)); // return !ec_ ? this : 0; // } // This macro should only persist within this file. # define BOOST_ASIO_PRIVATE_CONNECT_DEF(n) \ template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ - basic_socket_streambuf<Protocol, StreamSocketService, \ - Time, TimeTraits, TimerService>* connect(BOOST_ASIO_VARIADIC_PARAMS(n)) \ + basic_socket_streambuf* connect(BOOST_ASIO_VARIADIC_BYVAL_PARAMS(n)) \ { \ init_buffers(); \ - this->basic_socket<Protocol, StreamSocketService>::close(ec_); \ typedef typename Protocol::resolver resolver_type; \ - typedef typename resolver_type::query resolver_query; \ - resolver_query query(BOOST_ASIO_VARIADIC_ARGS(n)); \ - resolve_and_connect(query); \ + resolver_type resolver(socket().get_executor().context()); \ + connect_to_endpoints( \ + resolver.resolve(BOOST_ASIO_VARIADIC_BYVAL_ARGS(n), ec_)); \ return !ec_ ? this : 0; \ } \ /**/ #endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#if !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# define BOOST_ASIO_SVC_T1 detail::deadline_timer_service<traits_helper> +#endif // !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { -// A separate base class is used to ensure that the io_service is initialised -// prior to the basic_socket_streambuf's basic_socket base class. -class socket_streambuf_base +// A separate base class is used to ensure that the io_context member is +// initialised prior to the basic_socket_streambuf's basic_socket base class. +class socket_streambuf_io_context +{ +protected: + socket_streambuf_io_context(io_context* ctx) + : default_io_context_(ctx) + { + } + + shared_ptr<io_context> default_io_context_; +}; + +// A separate base class is used to ensure that the dynamically allocated +// buffers are constructed prior to the basic_socket_streambuf's basic_socket +// base class. This makes moving the socket is the last potentially throwing +// step in the streambuf's move constructor, giving the constructor a strong +// exception safety guarantee. +class socket_streambuf_buffers { protected: - io_service io_service_; + socket_streambuf_buffers() + : get_buffer_(buffer_size), + put_buffer_(buffer_size) + { + } + + enum { buffer_size = 512 }; + std::vector<char> get_buffer_; + std::vector<char> put_buffer_; }; } // namespace detail -/// Iostream streambuf for a socket. -template <typename Protocol, - typename StreamSocketService = stream_socket_service<Protocol>, -#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ - || defined(GENERATING_DOCUMENTATION) - typename Time = boost::posix_time::ptime, - typename TimeTraits = boost::asio::time_traits<Time>, - typename TimerService = deadline_timer_service<Time, TimeTraits> > +#if !defined(BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL) +#define BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename Protocol + BOOST_ASIO_SVC_TPARAM_DEF1(= stream_socket_service<Protocol>), +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + typename Clock = boost::posix_time::ptime, + typename WaitTraits = time_traits<Clock> + BOOST_ASIO_SVC_TPARAM1_DEF2(= deadline_timer_service<Clock, WaitTraits>)> #else - typename Time = steady_timer::clock_type, - typename TimeTraits = steady_timer::traits_type, - typename TimerService = steady_timer::service_type> + typename Clock = chrono::steady_clock, + typename WaitTraits = wait_traits<Clock> + BOOST_ASIO_SVC_TPARAM1_DEF1(= steady_timer::service_type)> #endif +class basic_socket_streambuf; + +#endif // !defined(BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL) + +/// Iostream streambuf for a socket. +#if defined(GENERATING_DOCUMENTATION) +template <typename Protocol, + typename Clock = chrono::steady_clock, + typename WaitTraits = wait_traits<Clock> > +#else // defined(GENERATING_DOCUMENTATION) +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename Clock, typename WaitTraits BOOST_ASIO_SVC_TPARAM1> +#endif // defined(GENERATING_DOCUMENTATION) class basic_socket_streambuf : public std::streambuf, - private detail::socket_streambuf_base, - public basic_socket<Protocol, StreamSocketService> + private detail::socket_streambuf_io_context, + private detail::socket_streambuf_buffers, +#if defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + private basic_socket<Protocol BOOST_ASIO_SVC_TARG> +#else // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + public basic_socket<Protocol BOOST_ASIO_SVC_TARG> +#endif // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) { private: // These typedefs are intended keep this class's implementation independent - // of whether it's using Boost.DateTime, Boost.Chrono or std::chrono. + // of whether it's using Boost.DateClock, Boost.Chrono or std::chrono. #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) - typedef TimeTraits traits_helper; + typedef WaitTraits traits_helper; #else - typedef detail::chrono_time_traits<Time, TimeTraits> traits_helper; + typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper; #endif public: + /// The protocol type. + typedef Protocol protocol_type; + /// The endpoint type. typedef typename Protocol::endpoint endpoint_type; + /// The clock type. + typedef Clock clock_type; + #if defined(GENERATING_DOCUMENTATION) + /// (Deprecated: Use time_point.) The time type. + typedef typename WaitTraits::time_type time_type; + /// The time type. - typedef typename TimeTraits::time_type time_type; + typedef typename WaitTraits::time_point time_point; + + /// (Deprecated: Use duration.) The duration type. + typedef typename WaitTraits::duration_type duration_type; /// The duration type. - typedef typename TimeTraits::duration_type duration_type; + typedef typename WaitTraits::duration duration; #else +# if !defined(BOOST_ASIO_NO_DEPRECATED) typedef typename traits_helper::time_type time_type; typedef typename traits_helper::duration_type duration_type; +# endif // !defined(BOOST_ASIO_NO_DEPRECATED) + typedef typename traits_helper::time_type time_point; + typedef typename traits_helper::duration_type duration; #endif /// Construct a basic_socket_streambuf without establishing a connection. basic_socket_streambuf() - : basic_socket<Protocol, StreamSocketService>( - this->detail::socket_streambuf_base::io_service_), - unbuffered_(false), - timer_service_(0), - timer_state_(no_timer) + : detail::socket_streambuf_io_context(new io_context), + basic_socket<Protocol BOOST_ASIO_SVC_TARG>(*default_io_context_), + expiry_time_(max_expiry_time()) + { + init_buffers(); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Construct a basic_socket_streambuf from the supplied socket. + explicit basic_socket_streambuf(basic_stream_socket<protocol_type> s) + : detail::socket_streambuf_io_context(0), + basic_socket<Protocol BOOST_ASIO_SVC_TARG>(std::move(s)), + expiry_time_(max_expiry_time()) { init_buffers(); } + /// Move-construct a basic_socket_streambuf from another. + basic_socket_streambuf(basic_socket_streambuf&& other) + : detail::socket_streambuf_io_context(other), + basic_socket<Protocol BOOST_ASIO_SVC_TARG>(std::move(other.socket())), + ec_(other.ec_), + expiry_time_(other.expiry_time_) + { + get_buffer_.swap(other.get_buffer_); + put_buffer_.swap(other.put_buffer_); + setg(other.eback(), other.gptr(), other.egptr()); + setp(other.pptr(), other.epptr()); + other.ec_ = boost::system::error_code(); + other.expiry_time_ = max_expiry_time(); + other.init_buffers(); + } + + /// Move-assign a basic_socket_streambuf from another. + basic_socket_streambuf& operator=(basic_socket_streambuf&& other) + { + this->close(); + socket() = std::move(other.socket()); + detail::socket_streambuf_io_context::operator=(other); + ec_ = other.ec_; + expiry_time_ = other.expiry_time_; + get_buffer_.swap(other.get_buffer_); + put_buffer_.swap(other.put_buffer_); + setg(other.eback(), other.gptr(), other.egptr()); + setp(other.pptr(), other.epptr()); + other.ec_ = boost::system::error_code(); + other.expiry_time_ = max_expiry_time(); + other.put_buffer_.resize(buffer_size); + other.init_buffers(); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Destructor flushes buffered data. virtual ~basic_socket_streambuf() { if (pptr() != pbase()) overflow(traits_type::eof()); - - destroy_timer(); } /// Establish a connection. @@ -155,29 +265,11 @@ public: * @return \c this if a connection was successfully established, a null * pointer otherwise. */ - basic_socket_streambuf<Protocol, StreamSocketService, - Time, TimeTraits, TimerService>* connect( - const endpoint_type& endpoint) + basic_socket_streambuf* connect(const endpoint_type& endpoint) { init_buffers(); - - this->basic_socket<Protocol, StreamSocketService>::close(ec_); - - if (timer_state_ == timer_has_expired) - { - ec_ = boost::asio::error::operation_aborted; - return 0; - } - - io_handler handler = { this }; - this->basic_socket<Protocol, StreamSocketService>::async_connect( - endpoint, handler); - - ec_ = boost::asio::error::would_block; - this->get_service().get_io_service().reset(); - do this->get_service().get_io_service().run_one(); - while (ec_ == boost::asio::error::would_block); - + ec_ = boost::system::error_code(); + this->connect_to_endpoints(&endpoint, &endpoint + 1); return !ec_ ? this : 0; } @@ -192,19 +284,15 @@ public: * pointer otherwise. */ template <typename T1, ..., typename TN> - basic_socket_streambuf<Protocol, StreamSocketService>* connect( - T1 t1, ..., TN tn); + basic_socket_streambuf* connect(T1 t1, ..., TN tn); #elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename... T> - basic_socket_streambuf<Protocol, StreamSocketService, - Time, TimeTraits, TimerService>* connect(T... x) + basic_socket_streambuf* connect(T... x) { init_buffers(); - this->basic_socket<Protocol, StreamSocketService>::close(ec_); typedef typename Protocol::resolver resolver_type; - typedef typename resolver_type::query resolver_query; - resolver_query query(x...); - resolve_and_connect(query); + resolver_type resolver(socket().get_executor().context()); + connect_to_endpoints(resolver.resolve(x..., ec_)); return !ec_ ? this : 0; } #else @@ -216,36 +304,63 @@ public: * @return \c this if a connection was successfully established, a null * pointer otherwise. */ - basic_socket_streambuf<Protocol, StreamSocketService, - Time, TimeTraits, TimerService>* close() + basic_socket_streambuf* close() { sync(); - this->basic_socket<Protocol, StreamSocketService>::close(ec_); + socket().close(ec_); if (!ec_) init_buffers(); return !ec_ ? this : 0; } + /// Get a reference to the underlying socket. + basic_socket<Protocol BOOST_ASIO_SVC_TARG>& socket() + { + return *this; + } + /// Get the last error associated with the stream buffer. /** * @return An \c error_code corresponding to the last error from the stream * buffer. */ + const boost::system::error_code& error() const + { + return ec_; + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use error().) Get the last error associated with the stream + /// buffer. + /** + * @return An \c error_code corresponding to the last error from the stream + * buffer. + */ const boost::system::error_code& puberror() const { return error(); } + /// (Deprecated: Use expiry().) Get the stream buffer's expiry time as an + /// absolute time. + /** + * @return An absolute time value representing the stream buffer's expiry + * time. + */ + time_point expires_at() const + { + return expiry_time_; + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + /// Get the stream buffer's expiry time as an absolute time. /** * @return An absolute time value representing the stream buffer's expiry * time. */ - time_type expires_at() const + time_point expiry() const { - return timer_service_ - ? timer_service_->expires_at(timer_implementation_) - : time_type(); + return expiry_time_; } /// Set the stream buffer's expiry time as an absolute time. @@ -257,27 +372,38 @@ public: * * @param expiry_time The expiry time to be used for the stream. */ - void expires_at(const time_type& expiry_time) + void expires_at(const time_point& expiry_time) { - construct_timer(); - - boost::system::error_code ec; - timer_service_->expires_at(timer_implementation_, expiry_time, ec); - boost::asio::detail::throw_error(ec, "expires_at"); + expiry_time_ = expiry_time; + } - start_timer(); + /// Set the stream buffer's expiry time relative to now. + /** + * This function sets the expiry time associated with the stream. Stream + * operations performed after this time (where the operations cannot be + * completed using the internal buffers) will fail with the error + * boost::asio::error::operation_aborted. + * + * @param expiry_time The expiry time to be used for the timer. + */ + void expires_after(const duration& expiry_time) + { + expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time); } - /// Get the stream buffer's expiry time relative to now. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the stream buffer's expiry time relative + /// to now. /** * @return A relative time value representing the stream buffer's expiry time. */ - duration_type expires_from_now() const + duration expires_from_now() const { return traits_helper::subtract(expires_at(), traits_helper::now()); } - /// Set the stream buffer's expiry time relative to now. + /// (Deprecated: Use expires_after().) Set the stream buffer's expiry time + /// relative to now. /** * This function sets the expiry time associated with the stream. Stream * operations performed after this time (where the operations cannot be @@ -286,109 +412,126 @@ public: * * @param expiry_time The expiry time to be used for the timer. */ - void expires_from_now(const duration_type& expiry_time) + void expires_from_now(const duration& expiry_time) { - construct_timer(); - - boost::system::error_code ec; - timer_service_->expires_from_now(timer_implementation_, expiry_time, ec); - boost::asio::detail::throw_error(ec, "expires_from_now"); - - start_timer(); + expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) protected: int_type underflow() { - if (gptr() == egptr()) +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + ec_ = boost::asio::error::operation_not_supported; + return traits_type::eof(); +#else // defined(BOOST_ASIO_WINDOWS_RUNTIME) + if (gptr() != egptr()) + return traits_type::eof(); + + for (;;) { - if (timer_state_ == timer_has_expired) + // Check if we are past the expiry time. + if (traits_helper::less_than(expiry_time_, traits_helper::now())) { - ec_ = boost::asio::error::operation_aborted; + ec_ = boost::asio::error::timed_out; return traits_type::eof(); } - io_handler handler = { this }; - this->get_service().async_receive(this->get_implementation(), - boost::asio::buffer(boost::asio::buffer(get_buffer_) + putback_max), - 0, handler); + // Try to complete the operation without blocking. + if (!socket().native_non_blocking()) + socket().native_non_blocking(true, ec_); + detail::buffer_sequence_adapter<mutable_buffer, mutable_buffer> + bufs(boost::asio::buffer(get_buffer_) + putback_max); + detail::signed_size_type bytes = detail::socket_ops::recv( + socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_); - ec_ = boost::asio::error::would_block; - this->get_service().get_io_service().reset(); - do this->get_service().get_io_service().run_one(); - while (ec_ == boost::asio::error::would_block); - if (ec_) + // Check if operation succeeded. + if (bytes > 0) + { + setg(&get_buffer_[0], &get_buffer_[0] + putback_max, + &get_buffer_[0] + putback_max + bytes); + return traits_type::to_int_type(*gptr()); + } + + // Check for EOF. + if (bytes == 0) + { + ec_ = boost::asio::error::eof; return traits_type::eof(); + } - setg(&get_buffer_[0], &get_buffer_[0] + putback_max, - &get_buffer_[0] + putback_max + bytes_transferred_); - return traits_type::to_int_type(*gptr()); - } - else - { - return traits_type::eof(); + // Operation failed. + if (ec_ != boost::asio::error::would_block + && ec_ != boost::asio::error::try_again) + return traits_type::eof(); + + // Wait for socket to become ready. + if (detail::socket_ops::poll_read( + socket().native_handle(), 0, timeout(), ec_) < 0) + return traits_type::eof(); } +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) } int_type overflow(int_type c) { - if (unbuffered_) +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + ec_ = boost::asio::error::operation_not_supported; + return traits_type::eof(); +#else // defined(BOOST_ASIO_WINDOWS_RUNTIME) + char_type ch = traits_type::to_char_type(c); + + // Determine what needs to be sent. + const_buffer output_buffer; + if (put_buffer_.empty()) { if (traits_type::eq_int_type(c, traits_type::eof())) + return traits_type::not_eof(c); // Nothing to do. + output_buffer = boost::asio::buffer(&ch, sizeof(char_type)); + } + else + { + output_buffer = boost::asio::buffer(pbase(), + (pptr() - pbase()) * sizeof(char_type)); + } + + while (output_buffer.size() > 0) + { + // Check if we are past the expiry time. + if (traits_helper::less_than(expiry_time_, traits_helper::now())) { - // Nothing to do. - return traits_type::not_eof(c); + ec_ = boost::asio::error::timed_out; + return traits_type::eof(); } - else + + // Try to complete the operation without blocking. + if (!socket().native_non_blocking()) + socket().native_non_blocking(true, ec_); + detail::buffer_sequence_adapter< + const_buffer, const_buffer> bufs(output_buffer); + detail::signed_size_type bytes = detail::socket_ops::send( + socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_); + + // Check if operation succeeded. + if (bytes > 0) { - if (timer_state_ == timer_has_expired) - { - ec_ = boost::asio::error::operation_aborted; - return traits_type::eof(); - } - - // Send the single character immediately. - char_type ch = traits_type::to_char_type(c); - io_handler handler = { this }; - this->get_service().async_send(this->get_implementation(), - boost::asio::buffer(&ch, sizeof(char_type)), 0, handler); - - ec_ = boost::asio::error::would_block; - this->get_service().get_io_service().reset(); - do this->get_service().get_io_service().run_one(); - while (ec_ == boost::asio::error::would_block); - if (ec_) - return traits_type::eof(); - - return c; + output_buffer += static_cast<std::size_t>(bytes); + continue; } + + // Operation failed. + if (ec_ != boost::asio::error::would_block + && ec_ != boost::asio::error::try_again) + return traits_type::eof(); + + // Wait for socket to become ready. + if (detail::socket_ops::poll_write( + socket().native_handle(), 0, timeout(), ec_) < 0) + return traits_type::eof(); } - else + + if (!put_buffer_.empty()) { - // Send all data in the output buffer. - boost::asio::const_buffer buffer = - boost::asio::buffer(pbase(), pptr() - pbase()); - while (boost::asio::buffer_size(buffer) > 0) - { - if (timer_state_ == timer_has_expired) - { - ec_ = boost::asio::error::operation_aborted; - return traits_type::eof(); - } - - io_handler handler = { this }; - this->get_service().async_send(this->get_implementation(), - boost::asio::buffer(buffer), 0, handler); - - ec_ = boost::asio::error::would_block; - this->get_service().get_io_service().reset(); - do this->get_service().get_io_service().run_one(); - while (ec_ == boost::asio::error::would_block); - if (ec_) - return traits_type::eof(); - - buffer = buffer + bytes_transferred_; - } setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size()); // If the new character is eof then our work here is done. @@ -396,10 +539,12 @@ protected: return traits_type::not_eof(c); // Add the new character to the output buffer. - *pptr() = traits_type::to_char_type(c); + *pptr() = ch; pbump(1); - return c; } + + return c; +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) } int sync() @@ -411,148 +556,127 @@ protected: { if (pptr() == pbase() && s == 0 && n == 0) { - unbuffered_ = true; + put_buffer_.clear(); setp(0, 0); + sync(); return this; } return 0; } - /// Get the last error associated with the stream buffer. - /** - * @return An \c error_code corresponding to the last error from the stream - * buffer. - */ - virtual const boost::system::error_code& error() const - { - return ec_; - } - private: + // Disallow copying and assignment. + basic_socket_streambuf(const basic_socket_streambuf&) BOOST_ASIO_DELETED; + basic_socket_streambuf& operator=( + const basic_socket_streambuf&) BOOST_ASIO_DELETED; + void init_buffers() { setg(&get_buffer_[0], &get_buffer_[0] + putback_max, &get_buffer_[0] + putback_max); - if (unbuffered_) + + if (put_buffer_.empty()) setp(0, 0); else setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size()); } - template <typename ResolverQuery> - void resolve_and_connect(const ResolverQuery& query) + int timeout() const { - typedef typename Protocol::resolver resolver_type; - typedef typename resolver_type::iterator iterator_type; - resolver_type resolver(detail::socket_streambuf_base::io_service_); - iterator_type i = resolver.resolve(query, ec_); - if (!ec_) - { - iterator_type end; - ec_ = boost::asio::error::host_not_found; - while (ec_ && i != end) - { - this->basic_socket<Protocol, StreamSocketService>::close(ec_); - - if (timer_state_ == timer_has_expired) - { - ec_ = boost::asio::error::operation_aborted; - return; - } - - io_handler handler = { this }; - this->basic_socket<Protocol, StreamSocketService>::async_connect( - *i, handler); - - ec_ = boost::asio::error::would_block; - this->get_service().get_io_service().reset(); - do this->get_service().get_io_service().run_one(); - while (ec_ == boost::asio::error::would_block); - - ++i; - } - } + int64_t msec = traits_helper::to_posix_duration( + traits_helper::subtract(expiry_time_, + traits_helper::now())).total_milliseconds(); + if (msec > (std::numeric_limits<int>::max)()) + msec = (std::numeric_limits<int>::max)(); + else if (msec < 0) + msec = 0; + return static_cast<int>(msec); } - struct io_handler; - friend struct io_handler; - struct io_handler + template <typename EndpointSequence> + void connect_to_endpoints(const EndpointSequence& endpoints) { - basic_socket_streambuf* this_; - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred = 0) - { - this_->ec_ = ec; - this_->bytes_transferred_ = bytes_transferred; - } - }; + this->connect_to_endpoints(endpoints.begin(), endpoints.end()); + } - struct timer_handler; - friend struct timer_handler; - struct timer_handler + template <typename EndpointIterator> + void connect_to_endpoints(EndpointIterator begin, EndpointIterator end) { - basic_socket_streambuf* this_; - - void operator()(const boost::system::error_code&) +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + ec_ = boost::asio::error::operation_not_supported; +#else // defined(BOOST_ASIO_WINDOWS_RUNTIME) + if (ec_) + return; + + ec_ = boost::asio::error::not_found; + for (EndpointIterator i = begin; i != end; ++i) { - time_type now = traits_helper::now(); - - time_type expiry_time = this_->timer_service_->expires_at( - this_->timer_implementation_); - - if (traits_helper::less_than(now, expiry_time)) + // Check if we are past the expiry time. + if (traits_helper::less_than(expiry_time_, traits_helper::now())) { - this_->timer_state_ = timer_is_pending; - this_->timer_service_->async_wait(this_->timer_implementation_, *this); + ec_ = boost::asio::error::timed_out; + return; } - else - { - this_->timer_state_ = timer_has_expired; - boost::system::error_code ec; - this_->basic_socket<Protocol, StreamSocketService>::close(ec); - } - } - }; - void construct_timer() - { - if (timer_service_ == 0) - { - TimerService& timer_service = use_service<TimerService>( - detail::socket_streambuf_base::io_service_); - timer_service.construct(timer_implementation_); - timer_service_ = &timer_service; + // Close and reopen the socket. + typename Protocol::endpoint ep(*i); + socket().close(ec_); + socket().open(ep.protocol(), ec_); + if (ec_) + continue; + + // Try to complete the operation without blocking. + if (!socket().native_non_blocking()) + socket().native_non_blocking(true, ec_); + detail::socket_ops::connect(socket().native_handle(), + ep.data(), ep.size(), ec_); + + // Check if operation succeeded. + if (!ec_) + return; + + // Operation failed. + if (ec_ != boost::asio::error::in_progress + && ec_ != boost::asio::error::would_block) + continue; + + // Wait for socket to become ready. + if (detail::socket_ops::poll_connect( + socket().native_handle(), timeout(), ec_) < 0) + continue; + + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (detail::socket_ops::getsockopt(socket().native_handle(), 0, + SOL_SOCKET, SO_ERROR, &connect_error, &connect_error_len, ec_) + == detail::socket_error_retval) + return; + + // Check the result of the connect operation. + ec_ = boost::system::error_code(connect_error, + boost::asio::error::get_system_category()); + if (!ec_) + return; } +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) } - void destroy_timer() + // Helper function to get the maximum expiry time. + static time_point max_expiry_time() { - if (timer_service_) - timer_service_->destroy(timer_implementation_); - } - - void start_timer() - { - if (timer_state_ != timer_is_pending) - { - timer_handler handler = { this }; - handler(boost::system::error_code()); - } +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + return boost::posix_time::pos_infin; +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + return (time_point::max)(); +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) } enum { putback_max = 8 }; - enum { buffer_size = 512 }; - boost::asio::detail::array<char, buffer_size> get_buffer_; - boost::asio::detail::array<char, buffer_size> put_buffer_; - bool unbuffered_; boost::system::error_code ec_; - std::size_t bytes_transferred_; - TimerService* timer_service_; - typename TimerService::implementation_type timer_implementation_; - enum state { no_timer, timer_is_pending, timer_has_expired } timer_state_; + time_point expiry_time_; }; } // namespace asio @@ -560,6 +684,10 @@ private: #include <boost/asio/detail/pop_options.hpp> +#if !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# undef BOOST_ASIO_SVC_T1 +#endif // !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) # undef BOOST_ASIO_PRIVATE_CONNECT_DEF #endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) diff --git a/boost/asio/basic_stream_socket.hpp b/boost/asio/basic_stream_socket.hpp index 5b959d7db8..709e214a37 100644 --- a/boost/asio/basic_stream_socket.hpp +++ b/boost/asio/basic_stream_socket.hpp @@ -22,7 +22,10 @@ #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/stream_socket_service.hpp> + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/stream_socket_service.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) #include <boost/asio/detail/push_options.hpp> @@ -41,18 +44,19 @@ namespace asio { * @par Concepts: * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. */ -template <typename Protocol, - typename StreamSocketService = stream_socket_service<Protocol> > +template <typename Protocol + BOOST_ASIO_SVC_TPARAM_DEF1(= stream_socket_service<Protocol>)> class basic_stream_socket - : public basic_socket<Protocol, StreamSocketService> + : public basic_socket<Protocol BOOST_ASIO_SVC_TARG> { public: - /// (Deprecated: Use native_handle_type.) The native representation of a - /// socket. - typedef typename StreamSocketService::native_handle_type native_type; - /// The native representation of a socket. - typedef typename StreamSocketService::native_handle_type native_handle_type; +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef typename basic_socket< + Protocol BOOST_ASIO_SVC_TARG>::native_handle_type native_handle_type; +#endif /// The protocol type. typedef Protocol protocol_type; @@ -66,11 +70,11 @@ public: * needs to be opened and then connected or accepted before data can be sent * or received on it. * - * @param io_service The io_service object that the stream socket will use to + * @param io_context The io_context object that the stream socket will use to * dispatch handlers for any asynchronous operations performed on the socket. */ - explicit basic_stream_socket(boost::asio::io_service& io_service) - : basic_socket<Protocol, StreamSocketService>(io_service) + explicit basic_stream_socket(boost::asio::io_context& io_context) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(io_context) { } @@ -79,16 +83,16 @@ public: * This constructor creates and opens a stream socket. The socket needs to be * connected or accepted before data can be sent or received on it. * - * @param io_service The io_service object that the stream socket will use to + * @param io_context The io_context object that the stream socket will use to * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. * * @throws boost::system::system_error Thrown on failure. */ - basic_stream_socket(boost::asio::io_service& io_service, + basic_stream_socket(boost::asio::io_context& io_context, const protocol_type& protocol) - : basic_socket<Protocol, StreamSocketService>(io_service, protocol) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(io_context, protocol) { } @@ -99,7 +103,7 @@ public: * to the specified endpoint on the local machine. The protocol used is the * protocol associated with the given endpoint. * - * @param io_service The io_service object that the stream socket will use to + * @param io_context The io_context object that the stream socket will use to * dispatch handlers for any asynchronous operations performed on the socket. * * @param endpoint An endpoint on the local machine to which the stream @@ -107,9 +111,9 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_stream_socket(boost::asio::io_service& io_service, + basic_stream_socket(boost::asio::io_context& io_context, const endpoint_type& endpoint) - : basic_socket<Protocol, StreamSocketService>(io_service, endpoint) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(io_context, endpoint) { } @@ -118,7 +122,7 @@ public: * This constructor creates a stream socket object to hold an existing native * socket. * - * @param io_service The io_service object that the stream socket will use to + * @param io_context The io_context object that the stream socket will use to * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. @@ -127,10 +131,10 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_stream_socket(boost::asio::io_service& io_service, + basic_stream_socket(boost::asio::io_context& io_context, const protocol_type& protocol, const native_handle_type& native_socket) - : basic_socket<Protocol, StreamSocketService>( - io_service, protocol, native_socket) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>( + io_context, protocol, native_socket) { } @@ -143,11 +147,10 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_stream_socket(io_service&) constructor. + * constructed using the @c basic_stream_socket(io_context&) constructor. */ basic_stream_socket(basic_stream_socket&& other) - : basic_socket<Protocol, StreamSocketService>( - BOOST_ASIO_MOVE_CAST(basic_stream_socket)(other)) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(std::move(other)) { } @@ -159,12 +162,11 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_stream_socket(io_service&) constructor. + * constructed using the @c basic_stream_socket(io_context&) constructor. */ basic_stream_socket& operator=(basic_stream_socket&& other) { - basic_socket<Protocol, StreamSocketService>::operator=( - BOOST_ASIO_MOVE_CAST(basic_stream_socket)(other)); + basic_socket<Protocol BOOST_ASIO_SVC_TARG>::operator=(std::move(other)); return *this; } @@ -177,15 +179,13 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_stream_socket(io_service&) constructor. + * constructed using the @c basic_stream_socket(io_context&) constructor. */ - template <typename Protocol1, typename StreamSocketService1> + template <typename Protocol1 BOOST_ASIO_SVC_TPARAM1> basic_stream_socket( - basic_stream_socket<Protocol1, StreamSocketService1>&& other, + basic_stream_socket<Protocol1 BOOST_ASIO_SVC_TARG1>&& other, typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0) - : basic_socket<Protocol, StreamSocketService>( - BOOST_ASIO_MOVE_CAST2(basic_stream_socket< - Protocol1, StreamSocketService1>)(other)) + : basic_socket<Protocol BOOST_ASIO_SVC_TARG>(std::move(other)) { } @@ -197,20 +197,27 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_stream_socket(io_service&) constructor. + * constructed using the @c basic_stream_socket(io_context&) constructor. */ - template <typename Protocol1, typename StreamSocketService1> + template <typename Protocol1 BOOST_ASIO_SVC_TPARAM1> typename enable_if<is_convertible<Protocol1, Protocol>::value, basic_stream_socket>::type& operator=( - basic_stream_socket<Protocol1, StreamSocketService1>&& other) + basic_stream_socket<Protocol1 BOOST_ASIO_SVC_TARG1>&& other) { - basic_socket<Protocol, StreamSocketService>::operator=( - BOOST_ASIO_MOVE_CAST2(basic_stream_socket< - Protocol1, StreamSocketService1>)(other)); + basic_socket<Protocol BOOST_ASIO_SVC_TARG>::operator=(std::move(other)); return *this; } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Destroys the socket. + /** + * This function destroys the socket, cancelling any outstanding asynchronous + * operations associated with the socket as if by calling @c cancel. + */ + ~basic_stream_socket() + { + } + /// Send some data on the socket. /** * This function is used to send data on the stream socket. The function @@ -330,7 +337,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The send operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all @@ -355,9 +362,20 @@ public: // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_send( this->get_implementation(), buffers, 0, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_send( + this->get_implementation(), buffers, 0, + init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Start an asynchronous send. @@ -382,7 +400,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The send operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all @@ -408,9 +426,20 @@ public: // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_send( this->get_implementation(), buffers, flags, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_send( + this->get_implementation(), buffers, flags, + init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Receive some data on the socket. @@ -538,7 +567,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The receive operation may not receive all of the requested number of * bytes. Consider using the @ref async_read function if you need to ensure @@ -565,8 +594,18 @@ public: // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_receive(this->get_implementation(), buffers, 0, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_receive(this->get_implementation(), + buffers, 0, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Start an asynchronous receive. @@ -591,7 +630,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The receive operation may not receive all of the requested number of * bytes. Consider using the @ref async_read function if you need to ensure @@ -619,8 +658,18 @@ public: // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_receive(this->get_implementation(), buffers, flags, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_receive(this->get_implementation(), + buffers, flags, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Write some data to the socket. @@ -703,7 +752,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The write operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all @@ -728,8 +777,18 @@ public: // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_send(this->get_implementation(), buffers, 0, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_send(this->get_implementation(), + buffers, 0, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } /// Read some data from the socket. @@ -815,7 +874,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The read operation may not read all of the requested number of bytes. * Consider using the @ref async_read function if you need to ensure that the @@ -841,8 +900,18 @@ public: // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) return this->get_service().async_receive(this->get_implementation(), buffers, 0, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_receive(this->get_implementation(), + buffers, 0, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } }; diff --git a/boost/asio/basic_streambuf.hpp b/boost/asio/basic_streambuf.hpp index 1392596dc5..d8bfecd6b6 100644 --- a/boost/asio/basic_streambuf.hpp +++ b/boost/asio/basic_streambuf.hpp @@ -120,8 +120,8 @@ public: /// The type used to represent the output sequence as a list of buffers. typedef implementation_defined mutable_buffers_type; #else - typedef boost::asio::const_buffers_1 const_buffers_type; - typedef boost::asio::mutable_buffers_1 mutable_buffers_type; + typedef BOOST_ASIO_CONST_BUFFER const_buffers_type; + typedef BOOST_ASIO_MUTABLE_BUFFER mutable_buffers_type; #endif /// Construct a basic_streambuf object. @@ -152,11 +152,11 @@ public: * while (i != bufs.end()) * { * const_buffer buf(*i++); - * s += buffer_size(buf); + * s += buf.size(); * } * @endcode */ - std::size_t size() const + std::size_t size() const BOOST_ASIO_NOEXCEPT { return pptr() - gptr(); } @@ -166,11 +166,21 @@ public: * @returns The allowed maximum of the sum of the sizes of the input sequence * and output sequence. */ - std::size_t max_size() const + std::size_t max_size() const BOOST_ASIO_NOEXCEPT { return max_size_; } + /// Get the current capacity of the basic_streambuf. + /** + * @returns The current total capacity of the streambuf, i.e. for both the + * input sequence and output sequence. + */ + std::size_t capacity() const BOOST_ASIO_NOEXCEPT + { + return buffer_.capacity(); + } + /// Get a list of buffers that represents the input sequence. /** * @returns An object of type @c const_buffers_type that satisfies @@ -180,7 +190,7 @@ public: * @note The returned object is invalidated by any @c basic_streambuf member * function that modifies the input sequence or output sequence. */ - const_buffers_type data() const + const_buffers_type data() const BOOST_ASIO_NOEXCEPT { return boost::asio::buffer(boost::asio::const_buffer(gptr(), (pptr() - gptr()) * sizeof(char_type))); @@ -223,8 +233,7 @@ public: */ void commit(std::size_t n) { - if (pptr() + n > epptr()) - n = epptr() - pptr(); + n = std::min<std::size_t>(n, epptr() - pptr()); pbump(static_cast<int>(n)); setg(eback(), gptr(), pptr()); } @@ -351,15 +360,89 @@ private: } }; -// Helper function to get the preferred size for reading data. Used for any -// user-provided specialisations of basic_streambuf. +/// Adapts basic_streambuf to the dynamic buffer sequence type requirements. +#if defined(GENERATING_DOCUMENTATION) +template <typename Allocator = std::allocator<char> > +#else template <typename Allocator> -inline std::size_t read_size_helper( - basic_streambuf<Allocator>& sb, std::size_t max_size) +#endif +class basic_streambuf_ref { - return std::min<std::size_t>(512, - std::min<std::size_t>(max_size, sb.max_size() - sb.size())); -} +public: + /// The type used to represent the input sequence as a list of buffers. + typedef typename basic_streambuf<Allocator>::const_buffers_type + const_buffers_type; + + /// The type used to represent the output sequence as a list of buffers. + typedef typename basic_streambuf<Allocator>::mutable_buffers_type + mutable_buffers_type; + + /// Construct a basic_streambuf_ref for the given basic_streambuf object. + explicit basic_streambuf_ref(basic_streambuf<Allocator>& sb) + : sb_(sb) + { + } + + /// Copy construct a basic_streambuf_ref. + basic_streambuf_ref(const basic_streambuf_ref& other) BOOST_ASIO_NOEXCEPT + : sb_(other.sb_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move construct a basic_streambuf_ref. + basic_streambuf_ref(basic_streambuf_ref&& other) BOOST_ASIO_NOEXCEPT + : sb_(other.sb_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Get the size of the input sequence. + std::size_t size() const BOOST_ASIO_NOEXCEPT + { + return sb_.size(); + } + + /// Get the maximum size of the dynamic buffer. + std::size_t max_size() const BOOST_ASIO_NOEXCEPT + { + return sb_.max_size(); + } + + /// Get the current capacity of the dynamic buffer. + std::size_t capacity() const BOOST_ASIO_NOEXCEPT + { + return sb_.capacity(); + } + + /// Get a list of buffers that represents the input sequence. + const_buffers_type data() const BOOST_ASIO_NOEXCEPT + { + return sb_.data(); + } + + /// Get a list of buffers that represents the output sequence, with the given + /// size. + mutable_buffers_type prepare(std::size_t n) + { + return sb_.prepare(n); + } + + /// Move bytes from the output sequence to the input sequence. + void commit(std::size_t n) + { + return sb_.commit(n); + } + + /// Remove characters from the input sequence. + void consume(std::size_t n) + { + return sb_.consume(n); + } + +private: + basic_streambuf<Allocator>& sb_; +}; } // namespace asio } // namespace boost diff --git a/boost/asio/basic_streambuf_fwd.hpp b/boost/asio/basic_streambuf_fwd.hpp index f3e006bf11..b34e3459bb 100644 --- a/boost/asio/basic_streambuf_fwd.hpp +++ b/boost/asio/basic_streambuf_fwd.hpp @@ -27,6 +27,9 @@ namespace asio { template <typename Allocator = std::allocator<char> > class basic_streambuf; +template <typename Allocator = std::allocator<char> > +class basic_streambuf_ref; + } // namespace asio } // namespace boost diff --git a/boost/asio/basic_waitable_timer.hpp b/boost/asio/basic_waitable_timer.hpp index e4aeb0b7d8..3657d8b429 100644 --- a/boost/asio/basic_waitable_timer.hpp +++ b/boost/asio/basic_waitable_timer.hpp @@ -22,13 +22,37 @@ #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/wait_traits.hpp> -#include <boost/asio/waitable_timer_service.hpp> + +#if defined(BOOST_ASIO_HAS_MOVE) +# include <utility> +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/waitable_timer_service.hpp> +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/detail/chrono_time_traits.hpp> +# include <boost/asio/detail/deadline_timer_service.hpp> +# define BOOST_ASIO_SVC_T \ + detail::deadline_timer_service< \ + detail::chrono_time_traits<Clock, WaitTraits> > +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { +#if !defined(BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) +#define BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename Clock, + typename WaitTraits = boost::asio::wait_traits<Clock> + BOOST_ASIO_SVC_TPARAM_DEF2(= waitable_timer_service<Clock, WaitTraits>)> +class basic_waitable_timer; + +#endif // !defined(BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) + /// Provides waitable timer functionality. /** * The basic_waitable_timer class template provides the ability to perform a @@ -52,10 +76,10 @@ namespace asio { * Performing a blocking wait (C++11): * @code * // Construct a timer without setting an expiry time. - * boost::asio::steady_timer timer(io_service); + * boost::asio::steady_timer timer(io_context); * * // Set an expiry time relative to now. - * timer.expires_from_now(std::chrono::seconds(5)); + * timer.expires_after(std::chrono::seconds(5)); * * // Wait for the timer to expire. * timer.wait(); @@ -75,7 +99,7 @@ namespace asio { * ... * * // Construct a timer with an absolute expiry time. - * boost::asio::steady_timer timer(io_service, + * boost::asio::steady_timer timer(io_context, * std::chrono::steady_clock::now() + std::chrono::seconds(60)); * * // Start an asynchronous wait. @@ -92,7 +116,7 @@ namespace asio { * @code * void on_some_event() * { - * if (my_timer.expires_from_now(seconds(5)) > 0) + * if (my_timer.expires_after(seconds(5)) > 0) * { * // We managed to cancel the timer. Start new asynchronous wait. * my_timer.async_wait(on_timeout); @@ -112,7 +136,7 @@ namespace asio { * } * @endcode * - * @li The boost::asio::basic_waitable_timer::expires_from_now() function + * @li The boost::asio::basic_waitable_timer::expires_after() function * cancels any pending asynchronous waits, and returns the number of * asynchronous waits that were cancelled. If it returns 0 then you were too * late and the wait handler has already been executed, or will soon be @@ -121,13 +145,14 @@ namespace asio { * @li If a wait handler is cancelled, the boost::system::error_code passed to * it contains the value boost::asio::error::operation_aborted. */ -template <typename Clock, - typename WaitTraits = boost::asio::wait_traits<Clock>, - typename WaitableTimerService = waitable_timer_service<Clock, WaitTraits> > +template <typename Clock, typename WaitTraits BOOST_ASIO_SVC_TPARAM> class basic_waitable_timer - : public basic_io_object<WaitableTimerService> + : BOOST_ASIO_SVC_ACCESS basic_io_object<BOOST_ASIO_SVC_T> { public: + /// The type of the executor associated with the object. + typedef io_context::executor_type executor_type; + /// The clock type. typedef Clock clock_type; @@ -143,14 +168,14 @@ public: /// Constructor. /** * This constructor creates a timer without setting an expiry time. The - * expires_at() or expires_from_now() functions must be called to set an - * expiry time before the timer can be waited on. + * expires_at() or expires_after() functions must be called to set an expiry + * time before the timer can be waited on. * - * @param io_service The io_service object that the timer will use to dispatch + * @param io_context The io_context object that the timer will use to dispatch * handlers for any asynchronous operations performed on the timer. */ - explicit basic_waitable_timer(boost::asio::io_service& io_service) - : basic_io_object<WaitableTimerService>(io_service) + explicit basic_waitable_timer(boost::asio::io_context& io_context) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) { } @@ -158,18 +183,18 @@ public: /** * This constructor creates a timer and sets the expiry time. * - * @param io_service The io_service object that the timer will use to dispatch + * @param io_context The io_context object that the timer will use to dispatch * handlers for any asynchronous operations performed on the timer. * * @param expiry_time The expiry time to be used for the timer, expressed * as an absolute time. */ - basic_waitable_timer(boost::asio::io_service& io_service, + basic_waitable_timer(boost::asio::io_context& io_context, const time_point& expiry_time) - : basic_io_object<WaitableTimerService>(io_service) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) { boost::system::error_code ec; - this->service.expires_at(this->implementation, expiry_time, ec); + this->get_service().expires_at(this->get_implementation(), expiry_time, ec); boost::asio::detail::throw_error(ec, "expires_at"); } @@ -177,21 +202,105 @@ public: /** * This constructor creates a timer and sets the expiry time. * - * @param io_service The io_service object that the timer will use to dispatch + * @param io_context The io_context object that the timer will use to dispatch * handlers for any asynchronous operations performed on the timer. * * @param expiry_time The expiry time to be used for the timer, relative to * now. */ - basic_waitable_timer(boost::asio::io_service& io_service, + basic_waitable_timer(boost::asio::io_context& io_context, const duration& expiry_time) - : basic_io_object<WaitableTimerService>(io_service) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) { boost::system::error_code ec; - this->service.expires_from_now(this->implementation, expiry_time, ec); - boost::asio::detail::throw_error(ec, "expires_from_now"); + this->get_service().expires_after( + this->get_implementation(), expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_after"); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_waitable_timer from another. + /** + * This constructor moves a timer from one object to another. + * + * @param other The other basic_waitable_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_waitable_timer(io_context&) constructor. + */ + basic_waitable_timer(basic_waitable_timer&& other) + : basic_io_object<BOOST_ASIO_SVC_T>(std::move(other)) + { + } + + /// Move-assign a basic_waitable_timer from another. + /** + * This assignment operator moves a timer from one object to another. Cancels + * any outstanding asynchronous operations associated with the target object. + * + * @param other The other basic_waitable_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_waitable_timer(io_context&) constructor. + */ + basic_waitable_timer& operator=(basic_waitable_timer&& other) + { + basic_io_object<BOOST_ASIO_SVC_T>::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the timer. + /** + * This function destroys the timer, cancelling any outstanding asynchronous + * wait operations associated with the timer as if by calling @c cancel. + */ + ~basic_waitable_timer() + { + } + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + // These functions are provided by basic_io_object<>. +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_context() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_context(); } + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_service() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_service(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_executor(); + } +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + /// Cancel any asynchronous operations that are waiting on the timer. /** * This function forces the completion of any pending asynchronous wait @@ -217,12 +326,14 @@ public: std::size_t cancel() { boost::system::error_code ec; - std::size_t s = this->service.cancel(this->implementation, ec); + std::size_t s = this->get_service().cancel(this->get_implementation(), ec); boost::asio::detail::throw_error(ec, "cancel"); return s; } - /// Cancel any asynchronous operations that are waiting on the timer. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overload.) Cancel any asynchronous + /// operations that are waiting on the timer. /** * This function forces the completion of any pending asynchronous wait * operations against the timer. The handler for each cancelled operation will @@ -246,8 +357,9 @@ public: */ std::size_t cancel(boost::system::error_code& ec) { - return this->service.cancel(this->implementation, ec); + return this->get_service().cancel(this->get_implementation(), ec); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Cancels one asynchronous operation that is waiting on the timer. /** @@ -276,12 +388,15 @@ public: std::size_t cancel_one() { boost::system::error_code ec; - std::size_t s = this->service.cancel_one(this->implementation, ec); + std::size_t s = this->get_service().cancel_one( + this->get_implementation(), ec); boost::asio::detail::throw_error(ec, "cancel_one"); return s; } - /// Cancels one asynchronous operation that is waiting on the timer. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overload.) Cancels one asynchronous + /// operation that is waiting on the timer. /** * This function forces the completion of one pending asynchronous wait * operation against the timer. Handlers are cancelled in FIFO order. The @@ -307,17 +422,29 @@ public: */ std::size_t cancel_one(boost::system::error_code& ec) { - return this->service.cancel_one(this->implementation, ec); + return this->get_service().cancel_one(this->get_implementation(), ec); } - /// Get the timer's expiry time as an absolute time. + /// (Deprecated: Use expiry().) Get the timer's expiry time as an absolute + /// time. /** * This function may be used to obtain the timer's current expiry time. * Whether the timer has expired or not does not affect this value. */ time_point expires_at() const { - return this->service.expires_at(this->implementation); + return this->get_service().expires_at(this->get_implementation()); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the timer's expiry time as an absolute time. + /** + * This function may be used to obtain the timer's current expiry time. + * Whether the timer has expired or not does not affect this value. + */ + time_point expiry() const + { + return this->get_service().expiry(this->get_implementation()); } /// Set the timer's expiry time as an absolute time. @@ -345,13 +472,15 @@ public: std::size_t expires_at(const time_point& expiry_time) { boost::system::error_code ec; - std::size_t s = this->service.expires_at( - this->implementation, expiry_time, ec); + std::size_t s = this->get_service().expires_at( + this->get_implementation(), expiry_time, ec); boost::asio::detail::throw_error(ec, "expires_at"); return s; } - /// Set the timer's expiry time as an absolute time. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overload.) Set the timer's expiry time as + /// an absolute time. /** * This function sets the expiry time. Any pending asynchronous wait * operations will be cancelled. The handler for each cancelled operation will @@ -376,20 +505,55 @@ public: std::size_t expires_at(const time_point& expiry_time, boost::system::error_code& ec) { - return this->service.expires_at(this->implementation, expiry_time, ec); + return this->get_service().expires_at( + this->get_implementation(), expiry_time, ec); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) - /// Get the timer's expiry time relative to now. + /// Set the timer's expiry time relative to now. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the boost::asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note If the timer has already expired when expires_after() is called, + * then the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_after(const duration& expiry_time) + { + boost::system::error_code ec; + std::size_t s = this->get_service().expires_after( + this->get_implementation(), expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_after"); + return s; + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the timer's expiry time relative to now. /** * This function may be used to obtain the timer's current expiry time. * Whether the timer has expired or not does not affect this value. */ duration expires_from_now() const { - return this->service.expires_from_now(this->implementation); + return this->get_service().expires_from_now(this->get_implementation()); } - /// Set the timer's expiry time relative to now. + /// (Deprecated: Use expires_after().) Set the timer's expiry time relative + /// to now. /** * This function sets the expiry time. Any pending asynchronous wait * operations will be cancelled. The handler for each cancelled operation will @@ -414,13 +578,14 @@ public: std::size_t expires_from_now(const duration& expiry_time) { boost::system::error_code ec; - std::size_t s = this->service.expires_from_now( - this->implementation, expiry_time, ec); + std::size_t s = this->get_service().expires_from_now( + this->get_implementation(), expiry_time, ec); boost::asio::detail::throw_error(ec, "expires_from_now"); return s; } - /// Set the timer's expiry time relative to now. + /// (Deprecated: Use expires_after().) Set the timer's expiry time relative + /// to now. /** * This function sets the expiry time. Any pending asynchronous wait * operations will be cancelled. The handler for each cancelled operation will @@ -445,9 +610,10 @@ public: std::size_t expires_from_now(const duration& expiry_time, boost::system::error_code& ec) { - return this->service.expires_from_now( - this->implementation, expiry_time, ec); + return this->get_service().expires_from_now( + this->get_implementation(), expiry_time, ec); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Perform a blocking wait on the timer. /** @@ -459,7 +625,7 @@ public: void wait() { boost::system::error_code ec; - this->service.wait(this->implementation, ec); + this->get_service().wait(this->get_implementation(), ec); boost::asio::detail::throw_error(ec, "wait"); } @@ -472,7 +638,7 @@ public: */ void wait(boost::system::error_code& ec) { - this->service.wait(this->implementation, ec); + this->get_service().wait(this->get_implementation(), ec); } /// Start an asynchronous wait on the timer. @@ -497,7 +663,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). */ template <typename WaitHandler> BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, @@ -508,9 +674,25 @@ public: // not meet the documented type requirements for a WaitHandler. BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; - return this->service.async_wait(this->implementation, +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + return this->get_service().async_wait(this->get_implementation(), BOOST_ASIO_MOVE_CAST(WaitHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + async_completion<WaitHandler, + void (boost::system::error_code)> init(handler); + + this->get_service().async_wait(this->get_implementation(), + init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } + +private: + // Disallow copying and assignment. + basic_waitable_timer(const basic_waitable_timer&) BOOST_ASIO_DELETED; + basic_waitable_timer& operator=( + const basic_waitable_timer&) BOOST_ASIO_DELETED; }; } // namespace asio @@ -518,4 +700,8 @@ public: #include <boost/asio/detail/pop_options.hpp> +#if !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# undef BOOST_ASIO_SVC_T +#endif // !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_BASIC_WAITABLE_TIMER_HPP diff --git a/boost/asio/bind_executor.hpp b/boost/asio/bind_executor.hpp new file mode 100644 index 0000000000..f6db65fc91 --- /dev/null +++ b/boost/asio/bind_executor.hpp @@ -0,0 +1,613 @@ +// +// bind_executor.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_BIND_EXECUTOR_HPP +#define BOOST_ASIO_BIND_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/type_traits.hpp> +#include <boost/asio/detail/variadic_templates.hpp> +#include <boost/asio/associated_executor.hpp> +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/async_result.hpp> +#include <boost/asio/execution_context.hpp> +#include <boost/asio/is_executor.hpp> +#include <boost/asio/uses_executor.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +template <typename T> +struct executor_binder_check +{ + typedef void type; +}; + +// Helper to automatically define nested typedef result_type. + +template <typename T, typename = void> +struct executor_binder_result_type +{ +protected: + typedef void result_type_or_void; +}; + +template <typename T> +struct executor_binder_result_type<T, + typename executor_binder_check<typename T::result_type>::type> +{ + typedef typename T::result_type result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R> +struct executor_binder_result_type<R(*)()> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R> +struct executor_binder_result_type<R(&)()> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R, typename A1> +struct executor_binder_result_type<R(*)(A1)> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R, typename A1> +struct executor_binder_result_type<R(&)(A1)> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R, typename A1, typename A2> +struct executor_binder_result_type<R(*)(A1, A2)> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template <typename R, typename A1, typename A2> +struct executor_binder_result_type<R(&)(A1, A2)> +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +// Helper to automatically define nested typedef argument_type. + +template <typename T, typename = void> +struct executor_binder_argument_type {}; + +template <typename T> +struct executor_binder_argument_type<T, + typename executor_binder_check<typename T::argument_type>::type> +{ + typedef typename T::argument_type argument_type; +}; + +template <typename R, typename A1> +struct executor_binder_argument_type<R(*)(A1)> +{ + typedef A1 argument_type; +}; + +template <typename R, typename A1> +struct executor_binder_argument_type<R(&)(A1)> +{ + typedef A1 argument_type; +}; + +// Helper to automatically define nested typedefs first_argument_type and +// second_argument_type. + +template <typename T, typename = void> +struct executor_binder_argument_types {}; + +template <typename T> +struct executor_binder_argument_types<T, + typename executor_binder_check<typename T::first_argument_type>::type> +{ + typedef typename T::first_argument_type first_argument_type; + typedef typename T::second_argument_type second_argument_type; +}; + +template <typename R, typename A1, typename A2> +struct executor_binder_argument_type<R(*)(A1, A2)> +{ + typedef A1 first_argument_type; + typedef A2 second_argument_type; +}; + +template <typename R, typename A1, typename A2> +struct executor_binder_argument_type<R(&)(A1, A2)> +{ + typedef A1 first_argument_type; + typedef A2 second_argument_type; +}; + +// Helper to: +// - Apply the empty base optimisation to the executor. +// - Perform uses_executor construction of the target type, if required. + +template <typename T, typename Executor, bool UsesExecutor> +class executor_binder_base; + +template <typename T, typename Executor> +class executor_binder_base<T, Executor, true> + : protected Executor +{ +protected: + template <typename E, typename U> + executor_binder_base(BOOST_ASIO_MOVE_ARG(E) e, BOOST_ASIO_MOVE_ARG(U) u) + : executor_(BOOST_ASIO_MOVE_CAST(E)(e)), + target_(executor_arg_t(), executor_, BOOST_ASIO_MOVE_CAST(U)(u)) + { + } + + Executor executor_; + T target_; +}; + +template <typename T, typename Executor> +class executor_binder_base<T, Executor, false> +{ +protected: + template <typename E, typename U> + executor_binder_base(BOOST_ASIO_MOVE_ARG(E) e, BOOST_ASIO_MOVE_ARG(U) u) + : executor_(BOOST_ASIO_MOVE_CAST(E)(e)), + target_(BOOST_ASIO_MOVE_CAST(U)(u)) + { + } + + Executor executor_; + T target_; +}; + +// Helper to enable SFINAE on zero-argument operator() below. + +template <typename T, typename = void> +struct executor_binder_result_of0 +{ + typedef void type; +}; + +template <typename T> +struct executor_binder_result_of0<T, + typename executor_binder_check<typename result_of<T()>::type>::type> +{ + typedef typename result_of<T()>::type type; +}; + +} // namespace detail + +/// A call wrapper type to bind an executor of type @c Executor to an object of +/// type @c T. +template <typename T, typename Executor> +class executor_binder +#if !defined(GENERATING_DOCUMENTATION) + : public detail::executor_binder_result_type<T>, + public detail::executor_binder_argument_type<T>, + public detail::executor_binder_argument_types<T>, + private detail::executor_binder_base< + T, Executor, uses_executor<T, Executor>::value> +#endif // !defined(GENERATING_DOCUMENTATION) +{ +public: + /// The type of the target object. + typedef T target_type; + + /// The type of the associated executor. + typedef Executor executor_type; + +#if defined(GENERATING_DOCUMENTATION) + /// The return type if a function. + /** + * The type of @c result_type is based on the type @c T of the wrapper's + * target object: + * + * @li if @c T is a pointer to function type, @c result_type is a synonym for + * the return type of @c T; + * + * @li if @c T is a class type with a member type @c result_type, then @c + * result_type is a synonym for @c T::result_type; + * + * @li otherwise @c result_type is not defined. + */ + typedef see_below result_type; + + /// The type of the function's argument. + /** + * The type of @c argument_type is based on the type @c T of the wrapper's + * target object: + * + * @li if @c T is a pointer to a function type accepting a single argument, + * @c argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c argument_type, then @c + * argument_type is a synonym for @c T::argument_type; + * + * @li otherwise @c argument_type is not defined. + */ + typedef see_below argument_type; + + /// The type of the function's first argument. + /** + * The type of @c first_argument_type is based on the type @c T of the + * wrapper's target object: + * + * @li if @c T is a pointer to a function type accepting two arguments, @c + * first_argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c first_argument_type, + * then @c first_argument_type is a synonym for @c T::first_argument_type; + * + * @li otherwise @c first_argument_type is not defined. + */ + typedef see_below first_argument_type; + + /// The type of the function's second argument. + /** + * The type of @c second_argument_type is based on the type @c T of the + * wrapper's target object: + * + * @li if @c T is a pointer to a function type accepting two arguments, @c + * second_argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c first_argument_type, + * then @c second_argument_type is a synonym for @c T::second_argument_type; + * + * @li otherwise @c second_argument_type is not defined. + */ + typedef see_below second_argument_type; +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct an executor wrapper for the specified object. + /** + * This constructor is only valid if the type @c T is constructible from type + * @c U. + */ + template <typename U> + executor_binder(executor_arg_t, const executor_type& e, + BOOST_ASIO_MOVE_ARG(U) u) + : base_type(e, BOOST_ASIO_MOVE_CAST(U)(u)) + { + } + + /// Copy constructor. + executor_binder(const executor_binder& other) + : base_type(other.get_executor(), other.get()) + { + } + + /// Construct a copy, but specify a different executor. + executor_binder(executor_arg_t, const executor_type& e, + const executor_binder& other) + : base_type(e, other.get()) + { + } + + /// Construct a copy of a different executor wrapper type. + /** + * This constructor is only valid if the @c Executor type is constructible + * from type @c OtherExecutor, and the type @c T is constructible from type + * @c U. + */ + template <typename U, typename OtherExecutor> + executor_binder(const executor_binder<U, OtherExecutor>& other) + : base_type(other.get_executor(), other.get()) + { + } + + /// Construct a copy of a different executor wrapper type, but specify a + /// different executor. + /** + * This constructor is only valid if the type @c T is constructible from type + * @c U. + */ + template <typename U, typename OtherExecutor> + executor_binder(executor_arg_t, const executor_type& e, + const executor_binder<U, OtherExecutor>& other) + : base_type(e, other.get()) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Move constructor. + executor_binder(executor_binder&& other) + : base_type(BOOST_ASIO_MOVE_CAST(executor_type)(other.get_executor()), + BOOST_ASIO_MOVE_CAST(T)(other.get())) + { + } + + /// Move construct the target object, but specify a different executor. + executor_binder(executor_arg_t, const executor_type& e, + executor_binder&& other) + : base_type(e, BOOST_ASIO_MOVE_CAST(T)(other.get())) + { + } + + /// Move construct from a different executor wrapper type. + template <typename U, typename OtherExecutor> + executor_binder(executor_binder<U, OtherExecutor>&& other) + : base_type(BOOST_ASIO_MOVE_CAST(OtherExecutor)(other.get_executor()), + BOOST_ASIO_MOVE_CAST(U)(other.get())) + { + } + + /// Move construct from a different executor wrapper type, but specify a + /// different executor. + template <typename U, typename OtherExecutor> + executor_binder(executor_arg_t, const executor_type& e, + executor_binder<U, OtherExecutor>&& other) + : base_type(e, BOOST_ASIO_MOVE_CAST(U)(other.get())) + { + } + +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destructor. + ~executor_binder() + { + } + + /// Obtain a reference to the target object. + target_type& get() BOOST_ASIO_NOEXCEPT + { + return this->target_; + } + + /// Obtain a reference to the target object. + const target_type& get() const BOOST_ASIO_NOEXCEPT + { + return this->target_; + } + + /// Obtain the associated executor. + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return this->executor_; + } + +#if defined(GENERATING_DOCUMENTATION) + + template <typename... Args> auto operator()(Args&& ...); + template <typename... Args> auto operator()(Args&& ...) const; + +#elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + /// Forwarding function call operator. + template <typename... Args> + typename result_of<T(Args...)>::type operator()( + BOOST_ASIO_MOVE_ARG(Args)... args) + { + return this->target_(BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + + /// Forwarding function call operator. + template <typename... Args> + typename result_of<T(Args...)>::type operator()( + BOOST_ASIO_MOVE_ARG(Args)... args) const + { + return this->target_(BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + +#elif defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER) + + typename detail::executor_binder_result_of0<T>::type operator()() + { + return this->target_(); + } + + typename detail::executor_binder_result_of0<T>::type operator()() const + { + return this->target_(); + } + +#define BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \ + template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + typename result_of<T(BOOST_ASIO_VARIADIC_TARGS(n))>::type operator()( \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + \ + template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + typename result_of<T(BOOST_ASIO_VARIADIC_TARGS(n))>::type operator()( \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) const \ + { \ + return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF) +#undef BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF + +#else // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER) + + typedef typename detail::executor_binder_result_type<T>::result_type_or_void + result_type_or_void; + + result_type_or_void operator()() + { + return this->target_(); + } + + result_type_or_void operator()() const + { + return this->target_(); + } + +#define BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \ + template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + result_type_or_void operator()( \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + \ + template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + result_type_or_void operator()( \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) const \ + { \ + return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF) +#undef BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF + +#endif // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER) + +private: + typedef detail::executor_binder_base<T, Executor, + uses_executor<T, Executor>::value> base_type; +}; + +/// Associate an object of type @c T with an executor of type @c Executor. +template <typename Executor, typename T> +inline executor_binder<typename decay<T>::type, Executor> +bind_executor(const Executor& ex, BOOST_ASIO_MOVE_ARG(T) t, + typename enable_if<is_executor<Executor>::value>::type* = 0) +{ + return executor_binder<typename decay<T>::type, Executor>( + executor_arg_t(), ex, BOOST_ASIO_MOVE_CAST(T)(t)); +} + +/// Associate an object of type @c T with an execution context's executor. +template <typename ExecutionContext, typename T> +inline executor_binder<typename decay<T>::type, + typename ExecutionContext::executor_type> +bind_executor(ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(T) t, + typename enable_if<is_convertible< + ExecutionContext&, execution_context&>::value>::type* = 0) +{ + return executor_binder<typename decay<T>::type, + typename ExecutionContext::executor_type>( + executor_arg_t(), ctx.get_executor(), BOOST_ASIO_MOVE_CAST(T)(t)); +} + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename T, typename Executor> +struct uses_executor<executor_binder<T, Executor>, Executor> + : true_type {}; + +template <typename T, typename Executor, typename Signature> +class async_result<executor_binder<T, Executor>, Signature> +{ +public: + typedef executor_binder< + typename async_result<T, Signature>::completion_handler_type, Executor> + completion_handler_type; + + typedef typename async_result<T, Signature>::return_type return_type; + + explicit async_result(executor_binder<T, Executor>& b) + : target_(b.get()) + { + } + + return_type get() + { + return target_.get(); + } + +private: + async_result(const async_result&) BOOST_ASIO_DELETED; + async_result& operator=(const async_result&) BOOST_ASIO_DELETED; + + async_result<T, Signature> target_; +}; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +template <typename T, typename Executor, typename Signature> +struct handler_type<executor_binder<T, Executor>, Signature> +{ + typedef executor_binder< + typename handler_type<T, Signature>::type, Executor> type; +}; + +template <typename T, typename Executor> +class async_result<executor_binder<T, Executor> > +{ +public: + typedef typename async_result<T>::type type; + + explicit async_result(executor_binder<T, Executor>& b) + : target_(b.get()) + { + } + + type get() + { + return target_.get(); + } + +private: + async_result<T> target_; +}; + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +template <typename T, typename Executor, typename Allocator> +struct associated_allocator<executor_binder<T, Executor>, Allocator> +{ + typedef typename associated_allocator<T, Allocator>::type type; + + static type get(const executor_binder<T, Executor>& b, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<T, Allocator>::get(b.get(), a); + } +}; + +template <typename T, typename Executor, typename Executor1> +struct associated_executor<executor_binder<T, Executor>, Executor1> +{ + typedef Executor type; + + static type get(const executor_binder<T, Executor>& b, + const Executor1& = Executor1()) BOOST_ASIO_NOEXCEPT + { + return b.get_executor(); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_BIND_EXECUTOR_HPP diff --git a/boost/asio/buffer.hpp b/boost/asio/buffer.hpp index 700654d21d..66d638ec51 100644 --- a/boost/asio/buffer.hpp +++ b/boost/asio/buffer.hpp @@ -18,17 +18,23 @@ #include <boost/asio/detail/config.hpp> #include <cstddef> #include <cstring> +#include <limits> +#include <stdexcept> #include <string> #include <vector> #include <boost/asio/detail/array_fwd.hpp> +#include <boost/asio/detail/is_buffer_sequence.hpp> +#include <boost/asio/detail/string_view.hpp> +#include <boost/asio/detail/throw_exception.hpp> +#include <boost/asio/detail/type_traits.hpp> -#if defined(BOOST_ASIO_MSVC) +#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1700) # if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0) # if !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING) # define BOOST_ASIO_ENABLE_BUFFER_DEBUGGING # endif // !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING) # endif // defined(_HAS_ITERATOR_DEBUGGING) -#endif // defined(BOOST_ASIO_MSVC) +#endif // defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1700) #if defined(__GNUC__) # if defined(_GLIBCXX_DEBUG) @@ -39,7 +45,7 @@ #endif // defined(__GNUC__) #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) -# include <boost/asio/detail/function.hpp> +# include <boost/asio/detail/functional.hpp> #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING #if defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) @@ -63,13 +69,6 @@ namespace asio { class mutable_buffer; class const_buffer; -namespace detail { -void* buffer_cast_helper(const mutable_buffer&); -const void* buffer_cast_helper(const const_buffer&); -std::size_t buffer_size_helper(const mutable_buffer&); -std::size_t buffer_size_helper(const const_buffer&); -} // namespace detail - /// Holds a buffer that can be modified. /** * The mutable_buffer class provides a safe representation of a buffer that can @@ -78,29 +77,29 @@ std::size_t buffer_size_helper(const const_buffer&); * * @par Accessing Buffer Contents * - * The contents of a buffer may be accessed using the @ref buffer_size - * and @ref buffer_cast functions: + * The contents of a buffer may be accessed using the @c data() and @c size() + * member functions: * * @code boost::asio::mutable_buffer b1 = ...; - * std::size_t s1 = boost::asio::buffer_size(b1); - * unsigned char* p1 = boost::asio::buffer_cast<unsigned char*>(b1); + * std::size_t s1 = b1.size(); + * unsigned char* p1 = static_cast<unsigned char*>(b1.data()); * @endcode * - * The boost::asio::buffer_cast function permits violations of type safety, so - * uses of it in application code should be carefully considered. + * The @c data() member function permits violations of type safety, so uses of + * it in application code should be carefully considered. */ class mutable_buffer { public: /// Construct an empty buffer. - mutable_buffer() + mutable_buffer() BOOST_ASIO_NOEXCEPT : data_(0), size_(0) { } /// Construct a buffer to represent a given memory range. - mutable_buffer(void* data, std::size_t size) + mutable_buffer(void* data, std::size_t size) BOOST_ASIO_NOEXCEPT : data_(data), size_(size) { @@ -121,12 +120,32 @@ public: } #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING -private: - friend void* boost::asio::detail::buffer_cast_helper( - const mutable_buffer& b); - friend std::size_t boost::asio::detail::buffer_size_helper( - const mutable_buffer& b); + /// Get a pointer to the beginning of the memory range. + void* data() const BOOST_ASIO_NOEXCEPT + { +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + if (size_ && debug_check_) + debug_check_(); +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + return data_; + } + + /// Get the size of the memory range. + std::size_t size() const BOOST_ASIO_NOEXCEPT + { + return size_; + } + + /// Move the start of the buffer by the specified number of bytes. + mutable_buffer& operator+=(std::size_t n) BOOST_ASIO_NOEXCEPT + { + std::size_t offset = n < size_ ? n : size_; + data_ = static_cast<char*>(data_) + offset; + size_ -= offset; + return *this; + } +private: void* data_; std::size_t size_; @@ -135,26 +154,10 @@ private: #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING }; -namespace detail { - -inline void* buffer_cast_helper(const mutable_buffer& b) -{ -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - if (b.size_ && b.debug_check_) - b.debug_check_(); -#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING - return b.data_; -} +#if !defined(BOOST_ASIO_NO_DEPRECATED) -inline std::size_t buffer_size_helper(const mutable_buffer& b) -{ - return b.size_; -} - -} // namespace detail - -/// Adapts a single modifiable buffer so that it meets the requirements of the -/// MutableBufferSequence concept. +/// (Deprecated: Use mutable_buffer.) Adapts a single modifiable buffer so that +/// it meets the requirements of the MutableBufferSequence concept. class mutable_buffers_1 : public mutable_buffer { @@ -166,30 +169,40 @@ public: typedef const mutable_buffer* const_iterator; /// Construct to represent a given memory range. - mutable_buffers_1(void* data, std::size_t size) + mutable_buffers_1(void* data, std::size_t size) BOOST_ASIO_NOEXCEPT : mutable_buffer(data, size) { } +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + mutable_buffers_1(void* data, std::size_t size, + boost::asio::detail::function<void()> debug_check) + : mutable_buffer(data, size, debug_check) + { + } +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + /// Construct to represent a single modifiable buffer. - explicit mutable_buffers_1(const mutable_buffer& b) + explicit mutable_buffers_1(const mutable_buffer& b) BOOST_ASIO_NOEXCEPT : mutable_buffer(b) { } /// Get a random-access iterator to the first element. - const_iterator begin() const + const_iterator begin() const BOOST_ASIO_NOEXCEPT { return this; } /// Get a random-access iterator for one past the last element. - const_iterator end() const + const_iterator end() const BOOST_ASIO_NOEXCEPT { return begin() + 1; } }; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + /// Holds a buffer that cannot be modified. /** * The const_buffer class provides a safe representation of a buffer that cannot @@ -198,38 +211,38 @@ public: * * @par Accessing Buffer Contents * - * The contents of a buffer may be accessed using the @ref buffer_size - * and @ref buffer_cast functions: + * The contents of a buffer may be accessed using the @c data() and @c size() + * member functions: * * @code boost::asio::const_buffer b1 = ...; - * std::size_t s1 = boost::asio::buffer_size(b1); - * const unsigned char* p1 = boost::asio::buffer_cast<const unsigned char*>(b1); + * std::size_t s1 = b1.size(); + * const unsigned char* p1 = static_cast<const unsigned char*>(b1.data()); * @endcode * - * The boost::asio::buffer_cast function permits violations of type safety, so - * uses of it in application code should be carefully considered. + * The @c data() member function permits violations of type safety, so uses of + * it in application code should be carefully considered. */ class const_buffer { public: /// Construct an empty buffer. - const_buffer() + const_buffer() BOOST_ASIO_NOEXCEPT : data_(0), size_(0) { } /// Construct a buffer to represent a given memory range. - const_buffer(const void* data, std::size_t size) + const_buffer(const void* data, std::size_t size) BOOST_ASIO_NOEXCEPT : data_(data), size_(size) { } /// Construct a non-modifiable buffer from a modifiable one. - const_buffer(const mutable_buffer& b) - : data_(boost::asio::detail::buffer_cast_helper(b)), - size_(boost::asio::detail::buffer_size_helper(b)) + const_buffer(const mutable_buffer& b) BOOST_ASIO_NOEXCEPT + : data_(b.data()), + size_(b.size()) #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) , debug_check_(b.get_debug_check()) #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING @@ -251,12 +264,32 @@ public: } #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING -private: - friend const void* boost::asio::detail::buffer_cast_helper( - const const_buffer& b); - friend std::size_t boost::asio::detail::buffer_size_helper( - const const_buffer& b); + /// Get a pointer to the beginning of the memory range. + const void* data() const BOOST_ASIO_NOEXCEPT + { +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + if (size_ && debug_check_) + debug_check_(); +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + return data_; + } + /// Get the size of the memory range. + std::size_t size() const BOOST_ASIO_NOEXCEPT + { + return size_; + } + + /// Move the start of the buffer by the specified number of bytes. + const_buffer& operator+=(std::size_t n) BOOST_ASIO_NOEXCEPT + { + std::size_t offset = n < size_ ? n : size_; + data_ = static_cast<const char*>(data_) + offset; + size_ -= offset; + return *this; + } + +private: const void* data_; std::size_t size_; @@ -265,26 +298,10 @@ private: #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING }; -namespace detail { - -inline const void* buffer_cast_helper(const const_buffer& b) -{ -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - if (b.size_ && b.debug_check_) - b.debug_check_(); -#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING - return b.data_; -} - -inline std::size_t buffer_size_helper(const const_buffer& b) -{ - return b.size_; -} - -} // namespace detail +#if !defined(BOOST_ASIO_NO_DEPRECATED) -/// Adapts a single non-modifiable buffer so that it meets the requirements of -/// the ConstBufferSequence concept. +/// (Deprecated: Use const_buffer.) Adapts a single non-modifiable buffer so +/// that it meets the requirements of the ConstBufferSequence concept. class const_buffers_1 : public const_buffer { @@ -296,32 +313,78 @@ public: typedef const const_buffer* const_iterator; /// Construct to represent a given memory range. - const_buffers_1(const void* data, std::size_t size) + const_buffers_1(const void* data, std::size_t size) BOOST_ASIO_NOEXCEPT : const_buffer(data, size) { } +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + const_buffers_1(const void* data, std::size_t size, + boost::asio::detail::function<void()> debug_check) + : const_buffer(data, size, debug_check) + { + } +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + /// Construct to represent a single non-modifiable buffer. - explicit const_buffers_1(const const_buffer& b) + explicit const_buffers_1(const const_buffer& b) BOOST_ASIO_NOEXCEPT : const_buffer(b) { } /// Get a random-access iterator to the first element. - const_iterator begin() const + const_iterator begin() const BOOST_ASIO_NOEXCEPT { return this; } /// Get a random-access iterator for one past the last element. - const_iterator end() const + const_iterator end() const BOOST_ASIO_NOEXCEPT { return begin() + 1; } }; -/// An implementation of both the ConstBufferSequence and MutableBufferSequence -/// concepts to represent a null buffer sequence. +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +/// Trait to determine whether a type satisfies the MutableBufferSequence +/// requirements. +template <typename T> +struct is_mutable_buffer_sequence +#if defined(GENERATING_DOCUMENTATION) + : integral_constant<bool, automatically_determined> +#else // defined(GENERATING_DOCUMENTATION) + : boost::asio::detail::is_buffer_sequence<T, mutable_buffer> +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +/// Trait to determine whether a type satisfies the ConstBufferSequence +/// requirements. +template <typename T> +struct is_const_buffer_sequence +#if defined(GENERATING_DOCUMENTATION) + : integral_constant<bool, automatically_determined> +#else // defined(GENERATING_DOCUMENTATION) + : boost::asio::detail::is_buffer_sequence<T, const_buffer> +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +/// Trait to determine whether a type satisfies the DynamicBuffer requirements. +template <typename T> +struct is_dynamic_buffer +#if defined(GENERATING_DOCUMENTATION) + : integral_constant<bool, automatically_determined> +#else // defined(GENERATING_DOCUMENTATION) + : boost::asio::detail::is_dynamic_buffer<T> +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +/// (Deprecated: Use the socket/descriptor wait() and async_wait() member +/// functions.) An implementation of both the ConstBufferSequence and +/// MutableBufferSequence concepts to represent a null buffer sequence. class null_buffers { public: @@ -332,13 +395,13 @@ public: typedef const mutable_buffer* const_iterator; /// Get a random-access iterator to the first element. - const_iterator begin() const + const_iterator begin() const BOOST_ASIO_NOEXCEPT { return &buf_; } /// Get a random-access iterator for one past the last element. - const_iterator end() const + const_iterator end() const BOOST_ASIO_NOEXCEPT { return &buf_; } @@ -347,61 +410,189 @@ private: mutable_buffer buf_; }; -/** @defgroup buffer_size boost::asio::buffer_size +/** @defgroup buffer_sequence_begin boost::asio::buffer_sequence_begin * - * @brief The boost::asio::buffer_size function determines the total number of - * bytes in a buffer or buffer sequence. + * @brief The boost::asio::buffer_sequence_begin function returns an iterator + * pointing to the first element in a buffer sequence. */ /*@{*/ -/// Get the number of bytes in a modifiable buffer. -inline std::size_t buffer_size(const mutable_buffer& b) +/// Get an iterator to the first element in a buffer sequence. +inline const mutable_buffer* buffer_sequence_begin(const mutable_buffer& b) { - return detail::buffer_size_helper(b); + return &b; } -/// Get the number of bytes in a modifiable buffer. -inline std::size_t buffer_size(const mutable_buffers_1& b) +/// Get an iterator to the first element in a buffer sequence. +inline const const_buffer* buffer_sequence_begin(const const_buffer& b) { - return detail::buffer_size_helper(b); + return &b; } -/// Get the number of bytes in a non-modifiable buffer. -inline std::size_t buffer_size(const const_buffer& b) +#if defined(BOOST_ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +/// Get an iterator to the first element in a buffer sequence. +template <typename C> +inline auto buffer_sequence_begin(C& c) -> decltype(c.begin()) { - return detail::buffer_size_helper(b); + return c.begin(); } -/// Get the number of bytes in a non-modifiable buffer. -inline std::size_t buffer_size(const const_buffers_1& b) +/// Get an iterator to the first element in a buffer sequence. +template <typename C> +inline auto buffer_sequence_begin(const C& c) -> decltype(c.begin()) { - return detail::buffer_size_helper(b); + return c.begin(); } -/// Get the total number of bytes in a buffer sequence. -/** - * The @c BufferSequence template parameter may meet either of the @c - * ConstBufferSequence or @c MutableBufferSequence type requirements. +#else // defined(BOOST_ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +template <typename C> +inline typename C::iterator buffer_sequence_begin(C& c) +{ + return c.begin(); +} + +template <typename C> +inline typename C::const_iterator buffer_sequence_begin(const C& c) +{ + return c.begin(); +} + +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +/*@}*/ + +/** @defgroup buffer_sequence_end boost::asio::buffer_sequence_end + * + * @brief The boost::asio::buffer_sequence_end function returns an iterator + * pointing to one past the end element in a buffer sequence. */ +/*@{*/ + +/// Get an iterator to one past the end element in a buffer sequence. +inline const mutable_buffer* buffer_sequence_end(const mutable_buffer& b) +{ + return &b + 1; +} + +/// Get an iterator to one past the end element in a buffer sequence. +inline const const_buffer* buffer_sequence_end(const const_buffer& b) +{ + return &b + 1; +} + +#if defined(BOOST_ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +/// Get an iterator to one past the end element in a buffer sequence. +template <typename C> +inline auto buffer_sequence_end(C& c) -> decltype(c.end()) +{ + return c.end(); +} + +/// Get an iterator to one past the end element in a buffer sequence. +template <typename C> +inline auto buffer_sequence_end(const C& c) -> decltype(c.end()) +{ + return c.end(); +} + +#else // defined(BOOST_ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +template <typename C> +inline typename C::iterator buffer_sequence_end(C& c) +{ + return c.end(); +} + +template <typename C> +inline typename C::const_iterator buffer_sequence_end(const C& c) +{ + return c.end(); +} + +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +/*@}*/ + +namespace detail { + +// Tag types used to select appropriately optimised overloads. +struct one_buffer {}; +struct multiple_buffers {}; + +// Helper trait to detect single buffers. template <typename BufferSequence> -inline std::size_t buffer_size(const BufferSequence& b) +struct buffer_sequence_cardinality : + conditional< + is_same<BufferSequence, mutable_buffer>::value +#if !defined(BOOST_ASIO_NO_DEPRECATED) + || is_same<BufferSequence, mutable_buffers_1>::value + || is_same<BufferSequence, const_buffers_1>::value +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + || is_same<BufferSequence, const_buffer>::value, + one_buffer, multiple_buffers>::type {}; + +template <typename Iterator> +inline std::size_t buffer_size(one_buffer, + Iterator begin, Iterator) BOOST_ASIO_NOEXCEPT +{ + return const_buffer(*begin).size(); +} + +template <typename Iterator> +inline std::size_t buffer_size(multiple_buffers, + Iterator begin, Iterator end) BOOST_ASIO_NOEXCEPT { std::size_t total_buffer_size = 0; - typename BufferSequence::const_iterator iter = b.begin(); - typename BufferSequence::const_iterator end = b.end(); + Iterator iter = begin; for (; iter != end; ++iter) - total_buffer_size += detail::buffer_size_helper(*iter); + { + const_buffer b(*iter); + total_buffer_size += b.size(); + } return total_buffer_size; } -/*@}*/ +} // namespace detail + +/// Get the total number of bytes in a buffer sequence. +/** + * The @c buffer_size function determines the total size of all buffers in the + * buffer sequence, as if computed as follows: + * + * @code size_t total_size = 0; + * auto i = boost::asio::buffer_sequence_begin(buffers); + * auto end = boost::asio::buffer_sequence_end(buffers); + * for (; i != end; ++i) + * { + * const_buffer b(*i); + * total_size += b.size(); + * } + * return total_size; @endcode + * + * The @c BufferSequence template parameter may meet either of the @c + * ConstBufferSequence or @c MutableBufferSequence type requirements. + */ +template <typename BufferSequence> +inline std::size_t buffer_size(const BufferSequence& b) BOOST_ASIO_NOEXCEPT +{ + return detail::buffer_size( + detail::buffer_sequence_cardinality<BufferSequence>(), + boost::asio::buffer_sequence_begin(b), + boost::asio::buffer_sequence_end(b)); +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) /** @defgroup buffer_cast boost::asio::buffer_cast * - * @brief The boost::asio::buffer_cast function is used to obtain a pointer to - * the underlying memory region associated with a buffer. + * @brief (Deprecated: Use the @c data() member function.) The + * boost::asio::buffer_cast function is used to obtain a pointer to the + * underlying memory region associated with a buffer. * * @par Examples: * @@ -422,30 +613,32 @@ inline std::size_t buffer_size(const BufferSequence& b) /// Cast a non-modifiable buffer to a specified pointer to POD type. template <typename PointerToPodType> -inline PointerToPodType buffer_cast(const mutable_buffer& b) +inline PointerToPodType buffer_cast(const mutable_buffer& b) BOOST_ASIO_NOEXCEPT { - return static_cast<PointerToPodType>(detail::buffer_cast_helper(b)); + return static_cast<PointerToPodType>(b.data()); } /// Cast a non-modifiable buffer to a specified pointer to POD type. template <typename PointerToPodType> -inline PointerToPodType buffer_cast(const const_buffer& b) +inline PointerToPodType buffer_cast(const const_buffer& b) BOOST_ASIO_NOEXCEPT { - return static_cast<PointerToPodType>(detail::buffer_cast_helper(b)); + return static_cast<PointerToPodType>(b.data()); } /*@}*/ +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + /// Create a new modifiable buffer that is offset from the start of another. /** * @relates mutable_buffer */ -inline mutable_buffer operator+(const mutable_buffer& b, std::size_t start) +inline mutable_buffer operator+(const mutable_buffer& b, + std::size_t n) BOOST_ASIO_NOEXCEPT { - if (start > buffer_size(b)) - return mutable_buffer(); - char* new_data = buffer_cast<char*>(b) + start; - std::size_t new_size = buffer_size(b) - start; + std::size_t offset = n < b.size() ? n : b.size(); + char* new_data = static_cast<char*>(b.data()) + offset; + std::size_t new_size = b.size() - offset; return mutable_buffer(new_data, new_size #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) , b.get_debug_check() @@ -457,29 +650,22 @@ inline mutable_buffer operator+(const mutable_buffer& b, std::size_t start) /** * @relates mutable_buffer */ -inline mutable_buffer operator+(std::size_t start, const mutable_buffer& b) +inline mutable_buffer operator+(std::size_t n, + const mutable_buffer& b) BOOST_ASIO_NOEXCEPT { - if (start > buffer_size(b)) - return mutable_buffer(); - char* new_data = buffer_cast<char*>(b) + start; - std::size_t new_size = buffer_size(b) - start; - return mutable_buffer(new_data, new_size -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - , b.get_debug_check() -#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING - ); + return b + n; } /// Create a new non-modifiable buffer that is offset from the start of another. /** * @relates const_buffer */ -inline const_buffer operator+(const const_buffer& b, std::size_t start) +inline const_buffer operator+(const const_buffer& b, + std::size_t n) BOOST_ASIO_NOEXCEPT { - if (start > buffer_size(b)) - return const_buffer(); - const char* new_data = buffer_cast<const char*>(b) + start; - std::size_t new_size = buffer_size(b) - start; + std::size_t offset = n < b.size() ? n : b.size(); + const char* new_data = static_cast<const char*>(b.data()) + offset; + std::size_t new_size = b.size() - offset; return const_buffer(new_data, new_size #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) , b.get_debug_check() @@ -491,17 +677,10 @@ inline const_buffer operator+(const const_buffer& b, std::size_t start) /** * @relates const_buffer */ -inline const_buffer operator+(std::size_t start, const const_buffer& b) +inline const_buffer operator+(std::size_t n, + const const_buffer& b) BOOST_ASIO_NOEXCEPT { - if (start > buffer_size(b)) - return const_buffer(); - const char* new_data = buffer_cast<const char*>(b) + start; - std::size_t new_size = buffer_size(b) - start; - return const_buffer(new_data, new_size -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - , b.get_debug_check() -#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING - ); + return b + n; } #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) @@ -586,32 +765,33 @@ private: * * @par Accessing Buffer Contents * - * The contents of a buffer may be accessed using the @ref buffer_size and - * @ref buffer_cast functions: + * The contents of a buffer may be accessed using the @c data() and @c size() + * member functions: * * @code boost::asio::mutable_buffer b1 = ...; - * std::size_t s1 = boost::asio::buffer_size(b1); - * unsigned char* p1 = boost::asio::buffer_cast<unsigned char*>(b1); + * std::size_t s1 = b1.size(); + * unsigned char* p1 = static_cast<unsigned char*>(b1.data()); * * boost::asio::const_buffer b2 = ...; - * std::size_t s2 = boost::asio::buffer_size(b2); - * const void* p2 = boost::asio::buffer_cast<const void*>(b2); @endcode + * std::size_t s2 = b2.size(); + * const void* p2 = b2.data(); @endcode * - * The boost::asio::buffer_cast function permits violations of type safety, so + * The @c data() member function permits violations of type safety, so * uses of it in application code should be carefully considered. * - * For convenience, the @ref buffer_size function also works on buffer - * sequences (that is, types meeting the ConstBufferSequence or - * MutableBufferSequence type requirements). In this case, the function returns - * the total size of all buffers in the sequence. + * For convenience, a @ref buffer_size function is provided that works with + * both buffers and buffer sequences (that is, types meeting the + * ConstBufferSequence or MutableBufferSequence type requirements). In this + * case, the function returns the total size of all buffers in the sequence. * * @par Buffer Copying * * The @ref buffer_copy function may be used to copy raw bytes between * individual buffers and buffer sequences. - * - * In particular, when used with the @ref buffer_size, the @ref buffer_copy - * function can be used to linearise a sequence of buffers. For example: +* + * In particular, when used with the @ref buffer_size function, the @ref + * buffer_copy function can be used to linearise a sequence of buffers. For + * example: * * @code vector<const_buffer> buffers = ...; * @@ -700,29 +880,38 @@ private: */ /*@{*/ +#if defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) +# define BOOST_ASIO_MUTABLE_BUFFER mutable_buffer +# define BOOST_ASIO_CONST_BUFFER const_buffer +#else // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) +# define BOOST_ASIO_MUTABLE_BUFFER mutable_buffers_1 +# define BOOST_ASIO_CONST_BUFFER const_buffers_1 +#endif // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + /// Create a new modifiable buffer from an existing buffer. /** - * @returns <tt>mutable_buffers_1(b)</tt>. + * @returns <tt>mutable_buffer(b)</tt>. */ -inline mutable_buffers_1 buffer(const mutable_buffer& b) +inline BOOST_ASIO_MUTABLE_BUFFER buffer( + const mutable_buffer& b) BOOST_ASIO_NOEXCEPT { - return mutable_buffers_1(b); + return BOOST_ASIO_MUTABLE_BUFFER(b); } /// Create a new modifiable buffer from an existing buffer. /** - * @returns A mutable_buffers_1 value equivalent to: - * @code mutable_buffers_1( - * buffer_cast<void*>(b), - * min(buffer_size(b), max_size_in_bytes)); @endcode + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * b.data(), + * min(b.size(), max_size_in_bytes)); @endcode */ -inline mutable_buffers_1 buffer(const mutable_buffer& b, - std::size_t max_size_in_bytes) +inline BOOST_ASIO_MUTABLE_BUFFER buffer(const mutable_buffer& b, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { - return mutable_buffers_1( - mutable_buffer(buffer_cast<void*>(b), - buffer_size(b) < max_size_in_bytes - ? buffer_size(b) : max_size_in_bytes + return BOOST_ASIO_MUTABLE_BUFFER( + mutable_buffer(b.data(), + b.size() < max_size_in_bytes + ? b.size() : max_size_in_bytes #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) , b.get_debug_check() #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING @@ -731,110 +920,110 @@ inline mutable_buffers_1 buffer(const mutable_buffer& b, /// Create a new non-modifiable buffer from an existing buffer. /** - * @returns <tt>const_buffers_1(b)</tt>. + * @returns <tt>const_buffer(b)</tt>. */ -inline const_buffers_1 buffer(const const_buffer& b) +inline BOOST_ASIO_CONST_BUFFER buffer( + const const_buffer& b) BOOST_ASIO_NOEXCEPT { - return const_buffers_1(b); + return BOOST_ASIO_CONST_BUFFER(b); } /// Create a new non-modifiable buffer from an existing buffer. /** - * @returns A const_buffers_1 value equivalent to: - * @code const_buffers_1( - * buffer_cast<const void*>(b), - * min(buffer_size(b), max_size_in_bytes)); @endcode + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * b.data(), + * min(b.size(), max_size_in_bytes)); @endcode */ -inline const_buffers_1 buffer(const const_buffer& b, - std::size_t max_size_in_bytes) +inline BOOST_ASIO_CONST_BUFFER buffer(const const_buffer& b, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { - return const_buffers_1( - const_buffer(buffer_cast<const void*>(b), - buffer_size(b) < max_size_in_bytes - ? buffer_size(b) : max_size_in_bytes + return BOOST_ASIO_CONST_BUFFER(b.data(), + b.size() < max_size_in_bytes + ? b.size() : max_size_in_bytes #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - , b.get_debug_check() + , b.get_debug_check() #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING - )); + ); } /// Create a new modifiable buffer that represents the given memory range. /** - * @returns <tt>mutable_buffers_1(data, size_in_bytes)</tt>. + * @returns <tt>mutable_buffer(data, size_in_bytes)</tt>. */ -inline mutable_buffers_1 buffer(void* data, std::size_t size_in_bytes) +inline BOOST_ASIO_MUTABLE_BUFFER buffer(void* data, + std::size_t size_in_bytes) BOOST_ASIO_NOEXCEPT { - return mutable_buffers_1(mutable_buffer(data, size_in_bytes)); + return BOOST_ASIO_MUTABLE_BUFFER(data, size_in_bytes); } /// Create a new non-modifiable buffer that represents the given memory range. /** - * @returns <tt>const_buffers_1(data, size_in_bytes)</tt>. + * @returns <tt>const_buffer(data, size_in_bytes)</tt>. */ -inline const_buffers_1 buffer(const void* data, - std::size_t size_in_bytes) +inline BOOST_ASIO_CONST_BUFFER buffer(const void* data, + std::size_t size_in_bytes) BOOST_ASIO_NOEXCEPT { - return const_buffers_1(const_buffer(data, size_in_bytes)); + return BOOST_ASIO_CONST_BUFFER(data, size_in_bytes); } /// Create a new modifiable buffer that represents the given POD array. /** - * @returns A mutable_buffers_1 value equivalent to: - * @code mutable_buffers_1( + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( * static_cast<void*>(data), * N * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> -inline mutable_buffers_1 buffer(PodType (&data)[N]) +inline BOOST_ASIO_MUTABLE_BUFFER buffer(PodType (&data)[N]) BOOST_ASIO_NOEXCEPT { - return mutable_buffers_1(mutable_buffer(data, N * sizeof(PodType))); + return BOOST_ASIO_MUTABLE_BUFFER(data, N * sizeof(PodType)); } /// Create a new modifiable buffer that represents the given POD array. /** - * @returns A mutable_buffers_1 value equivalent to: - * @code mutable_buffers_1( + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( * static_cast<void*>(data), * min(N * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> -inline mutable_buffers_1 buffer(PodType (&data)[N], - std::size_t max_size_in_bytes) +inline BOOST_ASIO_MUTABLE_BUFFER buffer(PodType (&data)[N], + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { - return mutable_buffers_1( - mutable_buffer(data, - N * sizeof(PodType) < max_size_in_bytes - ? N * sizeof(PodType) : max_size_in_bytes)); + return BOOST_ASIO_MUTABLE_BUFFER(data, + N * sizeof(PodType) < max_size_in_bytes + ? N * sizeof(PodType) : max_size_in_bytes); } /// Create a new non-modifiable buffer that represents the given POD array. /** - * @returns A const_buffers_1 value equivalent to: - * @code const_buffers_1( + * @returns A const_buffer value equivalent to: + * @code const_buffer( * static_cast<const void*>(data), * N * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> -inline const_buffers_1 buffer(const PodType (&data)[N]) +inline BOOST_ASIO_CONST_BUFFER buffer( + const PodType (&data)[N]) BOOST_ASIO_NOEXCEPT { - return const_buffers_1(const_buffer(data, N * sizeof(PodType))); + return BOOST_ASIO_CONST_BUFFER(data, N * sizeof(PodType)); } /// Create a new non-modifiable buffer that represents the given POD array. /** - * @returns A const_buffers_1 value equivalent to: - * @code const_buffers_1( + * @returns A const_buffer value equivalent to: + * @code const_buffer( * static_cast<const void*>(data), * min(N * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> -inline const_buffers_1 buffer(const PodType (&data)[N], - std::size_t max_size_in_bytes) +inline BOOST_ASIO_CONST_BUFFER buffer(const PodType (&data)[N], + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { - return const_buffers_1( - const_buffer(data, - N * sizeof(PodType) < max_size_in_bytes - ? N * sizeof(PodType) : max_size_in_bytes)); + return BOOST_ASIO_CONST_BUFFER(data, + N * sizeof(PodType) < max_size_in_bytes + ? N * sizeof(PodType) : max_size_in_bytes); } #if defined(BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) @@ -860,14 +1049,14 @@ template <> struct buffer_types_base<false> { typedef mutable_buffer buffer_type; - typedef mutable_buffers_1 container_type; + typedef BOOST_ASIO_MUTABLE_BUFFER container_type; }; template <> struct buffer_types_base<true> { typedef const_buffer buffer_type; - typedef const_buffers_1 container_type; + typedef BOOST_ASIO_CONST_BUFFER container_type; }; template <typename PodType> @@ -880,7 +1069,7 @@ struct buffer_types template <typename PodType, std::size_t N> inline typename detail::buffer_types<PodType>::container_type -buffer(boost::array<PodType, N>& data) +buffer(boost::array<PodType, N>& data) BOOST_ASIO_NOEXCEPT { typedef typename boost::asio::detail::buffer_types<PodType>::buffer_type buffer_type; @@ -892,7 +1081,8 @@ buffer(boost::array<PodType, N>& data) template <typename PodType, std::size_t N> inline typename detail::buffer_types<PodType>::container_type -buffer(boost::array<PodType, N>& data, std::size_t max_size_in_bytes) +buffer(boost::array<PodType, N>& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { typedef typename boost::asio::detail::buffer_types<PodType>::buffer_type buffer_type; @@ -908,200 +1098,195 @@ buffer(boost::array<PodType, N>& data, std::size_t max_size_in_bytes) /// Create a new modifiable buffer that represents the given POD array. /** - * @returns A mutable_buffers_1 value equivalent to: - * @code mutable_buffers_1( + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( * data.data(), * data.size() * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> -inline mutable_buffers_1 buffer(boost::array<PodType, N>& data) +inline BOOST_ASIO_MUTABLE_BUFFER buffer( + boost::array<PodType, N>& data) BOOST_ASIO_NOEXCEPT { - return mutable_buffers_1( - mutable_buffer(data.c_array(), data.size() * sizeof(PodType))); + return BOOST_ASIO_MUTABLE_BUFFER( + data.c_array(), data.size() * sizeof(PodType)); } /// Create a new modifiable buffer that represents the given POD array. /** - * @returns A mutable_buffers_1 value equivalent to: - * @code mutable_buffers_1( + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( * data.data(), * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> -inline mutable_buffers_1 buffer(boost::array<PodType, N>& data, - std::size_t max_size_in_bytes) +inline BOOST_ASIO_MUTABLE_BUFFER buffer(boost::array<PodType, N>& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { - return mutable_buffers_1( - mutable_buffer(data.c_array(), - data.size() * sizeof(PodType) < max_size_in_bytes - ? data.size() * sizeof(PodType) : max_size_in_bytes)); + return BOOST_ASIO_MUTABLE_BUFFER(data.c_array(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); } /// Create a new non-modifiable buffer that represents the given POD array. /** - * @returns A const_buffers_1 value equivalent to: - * @code const_buffers_1( + * @returns A const_buffer value equivalent to: + * @code const_buffer( * data.data(), * data.size() * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> -inline const_buffers_1 buffer(boost::array<const PodType, N>& data) +inline BOOST_ASIO_CONST_BUFFER buffer( + boost::array<const PodType, N>& data) BOOST_ASIO_NOEXCEPT { - return const_buffers_1( - const_buffer(data.data(), data.size() * sizeof(PodType))); + return BOOST_ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType)); } /// Create a new non-modifiable buffer that represents the given POD array. /** - * @returns A const_buffers_1 value equivalent to: - * @code const_buffers_1( + * @returns A const_buffer value equivalent to: + * @code const_buffer( * data.data(), * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> -inline const_buffers_1 buffer(boost::array<const PodType, N>& data, - std::size_t max_size_in_bytes) +inline BOOST_ASIO_CONST_BUFFER buffer(boost::array<const PodType, N>& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { - return const_buffers_1( - const_buffer(data.data(), - data.size() * sizeof(PodType) < max_size_in_bytes - ? data.size() * sizeof(PodType) : max_size_in_bytes)); + return BOOST_ASIO_CONST_BUFFER(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); } #endif // defined(BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) /// Create a new non-modifiable buffer that represents the given POD array. /** - * @returns A const_buffers_1 value equivalent to: - * @code const_buffers_1( + * @returns A const_buffer value equivalent to: + * @code const_buffer( * data.data(), * data.size() * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> -inline const_buffers_1 buffer(const boost::array<PodType, N>& data) +inline BOOST_ASIO_CONST_BUFFER buffer( + const boost::array<PodType, N>& data) BOOST_ASIO_NOEXCEPT { - return const_buffers_1( - const_buffer(data.data(), data.size() * sizeof(PodType))); + return BOOST_ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType)); } /// Create a new non-modifiable buffer that represents the given POD array. /** - * @returns A const_buffers_1 value equivalent to: - * @code const_buffers_1( + * @returns A const_buffer value equivalent to: + * @code const_buffer( * data.data(), * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> -inline const_buffers_1 buffer(const boost::array<PodType, N>& data, - std::size_t max_size_in_bytes) +inline BOOST_ASIO_CONST_BUFFER buffer(const boost::array<PodType, N>& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { - return const_buffers_1( - const_buffer(data.data(), - data.size() * sizeof(PodType) < max_size_in_bytes - ? data.size() * sizeof(PodType) : max_size_in_bytes)); + return BOOST_ASIO_CONST_BUFFER(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); } #if defined(BOOST_ASIO_HAS_STD_ARRAY) || defined(GENERATING_DOCUMENTATION) /// Create a new modifiable buffer that represents the given POD array. /** - * @returns A mutable_buffers_1 value equivalent to: - * @code mutable_buffers_1( + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( * data.data(), * data.size() * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> -inline mutable_buffers_1 buffer(std::array<PodType, N>& data) +inline BOOST_ASIO_MUTABLE_BUFFER buffer( + std::array<PodType, N>& data) BOOST_ASIO_NOEXCEPT { - return mutable_buffers_1( - mutable_buffer(data.data(), data.size() * sizeof(PodType))); + return BOOST_ASIO_MUTABLE_BUFFER(data.data(), data.size() * sizeof(PodType)); } /// Create a new modifiable buffer that represents the given POD array. /** - * @returns A mutable_buffers_1 value equivalent to: - * @code mutable_buffers_1( + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( * data.data(), * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> -inline mutable_buffers_1 buffer(std::array<PodType, N>& data, - std::size_t max_size_in_bytes) +inline BOOST_ASIO_MUTABLE_BUFFER buffer(std::array<PodType, N>& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { - return mutable_buffers_1( - mutable_buffer(data.data(), - data.size() * sizeof(PodType) < max_size_in_bytes - ? data.size() * sizeof(PodType) : max_size_in_bytes)); + return BOOST_ASIO_MUTABLE_BUFFER(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); } /// Create a new non-modifiable buffer that represents the given POD array. /** - * @returns A const_buffers_1 value equivalent to: - * @code const_buffers_1( + * @returns A const_buffer value equivalent to: + * @code const_buffer( * data.data(), * data.size() * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> -inline const_buffers_1 buffer(std::array<const PodType, N>& data) +inline BOOST_ASIO_CONST_BUFFER buffer( + std::array<const PodType, N>& data) BOOST_ASIO_NOEXCEPT { - return const_buffers_1( - const_buffer(data.data(), data.size() * sizeof(PodType))); + return BOOST_ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType)); } /// Create a new non-modifiable buffer that represents the given POD array. /** - * @returns A const_buffers_1 value equivalent to: - * @code const_buffers_1( + * @returns A const_buffer value equivalent to: + * @code const_buffer( * data.data(), * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> -inline const_buffers_1 buffer(std::array<const PodType, N>& data, - std::size_t max_size_in_bytes) +inline BOOST_ASIO_CONST_BUFFER buffer(std::array<const PodType, N>& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { - return const_buffers_1( - const_buffer(data.data(), - data.size() * sizeof(PodType) < max_size_in_bytes - ? data.size() * sizeof(PodType) : max_size_in_bytes)); + return BOOST_ASIO_CONST_BUFFER(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); } /// Create a new non-modifiable buffer that represents the given POD array. /** - * @returns A const_buffers_1 value equivalent to: - * @code const_buffers_1( + * @returns A const_buffer value equivalent to: + * @code const_buffer( * data.data(), * data.size() * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> -inline const_buffers_1 buffer(const std::array<PodType, N>& data) +inline BOOST_ASIO_CONST_BUFFER buffer( + const std::array<PodType, N>& data) BOOST_ASIO_NOEXCEPT { - return const_buffers_1( - const_buffer(data.data(), data.size() * sizeof(PodType))); + return BOOST_ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType)); } /// Create a new non-modifiable buffer that represents the given POD array. /** - * @returns A const_buffers_1 value equivalent to: - * @code const_buffers_1( + * @returns A const_buffer value equivalent to: + * @code const_buffer( * data.data(), * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> -inline const_buffers_1 buffer(const std::array<PodType, N>& data, - std::size_t max_size_in_bytes) +inline BOOST_ASIO_CONST_BUFFER buffer(const std::array<PodType, N>& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { - return const_buffers_1( - const_buffer(data.data(), - data.size() * sizeof(PodType) < max_size_in_bytes - ? data.size() * sizeof(PodType) : max_size_in_bytes)); + return BOOST_ASIO_CONST_BUFFER(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); } #endif // defined(BOOST_ASIO_HAS_STD_ARRAY) || defined(GENERATING_DOCUMENTATION) /// Create a new modifiable buffer that represents the given POD vector. /** - * @returns A mutable_buffers_1 value equivalent to: - * @code mutable_buffers_1( + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( * data.size() ? &data[0] : 0, * data.size() * sizeof(PodType)); @endcode * @@ -1109,22 +1294,23 @@ inline const_buffers_1 buffer(const std::array<PodType, N>& data, * invalidate iterators. */ template <typename PodType, typename Allocator> -inline mutable_buffers_1 buffer(std::vector<PodType, Allocator>& data) +inline BOOST_ASIO_MUTABLE_BUFFER buffer( + std::vector<PodType, Allocator>& data) BOOST_ASIO_NOEXCEPT { - return mutable_buffers_1( - mutable_buffer(data.size() ? &data[0] : 0, data.size() * sizeof(PodType) + return BOOST_ASIO_MUTABLE_BUFFER( + data.size() ? &data[0] : 0, data.size() * sizeof(PodType) #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - , detail::buffer_debug_check< - typename std::vector<PodType, Allocator>::iterator - >(data.begin()) + , detail::buffer_debug_check< + typename std::vector<PodType, Allocator>::iterator + >(data.begin()) #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING - )); + ); } /// Create a new modifiable buffer that represents the given POD vector. /** - * @returns A mutable_buffers_1 value equivalent to: - * @code mutable_buffers_1( + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( * data.size() ? &data[0] : 0, * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode * @@ -1132,25 +1318,24 @@ inline mutable_buffers_1 buffer(std::vector<PodType, Allocator>& data) * invalidate iterators. */ template <typename PodType, typename Allocator> -inline mutable_buffers_1 buffer(std::vector<PodType, Allocator>& data, - std::size_t max_size_in_bytes) +inline BOOST_ASIO_MUTABLE_BUFFER buffer(std::vector<PodType, Allocator>& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { - return mutable_buffers_1( - mutable_buffer(data.size() ? &data[0] : 0, - data.size() * sizeof(PodType) < max_size_in_bytes - ? data.size() * sizeof(PodType) : max_size_in_bytes + return BOOST_ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - , detail::buffer_debug_check< - typename std::vector<PodType, Allocator>::iterator - >(data.begin()) + , detail::buffer_debug_check< + typename std::vector<PodType, Allocator>::iterator + >(data.begin()) #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING - )); + ); } /// Create a new non-modifiable buffer that represents the given POD vector. /** - * @returns A const_buffers_1 value equivalent to: - * @code const_buffers_1( + * @returns A const_buffer value equivalent to: + * @code const_buffer( * data.size() ? &data[0] : 0, * data.size() * sizeof(PodType)); @endcode * @@ -1158,23 +1343,23 @@ inline mutable_buffers_1 buffer(std::vector<PodType, Allocator>& data, * invalidate iterators. */ template <typename PodType, typename Allocator> -inline const_buffers_1 buffer( - const std::vector<PodType, Allocator>& data) +inline BOOST_ASIO_CONST_BUFFER buffer( + const std::vector<PodType, Allocator>& data) BOOST_ASIO_NOEXCEPT { - return const_buffers_1( - const_buffer(data.size() ? &data[0] : 0, data.size() * sizeof(PodType) + return BOOST_ASIO_CONST_BUFFER( + data.size() ? &data[0] : 0, data.size() * sizeof(PodType) #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - , detail::buffer_debug_check< - typename std::vector<PodType, Allocator>::const_iterator - >(data.begin()) + , detail::buffer_debug_check< + typename std::vector<PodType, Allocator>::const_iterator + >(data.begin()) #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING - )); + ); } /// Create a new non-modifiable buffer that represents the given POD vector. /** - * @returns A const_buffers_1 value equivalent to: - * @code const_buffers_1( + * @returns A const_buffer value equivalent to: + * @code const_buffer( * data.size() ? &data[0] : 0, * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode * @@ -1182,527 +1367,640 @@ inline const_buffers_1 buffer( * invalidate iterators. */ template <typename PodType, typename Allocator> -inline const_buffers_1 buffer( - const std::vector<PodType, Allocator>& data, std::size_t max_size_in_bytes) +inline BOOST_ASIO_CONST_BUFFER buffer( + const std::vector<PodType, Allocator>& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { - return const_buffers_1( - const_buffer(data.size() ? &data[0] : 0, - data.size() * sizeof(PodType) < max_size_in_bytes - ? data.size() * sizeof(PodType) : max_size_in_bytes + return BOOST_ASIO_CONST_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - , detail::buffer_debug_check< - typename std::vector<PodType, Allocator>::const_iterator - >(data.begin()) + , detail::buffer_debug_check< + typename std::vector<PodType, Allocator>::const_iterator + >(data.begin()) #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING - )); + ); } -/// Create a new non-modifiable buffer that represents the given string. +/// Create a new modifiable buffer that represents the given string. /** - * @returns <tt>const_buffers_1(data.data(), data.size() * sizeof(Elem))</tt>. + * @returns <tt>mutable_buffer(data.size() ? &data[0] : 0, + * data.size() * sizeof(Elem))</tt>. * * @note The buffer is invalidated by any non-const operation called on the * given string object. */ template <typename Elem, typename Traits, typename Allocator> -inline const_buffers_1 buffer( - const std::basic_string<Elem, Traits, Allocator>& data) +inline BOOST_ASIO_MUTABLE_BUFFER buffer( + std::basic_string<Elem, Traits, Allocator>& data) BOOST_ASIO_NOEXCEPT { - return const_buffers_1(const_buffer(data.data(), data.size() * sizeof(Elem) + return BOOST_ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(Elem) #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - , detail::buffer_debug_check< - typename std::basic_string<Elem, Traits, Allocator>::const_iterator - >(data.begin()) + , detail::buffer_debug_check< + typename std::basic_string<Elem, Traits, Allocator>::iterator + >(data.begin()) #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING - )); + ); } /// Create a new non-modifiable buffer that represents the given string. /** - * @returns A const_buffers_1 value equivalent to: - * @code const_buffers_1( - * data.data(), + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.size() ? &data[0] : 0, * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode * * @note The buffer is invalidated by any non-const operation called on the * given string object. */ template <typename Elem, typename Traits, typename Allocator> -inline const_buffers_1 buffer( - const std::basic_string<Elem, Traits, Allocator>& data, - std::size_t max_size_in_bytes) +inline BOOST_ASIO_MUTABLE_BUFFER buffer( + std::basic_string<Elem, Traits, Allocator>& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { - return const_buffers_1( - const_buffer(data.data(), - data.size() * sizeof(Elem) < max_size_in_bytes - ? data.size() * sizeof(Elem) : max_size_in_bytes + return BOOST_ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(Elem) < max_size_in_bytes + ? data.size() * sizeof(Elem) : max_size_in_bytes #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - , detail::buffer_debug_check< - typename std::basic_string<Elem, Traits, Allocator>::const_iterator - >(data.begin()) + , detail::buffer_debug_check< + typename std::basic_string<Elem, Traits, Allocator>::iterator + >(data.begin()) #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING - )); + ); } -/*@}*/ - -/** @defgroup buffer_copy boost::asio::buffer_copy - * - * @brief The boost::asio::buffer_copy function is used to copy bytes from a - * source buffer (or buffer sequence) to a target buffer (or buffer sequence). - * - * The @c buffer_copy function is available in two forms: - * - * @li A 2-argument form: @c buffer_copy(target, source) - * - * @li A 3-argument form: @c buffer_copy(target, source, max_bytes_to_copy) - - * Both forms return the number of bytes actually copied. The number of bytes - * copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * @li @c If specified, @c max_bytes_to_copy. - * - * This prevents buffer overflow, regardless of the buffer sizes used in the - * copy operation. - * - * Note that @ref buffer_copy is implemented in terms of @c memcpy, and - * consequently it cannot be used to copy between overlapping memory regions. - */ -/*@{*/ - -/// Copies bytes from a source buffer to a target buffer. +/// Create a new non-modifiable buffer that represents the given string. /** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. + * @returns <tt>const_buffer(data.data(), data.size() * sizeof(Elem))</tt>. * - * @param source A non-modifiable buffer representing the memory region from - * which the bytes will be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. + * @note The buffer is invalidated by any non-const operation called on the + * given string object. */ -inline std::size_t buffer_copy(const mutable_buffer& target, - const const_buffer& source) +template <typename Elem, typename Traits, typename Allocator> +inline BOOST_ASIO_CONST_BUFFER buffer( + const std::basic_string<Elem, Traits, Allocator>& data) BOOST_ASIO_NOEXCEPT { - using namespace std; // For memcpy. - std::size_t target_size = buffer_size(target); - std::size_t source_size = buffer_size(source); - std::size_t n = target_size < source_size ? target_size : source_size; - memcpy(buffer_cast<void*>(target), buffer_cast<const void*>(source), n); - return n; + return BOOST_ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(Elem) +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::basic_string<Elem, Traits, Allocator>::const_iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); } -/// Copies bytes from a source buffer to a target buffer. +/// Create a new non-modifiable buffer that represents the given string. /** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A non-modifiable buffer representing the memory region from - * which the bytes will be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. + * @note The buffer is invalidated by any non-const operation called on the + * given string object. */ -inline std::size_t buffer_copy(const mutable_buffer& target, - const const_buffers_1& source) +template <typename Elem, typename Traits, typename Allocator> +inline BOOST_ASIO_CONST_BUFFER buffer( + const std::basic_string<Elem, Traits, Allocator>& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { - return buffer_copy(target, static_cast<const const_buffer&>(source)); + return BOOST_ASIO_CONST_BUFFER(data.data(), + data.size() * sizeof(Elem) < max_size_in_bytes + ? data.size() * sizeof(Elem) : max_size_in_bytes +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::basic_string<Elem, Traits, Allocator>::const_iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); } -/// Copies bytes from a source buffer to a target buffer. +#if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) \ + || defined(GENERATING_DOCUMENTATION) + +/// Create a new modifiable buffer that represents the given string_view. /** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A modifiable buffer representing the memory region from which - * the bytes will be copied. The contents of the source buffer will not be - * modified. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. + * @returns <tt>mutable_buffer(data.size() ? &data[0] : 0, + * data.size() * sizeof(Elem))</tt>. */ -inline std::size_t buffer_copy(const mutable_buffer& target, - const mutable_buffer& source) +template <typename Elem, typename Traits> +inline BOOST_ASIO_CONST_BUFFER buffer( + basic_string_view<Elem, Traits> data) BOOST_ASIO_NOEXCEPT { - return buffer_copy(target, const_buffer(source)); + return BOOST_ASIO_CONST_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(Elem) +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename basic_string_view<Elem, Traits>::iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); } -/// Copies bytes from a source buffer to a target buffer. +/// Create a new non-modifiable buffer that represents the given string. /** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A modifiable buffer representing the memory region from which - * the bytes will be copied. The contents of the source buffer will not be - * modified. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.size() ? &data[0] : 0, + * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode */ -inline std::size_t buffer_copy(const mutable_buffer& target, - const mutable_buffers_1& source) +template <typename Elem, typename Traits> +inline BOOST_ASIO_CONST_BUFFER buffer( + basic_string_view<Elem, Traits> data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { - return buffer_copy(target, const_buffer(source)); + return BOOST_ASIO_CONST_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(Elem) < max_size_in_bytes + ? data.size() * sizeof(Elem) : max_size_in_bytes +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename basic_string_view<Elem, Traits>::iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); } -/// Copies bytes from a source buffer sequence to a target buffer. +#endif // defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + // || defined(GENERATING_DOCUMENTATION) + +/*@}*/ + +/// Adapt a basic_string to the DynamicBuffer requirements. /** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A non-modifiable buffer sequence representing the memory - * regions from which the bytes will be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. + * Requires that <tt>sizeof(Elem) == 1</tt>. */ -template <typename ConstBufferSequence> -std::size_t buffer_copy(const mutable_buffer& target, - const ConstBufferSequence& source) +template <typename Elem, typename Traits, typename Allocator> +class dynamic_string_buffer { - std::size_t total_bytes_copied = 0; +public: + /// The type used to represent the input sequence as a list of buffers. + typedef BOOST_ASIO_CONST_BUFFER const_buffers_type; + + /// The type used to represent the output sequence as a list of buffers. + typedef BOOST_ASIO_MUTABLE_BUFFER mutable_buffers_type; + + /// Construct a dynamic buffer from a string. + /** + * @param s The string to be used as backing storage for the dynamic buffer. + * Any existing data in the string is treated as the dynamic buffer's input + * sequence. The object stores a reference to the string and the user is + * responsible for ensuring that the string object remains valid until the + * dynamic_string_buffer object is destroyed. + * + * @param maximum_size Specifies a maximum size for the buffer, in bytes. + */ + explicit dynamic_string_buffer(std::basic_string<Elem, Traits, Allocator>& s, + std::size_t maximum_size = + (std::numeric_limits<std::size_t>::max)()) BOOST_ASIO_NOEXCEPT + : string_(s), + size_(string_.size()), + max_size_(maximum_size) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move construct a dynamic buffer. + dynamic_string_buffer(dynamic_string_buffer&& other) BOOST_ASIO_NOEXCEPT + : string_(other.string_), + size_(other.size_), + max_size_(other.max_size_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - typename ConstBufferSequence::const_iterator source_iter = source.begin(); - typename ConstBufferSequence::const_iterator source_end = source.end(); + /// Get the size of the input sequence. + std::size_t size() const BOOST_ASIO_NOEXCEPT + { + return size_; + } - for (mutable_buffer target_buffer(target); - buffer_size(target_buffer) && source_iter != source_end; ++source_iter) + /// Get the maximum size of the dynamic buffer. + /** + * @returns The allowed maximum of the sum of the sizes of the input sequence + * and output sequence. + */ + std::size_t max_size() const BOOST_ASIO_NOEXCEPT { - const_buffer source_buffer(*source_iter); - std::size_t bytes_copied = buffer_copy(target_buffer, source_buffer); - total_bytes_copied += bytes_copied; - target_buffer = target_buffer + bytes_copied; + return max_size_; } - return total_bytes_copied; -} + /// Get the current capacity of the dynamic buffer. + /** + * @returns The current total capacity of the buffer, i.e. for both the input + * sequence and output sequence. + */ + std::size_t capacity() const BOOST_ASIO_NOEXCEPT + { + return string_.capacity(); + } + + /// Get a list of buffers that represents the input sequence. + /** + * @returns An object of type @c const_buffers_type that satisfies + * ConstBufferSequence requirements, representing the basic_string memory in + * input sequence. + * + * @note The returned object is invalidated by any @c dynamic_string_buffer + * or @c basic_string member function that modifies the input sequence or + * output sequence. + */ + const_buffers_type data() const BOOST_ASIO_NOEXCEPT + { + return const_buffers_type(boost::asio::buffer(string_, size_)); + } + + /// Get a list of buffers that represents the output sequence, with the given + /// size. + /** + * Ensures that the output sequence can accommodate @c n bytes, resizing the + * basic_string object as necessary. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing basic_string memory + * at the start of the output sequence of size @c n. + * + * @throws std::length_error If <tt>size() + n > max_size()</tt>. + * + * @note The returned object is invalidated by any @c dynamic_string_buffer + * or @c basic_string member function that modifies the input sequence or + * output sequence. + */ + mutable_buffers_type prepare(std::size_t n) + { + if (size () > max_size() || max_size() - size() < n) + { + std::length_error ex("dynamic_string_buffer too long"); + boost::asio::detail::throw_exception(ex); + } + + string_.resize(size_ + n); + + return boost::asio::buffer(boost::asio::buffer(string_) + size_, n); + } + + /// Move bytes from the output sequence to the input sequence. + /** + * @param n The number of bytes to append from the start of the output + * sequence to the end of the input sequence. The remainder of the output + * sequence is discarded. + * + * Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and + * no intervening operations that modify the input or output sequence. + * + * @note If @c n is greater than the size of the output sequence, the entire + * output sequence is moved to the input sequence and no error is issued. + */ + void commit(std::size_t n) + { + size_ += (std::min)(n, string_.size() - size_); + string_.resize(size_); + } + + /// Remove characters from the input sequence. + /** + * Removes @c n characters from the beginning of the input sequence. + * + * @note If @c n is greater than the size of the input sequence, the entire + * input sequence is consumed and no error is issued. + */ + void consume(std::size_t n) + { + std::size_t consume_length = (std::min)(n, size_); + string_.erase(0, consume_length); + size_ -= consume_length; + } + +private: + std::basic_string<Elem, Traits, Allocator>& string_; + std::size_t size_; + const std::size_t max_size_; +}; -/// Copies bytes from a source buffer to a target buffer. +/// Adapt a vector to the DynamicBuffer requirements. /** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A non-modifiable buffer representing the memory region from - * which the bytes will be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. + * Requires that <tt>sizeof(Elem) == 1</tt>. */ -inline std::size_t buffer_copy(const mutable_buffers_1& target, - const const_buffer& source) +template <typename Elem, typename Allocator> +class dynamic_vector_buffer { - return buffer_copy(static_cast<const mutable_buffer&>(target), source); -} +public: + /// The type used to represent the input sequence as a list of buffers. + typedef BOOST_ASIO_CONST_BUFFER const_buffers_type; + + /// The type used to represent the output sequence as a list of buffers. + typedef BOOST_ASIO_MUTABLE_BUFFER mutable_buffers_type; + + /// Construct a dynamic buffer from a string. + /** + * @param v The vector to be used as backing storage for the dynamic buffer. + * Any existing data in the vector is treated as the dynamic buffer's input + * sequence. The object stores a reference to the vector and the user is + * responsible for ensuring that the vector object remains valid until the + * dynamic_vector_buffer object is destroyed. + * + * @param maximum_size Specifies a maximum size for the buffer, in bytes. + */ + explicit dynamic_vector_buffer(std::vector<Elem, Allocator>& v, + std::size_t maximum_size = + (std::numeric_limits<std::size_t>::max)()) BOOST_ASIO_NOEXCEPT + : vector_(v), + size_(vector_.size()), + max_size_(maximum_size) + { + } -/// Copies bytes from a source buffer to a target buffer. -/** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A non-modifiable buffer representing the memory region from - * which the bytes will be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move construct a dynamic buffer. + dynamic_vector_buffer(dynamic_vector_buffer&& other) BOOST_ASIO_NOEXCEPT + : vector_(other.vector_), + size_(other.size_), + max_size_(other.max_size_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Get the size of the input sequence. + std::size_t size() const BOOST_ASIO_NOEXCEPT + { + return size_; + } + + /// Get the maximum size of the dynamic buffer. + /** + * @returns The allowed maximum of the sum of the sizes of the input sequence + * and output sequence. + */ + std::size_t max_size() const BOOST_ASIO_NOEXCEPT + { + return max_size_; + } + + /// Get the current capacity of the dynamic buffer. + /** + * @returns The current total capacity of the buffer, i.e. for both the input + * sequence and output sequence. + */ + std::size_t capacity() const BOOST_ASIO_NOEXCEPT + { + return vector_.capacity(); + } + + /// Get a list of buffers that represents the input sequence. + /** + * @returns An object of type @c const_buffers_type that satisfies + * ConstBufferSequence requirements, representing the basic_string memory in + * input sequence. + * + * @note The returned object is invalidated by any @c dynamic_vector_buffer + * or @c basic_string member function that modifies the input sequence or + * output sequence. + */ + const_buffers_type data() const BOOST_ASIO_NOEXCEPT + { + return const_buffers_type(boost::asio::buffer(vector_, size_)); + } + + /// Get a list of buffers that represents the output sequence, with the given + /// size. + /** + * Ensures that the output sequence can accommodate @c n bytes, resizing the + * basic_string object as necessary. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing basic_string memory + * at the start of the output sequence of size @c n. + * + * @throws std::length_error If <tt>size() + n > max_size()</tt>. + * + * @note The returned object is invalidated by any @c dynamic_vector_buffer + * or @c basic_string member function that modifies the input sequence or + * output sequence. + */ + mutable_buffers_type prepare(std::size_t n) + { + if (size () > max_size() || max_size() - size() < n) + { + std::length_error ex("dynamic_vector_buffer too long"); + boost::asio::detail::throw_exception(ex); + } + + vector_.resize(size_ + n); + + return boost::asio::buffer(boost::asio::buffer(vector_) + size_, n); + } + + /// Move bytes from the output sequence to the input sequence. + /** + * @param n The number of bytes to append from the start of the output + * sequence to the end of the input sequence. The remainder of the output + * sequence is discarded. + * + * Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and + * no intervening operations that modify the input or output sequence. + * + * @note If @c n is greater than the size of the output sequence, the entire + * output sequence is moved to the input sequence and no error is issued. + */ + void commit(std::size_t n) + { + size_ += (std::min)(n, vector_.size() - size_); + vector_.resize(size_); + } + + /// Remove characters from the input sequence. + /** + * Removes @c n characters from the beginning of the input sequence. + * + * @note If @c n is greater than the size of the input sequence, the entire + * input sequence is consumed and no error is issued. + */ + void consume(std::size_t n) + { + std::size_t consume_length = (std::min)(n, size_); + vector_.erase(vector_.begin(), vector_.begin() + consume_length); + size_ -= consume_length; + } + +private: + std::vector<Elem, Allocator>& vector_; + std::size_t size_; + const std::size_t max_size_; +}; + +/** @defgroup dynamic_buffer boost::asio::dynamic_buffer * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. + * @brief The boost::asio::dynamic_buffer function is used to create a + * dynamically resized buffer from a @c std::basic_string or @c std::vector. + */ +/*@{*/ + +/// Create a new dynamic buffer that represents the given string. +/** + * @returns <tt>dynamic_string_buffer<Elem, Traits, Allocator>(data)</tt>. */ -inline std::size_t buffer_copy(const mutable_buffers_1& target, - const const_buffers_1& source) +template <typename Elem, typename Traits, typename Allocator> +inline dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer( + std::basic_string<Elem, Traits, Allocator>& data) BOOST_ASIO_NOEXCEPT { - return buffer_copy(static_cast<const mutable_buffer&>(target), - static_cast<const const_buffer&>(source)); + return dynamic_string_buffer<Elem, Traits, Allocator>(data); } -/// Copies bytes from a source buffer to a target buffer. +/// Create a new dynamic buffer that represents the given string. /** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A modifiable buffer representing the memory region from which - * the bytes will be copied. The contents of the source buffer will not be - * modified. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. + * @returns <tt>dynamic_string_buffer<Elem, Traits, Allocator>(data, + * max_size)</tt>. */ -inline std::size_t buffer_copy(const mutable_buffers_1& target, - const mutable_buffer& source) +template <typename Elem, typename Traits, typename Allocator> +inline dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer( + std::basic_string<Elem, Traits, Allocator>& data, + std::size_t max_size) BOOST_ASIO_NOEXCEPT { - return buffer_copy(static_cast<const mutable_buffer&>(target), - const_buffer(source)); + return dynamic_string_buffer<Elem, Traits, Allocator>(data, max_size); } -/// Copies bytes from a source buffer to a target buffer. +/// Create a new dynamic buffer that represents the given vector. /** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A modifiable buffer representing the memory region from which - * the bytes will be copied. The contents of the source buffer will not be - * modified. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. + * @returns <tt>dynamic_vector_buffer<Elem, Allocator>(data)</tt>. */ -inline std::size_t buffer_copy(const mutable_buffers_1& target, - const mutable_buffers_1& source) +template <typename Elem, typename Allocator> +inline dynamic_vector_buffer<Elem, Allocator> dynamic_buffer( + std::vector<Elem, Allocator>& data) BOOST_ASIO_NOEXCEPT { - return buffer_copy(static_cast<const mutable_buffer&>(target), - const_buffer(source)); + return dynamic_vector_buffer<Elem, Allocator>(data); } -/// Copies bytes from a source buffer sequence to a target buffer. +/// Create a new dynamic buffer that represents the given vector. /** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A non-modifiable buffer sequence representing the memory - * regions from which the bytes will be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. + * @returns <tt>dynamic_vector_buffer<Elem, Allocator>(data, max_size)</tt>. */ -template <typename ConstBufferSequence> -inline std::size_t buffer_copy(const mutable_buffers_1& target, - const ConstBufferSequence& source) +template <typename Elem, typename Allocator> +inline dynamic_vector_buffer<Elem, Allocator> dynamic_buffer( + std::vector<Elem, Allocator>& data, + std::size_t max_size) BOOST_ASIO_NOEXCEPT { - return buffer_copy(static_cast<const mutable_buffer&>(target), source); + return dynamic_vector_buffer<Elem, Allocator>(data, max_size); } -/// Copies bytes from a source buffer to a target buffer sequence. -/** - * @param target A modifiable buffer sequence representing the memory regions to - * which the bytes will be copied. +/*@}*/ + +/** @defgroup buffer_copy boost::asio::buffer_copy * - * @param source A non-modifiable buffer representing the memory region from - * which the bytes will be copied. + * @brief The boost::asio::buffer_copy function is used to copy bytes from a + * source buffer (or buffer sequence) to a target buffer (or buffer sequence). * - * @returns The number of bytes copied. + * The @c buffer_copy function is available in two forms: * - * @note The number of bytes copied is the lesser of: + * @li A 2-argument form: @c buffer_copy(target, source) + * + * @li A 3-argument form: @c buffer_copy(target, source, max_bytes_to_copy) + * + * Both forms return the number of bytes actually copied. The number of bytes + * copied is the lesser of: * * @li @c buffer_size(target) * * @li @c buffer_size(source) * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. + * @li @c If specified, @c max_bytes_to_copy. + * + * This prevents buffer overflow, regardless of the buffer sizes used in the + * copy operation. + * + * Note that @ref buffer_copy is implemented in terms of @c memcpy, and + * consequently it cannot be used to copy between overlapping memory regions. */ -template <typename MutableBufferSequence> -std::size_t buffer_copy(const MutableBufferSequence& target, +/*@{*/ + +namespace detail { + +inline std::size_t buffer_copy_1(const mutable_buffer& target, const const_buffer& source) { - std::size_t total_bytes_copied = 0; + using namespace std; // For memcpy. + std::size_t target_size = target.size(); + std::size_t source_size = source.size(); + std::size_t n = target_size < source_size ? target_size : source_size; + if (n > 0) + memcpy(target.data(), source.data(), n); + return n; +} - typename MutableBufferSequence::const_iterator target_iter = target.begin(); - typename MutableBufferSequence::const_iterator target_end = target.end(); +template <typename TargetIterator, typename SourceIterator> +inline std::size_t buffer_copy(one_buffer, one_buffer, + TargetIterator target_begin, TargetIterator, + SourceIterator source_begin, SourceIterator) BOOST_ASIO_NOEXCEPT +{ + return (buffer_copy_1)(*target_begin, *source_begin); +} - for (const_buffer source_buffer(source); - buffer_size(source_buffer) && target_iter != target_end; ++target_iter) +template <typename TargetIterator, typename SourceIterator> +inline std::size_t buffer_copy(one_buffer, one_buffer, + TargetIterator target_begin, TargetIterator, + SourceIterator source_begin, SourceIterator, + std::size_t max_bytes_to_copy) BOOST_ASIO_NOEXCEPT +{ + return (buffer_copy_1)(*target_begin, + boost::asio::buffer(*source_begin, max_bytes_to_copy)); +} + +template <typename TargetIterator, typename SourceIterator> +std::size_t buffer_copy(one_buffer, multiple_buffers, + TargetIterator target_begin, TargetIterator, + SourceIterator source_begin, SourceIterator source_end, + std::size_t max_bytes_to_copy + = (std::numeric_limits<std::size_t>::max)()) BOOST_ASIO_NOEXCEPT +{ + std::size_t total_bytes_copied = 0; + SourceIterator source_iter = source_begin; + + for (mutable_buffer target_buffer( + boost::asio::buffer(*target_begin, max_bytes_to_copy)); + target_buffer.size() && source_iter != source_end; ++source_iter) { - mutable_buffer target_buffer(*target_iter); - std::size_t bytes_copied = buffer_copy(target_buffer, source_buffer); + const_buffer source_buffer(*source_iter); + std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer); total_bytes_copied += bytes_copied; - source_buffer = source_buffer + bytes_copied; + target_buffer += bytes_copied; } return total_bytes_copied; } -/// Copies bytes from a source buffer to a target buffer sequence. -/** - * @param target A modifiable buffer sequence representing the memory regions to - * which the bytes will be copied. - * - * @param source A non-modifiable buffer representing the memory region from - * which the bytes will be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -template <typename MutableBufferSequence> -inline std::size_t buffer_copy(const MutableBufferSequence& target, - const const_buffers_1& source) +template <typename TargetIterator, typename SourceIterator> +std::size_t buffer_copy(multiple_buffers, one_buffer, + TargetIterator target_begin, TargetIterator target_end, + SourceIterator source_begin, SourceIterator, + std::size_t max_bytes_to_copy + = (std::numeric_limits<std::size_t>::max)()) BOOST_ASIO_NOEXCEPT { - return buffer_copy(target, static_cast<const const_buffer&>(source)); -} + std::size_t total_bytes_copied = 0; + TargetIterator target_iter = target_begin; -/// Copies bytes from a source buffer to a target buffer sequence. -/** - * @param target A modifiable buffer sequence representing the memory regions to - * which the bytes will be copied. - * - * @param source A modifiable buffer representing the memory region from which - * the bytes will be copied. The contents of the source buffer will not be - * modified. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -template <typename MutableBufferSequence> -inline std::size_t buffer_copy(const MutableBufferSequence& target, - const mutable_buffer& source) -{ - return buffer_copy(target, const_buffer(source)); -} + for (const_buffer source_buffer( + boost::asio::buffer(*source_begin, max_bytes_to_copy)); + source_buffer.size() && target_iter != target_end; ++target_iter) + { + mutable_buffer target_buffer(*target_iter); + std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer); + total_bytes_copied += bytes_copied; + source_buffer += bytes_copied; + } -/// Copies bytes from a source buffer to a target buffer sequence. -/** - * @param target A modifiable buffer sequence representing the memory regions to - * which the bytes will be copied. - * - * @param source A modifiable buffer representing the memory region from which - * the bytes will be copied. The contents of the source buffer will not be - * modified. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -template <typename MutableBufferSequence> -inline std::size_t buffer_copy(const MutableBufferSequence& target, - const mutable_buffers_1& source) -{ - return buffer_copy(target, const_buffer(source)); + return total_bytes_copied; } -/// Copies bytes from a source buffer sequence to a target buffer sequence. -/** - * @param target A modifiable buffer sequence representing the memory regions to - * which the bytes will be copied. - * - * @param source A non-modifiable buffer sequence representing the memory - * regions from which the bytes will be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -template <typename MutableBufferSequence, typename ConstBufferSequence> -std::size_t buffer_copy(const MutableBufferSequence& target, - const ConstBufferSequence& source) +template <typename TargetIterator, typename SourceIterator> +std::size_t buffer_copy(multiple_buffers, multiple_buffers, + TargetIterator target_begin, TargetIterator target_end, + SourceIterator source_begin, SourceIterator source_end) BOOST_ASIO_NOEXCEPT { std::size_t total_bytes_copied = 0; - typename MutableBufferSequence::const_iterator target_iter = target.begin(); - typename MutableBufferSequence::const_iterator target_end = target.end(); + TargetIterator target_iter = target_begin; std::size_t target_buffer_offset = 0; - typename ConstBufferSequence::const_iterator source_iter = source.begin(); - typename ConstBufferSequence::const_iterator source_end = source.end(); + SourceIterator source_iter = source_begin; std::size_t source_buffer_offset = 0; while (target_iter != target_end && source_iter != source_end) @@ -1713,10 +2011,10 @@ std::size_t buffer_copy(const MutableBufferSequence& target, const_buffer source_buffer = const_buffer(*source_iter) + source_buffer_offset; - std::size_t bytes_copied = buffer_copy(target_buffer, source_buffer); + std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer); total_bytes_copied += bytes_copied; - if (bytes_copied == buffer_size(target_buffer)) + if (bytes_copied == target_buffer.size()) { ++target_iter; target_buffer_offset = 0; @@ -1724,7 +2022,7 @@ std::size_t buffer_copy(const MutableBufferSequence& target, else target_buffer_offset += bytes_copied; - if (bytes_copied == buffer_size(source_buffer)) + if (bytes_copied == source_buffer.size()) { ++source_iter; source_buffer_offset = 0; @@ -1736,409 +2034,63 @@ std::size_t buffer_copy(const MutableBufferSequence& target, return total_bytes_copied; } -/// Copies a limited number of bytes from a source buffer to a target buffer. -/** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A non-modifiable buffer representing the memory region from - * which the bytes will be copied. - * - * @param max_bytes_to_copy The maximum number of bytes to be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * @li @c max_bytes_to_copy - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -inline std::size_t buffer_copy(const mutable_buffer& target, - const const_buffer& source, std::size_t max_bytes_to_copy) +template <typename TargetIterator, typename SourceIterator> +std::size_t buffer_copy(multiple_buffers, multiple_buffers, + TargetIterator target_begin, TargetIterator target_end, + SourceIterator source_begin, SourceIterator source_end, + std::size_t max_bytes_to_copy) BOOST_ASIO_NOEXCEPT { - return buffer_copy(buffer(target, max_bytes_to_copy), source); -} - -/// Copies a limited number of bytes from a source buffer to a target buffer. -/** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A non-modifiable buffer representing the memory region from - * which the bytes will be copied. - * - * @param max_bytes_to_copy The maximum number of bytes to be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * @li @c max_bytes_to_copy - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -inline std::size_t buffer_copy(const mutable_buffer& target, - const const_buffers_1& source, std::size_t max_bytes_to_copy) -{ - return buffer_copy(buffer(target, max_bytes_to_copy), source); -} - -/// Copies a limited number of bytes from a source buffer to a target buffer. -/** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A modifiable buffer representing the memory region from which - * the bytes will be copied. The contents of the source buffer will not be - * modified. - * - * @param max_bytes_to_copy The maximum number of bytes to be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * @li @c max_bytes_to_copy - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -inline std::size_t buffer_copy(const mutable_buffer& target, - const mutable_buffer& source, std::size_t max_bytes_to_copy) -{ - return buffer_copy(buffer(target, max_bytes_to_copy), source); -} - -/// Copies a limited number of bytes from a source buffer to a target buffer. -/** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A modifiable buffer representing the memory region from which - * the bytes will be copied. The contents of the source buffer will not be - * modified. - * - * @param max_bytes_to_copy The maximum number of bytes to be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * @li @c max_bytes_to_copy - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -inline std::size_t buffer_copy(const mutable_buffer& target, - const mutable_buffers_1& source, std::size_t max_bytes_to_copy) -{ - return buffer_copy(buffer(target, max_bytes_to_copy), source); -} + std::size_t total_bytes_copied = 0; -/// Copies a limited number of bytes from a source buffer sequence to a target -/// buffer. -/** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A non-modifiable buffer sequence representing the memory - * regions from which the bytes will be copied. - * - * @param max_bytes_to_copy The maximum number of bytes to be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * @li @c max_bytes_to_copy - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -template <typename ConstBufferSequence> -inline std::size_t buffer_copy(const mutable_buffer& target, - const ConstBufferSequence& source, std::size_t max_bytes_to_copy) -{ - return buffer_copy(buffer(target, max_bytes_to_copy), source); -} + TargetIterator target_iter = target_begin; + std::size_t target_buffer_offset = 0; -/// Copies a limited number of bytes from a source buffer to a target buffer. -/** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A non-modifiable buffer representing the memory region from - * which the bytes will be copied. - * - * @param max_bytes_to_copy The maximum number of bytes to be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * @li @c max_bytes_to_copy - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -inline std::size_t buffer_copy(const mutable_buffers_1& target, - const const_buffer& source, std::size_t max_bytes_to_copy) -{ - return buffer_copy(buffer(target, max_bytes_to_copy), source); -} + SourceIterator source_iter = source_begin; + std::size_t source_buffer_offset = 0; -/// Copies a limited number of bytes from a source buffer to a target buffer. -/** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A non-modifiable buffer representing the memory region from - * which the bytes will be copied. - * - * @param max_bytes_to_copy The maximum number of bytes to be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * @li @c max_bytes_to_copy - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -inline std::size_t buffer_copy(const mutable_buffers_1& target, - const const_buffers_1& source, std::size_t max_bytes_to_copy) -{ - return buffer_copy(buffer(target, max_bytes_to_copy), source); -} + while (total_bytes_copied != max_bytes_to_copy + && target_iter != target_end && source_iter != source_end) + { + mutable_buffer target_buffer = + mutable_buffer(*target_iter) + target_buffer_offset; -/// Copies a limited number of bytes from a source buffer to a target buffer. -/** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A modifiable buffer representing the memory region from which - * the bytes will be copied. The contents of the source buffer will not be - * modified. - * - * @param max_bytes_to_copy The maximum number of bytes to be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * @li @c max_bytes_to_copy - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -inline std::size_t buffer_copy(const mutable_buffers_1& target, - const mutable_buffer& source, std::size_t max_bytes_to_copy) -{ - return buffer_copy(buffer(target, max_bytes_to_copy), source); -} + const_buffer source_buffer = + const_buffer(*source_iter) + source_buffer_offset; -/// Copies a limited number of bytes from a source buffer to a target buffer. -/** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A modifiable buffer representing the memory region from which - * the bytes will be copied. The contents of the source buffer will not be - * modified. - * - * @param max_bytes_to_copy The maximum number of bytes to be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * @li @c max_bytes_to_copy - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -inline std::size_t buffer_copy(const mutable_buffers_1& target, - const mutable_buffers_1& source, std::size_t max_bytes_to_copy) -{ - return buffer_copy(buffer(target, max_bytes_to_copy), source); -} + std::size_t bytes_copied = (buffer_copy_1)( + target_buffer, boost::asio::buffer(source_buffer, + max_bytes_to_copy - total_bytes_copied)); + total_bytes_copied += bytes_copied; -/// Copies a limited number of bytes from a source buffer sequence to a target -/// buffer. -/** - * @param target A modifiable buffer representing the memory region to which - * the bytes will be copied. - * - * @param source A non-modifiable buffer sequence representing the memory - * regions from which the bytes will be copied. - * - * @param max_bytes_to_copy The maximum number of bytes to be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * @li @c max_bytes_to_copy - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -template <typename ConstBufferSequence> -inline std::size_t buffer_copy(const mutable_buffers_1& target, - const ConstBufferSequence& source, std::size_t max_bytes_to_copy) -{ - return buffer_copy(buffer(target, max_bytes_to_copy), source); -} + if (bytes_copied == target_buffer.size()) + { + ++target_iter; + target_buffer_offset = 0; + } + else + target_buffer_offset += bytes_copied; -/// Copies a limited number of bytes from a source buffer to a target buffer -/// sequence. -/** - * @param target A modifiable buffer sequence representing the memory regions to - * which the bytes will be copied. - * - * @param source A non-modifiable buffer representing the memory region from - * which the bytes will be copied. - * - * @param max_bytes_to_copy The maximum number of bytes to be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * @li @c max_bytes_to_copy - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -template <typename MutableBufferSequence> -inline std::size_t buffer_copy(const MutableBufferSequence& target, - const const_buffer& source, std::size_t max_bytes_to_copy) -{ - return buffer_copy(target, buffer(source, max_bytes_to_copy)); -} + if (bytes_copied == source_buffer.size()) + { + ++source_iter; + source_buffer_offset = 0; + } + else + source_buffer_offset += bytes_copied; + } -/// Copies a limited number of bytes from a source buffer to a target buffer -/// sequence. -/** - * @param target A modifiable buffer sequence representing the memory regions to - * which the bytes will be copied. - * - * @param source A non-modifiable buffer representing the memory region from - * which the bytes will be copied. - * - * @param max_bytes_to_copy The maximum number of bytes to be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * @li @c max_bytes_to_copy - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -template <typename MutableBufferSequence> -inline std::size_t buffer_copy(const MutableBufferSequence& target, - const const_buffers_1& source, std::size_t max_bytes_to_copy) -{ - return buffer_copy(target, buffer(source, max_bytes_to_copy)); + return total_bytes_copied; } -/// Copies a limited number of bytes from a source buffer to a target buffer -/// sequence. -/** - * @param target A modifiable buffer sequence representing the memory regions to - * which the bytes will be copied. - * - * @param source A modifiable buffer representing the memory region from which - * the bytes will be copied. The contents of the source buffer will not be - * modified. - * - * @param max_bytes_to_copy The maximum number of bytes to be copied. - * - * @returns The number of bytes copied. - * - * @note The number of bytes copied is the lesser of: - * - * @li @c buffer_size(target) - * - * @li @c buffer_size(source) - * - * @li @c max_bytes_to_copy - * - * This function is implemented in terms of @c memcpy, and consequently it - * cannot be used to copy between overlapping memory regions. - */ -template <typename MutableBufferSequence> -inline std::size_t buffer_copy(const MutableBufferSequence& target, - const mutable_buffer& source, std::size_t max_bytes_to_copy) -{ - return buffer_copy(target, buffer(source, max_bytes_to_copy)); -} +} // namespace detail -/// Copies a limited number of bytes from a source buffer to a target buffer -/// sequence. +/// Copies bytes from a source buffer sequence to a target buffer sequence. /** * @param target A modifiable buffer sequence representing the memory regions to * which the bytes will be copied. * - * @param source A modifiable buffer representing the memory region from which - * the bytes will be copied. The contents of the source buffer will not be - * modified. - * - * @param max_bytes_to_copy The maximum number of bytes to be copied. + * @param source A non-modifiable buffer sequence representing the memory + * regions from which the bytes will be copied. * * @returns The number of bytes copied. * @@ -2148,16 +2100,20 @@ inline std::size_t buffer_copy(const MutableBufferSequence& target, * * @li @c buffer_size(source) * - * @li @c max_bytes_to_copy - * * This function is implemented in terms of @c memcpy, and consequently it * cannot be used to copy between overlapping memory regions. */ -template <typename MutableBufferSequence> +template <typename MutableBufferSequence, typename ConstBufferSequence> inline std::size_t buffer_copy(const MutableBufferSequence& target, - const mutable_buffers_1& source, std::size_t max_bytes_to_copy) + const ConstBufferSequence& source) BOOST_ASIO_NOEXCEPT { - return buffer_copy(target, buffer(source, max_bytes_to_copy)); + return detail::buffer_copy( + detail::buffer_sequence_cardinality<MutableBufferSequence>(), + detail::buffer_sequence_cardinality<ConstBufferSequence>(), + boost::asio::buffer_sequence_begin(target), + boost::asio::buffer_sequence_end(target), + boost::asio::buffer_sequence_begin(source), + boost::asio::buffer_sequence_end(source)); } /// Copies a limited number of bytes from a source buffer sequence to a target @@ -2185,50 +2141,17 @@ inline std::size_t buffer_copy(const MutableBufferSequence& target, * cannot be used to copy between overlapping memory regions. */ template <typename MutableBufferSequence, typename ConstBufferSequence> -std::size_t buffer_copy(const MutableBufferSequence& target, - const ConstBufferSequence& source, std::size_t max_bytes_to_copy) -{ - std::size_t total_bytes_copied = 0; - - typename MutableBufferSequence::const_iterator target_iter = target.begin(); - typename MutableBufferSequence::const_iterator target_end = target.end(); - std::size_t target_buffer_offset = 0; - - typename ConstBufferSequence::const_iterator source_iter = source.begin(); - typename ConstBufferSequence::const_iterator source_end = source.end(); - std::size_t source_buffer_offset = 0; - - while (total_bytes_copied != max_bytes_to_copy - && target_iter != target_end && source_iter != source_end) - { - mutable_buffer target_buffer = - mutable_buffer(*target_iter) + target_buffer_offset; - - const_buffer source_buffer = - const_buffer(*source_iter) + source_buffer_offset; - - std::size_t bytes_copied = buffer_copy(target_buffer, - source_buffer, max_bytes_to_copy - total_bytes_copied); - total_bytes_copied += bytes_copied; - - if (bytes_copied == buffer_size(target_buffer)) - { - ++target_iter; - target_buffer_offset = 0; - } - else - target_buffer_offset += bytes_copied; - - if (bytes_copied == buffer_size(source_buffer)) - { - ++source_iter; - source_buffer_offset = 0; - } - else - source_buffer_offset += bytes_copied; - } - - return total_bytes_copied; +inline std::size_t buffer_copy(const MutableBufferSequence& target, + const ConstBufferSequence& source, + std::size_t max_bytes_to_copy) BOOST_ASIO_NOEXCEPT +{ + return detail::buffer_copy( + detail::buffer_sequence_cardinality<MutableBufferSequence>(), + detail::buffer_sequence_cardinality<ConstBufferSequence>(), + boost::asio::buffer_sequence_begin(target), + boost::asio::buffer_sequence_end(target), + boost::asio::buffer_sequence_begin(source), + boost::asio::buffer_sequence_end(source), max_bytes_to_copy); } /*@}*/ diff --git a/boost/asio/buffered_read_stream.hpp b/boost/asio/buffered_read_stream.hpp index ece138b599..9774ee9d52 100644 --- a/boost/asio/buffered_read_stream.hpp +++ b/boost/asio/buffered_read_stream.hpp @@ -26,7 +26,7 @@ #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -56,6 +56,9 @@ public: /// The type of the lowest layer. typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + /// The type of the executor associated with the object. + typedef typename lowest_layer_type::executor_type executor_type; + #if defined(GENERATING_DOCUMENTATION) /// The default buffer size. static const std::size_t default_buffer_size = implementation_defined; @@ -97,11 +100,27 @@ public: return next_layer_.lowest_layer(); } - /// Get the io_service associated with the object. - boost::asio::io_service& get_io_service() + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return next_layer_.lowest_layer().get_executor(); + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + boost::asio::io_context& get_io_context() + { + return next_layer_.get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + boost::asio::io_context& get_io_service() { return next_layer_.get_io_service(); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Close the stream. void close() @@ -110,9 +129,10 @@ public: } /// Close the stream. - boost::system::error_code close(boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) { - return next_layer_.close(ec); + next_layer_.close(ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Write the given data to the stream. Returns the number of bytes written. @@ -140,15 +160,8 @@ public: async_write_some(const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( + return next_layer_.async_write_some(buffers, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); - - next_layer_.async_write_some(buffers, - BOOST_ASIO_MOVE_CAST(BOOST_ASIO_HANDLER_TYPE(WriteHandler, - void (boost::system::error_code, std::size_t)))(init.handler)); - - return init.result.get(); } /// Fill the buffer with some data. Returns the number of bytes placed in the diff --git a/boost/asio/buffered_stream.hpp b/boost/asio/buffered_stream.hpp index fae7c27113..a468370ffe 100644 --- a/boost/asio/buffered_stream.hpp +++ b/boost/asio/buffered_stream.hpp @@ -23,7 +23,7 @@ #include <boost/asio/buffered_stream_fwd.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -53,6 +53,9 @@ public: /// The type of the lowest layer. typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + /// The type of the executor associated with the object. + typedef typename lowest_layer_type::executor_type executor_type; + /// Construct, passing the specified argument to initialise the next layer. template <typename Arg> explicit buffered_stream(Arg& a) @@ -88,11 +91,27 @@ public: return stream_impl_.lowest_layer(); } - /// Get the io_service associated with the object. - boost::asio::io_service& get_io_service() + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return stream_impl_.lowest_layer().get_executor(); + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + boost::asio::io_context& get_io_context() + { + return stream_impl_.get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + boost::asio::io_context& get_io_service() { return stream_impl_.get_io_service(); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Close the stream. void close() @@ -101,9 +120,10 @@ public: } /// Close the stream. - boost::system::error_code close(boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) { - return stream_impl_.close(ec); + stream_impl_.close(ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Flush all data from the buffer to the next layer. Returns the number of diff --git a/boost/asio/buffered_write_stream.hpp b/boost/asio/buffered_write_stream.hpp index 5b8f31378d..a1b9c44016 100644 --- a/boost/asio/buffered_write_stream.hpp +++ b/boost/asio/buffered_write_stream.hpp @@ -25,7 +25,7 @@ #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/write.hpp> #include <boost/asio/detail/push_options.hpp> @@ -56,6 +56,9 @@ public: /// The type of the lowest layer. typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + /// The type of the executor associated with the object. + typedef typename lowest_layer_type::executor_type executor_type; + #if defined(GENERATING_DOCUMENTATION) /// The default buffer size. static const std::size_t default_buffer_size = implementation_defined; @@ -97,11 +100,27 @@ public: return next_layer_.lowest_layer(); } - /// Get the io_service associated with the object. - boost::asio::io_service& get_io_service() + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return next_layer_.lowest_layer().get_executor(); + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + boost::asio::io_context& get_io_context() + { + return next_layer_.get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + boost::asio::io_context& get_io_service() { return next_layer_.get_io_service(); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Close the stream. void close() @@ -110,9 +129,10 @@ public: } /// Close the stream. - boost::system::error_code close(boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) { - return next_layer_.close(ec); + next_layer_.close(ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Flush all data from the buffer to the next layer. Returns the number of @@ -175,15 +195,8 @@ public: async_read_some(const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( + return next_layer_.async_read_some(buffers, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); - - next_layer_.async_read_some(buffers, - BOOST_ASIO_MOVE_CAST(BOOST_ASIO_HANDLER_TYPE(ReadHandler, - void (boost::system::error_code, std::size_t)))(init.handler)); - - return init.result.get(); } /// Peek at the incoming data on the stream. Returns the number of bytes read. diff --git a/boost/asio/buffers_iterator.hpp b/boost/asio/buffers_iterator.hpp index c64b341b5b..bebbca1b9e 100644 --- a/boost/asio/buffers_iterator.hpp +++ b/boost/asio/buffers_iterator.hpp @@ -66,7 +66,44 @@ namespace detail typedef buffers_iterator_types_helper<is_mutable> helper; typedef typename helper::buffer_type buffer_type; typedef typename helper::template byte_type<ByteType>::type byte_type; + typedef typename BufferSequence::const_iterator const_iterator; }; + + template <typename ByteType> + struct buffers_iterator_types<mutable_buffer, ByteType> + { + typedef mutable_buffer buffer_type; + typedef ByteType byte_type; + typedef const mutable_buffer* const_iterator; + }; + + template <typename ByteType> + struct buffers_iterator_types<const_buffer, ByteType> + { + typedef const_buffer buffer_type; + typedef typename add_const<ByteType>::type byte_type; + typedef const const_buffer* const_iterator; + }; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + + template <typename ByteType> + struct buffers_iterator_types<mutable_buffers_1, ByteType> + { + typedef mutable_buffer buffer_type; + typedef ByteType byte_type; + typedef const mutable_buffer* const_iterator; + }; + + template <typename ByteType> + struct buffers_iterator_types<const_buffers_1, ByteType> + { + typedef const_buffer buffer_type; + typedef typename add_const<ByteType>::type byte_type; + typedef const const_buffer* const_iterator; + }; + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) } /// A random access iterator over the bytes in a buffer sequence. @@ -77,6 +114,9 @@ private: typedef typename detail::buffers_iterator_types< BufferSequence, ByteType>::buffer_type buffer_type; + typedef typename detail::buffers_iterator_types<BufferSequence, + ByteType>::const_iterator buffer_sequence_iterator_type; + public: /// The type used for the distance between two iterators. typedef std::ptrdiff_t difference_type; @@ -131,13 +171,13 @@ public: #endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) { buffers_iterator new_iter; - new_iter.begin_ = buffers.begin(); - new_iter.current_ = buffers.begin(); - new_iter.end_ = buffers.end(); + new_iter.begin_ = boost::asio::buffer_sequence_begin(buffers); + new_iter.current_ = boost::asio::buffer_sequence_begin(buffers); + new_iter.end_ = boost::asio::buffer_sequence_end(buffers); while (new_iter.current_ != new_iter.end_) { new_iter.current_buffer_ = *new_iter.current_; - if (boost::asio::buffer_size(new_iter.current_buffer_) > 0) + if (new_iter.current_buffer_.size() > 0) break; ++new_iter.current_; } @@ -151,13 +191,13 @@ public: #endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) { buffers_iterator new_iter; - new_iter.begin_ = buffers.begin(); - new_iter.current_ = buffers.begin(); - new_iter.end_ = buffers.end(); + new_iter.begin_ = boost::asio::buffer_sequence_begin(buffers); + new_iter.current_ = boost::asio::buffer_sequence_begin(buffers); + new_iter.end_ = boost::asio::buffer_sequence_end(buffers); while (new_iter.current_ != new_iter.end_) { buffer_type buffer = *new_iter.current_; - new_iter.position_ += boost::asio::buffer_size(buffer); + new_iter.position_ += buffer.size(); ++new_iter.current_; } return new_iter; @@ -301,7 +341,8 @@ private: // Dereference the iterator. reference dereference() const { - return buffer_cast<pointer>(current_buffer_)[current_buffer_position_]; + return static_cast<pointer>( + current_buffer_.data())[current_buffer_position_]; } // Compare two iterators for equality. @@ -318,7 +359,7 @@ private: // Check if the increment can be satisfied by the current buffer. ++current_buffer_position_; - if (current_buffer_position_ != boost::asio::buffer_size(current_buffer_)) + if (current_buffer_position_ != current_buffer_.size()) return; // Find the next non-empty buffer. @@ -327,7 +368,7 @@ private: while (current_ != end_) { current_buffer_ = *current_; - if (boost::asio::buffer_size(current_buffer_) > 0) + if (current_buffer_.size() > 0) return; ++current_; } @@ -347,12 +388,12 @@ private: } // Find the previous non-empty buffer. - typename BufferSequence::const_iterator iter = current_; + buffer_sequence_iterator_type iter = current_; while (iter != begin_) { --iter; buffer_type buffer = *iter; - std::size_t buffer_size = boost::asio::buffer_size(buffer); + std::size_t buffer_size = buffer.size(); if (buffer_size > 0) { current_ = iter; @@ -372,8 +413,7 @@ private: for (;;) { std::ptrdiff_t current_buffer_balance - = boost::asio::buffer_size(current_buffer_) - - current_buffer_position_; + = current_buffer_.size() - current_buffer_position_; // Check if the advance can be satisfied by the current buffer. if (current_buffer_balance > n) @@ -427,12 +467,12 @@ private: } // Find the previous non-empty buffer. - typename BufferSequence::const_iterator iter = current_; + buffer_sequence_iterator_type iter = current_; while (iter != begin_) { --iter; buffer_type buffer = *iter; - std::size_t buffer_size = boost::asio::buffer_size(buffer); + std::size_t buffer_size = buffer.size(); if (buffer_size > 0) { current_ = iter; @@ -453,9 +493,9 @@ private: buffer_type current_buffer_; std::size_t current_buffer_position_; - typename BufferSequence::const_iterator begin_; - typename BufferSequence::const_iterator current_; - typename BufferSequence::const_iterator end_; + buffer_sequence_iterator_type begin_; + buffer_sequence_iterator_type current_; + buffer_sequence_iterator_type end_; std::size_t position_; }; diff --git a/boost/asio/connect.hpp b/boost/asio/connect.hpp index 635a8ad9bd..e31e8c92cd 100644 --- a/boost/asio/connect.hpp +++ b/boost/asio/connect.hpp @@ -18,6 +18,7 @@ #include <boost/asio/detail/config.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/basic_socket.hpp> +#include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> @@ -25,6 +26,36 @@ namespace boost { namespace asio { +namespace detail +{ + char (&has_iterator_helper(...))[2]; + + template <typename T> + char has_iterator_helper(T*, typename T::iterator* = 0); + + template <typename T> + struct has_iterator_typedef + { + enum { value = (sizeof((has_iterator_helper)((T*)(0))) == 1) }; + }; +} // namespace detail + +/// Type trait used to determine whether a type is an endpoint sequence that can +/// be used with with @c connect and @c async_connect. +template <typename T> +struct is_endpoint_sequence +{ +#if defined(GENERATING_DOCUMENTATION) + /// The value member is true if the type may be used as an endpoint sequence. + static const bool value; +#else + enum + { + value = detail::has_iterator_typedef<T>::value + }; +#endif +}; + /** * @defgroup connect boost::asio::connect * @@ -42,27 +73,26 @@ namespace asio { * @param s The socket to be connected. If the socket is already open, it will * be closed. * - * @param begin An iterator pointing to the start of a sequence of endpoints. + * @param endpoints A sequence of endpoints. * - * @returns On success, an iterator denoting the successfully connected - * endpoint. Otherwise, the end iterator. + * @returns The successfully connected endpoint. * * @throws boost::system::system_error Thrown on failure. If the sequence is * empty, the associated @c error_code is boost::asio::error::not_found. * Otherwise, contains the error from the last connection attempt. * - * @note This overload assumes that a default constructed object of type @c - * Iterator represents the end of the sequence. This is a valid assumption for - * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. - * * @par Example - * @code tcp::resolver r(io_service); + * @code tcp::resolver r(io_context); * tcp::resolver::query q("host", "service"); - * tcp::socket s(io_service); + * tcp::socket s(io_context); * boost::asio::connect(s, r.resolve(q)); @endcode */ -template <typename Protocol, typename SocketService, typename Iterator> -Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin); +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename EndpointSequence> +typename Protocol::endpoint connect( + basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, + typename enable_if<is_endpoint_sequence< + EndpointSequence>::value>::type* = 0); /// Establishes a socket connection by trying each endpoint in a sequence. /** @@ -74,23 +104,19 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin); * @param s The socket to be connected. If the socket is already open, it will * be closed. * - * @param begin An iterator pointing to the start of a sequence of endpoints. + * @param endpoints A sequence of endpoints. * * @param ec Set to indicate what error occurred, if any. If the sequence is * empty, set to boost::asio::error::not_found. Otherwise, contains the error * from the last connection attempt. * - * @returns On success, an iterator denoting the successfully connected - * endpoint. Otherwise, the end iterator. - * - * @note This overload assumes that a default constructed object of type @c - * Iterator represents the end of the sequence. This is a valid assumption for - * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. + * @returns On success, the successfully connected endpoint. Otherwise, a + * default-constructed endpoint. * * @par Example - * @code tcp::resolver r(io_service); + * @code tcp::resolver r(io_context); * tcp::resolver::query q("host", "service"); - * tcp::socket s(io_service); + * tcp::socket s(io_context); * boost::system::error_code ec; * boost::asio::connect(s, r.resolve(q), ec); * if (ec) @@ -98,11 +124,16 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin); * // An error occurred. * } @endcode */ -template <typename Protocol, typename SocketService, typename Iterator> -Iterator connect(basic_socket<Protocol, SocketService>& s, - Iterator begin, boost::system::error_code& ec); +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename EndpointSequence> +typename Protocol::endpoint connect( + basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, boost::system::error_code& ec, + typename enable_if<is_endpoint_sequence< + EndpointSequence>::value>::type* = 0); -/// Establishes a socket connection by trying each endpoint in a sequence. +#if !defined(BOOST_ASIO_NO_DEPRECATED) +/// (Deprecated.) Establishes a socket connection by trying each endpoint in a +/// sequence. /** * This function attempts to connect a socket to one of a sequence of * endpoints. It does this by repeated calls to the socket's @c connect member @@ -114,24 +145,80 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, * * @param begin An iterator pointing to the start of a sequence of endpoints. * - * @param end An iterator pointing to the end of a sequence of endpoints. + * @returns On success, an iterator denoting the successfully connected + * endpoint. Otherwise, the end iterator. + * + * @throws boost::system::system_error Thrown on failure. If the sequence is + * empty, the associated @c error_code is boost::asio::error::not_found. + * Otherwise, contains the error from the last connection attempt. + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. + */ +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator> +Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, + typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); + +/// (Deprecated.) Establishes a socket connection by trying each endpoint in a +/// sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param ec Set to indicate what error occurred, if any. If the sequence is + * empty, set to boost::asio::error::not_found. Otherwise, contains the error + * from the last connection attempt. * * @returns On success, an iterator denoting the successfully connected * endpoint. Otherwise, the end iterator. * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. + */ +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator> +Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + Iterator begin, boost::system::error_code& ec, + typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param end An iterator pointing to the end of a sequence of endpoints. + * + * @returns An iterator denoting the successfully connected endpoint. + * * @throws boost::system::system_error Thrown on failure. If the sequence is * empty, the associated @c error_code is boost::asio::error::not_found. * Otherwise, contains the error from the last connection attempt. * * @par Example - * @code tcp::resolver r(io_service); + * @code tcp::resolver r(io_context); * tcp::resolver::query q("host", "service"); - * tcp::resolver::iterator i = r.resolve(q), end; - * tcp::socket s(io_service); - * boost::asio::connect(s, i, end); @endcode + * tcp::resolver::results_type e = r.resolve(q); + * tcp::socket s(io_context); + * boost::asio::connect(s, e.begin(), e.end()); @endcode */ -template <typename Protocol, typename SocketService, typename Iterator> -Iterator connect(basic_socket<Protocol, SocketService>& s, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator> +Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, Iterator end); /// Establishes a socket connection by trying each endpoint in a sequence. @@ -156,19 +243,19 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, * endpoint. Otherwise, the end iterator. * * @par Example - * @code tcp::resolver r(io_service); + * @code tcp::resolver r(io_context); * tcp::resolver::query q("host", "service"); - * tcp::resolver::iterator i = r.resolve(q), end; - * tcp::socket s(io_service); + * tcp::resolver::results_type e = r.resolve(q); + * tcp::socket s(io_context); * boost::system::error_code ec; - * boost::asio::connect(s, i, end, ec); + * boost::asio::connect(s, e.begin(), e.end(), ec); * if (ec) * { * // An error occurred. * } @endcode */ -template <typename Protocol, typename SocketService, typename Iterator> -Iterator connect(basic_socket<Protocol, SocketService>& s, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator> +Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, Iterator end, boost::system::error_code& ec); /// Establishes a socket connection by trying each endpoint in a sequence. @@ -181,59 +268,54 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, * @param s The socket to be connected. If the socket is already open, it will * be closed. * - * @param begin An iterator pointing to the start of a sequence of endpoints. + * @param endpoints A sequence of endpoints. * * @param connect_condition A function object that is called prior to each * connection attempt. The signature of the function object must be: - * @code Iterator connect_condition( + * @code bool connect_condition( * const boost::system::error_code& ec, - * Iterator next); @endcode + * const typename Protocol::endpoint& next); @endcode * The @c ec parameter contains the result from the most recent connect * operation. Before the first connection attempt, @c ec is always set to - * indicate success. The @c next parameter is an iterator pointing to the next - * endpoint to be tried. The function object should return the next iterator, - * but is permitted to return a different iterator so that endpoints may be - * skipped. The implementation guarantees that the function object will never - * be called with the end iterator. + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. * - * @returns On success, an iterator denoting the successfully connected - * endpoint. Otherwise, the end iterator. + * @returns The successfully connected endpoint. * * @throws boost::system::system_error Thrown on failure. If the sequence is * empty, the associated @c error_code is boost::asio::error::not_found. * Otherwise, contains the error from the last connection attempt. * - * @note This overload assumes that a default constructed object of type @c - * Iterator represents the end of the sequence. This is a valid assumption for - * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. - * * @par Example * The following connect condition function object can be used to output * information about the individual connection attempts: * @code struct my_connect_condition * { - * template <typename Iterator> - * Iterator operator()( + * bool operator()( * const boost::system::error_code& ec, - * Iterator next) + * const::tcp::endpoint& next) * { * if (ec) std::cout << "Error: " << ec.message() << std::endl; - * std::cout << "Trying: " << next->endpoint() << std::endl; - * return next; + * std::cout << "Trying: " << next << std::endl; + * return true; * } * }; @endcode * It would be used with the boost::asio::connect function as follows: - * @code tcp::resolver r(io_service); + * @code tcp::resolver r(io_context); * tcp::resolver::query q("host", "service"); - * tcp::socket s(io_service); - * tcp::resolver::iterator i = boost::asio::connect( - * s, r.resolve(q), my_connect_condition()); - * std::cout << "Connected to: " << i->endpoint() << std::endl; @endcode + * tcp::socket s(io_context); + * tcp::endpoint e = boost::asio::connect(s, + * r.resolve(q), my_connect_condition()); + * std::cout << "Connected to: " << e << std::endl; @endcode */ -template <typename Protocol, typename SocketService, - typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol, SocketService>& s, - Iterator begin, ConnectCondition connect_condition); +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition> +typename Protocol::endpoint connect( + basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + typename enable_if<is_endpoint_sequence< + EndpointSequence>::value>::type* = 0); /// Establishes a socket connection by trying each endpoint in a sequence. /** @@ -245,67 +327,148 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, * @param s The socket to be connected. If the socket is already open, it will * be closed. * - * @param begin An iterator pointing to the start of a sequence of endpoints. + * @param endpoints A sequence of endpoints. * * @param connect_condition A function object that is called prior to each * connection attempt. The signature of the function object must be: - * @code Iterator connect_condition( + * @code bool connect_condition( * const boost::system::error_code& ec, - * Iterator next); @endcode + * const typename Protocol::endpoint& next); @endcode * The @c ec parameter contains the result from the most recent connect * operation. Before the first connection attempt, @c ec is always set to - * indicate success. The @c next parameter is an iterator pointing to the next - * endpoint to be tried. The function object should return the next iterator, - * but is permitted to return a different iterator so that endpoints may be - * skipped. The implementation guarantees that the function object will never - * be called with the end iterator. + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. * * @param ec Set to indicate what error occurred, if any. If the sequence is * empty, set to boost::asio::error::not_found. Otherwise, contains the error * from the last connection attempt. * - * @returns On success, an iterator denoting the successfully connected - * endpoint. Otherwise, the end iterator. - * - * @note This overload assumes that a default constructed object of type @c - * Iterator represents the end of the sequence. This is a valid assumption for - * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. + * @returns On success, the successfully connected endpoint. Otherwise, a + * default-constructed endpoint. * * @par Example * The following connect condition function object can be used to output * information about the individual connection attempts: * @code struct my_connect_condition * { - * template <typename Iterator> - * Iterator operator()( + * bool operator()( * const boost::system::error_code& ec, - * Iterator next) + * const::tcp::endpoint& next) * { * if (ec) std::cout << "Error: " << ec.message() << std::endl; - * std::cout << "Trying: " << next->endpoint() << std::endl; - * return next; + * std::cout << "Trying: " << next << std::endl; + * return true; * } * }; @endcode * It would be used with the boost::asio::connect function as follows: - * @code tcp::resolver r(io_service); + * @code tcp::resolver r(io_context); * tcp::resolver::query q("host", "service"); - * tcp::socket s(io_service); + * tcp::socket s(io_context); * boost::system::error_code ec; - * tcp::resolver::iterator i = boost::asio::connect( - * s, r.resolve(q), my_connect_condition(), ec); + * tcp::endpoint e = boost::asio::connect(s, + * r.resolve(q), my_connect_condition(), ec); * if (ec) * { * // An error occurred. * } * else * { - * std::cout << "Connected to: " << i->endpoint() << std::endl; + * std::cout << "Connected to: " << e << std::endl; * } @endcode */ -template <typename Protocol, typename SocketService, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition> +typename Protocol::endpoint connect( + basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + boost::system::error_code& ec, + typename enable_if<is_endpoint_sequence< + EndpointSequence>::value>::type* = 0); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +/// (Deprecated.) Establishes a socket connection by trying each endpoint in a +/// sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const boost::system::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @returns On success, an iterator denoting the successfully connected + * endpoint. Otherwise, the end iterator. + * + * @throws boost::system::system_error Thrown on failure. If the sequence is + * empty, the associated @c error_code is boost::asio::error::not_found. + * Otherwise, contains the error from the last connection attempt. + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. + */ +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin, - ConnectCondition connect_condition, boost::system::error_code& ec); +Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + Iterator begin, ConnectCondition connect_condition, + typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); + +/// (Deprecated.) Establishes a socket connection by trying each endpoint in a +/// sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const boost::system::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @param ec Set to indicate what error occurred, if any. If the sequence is + * empty, set to boost::asio::error::not_found. Otherwise, contains the error + * from the last connection attempt. + * + * @returns On success, an iterator denoting the successfully connected + * endpoint. Otherwise, the end iterator. + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. + */ +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename Iterator, typename ConnectCondition> +Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, + ConnectCondition connect_condition, boost::system::error_code& ec, + typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Establishes a socket connection by trying each endpoint in a sequence. /** @@ -323,19 +486,16 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin, * * @param connect_condition A function object that is called prior to each * connection attempt. The signature of the function object must be: - * @code Iterator connect_condition( + * @code bool connect_condition( * const boost::system::error_code& ec, - * Iterator next); @endcode + * const typename Protocol::endpoint& next); @endcode * The @c ec parameter contains the result from the most recent connect * operation. Before the first connection attempt, @c ec is always set to - * indicate success. The @c next parameter is an iterator pointing to the next - * endpoint to be tried. The function object should return the next iterator, - * but is permitted to return a different iterator so that endpoints may be - * skipped. The implementation guarantees that the function object will never - * be called with the end iterator. + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. * - * @returns On success, an iterator denoting the successfully connected - * endpoint. Otherwise, the end iterator. + * @returns An iterator denoting the successfully connected endpoint. * * @throws boost::system::system_error Thrown on failure. If the sequence is * empty, the associated @c error_code is boost::asio::error::not_found. @@ -346,27 +506,27 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin, * information about the individual connection attempts: * @code struct my_connect_condition * { - * template <typename Iterator> - * Iterator operator()( + * bool operator()( * const boost::system::error_code& ec, - * Iterator next) + * const::tcp::endpoint& next) * { * if (ec) std::cout << "Error: " << ec.message() << std::endl; - * std::cout << "Trying: " << next->endpoint() << std::endl; - * return next; + * std::cout << "Trying: " << next << std::endl; + * return true; * } * }; @endcode * It would be used with the boost::asio::connect function as follows: - * @code tcp::resolver r(io_service); + * @code tcp::resolver r(io_context); * tcp::resolver::query q("host", "service"); - * tcp::resolver::iterator i = r.resolve(q), end; - * tcp::socket s(io_service); - * i = boost::asio::connect(s, i, end, my_connect_condition()); + * tcp::resolver::results_type e = r.resolve(q); + * tcp::socket s(io_context); + * tcp::resolver::results_type::iterator i = boost::asio::connect( + * s, e.begin(), e.end(), my_connect_condition()); * std::cout << "Connected to: " << i->endpoint() << std::endl; @endcode */ -template <typename Protocol, typename SocketService, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin, +Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, Iterator end, ConnectCondition connect_condition); /// Establishes a socket connection by trying each endpoint in a sequence. @@ -385,16 +545,14 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin, * * @param connect_condition A function object that is called prior to each * connection attempt. The signature of the function object must be: - * @code Iterator connect_condition( + * @code bool connect_condition( * const boost::system::error_code& ec, - * Iterator next); @endcode + * const typename Protocol::endpoint& next); @endcode * The @c ec parameter contains the result from the most recent connect * operation. Before the first connection attempt, @c ec is always set to - * indicate success. The @c next parameter is an iterator pointing to the next - * endpoint to be tried. The function object should return the next iterator, - * but is permitted to return a different iterator so that endpoints may be - * skipped. The implementation guarantees that the function object will never - * be called with the end iterator. + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. * * @param ec Set to indicate what error occurred, if any. If the sequence is * empty, set to boost::asio::error::not_found. Otherwise, contains the error @@ -408,23 +566,23 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin, * information about the individual connection attempts: * @code struct my_connect_condition * { - * template <typename Iterator> - * Iterator operator()( + * bool operator()( * const boost::system::error_code& ec, - * Iterator next) + * const::tcp::endpoint& next) * { * if (ec) std::cout << "Error: " << ec.message() << std::endl; - * std::cout << "Trying: " << next->endpoint() << std::endl; - * return next; + * std::cout << "Trying: " << next << std::endl; + * return true; * } * }; @endcode * It would be used with the boost::asio::connect function as follows: - * @code tcp::resolver r(io_service); + * @code tcp::resolver r(io_context); * tcp::resolver::query q("host", "service"); - * tcp::resolver::iterator i = r.resolve(q), end; - * tcp::socket s(io_service); + * tcp::resolver::results_type e = r.resolve(q); + * tcp::socket s(io_context); * boost::system::error_code ec; - * i = boost::asio::connect(s, i, end, my_connect_condition(), ec); + * tcp::resolver::results_type::iterator i = boost::asio::connect( + * s, e.begin(), e.end(), my_connect_condition()); * if (ec) * { * // An error occurred. @@ -434,9 +592,9 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin, * std::cout << "Connected to: " << i->endpoint() << std::endl; * } @endcode */ -template <typename Protocol, typename SocketService, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol, SocketService>& s, +Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, Iterator end, ConnectCondition connect_condition, boost::system::error_code& ec); @@ -461,7 +619,7 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, * @param s The socket to be connected. If the socket is already open, it will * be closed. * - * @param begin An iterator pointing to the start of a sequence of endpoints. + * @param endpoints A sequence of endpoints. * * @param handler The handler to be called when the connect operation * completes. Copies will be made of the handler as required. The function @@ -472,23 +630,19 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, * // error from the last connection attempt. * const boost::system::error_code& error, * - * // On success, an iterator denoting the successfully - * // connected endpoint. Otherwise, the end iterator. - * Iterator iterator + * // On success, the successfully connected endpoint. + * // Otherwise, a default-constructed endpoint. + * const typename Protocol::endpoint& endpoint * ); @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 - * boost::asio::io_service::post(). - * - * @note This overload assumes that a default constructed object of type @c - * Iterator represents the end of the sequence. This is a valid assumption for - * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. + * boost::asio::io_context::post(). * * @par Example - * @code tcp::resolver r(io_service); + * @code tcp::resolver r(io_context); * tcp::resolver::query q("host", "service"); - * tcp::socket s(io_service); + * tcp::socket s(io_context); * * // ... * @@ -498,11 +652,11 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, * * void resolve_handler( * const boost::system::error_code& ec, - * tcp::resolver::iterator i) + * tcp::resolver::results_type results) * { * if (!ec) * { - * boost::asio::async_connect(s, i, connect_handler); + * boost::asio::async_connect(s, results, connect_handler); * } * } * @@ -510,17 +664,65 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, * * void connect_handler( * const boost::system::error_code& ec, - * tcp::resolver::iterator i) + * const tcp::endpoint& endpoint) * { * // ... * } @endcode */ -template <typename Protocol, typename SocketService, - typename Iterator, typename ComposedConnectHandler> -BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename EndpointSequence, typename RangeConnectHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, + void (boost::system::error_code, typename Protocol::endpoint)) +async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, + BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, + typename enable_if<is_endpoint_sequence< + EndpointSequence>::value>::type* = 0); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +/// (Deprecated.) Asynchronously establishes a socket connection by trying each +/// endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c async_connect + * member function, once for each endpoint in the sequence, until a connection + * is successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param handler The handler to be called when the connect operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * // Result of operation. if the sequence is empty, set to + * // boost::asio::error::not_found. Otherwise, contains the + * // error from the last connection attempt. + * const boost::system::error_code& error, + * + * // On success, an iterator denoting the successfully + * // connected endpoint. Otherwise, the end iterator. + * Iterator iterator + * ); @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 + * boost::asio::io_context::post(). + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. + */ +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename Iterator, typename IteratorConnectHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) -async_connect(basic_socket<Protocol, SocketService>& s, - Iterator begin, BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler); +async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + Iterator begin, BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, + typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Asynchronously establishes a socket connection by trying each endpoint in a /// sequence. @@ -553,46 +755,31 @@ async_connect(basic_socket<Protocol, SocketService>& s, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example - * @code tcp::resolver r(io_service); - * tcp::resolver::query q("host", "service"); - * tcp::socket s(io_service); - * - * // ... - * - * r.async_resolve(q, resolve_handler); - * - * // ... - * - * void resolve_handler( - * const boost::system::error_code& ec, - * tcp::resolver::iterator i) - * { - * if (!ec) - * { - * tcp::resolver::iterator end; - * boost::asio::async_connect(s, i, end, connect_handler); - * } - * } + * @code std::vector<tcp::endpoint> endpoints = ...; + * tcp::socket s(io_context); + * boost::asio::async_connect(s, + * endpoints.begin(), endpoints.end(), + * connect_handler); * * // ... * * void connect_handler( * const boost::system::error_code& ec, - * tcp::resolver::iterator i) + * std::vector<tcp::endpoint>::iterator i) * { * // ... * } @endcode */ -template <typename Protocol, typename SocketService, - typename Iterator, typename ComposedConnectHandler> -BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename Iterator, typename IteratorConnectHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) -async_connect(basic_socket<Protocol, SocketService>& s, +async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, Iterator end, - BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler); + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler); /// Asynchronously establishes a socket connection by trying each endpoint in a /// sequence. @@ -605,20 +792,18 @@ async_connect(basic_socket<Protocol, SocketService>& s, * @param s The socket to be connected. If the socket is already open, it will * be closed. * - * @param begin An iterator pointing to the start of a sequence of endpoints. + * @param endpoints A sequence of endpoints. * * @param connect_condition A function object that is called prior to each * connection attempt. The signature of the function object must be: - * @code Iterator connect_condition( + * @code bool connect_condition( * const boost::system::error_code& ec, - * Iterator next); @endcode + * const typename Protocol::endpoint& next); @endcode * The @c ec parameter contains the result from the most recent connect * operation. Before the first connection attempt, @c ec is always set to - * indicate success. The @c next parameter is an iterator pointing to the next - * endpoint to be tried. The function object should return the next iterator, - * but is permitted to return a different iterator so that endpoints may be - * skipped. The implementation guarantees that the function object will never - * be called with the end iterator. + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. * * @param handler The handler to be called when the connect operation * completes. Copies will be made of the handler as required. The function @@ -636,31 +821,26 @@ async_connect(basic_socket<Protocol, SocketService>& s, * 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 - * boost::asio::io_service::post(). - * - * @note This overload assumes that a default constructed object of type @c - * Iterator represents the end of the sequence. This is a valid assumption for - * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. + * boost::asio::io_context::post(). * * @par Example * The following connect condition function object can be used to output * information about the individual connection attempts: * @code struct my_connect_condition * { - * template <typename Iterator> - * Iterator operator()( + * bool operator()( * const boost::system::error_code& ec, - * Iterator next) + * const::tcp::endpoint& next) * { * if (ec) std::cout << "Error: " << ec.message() << std::endl; - * std::cout << "Trying: " << next->endpoint() << std::endl; - * return next; + * std::cout << "Trying: " << next << std::endl; + * return true; * } * }; @endcode * It would be used with the boost::asio::connect function as follows: - * @code tcp::resolver r(io_service); + * @code tcp::resolver r(io_context); * tcp::resolver::query q("host", "service"); - * tcp::socket s(io_service); + * tcp::socket s(io_context); * * // ... * @@ -670,11 +850,11 @@ async_connect(basic_socket<Protocol, SocketService>& s, * * void resolve_handler( * const boost::system::error_code& ec, - * tcp::resolver::iterator i) + * tcp::resolver::results_type results) * { * if (!ec) * { - * boost::asio::async_connect(s, i, + * boost::asio::async_connect(s, results, * my_connect_condition(), * connect_handler); * } @@ -684,7 +864,7 @@ async_connect(basic_socket<Protocol, SocketService>& s, * * void connect_handler( * const boost::system::error_code& ec, - * tcp::resolver::iterator i) + * const tcp::endpoint& endpoint) * { * if (ec) * { @@ -692,17 +872,76 @@ async_connect(basic_socket<Protocol, SocketService>& s, * } * else * { - * std::cout << "Connected to: " << i->endpoint() << std::endl; + * std::cout << "Connected to: " << endpoint << std::endl; * } * } @endcode */ -template <typename Protocol, typename SocketService, typename Iterator, - typename ConnectCondition, typename ComposedConnectHandler> -BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename EndpointSequence, + typename ConnectCondition, typename RangeConnectHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, + void (boost::system::error_code, typename Protocol::endpoint)) +async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, + typename enable_if<is_endpoint_sequence< + EndpointSequence>::value>::type* = 0); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +/// (Deprecated.) Asynchronously establishes a socket connection by trying each +/// endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c async_connect + * member function, once for each endpoint in the sequence, until a connection + * is successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const boost::system::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @param handler The handler to be called when the connect operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * // Result of operation. if the sequence is empty, set to + * // boost::asio::error::not_found. Otherwise, contains the + * // error from the last connection attempt. + * const boost::system::error_code& error, + * + * // On success, an iterator denoting the successfully + * // connected endpoint. Otherwise, the end iterator. + * Iterator iterator + * ); @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 + * boost::asio::io_context::post(). + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. + */ +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) -async_connect(basic_socket<Protocol, SocketService>& s, Iterator begin, +async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, ConnectCondition connect_condition, - BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler); + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, + typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Asynchronously establishes a socket connection by trying each endpoint in a /// sequence. @@ -721,16 +960,14 @@ async_connect(basic_socket<Protocol, SocketService>& s, Iterator begin, * * @param connect_condition A function object that is called prior to each * connection attempt. The signature of the function object must be: - * @code Iterator connect_condition( + * @code bool connect_condition( * const boost::system::error_code& ec, - * Iterator next); @endcode + * const typename Protocol::endpoint& next); @endcode * The @c ec parameter contains the result from the most recent connect * operation. Before the first connection attempt, @c ec is always set to - * indicate success. The @c next parameter is an iterator pointing to the next - * endpoint to be tried. The function object should return the next iterator, - * but is permitted to return a different iterator so that endpoints may be - * skipped. The implementation guarantees that the function object will never - * be called with the end iterator. + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. * * @param handler The handler to be called when the connect operation * completes. Copies will be made of the handler as required. The function @@ -748,27 +985,26 @@ async_connect(basic_socket<Protocol, SocketService>& s, Iterator begin, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * The following connect condition function object can be used to output * information about the individual connection attempts: * @code struct my_connect_condition * { - * template <typename Iterator> - * Iterator operator()( + * bool operator()( * const boost::system::error_code& ec, - * Iterator next) + * const::tcp::endpoint& next) * { * if (ec) std::cout << "Error: " << ec.message() << std::endl; - * std::cout << "Trying: " << next->endpoint() << std::endl; - * return next; + * std::cout << "Trying: " << next << std::endl; + * return true; * } * }; @endcode * It would be used with the boost::asio::connect function as follows: - * @code tcp::resolver r(io_service); + * @code tcp::resolver r(io_context); * tcp::resolver::query q("host", "service"); - * tcp::socket s(io_service); + * tcp::socket s(io_context); * * // ... * @@ -805,13 +1041,13 @@ async_connect(basic_socket<Protocol, SocketService>& s, Iterator begin, * } * } @endcode */ -template <typename Protocol, typename SocketService, typename Iterator, - typename ConnectCondition, typename ComposedConnectHandler> -BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) -async_connect(basic_socket<Protocol, SocketService>& s, +async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, Iterator end, ConnectCondition connect_condition, - BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler); + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler); /*@}*/ diff --git a/boost/asio/coroutine.hpp b/boost/asio/coroutine.hpp index c4763f8524..7ac354de82 100644 --- a/boost/asio/coroutine.hpp +++ b/boost/asio/coroutine.hpp @@ -206,7 +206,7 @@ class coroutine_ref; * { * do * { - * socket_.reset(new tcp::socket(io_service_)); + * socket_.reset(new tcp::socket(io_context_)); * yield acceptor->async_accept(*socket_, *this); * fork server(*this)(); * } while (is_parent()); @@ -228,7 +228,7 @@ class coroutine_ref; * Note that @c fork doesn't do the actual forking by itself. It is the * application's responsibility to create a clone of the coroutine and call it. * The clone can be called immediately, as above, or scheduled for delayed - * execution using something like io_service::post(). + * execution using something like io_context::post(). * * @par Alternate macro names * @@ -291,7 +291,7 @@ private: bail_out_of_coroutine: \ break; \ } \ - else case 0: + else /* fall-through */ case 0: #define BOOST_ASIO_CORO_YIELD_IMPL(n) \ for (_coro_value = (n);;) \ @@ -303,12 +303,12 @@ private: else \ switch (_coro_value ? 0 : 1) \ for (;;) \ - case -1: if (_coro_value) \ + /* fall-through */ case -1: if (_coro_value) \ goto terminate_coroutine; \ else for (;;) \ - case 1: if (_coro_value) \ + /* fall-through */ case 1: if (_coro_value) \ goto bail_out_of_coroutine; \ - else case 0: + else /* fall-through */ case 0: #define BOOST_ASIO_CORO_FORK_IMPL(n) \ for (_coro_value = -(n);; _coro_value = (n)) \ diff --git a/boost/asio/datagram_socket_service.hpp b/boost/asio/datagram_socket_service.hpp index 95f179acfd..35bc2f5feb 100644 --- a/boost/asio/datagram_socket_service.hpp +++ b/boost/asio/datagram_socket_service.hpp @@ -16,11 +16,14 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #include <cstddef> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/null_socket_service.hpp> @@ -39,7 +42,7 @@ namespace asio { template <typename Protocol> class datagram_socket_service #if defined(GENERATING_DOCUMENTATION) - : public boost::asio::io_service::service + : public boost::asio::io_context::service #else : public boost::asio::detail::service_base<datagram_socket_service<Protocol> > #endif @@ -47,7 +50,7 @@ class datagram_socket_service public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. - static boost::asio::io_service::id id; + static boost::asio::io_context::id id; #endif /// The protocol type. @@ -74,13 +77,6 @@ public: typedef typename service_impl_type::implementation_type implementation_type; #endif - /// (Deprecated: Use native_handle_type.) The native socket type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_type; -#else - typedef typename service_impl_type::native_handle_type native_type; -#endif - /// The native socket type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; @@ -88,11 +84,11 @@ public: typedef typename service_impl_type::native_handle_type native_handle_type; #endif - /// Construct a new datagram socket service for the specified io_service. - explicit datagram_socket_service(boost::asio::io_service& io_service) + /// Construct a new datagram socket service for the specified io_context. + explicit datagram_socket_service(boost::asio::io_context& io_context) : boost::asio::detail::service_base< - datagram_socket_service<Protocol> >(io_service), - service_impl_(io_service) + datagram_socket_service<Protocol> >(io_context), + service_impl_(io_context) { } @@ -143,22 +139,23 @@ public: } // Open a new datagram socket implementation. - boost::system::error_code open(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID open(implementation_type& impl, const protocol_type& protocol, boost::system::error_code& ec) { if (protocol.type() == BOOST_ASIO_OS_DEF(SOCK_DGRAM)) service_impl_.open(impl, protocol, ec); else ec = boost::asio::error::invalid_argument; - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Assign an existing native socket to a datagram socket. - boost::system::error_code assign(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID assign(implementation_type& impl, const protocol_type& protocol, const native_handle_type& native_socket, boost::system::error_code& ec) { - return service_impl_.assign(impl, protocol, native_socket, ec); + service_impl_.assign(impl, protocol, native_socket, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the socket is open. @@ -168,16 +165,18 @@ public: } /// Close a datagram socket implementation. - boost::system::error_code close(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID close(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.close(impl, ec); + service_impl_.close(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } - /// (Deprecated: Use native_handle().) Get the native socket implementation. - native_type native(implementation_type& impl) + /// Release ownership of the underlying socket. + native_handle_type release(implementation_type& impl, + boost::system::error_code& ec) { - return service_impl_.native_handle(impl); + return service_impl_.release(impl, ec); } /// Get the native socket implementation. @@ -187,10 +186,11 @@ public: } /// Cancel all asynchronous operations associated with the socket. - boost::system::error_code cancel(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID cancel(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.cancel(impl, ec); + service_impl_.cancel(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the socket is at the out-of-band data mark. @@ -208,17 +208,19 @@ public: } // Bind the datagram socket to the specified local endpoint. - boost::system::error_code bind(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID bind(implementation_type& impl, const endpoint_type& endpoint, boost::system::error_code& ec) { - return service_impl_.bind(impl, endpoint, ec); + service_impl_.bind(impl, endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Connect the datagram socket to the specified endpoint. - boost::system::error_code connect(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID connect(implementation_type& impl, const endpoint_type& peer_endpoint, boost::system::error_code& ec) { - return service_impl_.connect(impl, peer_endpoint, ec); + service_impl_.connect(impl, peer_endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Start an asynchronous connect. @@ -229,37 +231,39 @@ public: const endpoint_type& peer_endpoint, BOOST_ASIO_MOVE_ARG(ConnectHandler) handler) { - detail::async_result_init< - ConnectHandler, void (boost::system::error_code)> init( - BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler)); + async_completion<ConnectHandler, + void (boost::system::error_code)> init(handler); - service_impl_.async_connect(impl, peer_endpoint, init.handler); + service_impl_.async_connect(impl, peer_endpoint, init.completion_handler); return init.result.get(); } /// Set a socket option. template <typename SettableSocketOption> - boost::system::error_code set_option(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID set_option(implementation_type& impl, const SettableSocketOption& option, boost::system::error_code& ec) { - return service_impl_.set_option(impl, option, ec); + service_impl_.set_option(impl, option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get a socket option. template <typename GettableSocketOption> - boost::system::error_code get_option(const implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID get_option(const implementation_type& impl, GettableSocketOption& option, boost::system::error_code& ec) const { - return service_impl_.get_option(impl, option, ec); + service_impl_.get_option(impl, option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Perform an IO control command on the socket. template <typename IoControlCommand> - boost::system::error_code io_control(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID io_control(implementation_type& impl, IoControlCommand& command, boost::system::error_code& ec) { - return service_impl_.io_control(impl, command, ec); + service_impl_.io_control(impl, command, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the socket. @@ -269,10 +273,11 @@ public: } /// Sets the non-blocking mode of the socket. - boost::system::error_code non_blocking(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID non_blocking(implementation_type& impl, bool mode, boost::system::error_code& ec) { - return service_impl_.non_blocking(impl, mode, ec); + service_impl_.non_blocking(impl, mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the native socket implementation. @@ -282,10 +287,11 @@ public: } /// Sets the non-blocking mode of the native socket implementation. - boost::system::error_code native_non_blocking(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID native_non_blocking(implementation_type& impl, bool mode, boost::system::error_code& ec) { - return service_impl_.native_non_blocking(impl, mode, ec); + service_impl_.native_non_blocking(impl, mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get the local endpoint. @@ -303,10 +309,36 @@ public: } /// Disable sends or receives on the socket. - boost::system::error_code shutdown(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID shutdown(implementation_type& impl, socket_base::shutdown_type what, boost::system::error_code& ec) { - return service_impl_.shutdown(impl, what, ec); + service_impl_.shutdown(impl, what, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Wait for the socket to become ready to read, ready to write, or to have + /// pending error conditions. + BOOST_ASIO_SYNC_OP_VOID wait(implementation_type& impl, + socket_base::wait_type w, boost::system::error_code& ec) + { + service_impl_.wait(impl, w, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Asynchronously wait for the socket to become ready to read, ready to + /// write, or to have pending error conditions. + template <typename WaitHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(implementation_type& impl, socket_base::wait_type w, + BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + async_completion<WaitHandler, + void (boost::system::error_code)> init(handler); + + service_impl_.async_wait(impl, w, init.completion_handler); + + return init.result.get(); } /// Send the given data to the peer. @@ -326,11 +358,10 @@ public: socket_base::message_flags flags, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); - service_impl_.async_send(impl, buffers, flags, init.handler); + service_impl_.async_send(impl, buffers, flags, init.completion_handler); return init.result.get(); } @@ -353,12 +384,11 @@ public: socket_base::message_flags flags, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); service_impl_.async_send_to(impl, buffers, - destination, flags, init.handler); + destination, flags, init.completion_handler); return init.result.get(); } @@ -381,11 +411,10 @@ public: socket_base::message_flags flags, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); - service_impl_.async_receive(impl, buffers, flags, init.handler); + service_impl_.async_receive(impl, buffers, flags, init.completion_handler); return init.result.get(); } @@ -409,21 +438,20 @@ public: socket_base::message_flags flags, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); service_impl_.async_receive_from(impl, buffers, - sender_endpoint, flags, init.handler); + sender_endpoint, flags, init.completion_handler); return init.result.get(); } private: // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { - service_impl_.shutdown_service(); + service_impl_.shutdown(); } // The platform-specific implementation. @@ -435,4 +463,6 @@ private: #include <boost/asio/detail/pop_options.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_DATAGRAM_SOCKET_SERVICE_HPP diff --git a/boost/asio/deadline_timer_service.hpp b/boost/asio/deadline_timer_service.hpp index 26dcb42e4c..d109815188 100644 --- a/boost/asio/deadline_timer_service.hpp +++ b/boost/asio/deadline_timer_service.hpp @@ -17,15 +17,16 @@ #include <boost/asio/detail/config.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ || defined(GENERATING_DOCUMENTATION) #include <cstddef> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/deadline_timer_service.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/time_traits.hpp> -#include <boost/asio/detail/timer_queue_ptime.hpp> #include <boost/asio/detail/push_options.hpp> @@ -37,7 +38,7 @@ template <typename TimeType, typename TimeTraits = boost::asio::time_traits<TimeType> > class deadline_timer_service #if defined(GENERATING_DOCUMENTATION) - : public boost::asio::io_service::service + : public boost::asio::io_context::service #else : public boost::asio::detail::service_base< deadline_timer_service<TimeType, TimeTraits> > @@ -46,7 +47,7 @@ class deadline_timer_service public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. - static boost::asio::io_service::id id; + static boost::asio::io_context::id id; #endif /// The time traits type. @@ -70,11 +71,11 @@ public: typedef typename service_impl_type::implementation_type implementation_type; #endif - /// Construct a new timer service for the specified io_service. - explicit deadline_timer_service(boost::asio::io_service& io_service) + /// Construct a new timer service for the specified io_context. + explicit deadline_timer_service(boost::asio::io_context& io_context) : boost::asio::detail::service_base< - deadline_timer_service<TimeType, TimeTraits> >(io_service), - service_impl_(io_service) + deadline_timer_service<TimeType, TimeTraits> >(io_context), + service_impl_(io_context) { } @@ -106,7 +107,7 @@ public: /// Get the expiry time for the timer as an absolute time. time_type expires_at(const implementation_type& impl) const { - return service_impl_.expires_at(impl); + return service_impl_.expiry(impl); } /// Set the expiry time for the timer as an absolute time. @@ -119,14 +120,14 @@ public: /// Get the expiry time for the timer relative to now. duration_type expires_from_now(const implementation_type& impl) const { - return service_impl_.expires_from_now(impl); + return TimeTraits::subtract(service_impl_.expiry(impl), TimeTraits::now()); } /// Set the expiry time for the timer relative to now. std::size_t expires_from_now(implementation_type& impl, const duration_type& expiry_time, boost::system::error_code& ec) { - return service_impl_.expires_from_now(impl, expiry_time, ec); + return service_impl_.expires_after(impl, expiry_time, ec); } // Perform a blocking wait on the timer. @@ -142,20 +143,19 @@ public: async_wait(implementation_type& impl, BOOST_ASIO_MOVE_ARG(WaitHandler) handler) { - detail::async_result_init< - WaitHandler, void (boost::system::error_code)> init( - BOOST_ASIO_MOVE_CAST(WaitHandler)(handler)); + async_completion<WaitHandler, + void (boost::system::error_code)> init(handler); - service_impl_.async_wait(impl, init.handler); + service_impl_.async_wait(impl, init.completion_handler); return init.result.get(); } private: // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { - service_impl_.shutdown_service(); + service_impl_.shutdown(); } // The platform-specific implementation. @@ -170,4 +170,6 @@ private: #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_DEADLINE_TIMER_SERVICE_HPP diff --git a/boost/asio/defer.hpp b/boost/asio/defer.hpp new file mode 100644 index 0000000000..966bfb4e14 --- /dev/null +++ b/boost/asio/defer.hpp @@ -0,0 +1,109 @@ +// +// defer.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DEFER_HPP +#define BOOST_ASIO_DEFER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/async_result.hpp> +#include <boost/asio/detail/type_traits.hpp> +#include <boost/asio/execution_context.hpp> +#include <boost/asio/is_executor.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +/// Submits a completion token or function object for execution. +/** + * This function submits an object for execution using the object's associated + * executor. The function object is queued for execution, and is never called + * from the current thread prior to returning from <tt>defer()</tt>. + * + * This function has the following effects: + * + * @li Constructs a function object handler of type @c Handler, initialized + * with <tt>handler(forward<CompletionToken>(token))</tt>. + * + * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, + * initializing the object as <tt>result(handler)</tt>. + * + * @li Obtains the handler's associated executor object @c ex by performing + * <tt>get_associated_executor(handler)</tt>. + * + * @li Obtains the handler's associated allocator object @c alloc by performing + * <tt>get_associated_allocator(handler)</tt>. + * + * @li Performs <tt>ex.defer(std::move(handler), alloc)</tt>. + * + * @li Returns <tt>result.get()</tt>. + */ +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( + BOOST_ASIO_MOVE_ARG(CompletionToken) token); + +/// Submits a completion token or function object for execution. +/** + * This function submits an object for execution using the specified executor. + * The function object is queued for execution, and is never called from the + * current thread prior to returning from <tt>defer()</tt>. + * + * This function has the following effects: + * + * @li Constructs a function object handler of type @c Handler, initialized + * with <tt>handler(forward<CompletionToken>(token))</tt>. + * + * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, + * initializing the object as <tt>result(handler)</tt>. + * + * @li Obtains the handler's associated executor object @c ex1 by performing + * <tt>get_associated_executor(handler)</tt>. + * + * @li Creates a work object @c w by performing <tt>make_work(ex1)</tt>. + * + * @li Obtains the handler's associated allocator object @c alloc by performing + * <tt>get_associated_allocator(handler)</tt>. + * + * @li Constructs a function object @c f with a function call operator that + * performs <tt>ex1.dispatch(std::move(handler), alloc)</tt> followed by + * <tt>w.reset()</tt>. + * + * @li Performs <tt>Executor(ex).defer(std::move(f), alloc)</tt>. + * + * @li Returns <tt>result.get()</tt>. + */ +template <typename Executor, typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( + const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_executor<Executor>::value>::type* = 0); + +/// Submits a completion token or function object for execution. +/** + * @returns <tt>defer(ctx.get_executor(), forward<CompletionToken>(token))</tt>. + */ +template <typename ExecutionContext, typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( + ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_convertible< + ExecutionContext&, execution_context&>::value>::type* = 0); + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#include <boost/asio/impl/defer.hpp> + +#endif // BOOST_ASIO_DEFER_HPP diff --git a/boost/asio/detail/addressof.hpp b/boost/asio/detail/addressof.hpp deleted file mode 100644 index cc1099764d..0000000000 --- a/boost/asio/detail/addressof.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// -// detail/addressof.hpp -// ~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2017 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) -// - -#ifndef BOOST_ASIO_DETAIL_ADDRESSOF_HPP -#define BOOST_ASIO_DETAIL_ADDRESSOF_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include <boost/asio/detail/config.hpp> - -#if defined(BOOST_ASIO_HAS_STD_ADDRESSOF) -# include <memory> -#else // defined(BOOST_ASIO_HAS_STD_ADDRESSOF) -# include <boost/utility/addressof.hpp> -#endif // defined(BOOST_ASIO_HAS_STD_ADDRESSOF) - -namespace boost { -namespace asio { -namespace detail { - -#if defined(BOOST_ASIO_HAS_STD_ADDRESSOF) -using std::addressof; -#else // defined(BOOST_ASIO_HAS_STD_ADDRESSOF) -using boost::addressof; -#endif // defined(BOOST_ASIO_HAS_STD_ADDRESSOF) - -} // namespace detail -} // namespace asio -} // namespace boost - -#endif // BOOST_ASIO_DETAIL_ADDRESSOF_HPP diff --git a/boost/asio/detail/bind_handler.hpp b/boost/asio/detail/bind_handler.hpp index 0f3672edab..b55c2acd5e 100644 --- a/boost/asio/detail/bind_handler.hpp +++ b/boost/asio/detail/bind_handler.hpp @@ -16,9 +16,12 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/associated_executor.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/push_options.hpp> @@ -30,8 +33,9 @@ template <typename Handler, typename Arg1> class binder1 { public: - binder1(const Handler& handler, const Arg1& arg1) - : handler_(handler), + template <typename T> + binder1(int, BOOST_ASIO_MOVE_ARG(T) handler, const Arg1& arg1) + : handler_(BOOST_ASIO_MOVE_CAST(T)(handler)), arg1_(arg1) { } @@ -42,6 +46,20 @@ public: { } +#if defined(BOOST_ASIO_HAS_MOVE) + binder1(const binder1& other) + : handler_(other.handler_), + arg1_(other.arg1_) + { + } + + binder1(binder1&& other) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + void operator()() { handler_(static_cast<const Arg1&>(arg1_)); @@ -98,18 +116,21 @@ inline void asio_handler_invoke(const Function& function, } template <typename Handler, typename Arg1> -inline binder1<Handler, Arg1> bind_handler(Handler handler, - const Arg1& arg1) +inline binder1<typename decay<Handler>::type, Arg1> bind_handler( + BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1) { - return binder1<Handler, Arg1>(handler, arg1); + return binder1<typename decay<Handler>::type, Arg1>(0, + BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1); } template <typename Handler, typename Arg1, typename Arg2> class binder2 { public: - binder2(const Handler& handler, const Arg1& arg1, const Arg2& arg2) - : handler_(handler), + template <typename T> + binder2(int, BOOST_ASIO_MOVE_ARG(T) handler, + const Arg1& arg1, const Arg2& arg2) + : handler_(BOOST_ASIO_MOVE_CAST(T)(handler)), arg1_(arg1), arg2_(arg2) { @@ -122,6 +143,22 @@ public: { } +#if defined(BOOST_ASIO_HAS_MOVE) + binder2(const binder2& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_) + { + } + + binder2(binder2&& other) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(other.arg2_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + void operator()() { handler_(static_cast<const Arg1&>(arg1_), @@ -180,27 +217,29 @@ inline void asio_handler_invoke(const Function& function, } template <typename Handler, typename Arg1, typename Arg2> -inline binder2<Handler, Arg1, Arg2> bind_handler(Handler handler, - const Arg1& arg1, const Arg2& arg2) +inline binder2<typename decay<Handler>::type, Arg1, Arg2> bind_handler( + BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2) { - return binder2<Handler, Arg1, Arg2>(handler, arg1, arg2); + return binder2<typename decay<Handler>::type, Arg1, Arg2>(0, + BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1, arg2); } template <typename Handler, typename Arg1, typename Arg2, typename Arg3> class binder3 { public: - binder3(const Handler& handler, const Arg1& arg1, const Arg2& arg2, - const Arg3& arg3) - : handler_(handler), + template <typename T> + binder3(int, BOOST_ASIO_MOVE_ARG(T) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3) + : handler_(BOOST_ASIO_MOVE_CAST(T)(handler)), arg1_(arg1), arg2_(arg2), arg3_(arg3) { } - binder3(Handler& handler, const Arg1& arg1, const Arg2& arg2, - const Arg3& arg3) + binder3(Handler& handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3) : handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), arg1_(arg1), arg2_(arg2), @@ -208,11 +247,28 @@ public: { } +#if defined(BOOST_ASIO_HAS_MOVE) + binder3(const binder3& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_), + arg3_(other.arg3_) + { + } + + binder3(binder3&& other) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(other.arg2_)), + arg3_(BOOST_ASIO_MOVE_CAST(Arg3)(other.arg3_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + void operator()() { handler_(static_cast<const Arg1&>(arg1_), - static_cast<const Arg2&>(arg2_), - static_cast<const Arg3&>(arg3_)); + static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_)); } void operator()() const @@ -251,8 +307,8 @@ inline bool asio_handler_is_continuation( this_handler->handler_); } -template <typename Function, typename Handler, typename Arg1, typename Arg2, - typename Arg3> +template <typename Function, typename Handler, + typename Arg1, typename Arg2, typename Arg3> inline void asio_handler_invoke(Function& function, binder3<Handler, Arg1, Arg2, Arg3>* this_handler) { @@ -260,8 +316,8 @@ inline void asio_handler_invoke(Function& function, function, this_handler->handler_); } -template <typename Function, typename Handler, typename Arg1, typename Arg2, - typename Arg3> +template <typename Function, typename Handler, + typename Arg1, typename Arg2, typename Arg3> inline void asio_handler_invoke(const Function& function, binder3<Handler, Arg1, Arg2, Arg3>* this_handler) { @@ -270,20 +326,23 @@ inline void asio_handler_invoke(const Function& function, } template <typename Handler, typename Arg1, typename Arg2, typename Arg3> -inline binder3<Handler, Arg1, Arg2, Arg3> bind_handler(Handler handler, - const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) +inline binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3> bind_handler( + BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3) { - return binder3<Handler, Arg1, Arg2, Arg3>(handler, arg1, arg2, arg3); + return binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3>(0, + BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3); } -template <typename Handler, typename Arg1, typename Arg2, typename Arg3, - typename Arg4> +template <typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> class binder4 { public: - binder4(const Handler& handler, const Arg1& arg1, const Arg2& arg2, - const Arg3& arg3, const Arg4& arg4) - : handler_(handler), + template <typename T> + binder4(int, BOOST_ASIO_MOVE_ARG(T) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) + : handler_(BOOST_ASIO_MOVE_CAST(T)(handler)), arg1_(arg1), arg2_(arg2), arg3_(arg3), @@ -291,8 +350,8 @@ public: { } - binder4(Handler& handler, const Arg1& arg1, const Arg2& arg2, - const Arg3& arg3, const Arg4& arg4) + binder4(Handler& handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) : handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), arg1_(arg1), arg2_(arg2), @@ -301,11 +360,30 @@ public: { } +#if defined(BOOST_ASIO_HAS_MOVE) + binder4(const binder4& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_), + arg3_(other.arg3_), + arg4_(other.arg4_) + { + } + + binder4(binder4&& other) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(other.arg2_)), + arg3_(BOOST_ASIO_MOVE_CAST(Arg3)(other.arg3_)), + arg4_(BOOST_ASIO_MOVE_CAST(Arg4)(other.arg4_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + void operator()() { handler_(static_cast<const Arg1&>(arg1_), - static_cast<const Arg2&>(arg2_), - static_cast<const Arg3&>(arg3_), + static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_), static_cast<const Arg4&>(arg4_)); } @@ -322,8 +400,8 @@ public: Arg4 arg4_; }; -template <typename Handler, typename Arg1, typename Arg2, typename Arg3, - typename Arg4> +template <typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> inline void* asio_handler_allocate(std::size_t size, binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler) { @@ -331,8 +409,8 @@ inline void* asio_handler_allocate(std::size_t size, size, this_handler->handler_); } -template <typename Handler, typename Arg1, typename Arg2, typename Arg3, - typename Arg4> +template <typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> inline void asio_handler_deallocate(void* pointer, std::size_t size, binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler) { @@ -340,8 +418,8 @@ inline void asio_handler_deallocate(void* pointer, std::size_t size, pointer, size, this_handler->handler_); } -template <typename Handler, typename Arg1, typename Arg2, typename Arg3, - typename Arg4> +template <typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> inline bool asio_handler_is_continuation( binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler) { @@ -349,8 +427,8 @@ inline bool asio_handler_is_continuation( this_handler->handler_); } -template <typename Function, typename Handler, typename Arg1, typename Arg2, - typename Arg3, typename Arg4> +template <typename Function, typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> inline void asio_handler_invoke(Function& function, binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler) { @@ -358,8 +436,8 @@ inline void asio_handler_invoke(Function& function, function, this_handler->handler_); } -template <typename Function, typename Handler, typename Arg1, typename Arg2, - typename Arg3, typename Arg4> +template <typename Function, typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> inline void asio_handler_invoke(const Function& function, binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler) { @@ -367,24 +445,25 @@ inline void asio_handler_invoke(const Function& function, function, this_handler->handler_); } -template <typename Handler, typename Arg1, typename Arg2, typename Arg3, - typename Arg4> -inline binder4<Handler, Arg1, Arg2, Arg3, Arg4> bind_handler( - Handler handler, const Arg1& arg1, const Arg2& arg2, - const Arg3& arg3, const Arg4& arg4) +template <typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4> +inline binder4<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4> +bind_handler(BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) { - return binder4<Handler, Arg1, Arg2, Arg3, Arg4>(handler, arg1, arg2, arg3, - arg4); + return binder4<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4>(0, + BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4); } -template <typename Handler, typename Arg1, typename Arg2, typename Arg3, - typename Arg4, typename Arg5> +template <typename Handler, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5> class binder5 { public: - binder5(const Handler& handler, const Arg1& arg1, const Arg2& arg2, - const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) - : handler_(handler), + template <typename T> + binder5(int, BOOST_ASIO_MOVE_ARG(T) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) + : handler_(BOOST_ASIO_MOVE_CAST(T)(handler)), arg1_(arg1), arg2_(arg2), arg3_(arg3), @@ -404,13 +483,33 @@ public: { } +#if defined(BOOST_ASIO_HAS_MOVE) + binder5(const binder5& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_), + arg3_(other.arg3_), + arg4_(other.arg4_), + arg5_(other.arg5_) + { + } + + binder5(binder5&& other) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(other.arg2_)), + arg3_(BOOST_ASIO_MOVE_CAST(Arg3)(other.arg3_)), + arg4_(BOOST_ASIO_MOVE_CAST(Arg4)(other.arg4_)), + arg5_(BOOST_ASIO_MOVE_CAST(Arg5)(other.arg5_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + void operator()() { handler_(static_cast<const Arg1&>(arg1_), - static_cast<const Arg2&>(arg2_), - static_cast<const Arg3&>(arg3_), - static_cast<const Arg4&>(arg4_), - static_cast<const Arg5&>(arg5_)); + static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_), + static_cast<const Arg4&>(arg4_), static_cast<const Arg5&>(arg5_)); } void operator()() const @@ -427,8 +526,8 @@ public: Arg5 arg5_; }; -template <typename Handler, typename Arg1, typename Arg2, typename Arg3, - typename Arg4, typename Arg5> +template <typename Handler, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5> inline void* asio_handler_allocate(std::size_t size, binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler) { @@ -436,8 +535,8 @@ inline void* asio_handler_allocate(std::size_t size, size, this_handler->handler_); } -template <typename Handler, typename Arg1, typename Arg2, typename Arg3, - typename Arg4, typename Arg5> +template <typename Handler, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5> inline void asio_handler_deallocate(void* pointer, std::size_t size, binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler) { @@ -445,8 +544,8 @@ inline void asio_handler_deallocate(void* pointer, std::size_t size, pointer, size, this_handler->handler_); } -template <typename Handler, typename Arg1, typename Arg2, typename Arg3, - typename Arg4, typename Arg5> +template <typename Handler, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5> inline bool asio_handler_is_continuation( binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler) { @@ -454,8 +553,8 @@ inline bool asio_handler_is_continuation( this_handler->handler_); } -template <typename Function, typename Handler, typename Arg1, typename Arg2, - typename Arg3, typename Arg4, typename Arg5> +template <typename Function, typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4, typename Arg5> inline void asio_handler_invoke(Function& function, binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler) { @@ -463,8 +562,8 @@ inline void asio_handler_invoke(Function& function, function, this_handler->handler_); } -template <typename Function, typename Handler, typename Arg1, typename Arg2, - typename Arg3, typename Arg4, typename Arg5> +template <typename Function, typename Handler, typename Arg1, + typename Arg2, typename Arg3, typename Arg4, typename Arg5> inline void asio_handler_invoke(const Function& function, binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler) { @@ -472,17 +571,245 @@ inline void asio_handler_invoke(const Function& function, function, this_handler->handler_); } -template <typename Handler, typename Arg1, typename Arg2, typename Arg3, - typename Arg4, typename Arg5> -inline binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5> bind_handler( - Handler handler, const Arg1& arg1, const Arg2& arg2, - const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) +template <typename Handler, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5> +inline binder5<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4, Arg5> +bind_handler(BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) +{ + return binder5<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4, Arg5>(0, + BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4, arg5); +} + +#if defined(BOOST_ASIO_HAS_MOVE) + +template <typename Handler, typename Arg1> +class move_binder1 +{ +public: + move_binder1(int, BOOST_ASIO_MOVE_ARG(Handler) handler, + BOOST_ASIO_MOVE_ARG(Arg1) arg1) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(arg1)) + { + } + + move_binder1(move_binder1&& other) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)) + { + } + + void operator()() + { + handler_(BOOST_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 boost_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) +{ + boost_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 boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template <typename Function, typename Handler, typename Arg1> +inline void asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function, + move_binder1<Handler, Arg1>* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + BOOST_ASIO_MOVE_CAST(Function)(function), this_handler->handler_); +} + +template <typename Handler, typename Arg1, typename Arg2> +class move_binder2 +{ +public: + move_binder2(int, BOOST_ASIO_MOVE_ARG(Handler) handler, + const Arg1& arg1, BOOST_ASIO_MOVE_ARG(Arg2) arg2) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(arg2)) + { + } + + move_binder2(move_binder2&& other) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(other.arg2_)) + { + } + + void operator()() + { + handler_(static_cast<const Arg1&>(arg1_), + BOOST_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 boost_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) +{ + boost_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 binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>(handler, arg1, arg2, - arg3, arg4, arg5); + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); } +template <typename Function, typename Handler, typename Arg1, typename Arg2> +inline void asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function, + move_binder2<Handler, Arg1, Arg2>* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + BOOST_ASIO_MOVE_CAST(Function)(function), this_handler->handler_); +} + +#endif // defined(BOOST_ASIO_HAS_MOVE) + } // namespace detail + +template <typename Handler, typename Arg1, typename Allocator> +struct associated_allocator<detail::binder1<Handler, Arg1>, Allocator> +{ + typedef typename associated_allocator<Handler, Allocator>::type type; + + static type get(const detail::binder1<Handler, Arg1>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<Handler, Allocator>::get(h.handler_, a); + } +}; + +template <typename Handler, typename Arg1, typename Arg2, typename Allocator> +struct associated_allocator<detail::binder2<Handler, Arg1, Arg2>, Allocator> +{ + typedef typename associated_allocator<Handler, Allocator>::type type; + + static type get(const detail::binder2<Handler, Arg1, Arg2>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<Handler, Allocator>::get(h.handler_, a); + } +}; + +template <typename Handler, typename Arg1, typename Executor> +struct associated_executor<detail::binder1<Handler, Arg1>, Executor> +{ + typedef typename associated_executor<Handler, Executor>::type type; + + static type get(const detail::binder1<Handler, Arg1>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<Handler, Executor>::get(h.handler_, ex); + } +}; + +template <typename Handler, typename Arg1, typename Arg2, typename Executor> +struct associated_executor<detail::binder2<Handler, Arg1, Arg2>, Executor> +{ + typedef typename associated_executor<Handler, Executor>::type type; + + static type get(const detail::binder2<Handler, Arg1, Arg2>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<Handler, Executor>::get(h.handler_, ex); + } +}; + +#if defined(BOOST_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()) BOOST_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()) BOOST_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()) BOOST_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()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<Handler, Executor>::get(h.handler_, ex); + } +}; + +#endif // defined(BOOST_ASIO_HAS_MOVE) + } // namespace asio } // namespace boost diff --git a/boost/asio/detail/buffer_sequence_adapter.hpp b/boost/asio/detail/buffer_sequence_adapter.hpp index 20c529e0a2..e04b292266 100644 --- a/boost/asio/detail/buffer_sequence_adapter.hpp +++ b/boost/asio/detail/buffer_sequence_adapter.hpp @@ -28,11 +28,12 @@ namespace detail { class buffer_sequence_adapter_base { -protected: #if defined(BOOST_ASIO_WINDOWS_RUNTIME) +public: // The maximum number of buffers to support in a single operation. enum { max_buffers = 1 }; +protected: typedef Windows::Storage::Streams::IBuffer^ native_buffer_type; BOOST_ASIO_DECL static void init_native_buffer( @@ -43,28 +44,32 @@ protected: native_buffer_type& buf, const boost::asio::const_buffer& buffer); #elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +public: // The maximum number of buffers to support in a single operation. enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; +protected: typedef WSABUF native_buffer_type; static void init_native_buffer(WSABUF& buf, const boost::asio::mutable_buffer& buffer) { - buf.buf = boost::asio::buffer_cast<char*>(buffer); - buf.len = static_cast<ULONG>(boost::asio::buffer_size(buffer)); + buf.buf = static_cast<char*>(buffer.data()); + buf.len = static_cast<ULONG>(buffer.size()); } static void init_native_buffer(WSABUF& buf, const boost::asio::const_buffer& buffer) { - buf.buf = const_cast<char*>(boost::asio::buffer_cast<const char*>(buffer)); - buf.len = static_cast<ULONG>(boost::asio::buffer_size(buffer)); + buf.buf = const_cast<char*>(static_cast<const char*>(buffer.data())); + buf.len = static_cast<ULONG>(buffer.size()); } #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +public: // The maximum number of buffers to support in a single operation. enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; +protected: typedef iovec native_buffer_type; static void init_iov_base(void*& base, void* addr) @@ -81,16 +86,15 @@ protected: static void init_native_buffer(iovec& iov, const boost::asio::mutable_buffer& buffer) { - init_iov_base(iov.iov_base, boost::asio::buffer_cast<void*>(buffer)); - iov.iov_len = boost::asio::buffer_size(buffer); + init_iov_base(iov.iov_base, buffer.data()); + iov.iov_len = buffer.size(); } static void init_native_buffer(iovec& iov, const boost::asio::const_buffer& buffer) { - init_iov_base(iov.iov_base, const_cast<void*>( - boost::asio::buffer_cast<const void*>(buffer))); - iov.iov_len = boost::asio::buffer_size(buffer); + init_iov_base(iov.iov_base, const_cast<void*>(buffer.data())); + iov.iov_len = buffer.size(); } #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) }; @@ -104,14 +108,9 @@ public: explicit buffer_sequence_adapter(const Buffers& buffer_sequence) : count_(0), total_buffer_size_(0) { - typename Buffers::const_iterator iter = buffer_sequence.begin(); - typename Buffers::const_iterator end = buffer_sequence.end(); - for (; iter != end && count_ < max_buffers; ++iter, ++count_) - { - Buffer buffer(*iter); - init_native_buffer(buffers_[count_], buffer); - total_buffer_size_ += boost::asio::buffer_size(buffer); - } + buffer_sequence_adapter::init( + boost::asio::buffer_sequence_begin(buffer_sequence), + boost::asio::buffer_sequence_end(buffer_sequence)); } native_buffer_type* buffers() @@ -124,6 +123,11 @@ public: return count_; } + std::size_t total_size() const + { + return total_buffer_size_; + } + bool all_empty() const { return total_buffer_size_ == 0; @@ -131,46 +135,185 @@ public: static bool all_empty(const Buffers& buffer_sequence) { - typename Buffers::const_iterator iter = buffer_sequence.begin(); - typename Buffers::const_iterator end = buffer_sequence.end(); + return buffer_sequence_adapter::all_empty( + boost::asio::buffer_sequence_begin(buffer_sequence), + boost::asio::buffer_sequence_end(buffer_sequence)); + } + + static void validate(const Buffers& buffer_sequence) + { + buffer_sequence_adapter::validate( + boost::asio::buffer_sequence_begin(buffer_sequence), + boost::asio::buffer_sequence_end(buffer_sequence)); + } + + static Buffer first(const Buffers& buffer_sequence) + { + return buffer_sequence_adapter::first( + boost::asio::buffer_sequence_begin(buffer_sequence), + boost::asio::buffer_sequence_end(buffer_sequence)); + } + +private: + template <typename Iterator> + void init(Iterator begin, Iterator end) + { + Iterator iter = begin; + for (; iter != end && count_ < max_buffers; ++iter, ++count_) + { + Buffer buffer(*iter); + init_native_buffer(buffers_[count_], buffer); + total_buffer_size_ += buffer.size(); + } + } + + template <typename Iterator> + static bool all_empty(Iterator begin, Iterator end) + { + Iterator iter = begin; std::size_t i = 0; for (; iter != end && i < max_buffers; ++iter, ++i) - if (boost::asio::buffer_size(Buffer(*iter)) > 0) + if (Buffer(*iter).size() > 0) return false; return true; } - static void validate(const Buffers& buffer_sequence) + template <typename Iterator> + static void validate(Iterator begin, Iterator end) { - typename Buffers::const_iterator iter = buffer_sequence.begin(); - typename Buffers::const_iterator end = buffer_sequence.end(); + Iterator iter = begin; for (; iter != end; ++iter) { Buffer buffer(*iter); - boost::asio::buffer_cast<const void*>(buffer); + buffer.data(); } } - static Buffer first(const Buffers& buffer_sequence) + template <typename Iterator> + static Buffer first(Iterator begin, Iterator end) { - typename Buffers::const_iterator iter = buffer_sequence.begin(); - typename Buffers::const_iterator end = buffer_sequence.end(); + Iterator iter = begin; for (; iter != end; ++iter) { Buffer buffer(*iter); - if (boost::asio::buffer_size(buffer) != 0) + if (buffer.size() != 0) return buffer; } return Buffer(); } -private: native_buffer_type buffers_[max_buffers]; std::size_t count_; std::size_t total_buffer_size_; }; template <typename Buffer> +class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffer> + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const boost::asio::mutable_buffer& buffer_sequence) + { + init_native_buffer(buffer_, Buffer(buffer_sequence)); + total_buffer_size_ = buffer_sequence.size(); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const boost::asio::mutable_buffer& buffer_sequence) + { + return buffer_sequence.size() == 0; + } + + static void validate(const boost::asio::mutable_buffer& buffer_sequence) + { + buffer_sequence.data(); + } + + static Buffer first(const boost::asio::mutable_buffer& buffer_sequence) + { + return Buffer(buffer_sequence); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +template <typename Buffer> +class buffer_sequence_adapter<Buffer, boost::asio::const_buffer> + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const boost::asio::const_buffer& buffer_sequence) + { + init_native_buffer(buffer_, Buffer(buffer_sequence)); + total_buffer_size_ = buffer_sequence.size(); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const boost::asio::const_buffer& buffer_sequence) + { + return buffer_sequence.size() == 0; + } + + static void validate(const boost::asio::const_buffer& buffer_sequence) + { + buffer_sequence.data(); + } + + static Buffer first(const boost::asio::const_buffer& buffer_sequence) + { + return Buffer(buffer_sequence); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +template <typename Buffer> class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffers_1> : buffer_sequence_adapter_base { @@ -179,7 +322,7 @@ public: const boost::asio::mutable_buffers_1& buffer_sequence) { init_native_buffer(buffer_, Buffer(buffer_sequence)); - total_buffer_size_ = boost::asio::buffer_size(buffer_sequence); + total_buffer_size_ = buffer_sequence.size(); } native_buffer_type* buffers() @@ -192,6 +335,11 @@ public: return 1; } + std::size_t total_size() const + { + return total_buffer_size_; + } + bool all_empty() const { return total_buffer_size_ == 0; @@ -199,12 +347,12 @@ public: static bool all_empty(const boost::asio::mutable_buffers_1& buffer_sequence) { - return boost::asio::buffer_size(buffer_sequence) == 0; + return buffer_sequence.size() == 0; } static void validate(const boost::asio::mutable_buffers_1& buffer_sequence) { - boost::asio::buffer_cast<const void*>(buffer_sequence); + buffer_sequence.data(); } static Buffer first(const boost::asio::mutable_buffers_1& buffer_sequence) @@ -226,7 +374,7 @@ public: const boost::asio::const_buffers_1& buffer_sequence) { init_native_buffer(buffer_, Buffer(buffer_sequence)); - total_buffer_size_ = boost::asio::buffer_size(buffer_sequence); + total_buffer_size_ = buffer_sequence.size(); } native_buffer_type* buffers() @@ -239,6 +387,11 @@ public: return 1; } + std::size_t total_size() const + { + return total_buffer_size_; + } + bool all_empty() const { return total_buffer_size_ == 0; @@ -246,12 +399,12 @@ public: static bool all_empty(const boost::asio::const_buffers_1& buffer_sequence) { - return boost::asio::buffer_size(buffer_sequence) == 0; + return buffer_sequence.size() == 0; } static void validate(const boost::asio::const_buffers_1& buffer_sequence) { - boost::asio::buffer_cast<const void*>(buffer_sequence); + buffer_sequence.data(); } static Buffer first(const boost::asio::const_buffers_1& buffer_sequence) @@ -264,6 +417,8 @@ private: std::size_t total_buffer_size_; }; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + template <typename Buffer, typename Elem> class buffer_sequence_adapter<Buffer, boost::array<Elem, 2> > : buffer_sequence_adapter_base @@ -274,8 +429,7 @@ public: { init_native_buffer(buffers_[0], Buffer(buffer_sequence[0])); init_native_buffer(buffers_[1], Buffer(buffer_sequence[1])); - total_buffer_size_ = boost::asio::buffer_size(buffer_sequence[0]) - + boost::asio::buffer_size(buffer_sequence[1]); + total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size(); } native_buffer_type* buffers() @@ -288,6 +442,11 @@ public: return 2; } + std::size_t total_size() const + { + return total_buffer_size_; + } + bool all_empty() const { return total_buffer_size_ == 0; @@ -295,19 +454,18 @@ public: static bool all_empty(const boost::array<Elem, 2>& buffer_sequence) { - return boost::asio::buffer_size(buffer_sequence[0]) == 0 - && boost::asio::buffer_size(buffer_sequence[1]) == 0; + return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0; } static void validate(const boost::array<Elem, 2>& buffer_sequence) { - boost::asio::buffer_cast<const void*>(buffer_sequence[0]); - boost::asio::buffer_cast<const void*>(buffer_sequence[1]); + buffer_sequence[0].data(); + buffer_sequence[1].data(); } static Buffer first(const boost::array<Elem, 2>& buffer_sequence) { - return Buffer(boost::asio::buffer_size(buffer_sequence[0]) != 0 + return Buffer(buffer_sequence[0].size() != 0 ? buffer_sequence[0] : buffer_sequence[1]); } @@ -328,8 +486,7 @@ public: { init_native_buffer(buffers_[0], Buffer(buffer_sequence[0])); init_native_buffer(buffers_[1], Buffer(buffer_sequence[1])); - total_buffer_size_ = boost::asio::buffer_size(buffer_sequence[0]) - + boost::asio::buffer_size(buffer_sequence[1]); + total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size(); } native_buffer_type* buffers() @@ -342,6 +499,11 @@ public: return 2; } + std::size_t total_size() const + { + return total_buffer_size_; + } + bool all_empty() const { return total_buffer_size_ == 0; @@ -349,19 +511,18 @@ public: static bool all_empty(const std::array<Elem, 2>& buffer_sequence) { - return boost::asio::buffer_size(buffer_sequence[0]) == 0 - && boost::asio::buffer_size(buffer_sequence[1]) == 0; + return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0; } static void validate(const std::array<Elem, 2>& buffer_sequence) { - boost::asio::buffer_cast<const void*>(buffer_sequence[0]); - boost::asio::buffer_cast<const void*>(buffer_sequence[1]); + buffer_sequence[0].data(); + buffer_sequence[1].data(); } static Buffer first(const std::array<Elem, 2>& buffer_sequence) { - return Buffer(boost::asio::buffer_size(buffer_sequence[0]) != 0 + return Buffer(buffer_sequence[0].size() != 0 ? buffer_sequence[0] : buffer_sequence[1]); } diff --git a/boost/asio/detail/call_stack.hpp b/boost/asio/detail/call_stack.hpp index 5253e3b153..52de6ef00d 100644 --- a/boost/asio/detail/call_stack.hpp +++ b/boost/asio/detail/call_stack.hpp @@ -26,7 +26,7 @@ namespace asio { namespace detail { // Helper class to determine whether or not the current thread is inside an -// invocation of io_service::run() for a specified io_service object. +// invocation of io_context::run() for a specified io_context object. template <typename Key, typename Value = unsigned char> class call_stack { diff --git a/boost/asio/detail/chrono.hpp b/boost/asio/detail/chrono.hpp new file mode 100644 index 0000000000..923e7697b2 --- /dev/null +++ b/boost/asio/detail/chrono.hpp @@ -0,0 +1,68 @@ +// +// detail/chrono.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_CHRONO_HPP +#define BOOST_ASIO_DETAIL_CHRONO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_HAS_STD_CHRONO) +# include <chrono> +#elif defined(BOOST_ASIO_HAS_BOOST_CHRONO) +# include <boost/chrono/system_clocks.hpp> +#endif // defined(BOOST_ASIO_HAS_BOOST_CHRONO) + +namespace boost { +namespace asio { +namespace chrono { + +#if defined(BOOST_ASIO_HAS_STD_CHRONO) +using std::chrono::duration; +using std::chrono::time_point; +using std::chrono::duration_cast; +using std::chrono::nanoseconds; +using std::chrono::microseconds; +using std::chrono::milliseconds; +using std::chrono::seconds; +using std::chrono::minutes; +using std::chrono::hours; +using std::chrono::time_point_cast; +#if defined(BOOST_ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) +typedef std::chrono::monotonic_clock steady_clock; +#else // defined(BOOST_ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) +using std::chrono::steady_clock; +#endif // defined(BOOST_ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) +using std::chrono::system_clock; +using std::chrono::high_resolution_clock; +#elif defined(BOOST_ASIO_HAS_BOOST_CHRONO) +using boost::chrono::duration; +using boost::chrono::time_point; +using boost::chrono::duration_cast; +using boost::chrono::nanoseconds; +using boost::chrono::microseconds; +using boost::chrono::milliseconds; +using boost::chrono::seconds; +using boost::chrono::minutes; +using boost::chrono::hours; +using boost::chrono::time_point_cast; +using boost::chrono::system_clock; +using boost::chrono::steady_clock; +using boost::chrono::high_resolution_clock; +#endif // defined(BOOST_ASIO_HAS_BOOST_CHRONO) + +} // namespace chrono +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_CHRONO_HPP diff --git a/boost/asio/detail/completion_handler.hpp b/boost/asio/detail/completion_handler.hpp index 6333dce569..d18d372eeb 100644 --- a/boost/asio/detail/completion_handler.hpp +++ b/boost/asio/detail/completion_handler.hpp @@ -15,11 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> -#include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/handler_work.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/push_options.hpp> @@ -38,17 +38,19 @@ public: : operation(&completion_handler::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(h)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. completion_handler* h(static_cast<completion_handler*>(base)); ptr p = { boost::asio::detail::addressof(h->handler_), h, h }; + handler_work<Handler> w(h->handler_); - BOOST_ASIO_HANDLER_COMPLETION((h)); + BOOST_ASIO_HANDLER_COMPLETION((*h)); // 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 @@ -65,7 +67,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN(()); - boost_asio_handler_invoke_helpers::invoke(handler, handler); + w.complete(handler, handler); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/concurrency_hint.hpp b/boost/asio/detail/concurrency_hint.hpp new file mode 100644 index 0000000000..0a13205499 --- /dev/null +++ b/boost/asio/detail/concurrency_hint.hpp @@ -0,0 +1,94 @@ +// +// detail/concurrency_hint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_CONCURRENCY_HINT_HPP +#define BOOST_ASIO_DETAIL_CONCURRENCY_HINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/noncopyable.hpp> + +// The concurrency hint ID and mask are used to identify when a "well-known" +// concurrency hint value has been passed to the io_context. +#define BOOST_ASIO_CONCURRENCY_HINT_ID 0xA5100000u +#define BOOST_ASIO_CONCURRENCY_HINT_ID_MASK 0xFFFF0000u + +// If set, this bit indicates that the scheduler should perform locking. +#define BOOST_ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER 0x1u + +// If set, this bit indicates that the reactor should perform locking when +// managing descriptor registrations. +#define BOOST_ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION 0x2u + +// If set, this bit indicates that the reactor should perform locking for I/O. +#define BOOST_ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO 0x4u + +// Helper macro to determine if we have a special concurrency hint. +#define BOOST_ASIO_CONCURRENCY_HINT_IS_SPECIAL(hint) \ + ((static_cast<unsigned>(hint) \ + & BOOST_ASIO_CONCURRENCY_HINT_ID_MASK) \ + == BOOST_ASIO_CONCURRENCY_HINT_ID) + +// Helper macro to determine if locking is enabled for a given facility. +#define BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(facility, hint) \ + (((static_cast<unsigned>(hint) \ + & (BOOST_ASIO_CONCURRENCY_HINT_ID_MASK \ + | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_ ## facility)) \ + ^ BOOST_ASIO_CONCURRENCY_HINT_ID) != 0) + +// This special concurrency hint disables locking in both the scheduler and +// reactor I/O. This hint has the following restrictions: +// +// - Care must be taken to ensure that all operations on the io_context and any +// of its associated I/O objects (such as sockets and timers) occur in only +// one thread at a time. +// +// - Asynchronous resolve operations fail with operation_not_supported. +// +// - If a signal_set is used with the io_context, signal_set objects cannot be +// used with any other io_context in the program. +#define BOOST_ASIO_CONCURRENCY_HINT_UNSAFE \ + static_cast<int>(BOOST_ASIO_CONCURRENCY_HINT_ID) + +// This special concurrency hint disables locking in the reactor I/O. This hint +// has the following restrictions: +// +// - Care must be taken to ensure that run functions on the io_context, and all +// operations on the io_context's associated I/O objects (such as sockets and +// timers), occur in only one thread at a time. +#define BOOST_ASIO_CONCURRENCY_HINT_UNSAFE_IO \ + static_cast<int>(BOOST_ASIO_CONCURRENCY_HINT_ID \ + | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \ + | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION) + +// The special concurrency hint provides full thread safety. +#define BOOST_ASIO_CONCURRENCY_HINT_SAFE \ + static_cast<int>(BOOST_ASIO_CONCURRENCY_HINT_ID \ + | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \ + | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION \ + | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO) + +// This #define may be overridden at compile time to specify a program-wide +// default concurrency hint, used by the zero-argument io_context constructor. +#if !defined(BOOST_ASIO_CONCURRENCY_HINT_DEFAULT) +# define BOOST_ASIO_CONCURRENCY_HINT_DEFAULT -1 +#endif // !defined(BOOST_ASIO_CONCURRENCY_HINT_DEFAULT) + +// This #define may be overridden at compile time to specify a program-wide +// concurrency hint, used by the one-argument io_context constructor when +// passed a value of 1. +#if !defined(BOOST_ASIO_CONCURRENCY_HINT_1) +# define BOOST_ASIO_CONCURRENCY_HINT_1 1 +#endif // !defined(BOOST_ASIO_CONCURRENCY_HINT_DEFAULT) + +#endif // BOOST_ASIO_DETAIL_CONCURRENCY_HINT_HPP diff --git a/boost/asio/detail/conditionally_enabled_event.hpp b/boost/asio/detail/conditionally_enabled_event.hpp new file mode 100644 index 0000000000..c2be28587c --- /dev/null +++ b/boost/asio/detail/conditionally_enabled_event.hpp @@ -0,0 +1,114 @@ +// +// detail/conditionally_enabled_event.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP +#define BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/conditionally_enabled_mutex.hpp> +#include <boost/asio/detail/event.hpp> +#include <boost/asio/detail/noncopyable.hpp> +#include <boost/asio/detail/null_event.hpp> +#include <boost/asio/detail/scoped_lock.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +// Mutex adapter used to conditionally enable or disable locking. +class conditionally_enabled_event + : private noncopyable +{ +public: + // Constructor. + conditionally_enabled_event() + { + } + + // Destructor. + ~conditionally_enabled_event() + { + } + + // Signal the event. (Retained for backward compatibility.) + void signal(conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.signal(lock); + } + + // Signal all waiters. + void signal_all(conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.signal_all(lock); + } + + // Unlock the mutex and signal one waiter. + void unlock_and_signal_one( + conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.unlock_and_signal_one(lock); + } + + // If there's a waiter, unlock the mutex and signal it. + bool maybe_unlock_and_signal_one( + conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + return event_.maybe_unlock_and_signal_one(lock); + else + return false; + } + + // Reset the event. + void clear(conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.clear(lock); + } + + // Wait for the event to become signalled. + void wait(conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.wait(lock); + else + null_event().wait(lock); + } + + // Timed wait for the event to become signalled. + bool wait_for_usec( + conditionally_enabled_mutex::scoped_lock& lock, long usec) + { + if (lock.mutex_.enabled_) + return event_.wait_for_usec(lock, usec); + else + return null_event().wait_for_usec(lock, usec); + } + +private: + boost::asio::detail::event event_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP diff --git a/boost/asio/detail/conditionally_enabled_mutex.hpp b/boost/asio/detail/conditionally_enabled_mutex.hpp new file mode 100644 index 0000000000..c7762b6889 --- /dev/null +++ b/boost/asio/detail/conditionally_enabled_mutex.hpp @@ -0,0 +1,151 @@ +// +// detail/conditionally_enabled_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP +#define BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/mutex.hpp> +#include <boost/asio/detail/noncopyable.hpp> +#include <boost/asio/detail/scoped_lock.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +// Mutex adapter used to conditionally enable or disable locking. +class conditionally_enabled_mutex + : private noncopyable +{ +public: + // Helper class to lock and unlock a mutex automatically. + class scoped_lock + : private noncopyable + { + public: + // Tag type used to distinguish constructors. + enum adopt_lock_t { adopt_lock }; + + // Constructor adopts a lock that is already held. + scoped_lock(conditionally_enabled_mutex& m, adopt_lock_t) + : mutex_(m), + locked_(m.enabled_) + { + } + + // Constructor acquires the lock. + explicit scoped_lock(conditionally_enabled_mutex& m) + : mutex_(m) + { + if (m.enabled_) + { + mutex_.mutex_.lock(); + locked_ = true; + } + else + locked_ = false; + } + + // Destructor releases the lock. + ~scoped_lock() + { + if (locked_) + mutex_.mutex_.unlock(); + } + + // Explicitly acquire the lock. + void lock() + { + if (mutex_.enabled_ && !locked_) + { + mutex_.mutex_.lock(); + locked_ = true; + } + } + + // Explicitly release the lock. + void unlock() + { + if (locked_) + { + mutex_.unlock(); + locked_ = false; + } + } + + // Test whether the lock is held. + bool locked() const + { + return locked_; + } + + // Get the underlying mutex. + boost::asio::detail::mutex& mutex() + { + return mutex_.mutex_; + } + + private: + friend class conditionally_enabled_event; + conditionally_enabled_mutex& mutex_; + bool locked_; + }; + + // Constructor. + explicit conditionally_enabled_mutex(bool enabled) + : enabled_(enabled) + { + } + + // Destructor. + ~conditionally_enabled_mutex() + { + } + + // Determine whether locking is enabled. + bool enabled() const + { + return enabled_; + } + + // Lock the mutex. + void lock() + { + if (enabled_) + mutex_.lock(); + } + + // Unlock the mutex. + void unlock() + { + if (enabled_) + mutex_.unlock(); + } + +private: + friend class scoped_lock; + friend class conditionally_enabled_event; + boost::asio::detail::mutex mutex_; + const bool enabled_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP diff --git a/boost/asio/detail/config.hpp b/boost/asio/detail/config.hpp index afe400e5b7..b3272a666f 100644 --- a/boost/asio/detail/config.hpp +++ b/boost/asio/detail/config.hpp @@ -83,6 +83,11 @@ # endif // (__cplusplus >= 201103) #endif // defined(__clang__) +// Android platform detection. +#if defined(__ANDROID__) +# include <android/api-level.h> +#endif // defined(__ANDROID__) + // Support move construction and assignment on compilers known to allow it. #if !defined(BOOST_ASIO_HAS_MOVE) # if !defined(BOOST_ASIO_DISABLE_MOVE) @@ -111,6 +116,7 @@ // references and perfect forwarding. #if defined(BOOST_ASIO_HAS_MOVE) && !defined(BOOST_ASIO_MOVE_CAST) # define BOOST_ASIO_MOVE_ARG(type) type&& +# define BOOST_ASIO_MOVE_ARG2(type1, type2) type1, type2&& # define BOOST_ASIO_MOVE_CAST(type) static_cast<type&&> # define BOOST_ASIO_MOVE_CAST2(type1, type2) static_cast<type1, type2&&> #endif // defined(BOOST_ASIO_HAS_MOVE) && !defined(BOOST_ASIO_MOVE_CAST) @@ -163,6 +169,30 @@ # endif // !defined(BOOST_ASIO_DISABLE_VARIADIC_TEMPLATES) #endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +// Support deleted functions on compilers known to allow it. +#if !defined(BOOST_ASIO_DELETED) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_DELETED = delete +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(__clang__) +# if __has_feature(__cxx_deleted_functions__) +# define BOOST_ASIO_DELETED = delete +# endif // __has_feature(__cxx_deleted_functions__) +# endif // defined(__clang__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_DELETED = delete +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# if !defined(BOOST_ASIO_DELETED) +# define BOOST_ASIO_DELETED +# endif // !defined(BOOST_ASIO_DELETED) +#endif // !defined(BOOST_ASIO_DELETED) + // Support constexpr on compilers known to allow it. #if !defined(BOOST_ASIO_HAS_CONSTEXPR) # if !defined(BOOST_ASIO_DISABLE_CONSTEXPR) @@ -193,6 +223,85 @@ # endif // defined(BOOST_ASIO_HAS_CONSTEXPR) #endif // !defined(BOOST_ASIO_CONSTEXPR) +// Support noexcept on compilers known to allow it. +#if !defined(BOOST_ASIO_NOEXCEPT) +# if !defined(BOOST_ASIO_DISABLE_NOEXCEPT) +# if (BOOST_VERSION >= 105300) +# define BOOST_ASIO_NOEXCEPT BOOST_NOEXCEPT +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW BOOST_NOEXCEPT_OR_NOTHROW +# elif defined(__clang__) +# if __has_feature(__cxx_noexcept__) +# define BOOST_ASIO_NOEXCEPT noexcept(true) +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# endif // __has_feature(__cxx_noexcept__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_NOEXCEPT noexcept(true) +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_NOEXCEPT noexcept(true) +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_NOEXCEPT) +# if !defined(BOOST_ASIO_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT +# endif // !defined(BOOST_ASIO_NOEXCEPT) +# if !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW throw() +# endif // !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) +#endif // !defined(BOOST_ASIO_NOEXCEPT) + +// Support automatic type deduction on compilers known to support it. +#if !defined(BOOST_ASIO_HAS_DECLTYPE) +# if !defined(BOOST_ASIO_DISABLE_DECLTYPE) +# if defined(__clang__) +# if __has_feature(__cxx_decltype__) +# define BOOST_ASIO_HAS_DECLTYPE 1 +# endif // __has_feature(__cxx_decltype__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_DECLTYPE 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_DECLTYPE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_DECLTYPE) +#endif // !defined(BOOST_ASIO_HAS_DECLTYPE) + +// Support alias templates on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_ALIAS_TEMPLATES) +# if defined(__clang__) +# if __has_feature(__cxx_alias_templates__) +# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // __has_feature(__cxx_alias_templates__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_ALIAS_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) + // Standard library support for system errors. # if !defined(BOOST_ASIO_DISABLE_STD_SYSTEM_ERROR) # if defined(__clang__) @@ -294,6 +403,31 @@ # endif // !defined(BOOST_ASIO_DISABLE_STD_SHARED_PTR) #endif // !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) +// Standard library support for allocator_arg_t. +#if !defined(BOOST_ASIO_HAS_STD_ALLOCATOR_ARG) +# if !defined(BOOST_ASIO_DISABLE_STD_ALLOCATOR_ARG) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ALLOCATOR_ARG) +#endif // !defined(BOOST_ASIO_HAS_STD_ALLOCATOR_ARG) + // Standard library support for atomic operations. #if !defined(BOOST_ASIO_HAS_STD_ATOMIC) # if !defined(BOOST_ASIO_DISABLE_STD_ATOMIC) @@ -362,6 +496,15 @@ # endif // !defined(BOOST_ASIO_DISABLE_BOOST_CHRONO) #endif // !defined(BOOST_ASIO_HAS_BOOST_CHRONO) +// Some form of chrono library is available. +#if !defined(BOOST_ASIO_HAS_CHRONO) +# if defined(BOOST_ASIO_HAS_STD_CHRONO) \ + || defined(BOOST_ASIO_HAS_BOOST_CHRONO) +# define BOOST_ASIO_HAS_CHRONO 1 +# endif // defined(BOOST_ASIO_HAS_STD_CHRONO) + // || defined(BOOST_ASIO_HAS_BOOST_CHRONO) +#endif // !defined(BOOST_ASIO_HAS_CHRONO) + // Boost support for the DateTime library. #if !defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) # if !defined(BOOST_ASIO_DISABLE_BOOST_DATE_TIME) @@ -446,6 +589,28 @@ # endif // !defined(BOOST_ASIO_DISABLE_STD_TYPE_TRAITS) #endif // !defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) +// Standard library support for the nullptr_t type. +#if !defined(BOOST_ASIO_HAS_NULLPTR) +# if !defined(BOOST_ASIO_DISABLE_NULLPTR) +# if defined(__clang__) +# if __has_feature(__cxx_nullptr__) +# define BOOST_ASIO_HAS_NULLPTR 1 +# endif // __has_feature(__cxx_rvalue_references__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_NULLPTR 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_NULLPTR 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_NULLPTR) +#endif // !defined(BOOST_ASIO_HAS_NULLPTR) + // Standard library support for the C++11 allocator additions. #if !defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) # if !defined(BOOST_ASIO_DISABLE_CXX11_ALLOCATORS) @@ -456,16 +621,16 @@ # define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 # endif // (__cplusplus >= 201103) # elif defined(__GNUC__) -# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) # if defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 # endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) # endif // defined(__GNUC__) # if defined(BOOST_ASIO_MSVC) -# if (_MSC_VER >= 1700) +# if (_MSC_VER >= 1800) # define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 -# endif // (_MSC_VER >= 1700) +# endif // (_MSC_VER >= 1800) # endif // defined(BOOST_ASIO_MSVC) # endif // !defined(BOOST_ASIO_DISABLE_CXX11_ALLOCATORS) #endif // !defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) @@ -549,6 +714,105 @@ # endif // !defined(BOOST_ASIO_DISABLE_STD_MUTEX_AND_CONDVAR) #endif // !defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) +// Standard library support for the call_once function. +#if !defined(BOOST_ASIO_HAS_STD_CALL_ONCE) +# if !defined(BOOST_ASIO_DISABLE_STD_CALL_ONCE) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# elif (__cplusplus >= 201103) +# if __has_include(<mutex>) +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# endif // __has_include(<mutex>) +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_CALL_ONCE) +#endif // !defined(BOOST_ASIO_HAS_STD_CALL_ONCE) + +// Standard library support for futures. +#if !defined(BOOST_ASIO_HAS_STD_FUTURE) +# if !defined(BOOST_ASIO_DISABLE_STD_FUTURE) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# elif (__cplusplus >= 201103) +# if __has_include(<future>) +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# endif // __has_include(<mutex>) +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_FUTURE) +#endif // !defined(BOOST_ASIO_HAS_STD_FUTURE) + +// Standard library support for experimental::string_view. +#if !defined(BOOST_ASIO_HAS_STD_STRING_VIEW) +# if !defined(BOOST_ASIO_DISABLE_STD_STRING_VIEW) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# if __has_include(<experimental/string_view>) +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __has_include(<experimental/string_view>) +# endif // (__cplusplus >= 201402) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // (__cplusplus >= 201402) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910 && _HAS_CXX17) +# define BOOST_ASIO_HAS_STD_STRING_VIEW +# endif // (_MSC_VER >= 1910) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_STRING_VIEW) +#endif // !defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + +// Standard library support for iostream move construction and assignment. +#if !defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) +# if !defined(BOOST_ASIO_DISABLE_STD_IOSTREAM_MOVE) +# if defined(__GNUC__) +# if (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_IOSTREAM_MOVE) +#endif // !defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) + // Windows App target. Windows but with a limited API. #if !defined(BOOST_ASIO_WINDOWS_APP) # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) @@ -884,11 +1148,18 @@ # if !defined(BOOST_ASIO_DISABLE_THREADS) # if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) # define BOOST_ASIO_HAS_THREADS 1 -# elif defined(_MSC_VER) && defined(_MT) +# elif defined(__GNUC__) && !defined(__MINGW32__) \ + && !defined(linux) && !defined(__linux) && !defined(__linux__) # define BOOST_ASIO_HAS_THREADS 1 -# elif defined(__BORLANDC__) && defined(__MT__) +# elif defined(_MT) || defined(__MT__) # define BOOST_ASIO_HAS_THREADS 1 -# elif defined(_POSIX_THREADS) +# elif defined(_REENTRANT) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(__APPLE__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_PTHREADS) # define BOOST_ASIO_HAS_THREADS 1 # endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) # endif // !defined(BOOST_ASIO_DISABLE_THREADS) @@ -899,7 +1170,7 @@ # if defined(BOOST_ASIO_HAS_THREADS) # if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) # define BOOST_ASIO_HAS_PTHREADS 1 -# elif defined(_POSIX_THREADS) +# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) # define BOOST_ASIO_HAS_PTHREADS 1 # endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) # endif // defined(BOOST_ASIO_HAS_THREADS) @@ -1030,6 +1301,42 @@ // || (defined(__MACH__) && defined(__APPLE__)) #endif // !defined(BOOST_ASIO_DISABLE_SSIZE_T) +// Helper macros to manage the transition away from the old services-based API. +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# define BOOST_ASIO_SVC_TPARAM , typename Service +# define BOOST_ASIO_SVC_TPARAM_DEF1(d1) , typename Service d1 +# define BOOST_ASIO_SVC_TPARAM_DEF2(d1, d2) , typename Service d1, d2 +# define BOOST_ASIO_SVC_TARG , Service +# define BOOST_ASIO_SVC_T Service +# define BOOST_ASIO_SVC_TPARAM1 , typename Service1 +# define BOOST_ASIO_SVC_TPARAM1_DEF1(d1) , typename Service1 d1 +# define BOOST_ASIO_SVC_TPARAM1_DEF2(d1, d2) , typename Service1 d1, d2 +# define BOOST_ASIO_SVC_TARG1 , Service1 +# define BOOST_ASIO_SVC_T1 Service1 +# define BOOST_ASIO_SVC_ACCESS public +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# define BOOST_ASIO_SVC_TPARAM +# define BOOST_ASIO_SVC_TPARAM_DEF1(d1) +# define BOOST_ASIO_SVC_TPARAM_DEF2(d1, d2) +# define BOOST_ASIO_SVC_TARG +// BOOST_ASIO_SVC_T is defined at each point of use. +# define BOOST_ASIO_SVC_TPARAM1 +# define BOOST_ASIO_SVC_TPARAM1_DEF1(d1) +# define BOOST_ASIO_SVC_TPARAM1_DEF2(d1, d2) +# define BOOST_ASIO_SVC_TARG1 +// BOOST_ASIO_SVC_T1 is defined at each point of use. +# define BOOST_ASIO_SVC_ACCESS protected +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + +// Helper macros to manage transition away from error_code return values. +#if defined(BOOST_ASIO_NO_DEPRECATED) +# define BOOST_ASIO_SYNC_OP_VOID void +# define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return +#else // defined(BOOST_ASIO_NO_DEPRECATED) +# define BOOST_ASIO_SYNC_OP_VOID boost::system::error_code +# define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return e +#endif // defined(BOOST_ASIO_NO_DEPRECATED) + // Newer gcc, clang need special treatment to suppress unused typedef warnings. #if defined(__clang__) # if defined(__apple_build_version__) diff --git a/boost/asio/detail/consuming_buffers.hpp b/boost/asio/detail/consuming_buffers.hpp index f0978b54d3..a429f974d6 100644 --- a/boost/asio/detail/consuming_buffers.hpp +++ b/boost/asio/detail/consuming_buffers.hpp @@ -17,8 +17,8 @@ #include <boost/asio/detail/config.hpp> #include <cstddef> -#include <iterator> #include <boost/asio/buffer.hpp> +#include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/push_options.hpp> @@ -27,262 +27,384 @@ namespace boost { namespace asio { namespace detail { -// A proxy iterator for a sub-range in a list of buffers. -template <typename Buffer, typename Buffer_Iterator> -class consuming_buffers_iterator +// Helper template to determine the maximum number of prepared buffers. +template <typename Buffers> +struct prepared_buffers_max { -public: - /// The type used for the distance between two iterators. - typedef std::ptrdiff_t difference_type; + enum { value = buffer_sequence_adapter_base::max_buffers }; +}; + +template <typename Elem, std::size_t N> +struct prepared_buffers_max<boost::array<Elem, N> > +{ + enum { value = N }; +}; + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + +template <typename Elem, std::size_t N> +struct prepared_buffers_max<std::array<Elem, N> > +{ + enum { value = N }; +}; - /// The type of the value pointed to by the iterator. +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + +// A buffer sequence used to represent a subsequence of the buffers. +template <typename Buffer, std::size_t MaxBuffers> +struct prepared_buffers +{ typedef Buffer value_type; + typedef const Buffer* const_iterator; - /// The type of the result of applying operator->() to the iterator. - typedef const Buffer* pointer; + enum { max_buffers = MaxBuffers < 16 ? MaxBuffers : 16 }; - /// The type of the result of applying operator*() to the iterator. - typedef const Buffer& reference; + prepared_buffers() : count(0) {} + const_iterator begin() const { return elems; } + const_iterator end() const { return elems + count; } + + Buffer elems[max_buffers]; + std::size_t count; +}; - /// The iterator category. - typedef std::forward_iterator_tag iterator_category; +// A proxy for a sub-range in a list of buffers. +template <typename Buffer, typename Buffers, typename Buffer_Iterator> +class consuming_buffers +{ +public: + typedef prepared_buffers<Buffer, prepared_buffers_max<Buffers>::value> + prepared_buffers_type; - // Default constructor creates an end iterator. - consuming_buffers_iterator() - : at_end_(true) + // Construct to represent the entire list of buffers. + explicit consuming_buffers(const Buffers& buffers) + : buffers_(buffers), + total_consumed_(0), + next_elem_(0), + next_elem_offset_(0) { + using boost::asio::buffer_size; + total_size_ = buffer_size(buffers); } - // Construct with a buffer for the first entry and an iterator - // range for the remaining entries. - consuming_buffers_iterator(bool at_end, const Buffer& first, - Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder, - std::size_t max_size) - : at_end_(max_size > 0 ? at_end : true), - first_(buffer(first, max_size)), - begin_remainder_(begin_remainder), - end_remainder_(end_remainder), - offset_(0), - max_size_(max_size) + // Determine if we are at the end of the buffers. + bool empty() const { + return total_consumed_ >= total_size_; } - // Dereference an iterator. - const Buffer& operator*() const + // Get the buffer for a single transfer, with a size. + prepared_buffers_type prepare(std::size_t max_size) { - return dereference(); + prepared_buffers_type result; + + Buffer_Iterator next = boost::asio::buffer_sequence_begin(buffers_); + Buffer_Iterator end = boost::asio::buffer_sequence_end(buffers_); + + std::advance(next, next_elem_); + std::size_t elem_offset = next_elem_offset_; + while (next != end && max_size > 0 && result.count < result.max_buffers) + { + Buffer next_buf = Buffer(*next) + elem_offset; + result.elems[result.count] = boost::asio::buffer(next_buf, max_size); + max_size -= result.elems[result.count].size(); + elem_offset = 0; + if (result.elems[result.count].size() > 0) + ++result.count; + ++next; + } + + return result; } - // Dereference an iterator. - const Buffer* operator->() const + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + + Buffer_Iterator next = boost::asio::buffer_sequence_begin(buffers_); + Buffer_Iterator end = boost::asio::buffer_sequence_end(buffers_); + + std::advance(next, next_elem_); + while (next != end && size > 0) + { + Buffer next_buf = Buffer(*next) + next_elem_offset_; + if (size < next_buf.size()) + { + next_elem_offset_ += size; + size = 0; + } + else + { + size -= next_buf.size(); + next_elem_offset_ = 0; + ++next_elem_; + ++next; + } + } + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + Buffers buffers_; + std::size_t total_size_; + std::size_t total_consumed_; + std::size_t next_elem_; + std::size_t next_elem_offset_; +}; + +// Base class of all consuming_buffers specialisations for single buffers. +template <typename Buffer> +class consuming_single_buffer +{ +public: + // Construct to represent the entire list of buffers. + template <typename Buffer1> + explicit consuming_single_buffer(const Buffer1& buffer) + : buffer_(buffer), + total_consumed_(0) { - return &dereference(); } - // Increment operator (prefix). - consuming_buffers_iterator& operator++() + // Determine if we are at the end of the buffers. + bool empty() const { - increment(); - return *this; + return total_consumed_ >= buffer_.size(); } - // Increment operator (postfix). - consuming_buffers_iterator operator++(int) + // Get the buffer for a single transfer, with a size. + Buffer prepare(std::size_t max_size) { - consuming_buffers_iterator tmp(*this); - ++*this; - return tmp; + return boost::asio::buffer(buffer_ + total_consumed_, max_size); } - // Test two iterators for equality. - friend bool operator==(const consuming_buffers_iterator& a, - const consuming_buffers_iterator& b) + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) { - return a.equal(b); + total_consumed_ += size; } - // Test two iterators for inequality. - friend bool operator!=(const consuming_buffers_iterator& a, - const consuming_buffers_iterator& b) + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const { - return !a.equal(b); + return total_consumed_; } private: - void increment() + Buffer buffer_; + std::size_t total_consumed_; +}; + +template <> +class consuming_buffers<mutable_buffer, mutable_buffer, const mutable_buffer*> + : public consuming_single_buffer<BOOST_ASIO_MUTABLE_BUFFER> +{ +public: + explicit consuming_buffers(const mutable_buffer& buffer) + : consuming_single_buffer<BOOST_ASIO_MUTABLE_BUFFER>(buffer) { - if (!at_end_) - { - if (begin_remainder_ == end_remainder_ - || offset_ + buffer_size(first_) >= max_size_) - { - at_end_ = true; - } - else - { - offset_ += buffer_size(first_); - first_ = buffer(*begin_remainder_++, max_size_ - offset_); - } - } } +}; - bool equal(const consuming_buffers_iterator& other) const +template <> +class consuming_buffers<const_buffer, mutable_buffer, const mutable_buffer*> + : public consuming_single_buffer<BOOST_ASIO_CONST_BUFFER> +{ +public: + explicit consuming_buffers(const mutable_buffer& buffer) + : consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>(buffer) { - if (at_end_ && other.at_end_) - return true; - return !at_end_ && !other.at_end_ - && buffer_cast<const void*>(first_) - == buffer_cast<const void*>(other.first_) - && buffer_size(first_) == buffer_size(other.first_) - && begin_remainder_ == other.begin_remainder_ - && end_remainder_ == other.end_remainder_; } +}; - const Buffer& dereference() const +template <> +class consuming_buffers<const_buffer, const_buffer, const const_buffer*> + : public consuming_single_buffer<BOOST_ASIO_CONST_BUFFER> +{ +public: + explicit consuming_buffers(const const_buffer& buffer) + : consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>(buffer) { - return first_; } +}; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) - bool at_end_; - Buffer first_; - Buffer_Iterator begin_remainder_; - Buffer_Iterator end_remainder_; - std::size_t offset_; - std::size_t max_size_; +template <> +class consuming_buffers<mutable_buffer, + mutable_buffers_1, const mutable_buffer*> + : public consuming_single_buffer<BOOST_ASIO_MUTABLE_BUFFER> +{ +public: + explicit consuming_buffers(const mutable_buffers_1& buffer) + : consuming_single_buffer<BOOST_ASIO_MUTABLE_BUFFER>(buffer) + { + } }; -// A proxy for a sub-range in a list of buffers. -template <typename Buffer, typename Buffers> -class consuming_buffers +template <> +class consuming_buffers<const_buffer, mutable_buffers_1, const mutable_buffer*> + : public consuming_single_buffer<BOOST_ASIO_CONST_BUFFER> { public: - // The type for each element in the list of buffers. - typedef Buffer value_type; + explicit consuming_buffers(const mutable_buffers_1& buffer) + : consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>(buffer) + { + } +}; - // A forward-only iterator type that may be used to read elements. - typedef consuming_buffers_iterator<Buffer, typename Buffers::const_iterator> - const_iterator; +template <> +class consuming_buffers<const_buffer, const_buffers_1, const const_buffer*> + : public consuming_single_buffer<BOOST_ASIO_CONST_BUFFER> +{ +public: + explicit consuming_buffers(const const_buffers_1& buffer) + : consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>(buffer) + { + } +}; + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) +template <typename Buffer, typename Elem> +class consuming_buffers<Buffer, boost::array<Elem, 2>, + typename boost::array<Elem, 2>::const_iterator> +{ +public: // Construct to represent the entire list of buffers. - consuming_buffers(const Buffers& buffers) + explicit consuming_buffers(const boost::array<Elem, 2>& buffers) : buffers_(buffers), - at_end_(buffers_.begin() == buffers_.end()), - begin_remainder_(buffers_.begin()), - max_size_((std::numeric_limits<std::size_t>::max)()) + total_consumed_(0) { - if (!at_end_) - { - first_ = *buffers_.begin(); - ++begin_remainder_; - } } - // Copy constructor. - consuming_buffers(const consuming_buffers& other) - : buffers_(other.buffers_), - at_end_(other.at_end_), - first_(other.first_), - begin_remainder_(buffers_.begin()), - max_size_(other.max_size_) + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= + Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size(); + } + + // Get the buffer for a single transfer, with a size. + boost::array<Buffer, 2> prepare(std::size_t max_size) + { + boost::array<Buffer, 2> result = {{ + Buffer(buffers_[0]), Buffer(buffers_[1]) }}; + std::size_t buffer0_size = result[0].size(); + result[0] = boost::asio::buffer(result[0] + total_consumed_, max_size); + result[1] = boost::asio::buffer( + result[1] + (total_consumed_ < buffer0_size + ? 0 : total_consumed_ - buffer0_size), + max_size - result[0].size()); + return result; + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) { - typename Buffers::const_iterator first = other.buffers_.begin(); - typename Buffers::const_iterator second = other.begin_remainder_; - std::advance(begin_remainder_, std::distance(first, second)); + total_consumed_ += size; } - // Assignment operator. - consuming_buffers& operator=(const consuming_buffers& other) + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const { - buffers_ = other.buffers_; - at_end_ = other.at_end_; - first_ = other.first_; - begin_remainder_ = buffers_.begin(); - typename Buffers::const_iterator first = other.buffers_.begin(); - typename Buffers::const_iterator second = other.begin_remainder_; - std::advance(begin_remainder_, std::distance(first, second)); - max_size_ = other.max_size_; - return *this; + return total_consumed_; } - // Get a forward-only iterator to the first element. - const_iterator begin() const +private: + boost::array<Elem, 2> buffers_; + std::size_t total_consumed_; +}; + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + +template <typename Buffer, typename Elem> +class consuming_buffers<Buffer, std::array<Elem, 2>, + typename std::array<Elem, 2>::const_iterator> +{ +public: + // Construct to represent the entire list of buffers. + explicit consuming_buffers(const std::array<Elem, 2>& buffers) + : buffers_(buffers), + total_consumed_(0) { - return const_iterator(at_end_, first_, - begin_remainder_, buffers_.end(), max_size_); } - // Get a forward-only iterator for one past the last element. - const_iterator end() const + // Determine if we are at the end of the buffers. + bool empty() const { - return const_iterator(); + return total_consumed_ >= + Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size(); } - // Set the maximum size for a single transfer. - void prepare(std::size_t max_size) + // Get the buffer for a single transfer, with a size. + std::array<Buffer, 2> prepare(std::size_t max_size) { - max_size_ = max_size; + std::array<Buffer, 2> result = {{ + Buffer(buffers_[0]), Buffer(buffers_[1]) }}; + std::size_t buffer0_size = result[0].size(); + result[0] = boost::asio::buffer(result[0] + total_consumed_, max_size); + result[1] = boost::asio::buffer( + result[1] + (total_consumed_ < buffer0_size + ? 0 : total_consumed_ - buffer0_size), + max_size - result[0].size()); + return result; } // Consume the specified number of bytes from the buffers. void consume(std::size_t size) { - // Remove buffers from the start until the specified size is reached. - while (size > 0 && !at_end_) - { - if (buffer_size(first_) <= size) - { - size -= buffer_size(first_); - if (begin_remainder_ == buffers_.end()) - at_end_ = true; - else - first_ = *begin_remainder_++; - } - else - { - first_ = first_ + size; - size = 0; - } - } + total_consumed_ += size; + } - // Remove any more empty buffers at the start. - while (!at_end_ && buffer_size(first_) == 0) - { - if (begin_remainder_ == buffers_.end()) - at_end_ = true; - else - first_ = *begin_remainder_++; - } + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; } private: - Buffers buffers_; - bool at_end_; - Buffer first_; - typename Buffers::const_iterator begin_remainder_; - std::size_t max_size_; + std::array<Elem, 2> buffers_; + std::size_t total_consumed_; }; +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + // Specialisation for null_buffers to ensure that the null_buffers type is // always passed through to the underlying read or write operation. template <typename Buffer> -class consuming_buffers<Buffer, boost::asio::null_buffers> +class consuming_buffers<Buffer, null_buffers, const mutable_buffer*> : public boost::asio::null_buffers { public: - consuming_buffers(const boost::asio::null_buffers&) + consuming_buffers(const null_buffers&) { // No-op. } - void prepare(std::size_t) + bool empty() { - // No-op. + return false; + } + + null_buffers prepare(std::size_t) + { + return null_buffers(); } void consume(std::size_t) { // No-op. } + + std::size_t total_consume() const + { + return 0; + } }; } // namespace detail diff --git a/boost/asio/detail/cstddef.hpp b/boost/asio/detail/cstddef.hpp new file mode 100644 index 0000000000..a6dacc1de4 --- /dev/null +++ b/boost/asio/detail/cstddef.hpp @@ -0,0 +1,33 @@ +// +// detail/cstddef.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_CSTDDEF_HPP +#define BOOST_ASIO_DETAIL_CSTDDEF_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <cstddef> + +namespace boost { +namespace asio { + +#if defined(BOOST_ASIO_HAS_NULLPTR) +using std::nullptr_t; +#else // defined(BOOST_ASIO_HAS_NULLPTR) +struct nullptr_t {}; +#endif // defined(BOOST_ASIO_HAS_NULLPTR) + +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_CSTDDEF_HPP diff --git a/boost/asio/detail/cstdint.hpp b/boost/asio/detail/cstdint.hpp index a1be0dced0..61627c7ed3 100644 --- a/boost/asio/detail/cstdint.hpp +++ b/boost/asio/detail/cstdint.hpp @@ -28,18 +28,32 @@ namespace asio { #if defined(BOOST_ASIO_HAS_CSTDINT) using std::int16_t; +using std::int_least16_t; using std::uint16_t; +using std::uint_least16_t; using std::int32_t; +using std::int_least32_t; using std::uint32_t; +using std::uint_least32_t; using std::int64_t; +using std::int_least64_t; using std::uint64_t; +using std::uint_least64_t; +using std::uintmax_t; #else // defined(BOOST_ASIO_HAS_CSTDINT) using boost::int16_t; +using boost::int_least16_t; using boost::uint16_t; +using boost::uint_least16_t; using boost::int32_t; +using boost::int_least32_t; using boost::uint32_t; +using boost::uint_least32_t; using boost::int64_t; +using boost::int_least64_t; using boost::uint64_t; +using boost::uint_least64_t; +using boost::uintmax_t; #endif // defined(BOOST_ASIO_HAS_CSTDINT) } // namespace asio diff --git a/boost/asio/detail/deadline_timer_service.hpp b/boost/asio/detail/deadline_timer_service.hpp index bbd5358425..bc17eb288c 100644 --- a/boost/asio/detail/deadline_timer_service.hpp +++ b/boost/asio/detail/deadline_timer_service.hpp @@ -18,14 +18,15 @@ #include <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> -#include <boost/asio/detail/addressof.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/timer_queue.hpp> +#include <boost/asio/detail/timer_queue_ptime.hpp> #include <boost/asio/detail/timer_scheduler.hpp> #include <boost/asio/detail/wait_handler.hpp> #include <boost/asio/detail/wait_op.hpp> @@ -43,6 +44,7 @@ namespace detail { template <typename Time_Traits> class deadline_timer_service + : public service_base<deadline_timer_service<Time_Traits> > { public: // The time type. @@ -62,8 +64,9 @@ public: }; // Constructor. - deadline_timer_service(boost::asio::io_service& io_service) - : scheduler_(boost::asio::use_service<timer_scheduler>(io_service)) + deadline_timer_service(boost::asio::io_context& io_context) + : service_base<deadline_timer_service<Time_Traits> >(io_context), + scheduler_(boost::asio::use_service<timer_scheduler>(io_context)) { scheduler_.init_task(); scheduler_.add_timer_queue(timer_queue_); @@ -76,7 +79,7 @@ public: } // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { } @@ -94,6 +97,38 @@ public: cancel(impl, ec); } + // Move-construct a new serial port implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + scheduler_.move_timer(timer_queue_, impl.timer_data, other_impl.timer_data); + + impl.expiry = other_impl.expiry; + other_impl.expiry = time_type(); + + impl.might_have_pending_waits = other_impl.might_have_pending_waits; + other_impl.might_have_pending_waits = false; + } + + // Move-assign from another serial port implementation. + void move_assign(implementation_type& impl, + deadline_timer_service& other_service, + implementation_type& other_impl) + { + if (this != &other_service) + if (impl.might_have_pending_waits) + scheduler_.cancel_timer(timer_queue_, impl.timer_data); + + other_service.scheduler_.move_timer(other_service.timer_queue_, + impl.timer_data, other_impl.timer_data); + + impl.expiry = other_impl.expiry; + other_impl.expiry = time_type(); + + impl.might_have_pending_waits = other_impl.might_have_pending_waits; + other_impl.might_have_pending_waits = false; + } + // Cancel any asynchronous wait operations associated with the timer. std::size_t cancel(implementation_type& impl, boost::system::error_code& ec) { @@ -103,7 +138,8 @@ public: return 0; } - BOOST_ASIO_HANDLER_OPERATION(("deadline_timer", &impl, "cancel")); + BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(), + "deadline_timer", &impl, 0, "cancel")); std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data); impl.might_have_pending_waits = false; @@ -121,7 +157,8 @@ public: return 0; } - BOOST_ASIO_HANDLER_OPERATION(("deadline_timer", &impl, "cancel_one")); + BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(), + "deadline_timer", &impl, 0, "cancel_one")); std::size_t count = scheduler_.cancel_timer( timer_queue_, impl.timer_data, 1); @@ -132,11 +169,23 @@ public: } // Get the expiry time for the timer as an absolute time. + time_type expiry(const implementation_type& impl) const + { + return impl.expiry; + } + + // Get the expiry time for the timer as an absolute time. time_type expires_at(const implementation_type& impl) const { return impl.expiry; } + // Get the expiry time for the timer relative to now. + duration_type expires_from_now(const implementation_type& impl) const + { + return Time_Traits::subtract(this->expiry(impl), Time_Traits::now()); + } + // Set the expiry time for the timer as an absolute time. std::size_t expires_at(implementation_type& impl, const time_type& expiry_time, boost::system::error_code& ec) @@ -147,10 +196,12 @@ public: return count; } - // Get the expiry time for the timer relative to now. - duration_type expires_from_now(const implementation_type& impl) const + // Set the expiry time for the timer relative to now. + std::size_t expires_after(implementation_type& impl, + const duration_type& expiry_time, boost::system::error_code& ec) { - return Time_Traits::subtract(expires_at(impl), Time_Traits::now()); + return expires_at(impl, + Time_Traits::add(Time_Traits::now(), expiry_time), ec); } // Set the expiry time for the timer relative to now. @@ -181,13 +232,13 @@ public: // Allocate and construct an operation to wrap the handler. typedef wait_handler<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); impl.might_have_pending_waits = true; - BOOST_ASIO_HANDLER_CREATION((p.p, "deadline_timer", &impl, "async_wait")); + BOOST_ASIO_HANDLER_CREATION((scheduler_.context(), + *p.p, "deadline_timer", &impl, 0, "async_wait")); scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p); p.v = p.p = 0; diff --git a/boost/asio/detail/descriptor_ops.hpp b/boost/asio/detail/descriptor_ops.hpp index 62100392da..5c1ce20d9c 100644 --- a/boost/asio/detail/descriptor_ops.hpp +++ b/boost/asio/detail/descriptor_ops.hpp @@ -22,6 +22,7 @@ && !defined(__CYGWIN__) #include <cstddef> +#include <boost/asio/error.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/detail/socket_types.hpp> @@ -101,6 +102,9 @@ BOOST_ASIO_DECL int poll_read(int d, BOOST_ASIO_DECL int poll_write(int d, state_type state, boost::system::error_code& ec); +BOOST_ASIO_DECL int poll_error(int d, + state_type state, boost::system::error_code& ec); + } // namespace descriptor_ops } // namespace detail } // namespace asio diff --git a/boost/asio/detail/descriptor_read_op.hpp b/boost/asio/detail/descriptor_read_op.hpp index ddbdf7d3e5..1ca2d236fe 100644 --- a/boost/asio/detail/descriptor_read_op.hpp +++ b/boost/asio/detail/descriptor_read_op.hpp @@ -19,11 +19,12 @@ #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/descriptor_ops.hpp> #include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/handler_work.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/push_options.hpp> @@ -44,15 +45,21 @@ public: { } - static bool do_perform(reactor_op* base) + static status do_perform(reactor_op* base) { descriptor_read_op_base* o(static_cast<descriptor_read_op_base*>(base)); buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence> bufs(o->buffers_); - return descriptor_ops::non_blocking_read(o->descriptor_, - bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_); + status result = descriptor_ops::non_blocking_read(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) + ? done : not_done; + + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_read", + o->ec_, o->bytes_transferred_)); + + return result; } private: @@ -73,17 +80,19 @@ public: descriptor, buffers, &descriptor_read_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. descriptor_read_op* o(static_cast<descriptor_read_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_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 @@ -101,7 +110,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/descriptor_write_op.hpp b/boost/asio/detail/descriptor_write_op.hpp index f635feb122..0063491742 100644 --- a/boost/asio/detail/descriptor_write_op.hpp +++ b/boost/asio/detail/descriptor_write_op.hpp @@ -19,11 +19,12 @@ #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/descriptor_ops.hpp> #include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/handler_work.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/push_options.hpp> @@ -44,15 +45,21 @@ public: { } - static bool do_perform(reactor_op* base) + static status do_perform(reactor_op* base) { descriptor_write_op_base* o(static_cast<descriptor_write_op_base*>(base)); buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence> bufs(o->buffers_); - return descriptor_ops::non_blocking_write(o->descriptor_, - bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_); + status result = descriptor_ops::non_blocking_write(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) + ? done : not_done; + + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_write", + o->ec_, o->bytes_transferred_)); + + return result; } private: @@ -73,17 +80,19 @@ public: descriptor, buffers, &descriptor_write_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. descriptor_write_op* o(static_cast<descriptor_write_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_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 @@ -101,7 +110,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/dev_poll_reactor.hpp b/boost/asio/detail/dev_poll_reactor.hpp index 17f57d5221..805f44b6ee 100644 --- a/boost/asio/detail/dev_poll_reactor.hpp +++ b/boost/asio/detail/dev_poll_reactor.hpp @@ -33,7 +33,7 @@ #include <boost/asio/detail/timer_queue_base.hpp> #include <boost/asio/detail/timer_queue_set.hpp> #include <boost/asio/detail/wait_op.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/execution_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -42,7 +42,7 @@ namespace asio { namespace detail { class dev_poll_reactor - : public boost::asio::detail::service_base<dev_poll_reactor> + : public execution_context_service_base<dev_poll_reactor> { public: enum op_types { read_op = 0, write_op = 1, @@ -54,17 +54,17 @@ public: }; // Constructor. - BOOST_ASIO_DECL dev_poll_reactor(boost::asio::io_service& io_service); + BOOST_ASIO_DECL dev_poll_reactor(boost::asio::execution_context& ctx); // Destructor. BOOST_ASIO_DECL ~dev_poll_reactor(); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void shutdown(); // Recreate internal descriptors following a fork. - BOOST_ASIO_DECL void fork_service( - boost::asio::io_service::fork_event fork_ev); + BOOST_ASIO_DECL void notify_fork( + boost::asio::execution_context::fork_event fork_ev); // Initialise the task. BOOST_ASIO_DECL void init_task(); @@ -87,7 +87,7 @@ public: // Post a reactor operation for immediate completion. void post_immediate_completion(reactor_op* op, bool is_continuation) { - io_service_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); } // Start a new operation. The reactor operation will be performed when the @@ -139,8 +139,14 @@ public: typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source); + // Run /dev/poll once until interrupted or events are ready to be dispatched. - BOOST_ASIO_DECL void run(bool block, op_queue<operation>& ops); + BOOST_ASIO_DECL void run(long usec, op_queue<operation>& ops); // Interrupt the select loop. BOOST_ASIO_DECL void interrupt(); @@ -159,7 +165,7 @@ private: // Get the timeout value for the /dev/poll DP_POLL operation. The timeout // value is returned as a number of milliseconds. A return value of -1 // indicates that the poll should block indefinitely. - BOOST_ASIO_DECL int get_timeout(); + BOOST_ASIO_DECL int get_timeout(int msec); // Cancel all operations associated with the given descriptor. The do_cancel // function of the handler objects will be invoked. This function does not @@ -170,8 +176,8 @@ private: // Add a pending event entry for the given descriptor. BOOST_ASIO_DECL ::pollfd& add_pending_event_change(int descriptor); - // The io_service implementation used to post completions. - io_service_impl& io_service_; + // The scheduler implementation used to post completions. + scheduler& scheduler_; // Mutex to protect access to internal data. boost::asio::detail::mutex mutex_; diff --git a/boost/asio/detail/epoll_reactor.hpp b/boost/asio/detail/epoll_reactor.hpp index 34ed0370f5..e1acb48da7 100644 --- a/boost/asio/detail/epoll_reactor.hpp +++ b/boost/asio/detail/epoll_reactor.hpp @@ -19,10 +19,9 @@ #if defined(BOOST_ASIO_HAS_EPOLL) -#include <boost/asio/io_service.hpp> #include <boost/asio/detail/atomic_count.hpp> +#include <boost/asio/detail/conditionally_enabled_mutex.hpp> #include <boost/asio/detail/limits.hpp> -#include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/object_pool.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/reactor_op.hpp> @@ -31,6 +30,7 @@ #include <boost/asio/detail/timer_queue_base.hpp> #include <boost/asio/detail/timer_queue_set.hpp> #include <boost/asio/detail/wait_op.hpp> +#include <boost/asio/execution_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -39,8 +39,12 @@ namespace asio { namespace detail { class epoll_reactor - : public boost::asio::detail::service_base<epoll_reactor> + : public execution_context_service_base<epoll_reactor> { +private: + // The mutex type used by this reactor. + typedef conditionally_enabled_mutex mutex; + public: enum op_types { read_op = 0, write_op = 1, connect_op = 1, except_op = 2, max_ops = 3 }; @@ -59,14 +63,15 @@ public: int descriptor_; uint32_t registered_events_; op_queue<reactor_op> op_queue_[max_ops]; + bool try_speculative_[max_ops]; bool shutdown_; - BOOST_ASIO_DECL descriptor_state(); + BOOST_ASIO_DECL descriptor_state(bool locking); void set_ready_events(uint32_t events) { task_result_ = events; } void add_ready_events(uint32_t events) { task_result_ |= events; } BOOST_ASIO_DECL operation* perform_io(uint32_t events); BOOST_ASIO_DECL static void do_complete( - io_service_impl* owner, operation* base, + void* owner, operation* base, const boost::system::error_code& ec, std::size_t bytes_transferred); }; @@ -74,17 +79,17 @@ public: typedef descriptor_state* per_descriptor_data; // Constructor. - BOOST_ASIO_DECL epoll_reactor(boost::asio::io_service& io_service); + BOOST_ASIO_DECL epoll_reactor(boost::asio::execution_context& ctx); // Destructor. BOOST_ASIO_DECL ~epoll_reactor(); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void shutdown(); // Recreate internal descriptors following a fork. - BOOST_ASIO_DECL void fork_service( - boost::asio::io_service::fork_event fork_ev); + BOOST_ASIO_DECL void notify_fork( + boost::asio::execution_context::fork_event fork_ev); // Initialise the task. BOOST_ASIO_DECL void init_task(); @@ -108,7 +113,7 @@ public: // Post a reactor operation for immediate completion. void post_immediate_completion(reactor_op* op, bool is_continuation) { - io_service_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); } // Start a new operation. The reactor operation will be performed when the @@ -162,8 +167,14 @@ public: typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source); + // Run epoll once until interrupted or events are ready to be dispatched. - BOOST_ASIO_DECL void run(bool block, op_queue<operation>& ops); + BOOST_ASIO_DECL void run(long usec, op_queue<operation>& ops); // Interrupt the select loop. BOOST_ASIO_DECL void interrupt(); @@ -197,7 +208,7 @@ private: // Get the timeout value for the epoll_wait call. The timeout value is // returned as a number of milliseconds. A return value of -1 indicates // that epoll_wait should block indefinitely. - BOOST_ASIO_DECL int get_timeout(); + BOOST_ASIO_DECL int get_timeout(int msec); #if defined(BOOST_ASIO_HAS_TIMERFD) // Get the timeout value for the timer descriptor. The return value is the @@ -205,8 +216,8 @@ private: BOOST_ASIO_DECL int get_timeout(itimerspec& ts); #endif // defined(BOOST_ASIO_HAS_TIMERFD) - // The io_service implementation used to post completions. - io_service_impl& io_service_; + // The scheduler implementation used to post completions. + scheduler& scheduler_; // Mutex to protect access to internal data. mutex mutex_; diff --git a/boost/asio/detail/executor_op.hpp b/boost/asio/detail/executor_op.hpp new file mode 100644 index 0000000000..f3364f5155 --- /dev/null +++ b/boost/asio/detail/executor_op.hpp @@ -0,0 +1,86 @@ +// +// detail/executor_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_EXECUTOR_OP_HPP +#define BOOST_ASIO_DETAIL_EXECUTOR_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/handler_alloc_helpers.hpp> +#include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/scheduler_operation.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +template <typename Handler, typename Alloc, + typename Operation = scheduler_operation> +class executor_op : public Operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(executor_op); + + template <typename H> + executor_op(BOOST_ASIO_MOVE_ARG(H) h, const Alloc& allocator) + : Operation(&executor_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(H)(h)), + allocator_(allocator) + { + } + + static void do_complete(void* owner, Operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + executor_op* o(static_cast<executor_op*>(base)); + Alloc allocator(o->allocator_); + ptr p = { detail::addressof(allocator), o, o }; + + BOOST_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. + Handler handler(BOOST_ASIO_MOVE_CAST(Handler)(o->handler_)); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN(()); + boost_asio_handler_invoke_helpers::invoke(handler, handler); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + Alloc allocator_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_EXECUTOR_OP_HPP diff --git a/boost/asio/detail/function.hpp b/boost/asio/detail/functional.hpp index db26144c5f..a7d6064e4a 100644 --- a/boost/asio/detail/function.hpp +++ b/boost/asio/detail/functional.hpp @@ -1,6 +1,6 @@ // -// detail/function.hpp -// ~~~~~~~~~~~~~~~~~~~ +// detail/functional.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,8 +8,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_DETAIL_FUNCTION_HPP -#define BOOST_ASIO_DETAIL_FUNCTION_HPP +#ifndef BOOST_ASIO_DETAIL_FUNCTIONAL_HPP +#define BOOST_ASIO_DETAIL_FUNCTIONAL_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once @@ -17,11 +17,11 @@ #include <boost/asio/detail/config.hpp> -#if defined(BOOST_ASIO_HAS_STD_FUNCTION) -# include <functional> -#else // defined(BOOST_ASIO_HAS_STD_FUNCTION) +#include <functional> + +#if !defined(BOOST_ASIO_HAS_STD_FUNCTION) # include <boost/function.hpp> -#endif // defined(BOOST_ASIO_HAS_STD_FUNCTION) +#endif // !defined(BOOST_ASIO_HAS_STD_FUNCTION) namespace boost { namespace asio { @@ -37,4 +37,4 @@ using boost::function; } // namespace asio } // namespace boost -#endif // BOOST_ASIO_DETAIL_FUNCTION_HPP +#endif // BOOST_ASIO_DETAIL_FUNCTIONAL_HPP diff --git a/boost/asio/detail/gcc_arm_fenced_block.hpp b/boost/asio/detail/gcc_arm_fenced_block.hpp index b4805c35cd..51a8ca7c55 100644 --- a/boost/asio/detail/gcc_arm_fenced_block.hpp +++ b/boost/asio/detail/gcc_arm_fenced_block.hpp @@ -19,6 +19,8 @@ #if defined(__GNUC__) && defined(__arm__) +#include <boost/asio/detail/noncopyable.hpp> + #include <boost/asio/detail/push_options.hpp> namespace boost { diff --git a/boost/asio/detail/gcc_hppa_fenced_block.hpp b/boost/asio/detail/gcc_hppa_fenced_block.hpp index b9aa9e2ca4..95f47ac8eb 100644 --- a/boost/asio/detail/gcc_hppa_fenced_block.hpp +++ b/boost/asio/detail/gcc_hppa_fenced_block.hpp @@ -19,6 +19,8 @@ #if defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) +#include <boost/asio/detail/noncopyable.hpp> + #include <boost/asio/detail/push_options.hpp> namespace boost { diff --git a/boost/asio/detail/gcc_sync_fenced_block.hpp b/boost/asio/detail/gcc_sync_fenced_block.hpp index e8e6c54643..b9026b1206 100644 --- a/boost/asio/detail/gcc_sync_fenced_block.hpp +++ b/boost/asio/detail/gcc_sync_fenced_block.hpp @@ -22,6 +22,8 @@ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) +#include <boost/asio/detail/noncopyable.hpp> + #include <boost/asio/detail/push_options.hpp> namespace boost { diff --git a/boost/asio/detail/gcc_x86_fenced_block.hpp b/boost/asio/detail/gcc_x86_fenced_block.hpp index fe0ce8a316..be355a115a 100644 --- a/boost/asio/detail/gcc_x86_fenced_block.hpp +++ b/boost/asio/detail/gcc_x86_fenced_block.hpp @@ -19,6 +19,8 @@ #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#include <boost/asio/detail/noncopyable.hpp> + #include <boost/asio/detail/push_options.hpp> namespace boost { diff --git a/boost/asio/detail/global.hpp b/boost/asio/detail/global.hpp new file mode 100644 index 0000000000..581478909f --- /dev/null +++ b/boost/asio/detail/global.hpp @@ -0,0 +1,54 @@ +// +// detail/global.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_GLOBAL_HPP +#define BOOST_ASIO_DETAIL_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> + +#if !defined(BOOST_ASIO_HAS_THREADS) +# include <boost/asio/detail/null_global.hpp> +#elif defined(BOOST_ASIO_WINDOWS) +# include <boost/asio/detail/win_global.hpp> +#elif defined(BOOST_ASIO_HAS_PTHREADS) +# include <boost/asio/detail/posix_global.hpp> +#elif defined(BOOST_ASIO_HAS_STD_CALL_ONCE) +# include <boost/asio/detail/std_global.hpp> +#else +# error Only Windows, POSIX and std::call_once are supported! +#endif + +namespace boost { +namespace asio { +namespace detail { + +template <typename T> +inline T& global() +{ +#if !defined(BOOST_ASIO_HAS_THREADS) + return null_global<T>(); +#elif defined(BOOST_ASIO_WINDOWS) + return win_global<T>(); +#elif defined(BOOST_ASIO_HAS_PTHREADS) + return posix_global<T>(); +#elif defined(BOOST_ASIO_HAS_STD_CALL_ONCE) + return std_global<T>(); +#endif +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_GLOBAL_HPP diff --git a/boost/asio/detail/handler_alloc_helpers.hpp b/boost/asio/detail/handler_alloc_helpers.hpp index a03cb41976..ee2e80c81d 100644 --- a/boost/asio/detail/handler_alloc_helpers.hpp +++ b/boost/asio/detail/handler_alloc_helpers.hpp @@ -16,8 +16,10 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/detail/addressof.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/noncopyable.hpp> +#include <boost/asio/detail/recycling_allocator.hpp> +#include <boost/asio/associated_allocator.hpp> #include <boost/asio/handler_alloc_hook.hpp> #include <boost/asio/detail/push_options.hpp> @@ -51,16 +53,165 @@ inline void deallocate(void* p, std::size_t s, Handler& h) } // namespace boost_asio_handler_alloc_helpers +namespace boost { +namespace asio { +namespace detail { + +template <typename Handler, typename T> +class hook_allocator +{ +public: + typedef T value_type; + + template <typename U> + struct rebind + { + typedef hook_allocator<Handler, U> other; + }; + + explicit hook_allocator(Handler& h) + : handler_(h) + { + } + + template <typename U> + hook_allocator(const hook_allocator<Handler, U>& a) + : handler_(a.handler_) + { + } + + T* allocate(std::size_t n) + { + return static_cast<T*>( + boost_asio_handler_alloc_helpers::allocate(sizeof(T) * n, handler_)); + } + + void deallocate(T* p, std::size_t n) + { + boost_asio_handler_alloc_helpers::deallocate(p, sizeof(T) * n, handler_); + } + +//private: + Handler& handler_; +}; + +template <typename Handler> +class hook_allocator<Handler, void> +{ +public: + typedef void value_type; + + template <typename U> + struct rebind + { + typedef hook_allocator<Handler, U> other; + }; + + explicit hook_allocator(Handler& h) + : handler_(h) + { + } + + template <typename U> + hook_allocator(const hook_allocator<Handler, U>& a) + : handler_(a.handler_) + { + } + +//private: + Handler& handler_; +}; + +template <typename Handler, typename Allocator> +struct get_hook_allocator +{ + typedef Allocator type; + + static type get(Handler&, const Allocator& a) + { + return a; + } +}; + +template <typename Handler, typename T> +struct get_hook_allocator<Handler, std::allocator<T> > +{ + typedef hook_allocator<Handler, T> type; + + static type get(Handler& handler, const std::allocator<T>&) + { + return type(handler); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + #define BOOST_ASIO_DEFINE_HANDLER_PTR(op) \ struct ptr \ { \ Handler* h; \ + op* v; \ + op* p; \ + ~ptr() \ + { \ + reset(); \ + } \ + static op* allocate(Handler& handler) \ + { \ + typedef typename ::boost::asio::associated_allocator< \ + Handler>::type associated_allocator_type; \ + typedef typename ::boost::asio::detail::get_hook_allocator< \ + Handler, associated_allocator_type>::type hook_allocator_type; \ + BOOST_ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \ + ::boost::asio::detail::get_hook_allocator< \ + Handler, associated_allocator_type>::get( \ + handler, ::boost::asio::get_associated_allocator(handler))); \ + return a.allocate(1); \ + } \ + void reset() \ + { \ + if (p) \ + { \ + p->~op(); \ + p = 0; \ + } \ + if (v) \ + { \ + typedef typename ::boost::asio::associated_allocator< \ + Handler>::type associated_allocator_type; \ + typedef typename ::boost::asio::detail::get_hook_allocator< \ + Handler, associated_allocator_type>::type hook_allocator_type; \ + BOOST_ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \ + ::boost::asio::detail::get_hook_allocator< \ + Handler, associated_allocator_type>::get( \ + *h, ::boost::asio::get_associated_allocator(*h))); \ + a.deallocate(static_cast<op*>(v), 1); \ + v = 0; \ + } \ + } \ + } \ + /**/ + +#define BOOST_ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(op) \ + struct ptr \ + { \ + const Alloc* a; \ void* v; \ op* p; \ ~ptr() \ { \ reset(); \ } \ + static op* allocate(const Alloc& a) \ + { \ + typedef typename ::boost::asio::detail::get_recycling_allocator< \ + Alloc>::type recycling_allocator_type; \ + BOOST_ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \ + ::boost::asio::detail::get_recycling_allocator<Alloc>::get(a)); \ + return a1.allocate(1); \ + } \ void reset() \ { \ if (p) \ @@ -70,7 +221,11 @@ inline void deallocate(void* p, std::size_t s, Handler& h) } \ if (v) \ { \ - boost_asio_handler_alloc_helpers::deallocate(v, sizeof(op), *h); \ + typedef typename ::boost::asio::detail::get_recycling_allocator< \ + Alloc>::type recycling_allocator_type; \ + BOOST_ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \ + ::boost::asio::detail::get_recycling_allocator<Alloc>::get(*a)); \ + a1.deallocate(static_cast<op*>(v), 1); \ v = 0; \ } \ } \ diff --git a/boost/asio/detail/handler_cont_helpers.hpp b/boost/asio/detail/handler_cont_helpers.hpp index 9a361a9ca4..a47ecf2d4a 100644 --- a/boost/asio/detail/handler_cont_helpers.hpp +++ b/boost/asio/detail/handler_cont_helpers.hpp @@ -16,7 +16,7 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/detail/addressof.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/handler_continuation_hook.hpp> #include <boost/asio/detail/push_options.hpp> diff --git a/boost/asio/detail/handler_invoke_helpers.hpp b/boost/asio/detail/handler_invoke_helpers.hpp index 43f74f3272..290ecb194f 100644 --- a/boost/asio/detail/handler_invoke_helpers.hpp +++ b/boost/asio/detail/handler_invoke_helpers.hpp @@ -16,7 +16,7 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/detail/addressof.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/handler_invoke_hook.hpp> #include <boost/asio/detail/push_options.hpp> diff --git a/boost/asio/detail/handler_tracking.hpp b/boost/asio/detail/handler_tracking.hpp index fd69bdd5b6..92e8a469f1 100644 --- a/boost/asio/detail/handler_tracking.hpp +++ b/boost/asio/detail/handler_tracking.hpp @@ -17,7 +17,17 @@ #include <boost/asio/detail/config.hpp> -#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) +namespace boost { +namespace asio { + +class execution_context; + +} // namespace asio +} // namespace boost + +#if defined(BOOST_ASIO_CUSTOM_HANDLER_TRACKING) +# include BOOST_ASIO_CUSTOM_HANDLER_TRACKING +#elif defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) # include <boost/system/error_code.hpp> # include <boost/asio/detail/cstdint.hpp> # include <boost/asio/detail/static_mutex.hpp> @@ -30,7 +40,30 @@ namespace boost { namespace asio { namespace detail { -#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) +#if defined(BOOST_ASIO_CUSTOM_HANDLER_TRACKING) + +// The user-specified header must define the following macros: +// - BOOST_ASIO_INHERIT_TRACKED_HANDLER +// - BOOST_ASIO_ALSO_INHERIT_TRACKED_HANDLER +// - BOOST_ASIO_HANDLER_TRACKING_INIT +// - BOOST_ASIO_HANDLER_CREATION(args) +// - BOOST_ASIO_HANDLER_COMPLETION(args) +// - BOOST_ASIO_HANDLER_INVOCATION_BEGIN(args) +// - BOOST_ASIO_HANDLER_INVOCATION_END +// - BOOST_ASIO_HANDLER_OPERATION(args) +// - BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(args) +// - BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(args) +// - BOOST_ASIO_HANDLER_REACTOR_READ_EVENT +// - BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT +// - BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT +// - BOOST_ASIO_HANDLER_REACTOR_EVENTS(args) +// - BOOST_ASIO_HANDLER_REACTOR_OPERATION(args) + +# if !defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) +# define BOOST_ASIO_ENABLE_HANDLER_TRACKING 1 +# endif /// !defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + +#elif defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) class handler_tracking { @@ -58,14 +91,16 @@ public: BOOST_ASIO_DECL static void init(); // Record the creation of a tracked handler. - BOOST_ASIO_DECL static void creation(tracked_handler* h, - const char* object_type, void* object, const char* op_name); + BOOST_ASIO_DECL static void creation( + execution_context& context, tracked_handler& h, + const char* object_type, void* object, + uintmax_t native_handle, const char* op_name); class completion { public: // Constructor records that handler is to be invoked with no arguments. - BOOST_ASIO_DECL explicit completion(tracked_handler* h); + BOOST_ASIO_DECL explicit completion(const tracked_handler& h); // Destructor records only when an exception is thrown from the handler, or // if the memory is being freed without the handler having been invoked. @@ -99,9 +134,32 @@ public: completion* next_; }; - // Record an operation that affects pending handlers. - BOOST_ASIO_DECL static void operation(const char* object_type, - void* object, const char* op_name); + // Record an operation that is not directly associated with a handler. + BOOST_ASIO_DECL static void operation(execution_context& context, + const char* object_type, void* object, + uintmax_t native_handle, const char* op_name); + + // Record that a descriptor has been registered with the reactor. + BOOST_ASIO_DECL static void reactor_registration(execution_context& context, + uintmax_t native_handle, uintmax_t registration); + + // Record that a descriptor has been deregistered from the reactor. + BOOST_ASIO_DECL static void reactor_deregistration(execution_context& context, + uintmax_t native_handle, uintmax_t registration); + + // Record a reactor-based operation that is associated with a handler. + BOOST_ASIO_DECL static void reactor_events(execution_context& context, + uintmax_t registration, unsigned events); + + // Record a reactor-based operation that is associated with a handler. + BOOST_ASIO_DECL static void reactor_operation( + const tracked_handler& h, const char* op_name, + const boost::system::error_code& ec); + + // Record a reactor-based operation that is associated with a handler. + BOOST_ASIO_DECL static void reactor_operation( + const tracked_handler& h, const char* op_name, + const boost::system::error_code& ec, std::size_t bytes_transferred); // Write a line of output. BOOST_ASIO_DECL static void write_line(const char* format, ...); @@ -135,6 +193,22 @@ private: # define BOOST_ASIO_HANDLER_OPERATION(args) \ boost::asio::detail::handler_tracking::operation args +# define BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(args) \ + boost::asio::detail::handler_tracking::reactor_registration args + +# define BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(args) \ + boost::asio::detail::handler_tracking::reactor_deregistration args + +# define BOOST_ASIO_HANDLER_REACTOR_READ_EVENT 1 +# define BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT 2 +# define BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT 4 + +# define BOOST_ASIO_HANDLER_REACTOR_EVENTS(args) \ + boost::asio::detail::handler_tracking::reactor_events args + +# define BOOST_ASIO_HANDLER_REACTOR_OPERATION(args) \ + boost::asio::detail::handler_tracking::reactor_operation args + #else // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) # define BOOST_ASIO_INHERIT_TRACKED_HANDLER @@ -145,6 +219,13 @@ private: # define BOOST_ASIO_HANDLER_INVOCATION_BEGIN(args) (void)0 # define BOOST_ASIO_HANDLER_INVOCATION_END (void)0 # define BOOST_ASIO_HANDLER_OPERATION(args) (void)0 +# define BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(args) (void)0 +# define BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(args) (void)0 +# define BOOST_ASIO_HANDLER_REACTOR_READ_EVENT 0 +# define BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT 0 +# define BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT 0 +# define BOOST_ASIO_HANDLER_REACTOR_EVENTS(args) (void)0 +# define BOOST_ASIO_HANDLER_REACTOR_OPERATION(args) (void)0 #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) diff --git a/boost/asio/detail/handler_type_requirements.hpp b/boost/asio/detail/handler_type_requirements.hpp index bc2fbce0ce..65b5e62dac 100644 --- a/boost/asio/detail/handler_type_requirements.hpp +++ b/boost/asio/detail/handler_type_requirements.hpp @@ -50,7 +50,7 @@ #endif // !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS) #if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) -# include <boost/asio/handler_type.hpp> +# include <boost/asio/async_result.hpp> #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) namespace boost { @@ -62,19 +62,19 @@ namespace detail { # if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT) template <typename Handler> -auto zero_arg_handler_test(Handler h, void*) +auto zero_arg_copyable_handler_test(Handler h, void*) -> decltype( sizeof(Handler(static_cast<const Handler&>(h))), ((h)()), char(0)); template <typename Handler> -char (&zero_arg_handler_test(Handler, ...))[2]; +char (&zero_arg_copyable_handler_test(Handler, ...))[2]; template <typename Handler, typename Arg1> auto one_arg_handler_test(Handler h, Arg1* a1) -> decltype( - sizeof(Handler(static_cast<const Handler&>(h))), + sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))), ((h)(*a1)), char(0)); @@ -84,13 +84,23 @@ char (&one_arg_handler_test(Handler h, ...))[2]; template <typename Handler, typename Arg1, typename Arg2> auto two_arg_handler_test(Handler h, Arg1* a1, Arg2* a2) -> decltype( - sizeof(Handler(static_cast<const Handler&>(h))), + sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))), ((h)(*a1, *a2)), char(0)); 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(BOOST_ASIO_MOVE_CAST(Handler)(h))), + ((h)(*a1, BOOST_ASIO_MOVE_CAST(Arg2)(*a2))), + char(0)); + +template <typename Handler> +char (&two_arg_move_handler_test(Handler, ...))[2]; + # define BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg) \ static_assert(expr, msg); @@ -104,6 +114,13 @@ template <typename T> T& lvref(); template <typename T> T& lvref(T); template <typename T> const T& clvref(); template <typename T> const T& clvref(T); +#if defined(BOOST_ASIO_HAS_MOVE) +template <typename T> T rvref(); +template <typename T> T rvref(T); +#else // defined(BOOST_ASIO_HAS_MOVE) +template <typename T> const T& rvref(); +template <typename T> const T& rvref(T); +#endif // defined(BOOST_ASIO_HAS_MOVE) template <typename T> char argbyv(T); template <int> @@ -118,7 +135,7 @@ struct handler_type_requirements void()) asio_true_handler_type; \ \ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ - sizeof(boost::asio::detail::zero_arg_handler_test( \ + sizeof(boost::asio::detail::zero_arg_copyable_handler_test( \ boost::asio::detail::clvref< \ asio_true_handler_type>(), 0)) == 1, \ "CompletionHandler type requirements not met") \ @@ -142,7 +159,7 @@ struct handler_type_requirements \ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ sizeof(boost::asio::detail::two_arg_handler_test( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>(), \ static_cast<const boost::system::error_code*>(0), \ static_cast<const std::size_t*>(0))) == 1, \ @@ -151,7 +168,7 @@ struct handler_type_requirements typedef boost::asio::detail::handler_type_requirements< \ sizeof( \ boost::asio::detail::argbyv( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ boost::asio::detail::lvref< \ @@ -160,7 +177,6 @@ struct handler_type_requirements boost::asio::detail::lvref<const std::size_t>()), \ char(0))> BOOST_ASIO_UNUSED_TYPEDEF - #define BOOST_ASIO_WRITE_HANDLER_CHECK( \ handler_type, handler) \ \ @@ -170,7 +186,7 @@ struct handler_type_requirements \ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ sizeof(boost::asio::detail::two_arg_handler_test( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>(), \ static_cast<const boost::system::error_code*>(0), \ static_cast<const std::size_t*>(0))) == 1, \ @@ -179,7 +195,7 @@ struct handler_type_requirements typedef boost::asio::detail::handler_type_requirements< \ sizeof( \ boost::asio::detail::argbyv( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ boost::asio::detail::lvref< \ @@ -197,7 +213,7 @@ struct handler_type_requirements \ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ sizeof(boost::asio::detail::one_arg_handler_test( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>(), \ static_cast<const boost::system::error_code*>(0))) == 1, \ "AcceptHandler type requirements not met") \ @@ -205,7 +221,7 @@ struct handler_type_requirements typedef boost::asio::detail::handler_type_requirements< \ sizeof( \ boost::asio::detail::argbyv( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ boost::asio::detail::lvref< \ @@ -213,6 +229,33 @@ struct handler_type_requirements boost::asio::detail::lvref<const boost::system::error_code>()), \ char(0))> BOOST_ASIO_UNUSED_TYPEDEF +#define BOOST_ASIO_MOVE_ACCEPT_HANDLER_CHECK( \ + handler_type, handler, socket_type) \ + \ + typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ + void(boost::system::error_code, socket_type)) \ + asio_true_handler_type; \ + \ + BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(boost::asio::detail::two_arg_move_handler_test( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast<const boost::system::error_code*>(0), \ + static_cast<socket_type*>(0))) == 1, \ + "MoveAcceptHandler type requirements not met") \ + \ + typedef boost::asio::detail::handler_type_requirements< \ + sizeof( \ + boost::asio::detail::argbyv( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + boost::asio::detail::lvref< \ + asio_true_handler_type>()( \ + boost::asio::detail::lvref<const boost::system::error_code>(), \ + boost::asio::detail::rvref<socket_type>()), \ + char(0))> BOOST_ASIO_UNUSED_TYPEDEF + #define BOOST_ASIO_CONNECT_HANDLER_CHECK( \ handler_type, handler) \ \ @@ -222,7 +265,7 @@ struct handler_type_requirements \ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ sizeof(boost::asio::detail::one_arg_handler_test( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>(), \ static_cast<const boost::system::error_code*>(0))) == 1, \ "ConnectHandler type requirements not met") \ @@ -230,7 +273,7 @@ struct handler_type_requirements typedef boost::asio::detail::handler_type_requirements< \ sizeof( \ boost::asio::detail::argbyv( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ boost::asio::detail::lvref< \ @@ -238,7 +281,34 @@ struct handler_type_requirements boost::asio::detail::lvref<const boost::system::error_code>()), \ char(0))> BOOST_ASIO_UNUSED_TYPEDEF -#define BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK( \ +#define BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK( \ + handler_type, handler, endpoint_type) \ + \ + typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ + void(boost::system::error_code, endpoint_type)) \ + asio_true_handler_type; \ + \ + BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(boost::asio::detail::two_arg_handler_test( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast<const boost::system::error_code*>(0), \ + static_cast<const endpoint_type*>(0))) == 1, \ + "RangeConnectHandler type requirements not met") \ + \ + typedef boost::asio::detail::handler_type_requirements< \ + sizeof( \ + boost::asio::detail::argbyv( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + boost::asio::detail::lvref< \ + asio_true_handler_type>()( \ + boost::asio::detail::lvref<const boost::system::error_code>(), \ + boost::asio::detail::lvref<const endpoint_type>()), \ + char(0))> BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \ handler_type, handler, iter_type) \ \ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ @@ -247,16 +317,16 @@ struct handler_type_requirements \ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ sizeof(boost::asio::detail::two_arg_handler_test( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>(), \ static_cast<const boost::system::error_code*>(0), \ static_cast<const iter_type*>(0))) == 1, \ - "ComposedConnectHandler type requirements not met") \ + "IteratorConnectHandler type requirements not met") \ \ typedef boost::asio::detail::handler_type_requirements< \ sizeof( \ boost::asio::detail::argbyv( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ boost::asio::detail::lvref< \ @@ -266,30 +336,30 @@ struct handler_type_requirements char(0))> BOOST_ASIO_UNUSED_TYPEDEF #define BOOST_ASIO_RESOLVE_HANDLER_CHECK( \ - handler_type, handler, iter_type) \ + handler_type, handler, range_type) \ \ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ - void(boost::system::error_code, iter_type)) \ + void(boost::system::error_code, range_type)) \ asio_true_handler_type; \ \ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ sizeof(boost::asio::detail::two_arg_handler_test( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>(), \ static_cast<const boost::system::error_code*>(0), \ - static_cast<const iter_type*>(0))) == 1, \ + static_cast<const range_type*>(0))) == 1, \ "ResolveHandler type requirements not met") \ \ typedef boost::asio::detail::handler_type_requirements< \ sizeof( \ boost::asio::detail::argbyv( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ boost::asio::detail::lvref< \ asio_true_handler_type>()( \ boost::asio::detail::lvref<const boost::system::error_code>(), \ - boost::asio::detail::lvref<const iter_type>()), \ + boost::asio::detail::lvref<const range_type>()), \ char(0))> BOOST_ASIO_UNUSED_TYPEDEF #define BOOST_ASIO_WAIT_HANDLER_CHECK( \ @@ -301,7 +371,7 @@ struct handler_type_requirements \ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ sizeof(boost::asio::detail::one_arg_handler_test( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>(), \ static_cast<const boost::system::error_code*>(0))) == 1, \ "WaitHandler type requirements not met") \ @@ -309,7 +379,7 @@ struct handler_type_requirements typedef boost::asio::detail::handler_type_requirements< \ sizeof( \ boost::asio::detail::argbyv( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ boost::asio::detail::lvref< \ @@ -326,7 +396,7 @@ struct handler_type_requirements \ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ sizeof(boost::asio::detail::two_arg_handler_test( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>(), \ static_cast<const boost::system::error_code*>(0), \ static_cast<const int*>(0))) == 1, \ @@ -335,7 +405,7 @@ struct handler_type_requirements typedef boost::asio::detail::handler_type_requirements< \ sizeof( \ boost::asio::detail::argbyv( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ boost::asio::detail::lvref< \ @@ -353,7 +423,7 @@ struct handler_type_requirements \ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ sizeof(boost::asio::detail::one_arg_handler_test( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>(), \ static_cast<const boost::system::error_code*>(0))) == 1, \ "HandshakeHandler type requirements not met") \ @@ -361,7 +431,7 @@ struct handler_type_requirements typedef boost::asio::detail::handler_type_requirements< \ sizeof( \ boost::asio::detail::argbyv( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ boost::asio::detail::lvref< \ @@ -378,7 +448,7 @@ struct handler_type_requirements \ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ sizeof(boost::asio::detail::two_arg_handler_test( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>(), \ static_cast<const boost::system::error_code*>(0), \ static_cast<const std::size_t*>(0))) == 1, \ @@ -387,7 +457,7 @@ struct handler_type_requirements typedef boost::asio::detail::handler_type_requirements< \ sizeof( \ boost::asio::detail::argbyv( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ boost::asio::detail::lvref< \ @@ -405,7 +475,7 @@ struct handler_type_requirements \ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ sizeof(boost::asio::detail::one_arg_handler_test( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>(), \ static_cast<const boost::system::error_code*>(0))) == 1, \ "ShutdownHandler type requirements not met") \ @@ -413,7 +483,7 @@ struct handler_type_requirements typedef boost::asio::detail::handler_type_requirements< \ sizeof( \ boost::asio::detail::argbyv( \ - boost::asio::detail::clvref< \ + boost::asio::detail::rvref< \ asio_true_handler_type>())) + \ sizeof( \ boost::asio::detail::lvref< \ @@ -439,11 +509,19 @@ struct handler_type_requirements handler_type, handler) \ typedef int BOOST_ASIO_UNUSED_TYPEDEF +#define BOOST_ASIO_MOVE_ACCEPT_HANDLER_CHECK( \ + handler_type, handler, socket_type) \ + typedef int BOOST_ASIO_UNUSED_TYPEDEF + #define BOOST_ASIO_CONNECT_HANDLER_CHECK( \ handler_type, handler) \ typedef int BOOST_ASIO_UNUSED_TYPEDEF -#define BOOST_ASIO_COMPOSED_CONNECT_HANDLER_CHECK( \ +#define BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK( \ + handler_type, handler, iter_type) \ + typedef int BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \ handler_type, handler, iter_type) \ typedef int BOOST_ASIO_UNUSED_TYPEDEF diff --git a/boost/asio/detail/handler_work.hpp b/boost/asio/detail/handler_work.hpp new file mode 100644 index 0000000000..62fbe68e46 --- /dev/null +++ b/boost/asio/detail/handler_work.hpp @@ -0,0 +1,97 @@ +// +// detail/handler_work.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_HANDLER_WORK_HPP +#define BOOST_ASIO_DETAIL_HANDLER_WORK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/associated_executor.hpp> +#include <boost/asio/detail/handler_invoke_helpers.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +// A helper class template to allow completion handlers to be dispatched +// through either the new executors framework or the old invocaton hook. The +// primary template uses the new executors framework. +template <typename Handler, typename Executor + = typename associated_executor<Handler>::type> +class handler_work +{ +public: + explicit handler_work(Handler& handler) BOOST_ASIO_NOEXCEPT + : executor_(associated_executor<Handler>::get(handler)) + { + } + + static void start(Handler& handler) BOOST_ASIO_NOEXCEPT + { + Executor ex(associated_executor<Handler>::get(handler)); + ex.on_work_started(); + } + + ~handler_work() + { + executor_.on_work_finished(); + } + + template <typename Function> + void complete(Function& function, Handler& handler) + { + executor_.dispatch(BOOST_ASIO_MOVE_CAST(Function)(function), + associated_allocator<Handler>::get(handler)); + } + +private: + // Disallow copying and assignment. + handler_work(const handler_work&); + handler_work& operator=(const handler_work&); + + typename associated_executor<Handler>::type executor_; +}; + +// This specialisation dispatches a handler through the old invocation hook. +// The specialisation is not strictly required for correctness, as the +// system_executor will dispatch through the hook anyway. However, by doing +// this we avoid an extra copy of the handler. +template <typename Handler> +class handler_work<Handler, system_executor> +{ +public: + explicit handler_work(Handler&) BOOST_ASIO_NOEXCEPT {} + static void start(Handler&) BOOST_ASIO_NOEXCEPT {} + ~handler_work() {} + + template <typename Function> + void complete(Function& function, Handler& handler) + { + boost_asio_handler_invoke_helpers::invoke(function, handler); + } + +private: + // Disallow copying and assignment. + handler_work(const handler_work&); + handler_work& operator=(const handler_work&); +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_HANDLER_WORK_HPP diff --git a/boost/asio/detail/impl/buffer_sequence_adapter.ipp b/boost/asio/detail/impl/buffer_sequence_adapter.ipp index f471863e1a..c2114ba1cf 100644 --- a/boost/asio/detail/impl/buffer_sequence_adapter.ipp +++ b/boost/asio/detail/impl/buffer_sequence_adapter.ipp @@ -40,16 +40,16 @@ class winrt_buffer_impl : public: explicit winrt_buffer_impl(const boost::asio::const_buffer& b) { - bytes_ = const_cast<byte*>(boost::asio::buffer_cast<const byte*>(b)); - length_ = boost::asio::buffer_size(b); - capacity_ = boost::asio::buffer_size(b); + bytes_ = const_cast<byte*>(static_cast<const byte*>(b.data())); + length_ = b.size(); + capacity_ = b.size(); } explicit winrt_buffer_impl(const boost::asio::mutable_buffer& b) { - bytes_ = const_cast<byte*>(boost::asio::buffer_cast<const byte*>(b)); + bytes_ = static_cast<byte*>(b.data()); length_ = 0; - capacity_ = boost::asio::buffer_size(b); + capacity_ = b.size(); } ~winrt_buffer_impl() diff --git a/boost/asio/detail/impl/descriptor_ops.ipp b/boost/asio/detail/impl/descriptor_ops.ipp index 00f6b4796e..cdf5022306 100644 --- a/boost/asio/detail/impl/descriptor_ops.ipp +++ b/boost/asio/detail/impl/descriptor_ops.ipp @@ -439,6 +439,29 @@ int poll_write(int d, state_type state, boost::system::error_code& ec) return result; } +int poll_error(int d, state_type state, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + pollfd fds; + fds.fd = d; + fds.events = POLLPRI | POLLERR | POLLHUP; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : -1; + errno = 0; + int result = error_wrapper(::poll(&fds, 1, timeout), ec); + if (result == 0) + ec = (state & user_set_non_blocking) + ? boost::asio::error::would_block : boost::system::error_code(); + else if (result > 0) + ec = boost::system::error_code(); + return result; +} + } // namespace descriptor_ops } // namespace detail } // namespace asio diff --git a/boost/asio/detail/impl/dev_poll_reactor.hpp b/boost/asio/detail/impl/dev_poll_reactor.hpp index 623346edd5..c01450ffea 100644 --- a/boost/asio/detail/impl/dev_poll_reactor.hpp +++ b/boost/asio/detail/impl/dev_poll_reactor.hpp @@ -46,12 +46,12 @@ void dev_poll_reactor::schedule_timer(timer_queue<Time_Traits>& queue, if (shutdown_) { - io_service_.post_immediate_completion(op, false); + scheduler_.post_immediate_completion(op, false); return; } bool earliest = queue.enqueue_timer(time, timer, op); - io_service_.work_started(); + scheduler_.work_started(); if (earliest) interrupter_.interrupt(); } @@ -65,10 +65,23 @@ std::size_t dev_poll_reactor::cancel_timer(timer_queue<Time_Traits>& queue, op_queue<operation> ops; std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); lock.unlock(); - io_service_.post_deferred_completions(ops); + scheduler_.post_deferred_completions(ops); return n; } +template <typename Time_Traits> +void dev_poll_reactor::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + } // namespace detail } // namespace asio } // namespace boost diff --git a/boost/asio/detail/impl/dev_poll_reactor.ipp b/boost/asio/detail/impl/dev_poll_reactor.ipp index 7efb05ed02..5186d30473 100644 --- a/boost/asio/detail/impl/dev_poll_reactor.ipp +++ b/boost/asio/detail/impl/dev_poll_reactor.ipp @@ -30,9 +30,9 @@ namespace boost { namespace asio { namespace detail { -dev_poll_reactor::dev_poll_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base<dev_poll_reactor>(io_service), - io_service_(use_service<io_service_impl>(io_service)), +dev_poll_reactor::dev_poll_reactor(boost::asio::execution_context& ctx) + : boost::asio::detail::execution_context_service_base<dev_poll_reactor>(ctx), + scheduler_(use_service<scheduler>(ctx)), mutex_(), dev_poll_fd_(do_dev_poll_create()), interrupter_(), @@ -48,11 +48,11 @@ dev_poll_reactor::dev_poll_reactor(boost::asio::io_service& io_service) dev_poll_reactor::~dev_poll_reactor() { - shutdown_service(); + shutdown(); ::close(dev_poll_fd_); } -void dev_poll_reactor::shutdown_service() +void dev_poll_reactor::shutdown() { boost::asio::detail::mutex::scoped_lock lock(mutex_); shutdown_ = true; @@ -65,12 +65,13 @@ void dev_poll_reactor::shutdown_service() timer_queues_.get_all_timers(ops); - io_service_.abandon_operations(ops); + scheduler_.abandon_operations(ops); } -void dev_poll_reactor::fork_service(boost::asio::io_service::fork_event fork_ev) +void dev_poll_reactor::notify_fork( + boost::asio::execution_context::fork_event fork_ev) { - if (fork_ev == boost::asio::io_service::fork_child) + if (fork_ev == boost::asio::execution_context::fork_child) { detail::mutex::scoped_lock lock(mutex_); @@ -113,7 +114,7 @@ void dev_poll_reactor::fork_service(boost::asio::io_service::fork_event fork_ev) void dev_poll_reactor::init_task() { - io_service_.init_task(); + scheduler_.init_task(); } int dev_poll_reactor::register_descriptor(socket_type, per_descriptor_data&) @@ -168,7 +169,7 @@ void dev_poll_reactor::start_op(int op_type, socket_type descriptor, if (op->perform()) { lock.unlock(); - io_service_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); return; } } @@ -176,7 +177,7 @@ void dev_poll_reactor::start_op(int op_type, socket_type descriptor, } bool first = op_queue_[op_type].enqueue_operation(descriptor, op); - io_service_.work_started(); + scheduler_.work_started(); if (first) { ::pollfd& ev = add_pending_event_change(descriptor); @@ -240,13 +241,13 @@ void dev_poll_reactor::cleanup_descriptor_data( { } -void dev_poll_reactor::run(bool block, op_queue<operation>& ops) +void dev_poll_reactor::run(long usec, op_queue<operation>& ops) { boost::asio::detail::mutex::scoped_lock lock(mutex_); // We can return immediately if there's no work to do and the reactor is // not supposed to block. - if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty() + if (usec == 0 && op_queue_[read_op].empty() && op_queue_[write_op].empty() && op_queue_[except_op].empty() && timer_queues_.all_empty()) return; @@ -272,7 +273,15 @@ void dev_poll_reactor::run(bool block, op_queue<operation>& ops) pending_event_change_index_.clear(); } - int timeout = block ? get_timeout() : 0; + // Calculate timeout. + int timeout; + if (usec == 0) + timeout = 0; + else + { + timeout = (usec < 0) ? -1 : ((usec - 1) / 1000 + 1); + timeout = get_timeout(timeout); + } lock.unlock(); // Block on the /dev/poll descriptor. @@ -386,11 +395,13 @@ void dev_poll_reactor::do_remove_timer_queue(timer_queue_base& queue) timer_queues_.erase(&queue); } -int dev_poll_reactor::get_timeout() +int dev_poll_reactor::get_timeout(int msec) { // By default we will wait no longer than 5 minutes. This will ensure that // any changes to the system clock are detected after no longer than this. - return timer_queues_.wait_duration_msec(5 * 60 * 1000); + const int max_msec = 5 * 60 * 1000; + return timer_queues_.wait_duration_msec( + (msec < 0 || max_msec < msec) ? max_msec : msec); } void dev_poll_reactor::cancel_ops_unlocked(socket_type descriptor, @@ -401,7 +412,7 @@ void dev_poll_reactor::cancel_ops_unlocked(socket_type descriptor, for (int i = 0; i < max_ops; ++i) need_interrupt = op_queue_[i].cancel_operations( descriptor, ops, ec) || need_interrupt; - io_service_.post_deferred_completions(ops); + scheduler_.post_deferred_completions(ops); if (need_interrupt) interrupter_.interrupt(); } diff --git a/boost/asio/detail/impl/epoll_reactor.hpp b/boost/asio/detail/impl/epoll_reactor.hpp index ea5c6bfc69..537b0fc7da 100644 --- a/boost/asio/detail/impl/epoll_reactor.hpp +++ b/boost/asio/detail/impl/epoll_reactor.hpp @@ -44,12 +44,12 @@ void epoll_reactor::schedule_timer(timer_queue<Time_Traits>& queue, if (shutdown_) { - io_service_.post_immediate_completion(op, false); + scheduler_.post_immediate_completion(op, false); return; } bool earliest = queue.enqueue_timer(time, timer, op); - io_service_.work_started(); + scheduler_.work_started(); if (earliest) update_timeout(); } @@ -63,10 +63,23 @@ std::size_t epoll_reactor::cancel_timer(timer_queue<Time_Traits>& queue, op_queue<operation> ops; std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); lock.unlock(); - io_service_.post_deferred_completions(ops); + scheduler_.post_deferred_completions(ops); return n; } +template <typename Time_Traits> +void epoll_reactor::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source) +{ + mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + } // namespace detail } // namespace asio } // namespace boost diff --git a/boost/asio/detail/impl/epoll_reactor.ipp b/boost/asio/detail/impl/epoll_reactor.ipp index 3d3d244e0a..a9c2602fbe 100644 --- a/boost/asio/detail/impl/epoll_reactor.ipp +++ b/boost/asio/detail/impl/epoll_reactor.ipp @@ -35,14 +35,16 @@ namespace boost { namespace asio { namespace detail { -epoll_reactor::epoll_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base<epoll_reactor>(io_service), - io_service_(use_service<io_service_impl>(io_service)), - mutex_(), +epoll_reactor::epoll_reactor(boost::asio::execution_context& ctx) + : execution_context_service_base<epoll_reactor>(ctx), + scheduler_(use_service<scheduler>(ctx)), + mutex_(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_REGISTRATION, scheduler_.concurrency_hint())), interrupter_(), epoll_fd_(do_epoll_create()), timer_fd_(do_timerfd_create()), - shutdown_(false) + shutdown_(false), + registered_descriptors_mutex_(mutex_.enabled()) { // Add the interrupter's descriptor to epoll. epoll_event ev = { 0, { 0 } }; @@ -68,7 +70,7 @@ epoll_reactor::~epoll_reactor() close(timer_fd_); } -void epoll_reactor::shutdown_service() +void epoll_reactor::shutdown() { mutex::scoped_lock lock(mutex_); shutdown_ = true; @@ -86,12 +88,13 @@ void epoll_reactor::shutdown_service() timer_queues_.get_all_timers(ops); - io_service_.abandon_operations(ops); + scheduler_.abandon_operations(ops); } -void epoll_reactor::fork_service(boost::asio::io_service::fork_event fork_ev) +void epoll_reactor::notify_fork( + boost::asio::execution_context::fork_event fork_ev) { - if (fork_ev == boost::asio::io_service::fork_child) + if (fork_ev == boost::asio::execution_context::fork_child) { if (epoll_fd_ != -1) ::close(epoll_fd_); @@ -142,7 +145,7 @@ void epoll_reactor::fork_service(boost::asio::io_service::fork_event fork_ev) void epoll_reactor::init_task() { - io_service_.init_task(); + scheduler_.init_task(); } int epoll_reactor::register_descriptor(socket_type descriptor, @@ -150,12 +153,18 @@ int epoll_reactor::register_descriptor(socket_type descriptor, { descriptor_data = allocate_descriptor_state(); + BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(( + context(), static_cast<uintmax_t>(descriptor), + reinterpret_cast<uintmax_t>(descriptor_data))); + { mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); descriptor_data->reactor_ = this; descriptor_data->descriptor_ = descriptor; descriptor_data->shutdown_ = false; + for (int i = 0; i < max_ops; ++i) + descriptor_data->try_speculative_[i] = true; } epoll_event ev = { 0, { 0 } }; @@ -186,6 +195,10 @@ int epoll_reactor::register_internal_descriptor( { descriptor_data = allocate_descriptor_state(); + BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(( + context(), static_cast<uintmax_t>(descriptor), + reinterpret_cast<uintmax_t>(descriptor_data))); + { mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); @@ -193,6 +206,8 @@ int epoll_reactor::register_internal_descriptor( descriptor_data->descriptor_ = descriptor; descriptor_data->shutdown_ = false; descriptor_data->op_queue_[op_type].push(op); + for (int i = 0; i < max_ops; ++i) + descriptor_data->try_speculative_[i] = true; } epoll_event ev = { 0, { 0 } }; @@ -239,17 +254,23 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor, && (op_type != read_op || descriptor_data->op_queue_[except_op].empty())) { - if (op->perform()) + if (descriptor_data->try_speculative_[op_type]) { - descriptor_lock.unlock(); - io_service_.post_immediate_completion(op, is_continuation); - return; + if (reactor_op::status status = op->perform()) + { + if (status == reactor_op::done_and_exhausted) + if (descriptor_data->registered_events_ != 0) + descriptor_data->try_speculative_[op_type] = false; + descriptor_lock.unlock(); + scheduler_.post_immediate_completion(op, is_continuation); + return; + } } if (descriptor_data->registered_events_ == 0) { op->ec_ = boost::asio::error::operation_not_supported; - io_service_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); return; } @@ -268,7 +289,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor, { op->ec_ = boost::system::error_code(errno, boost::asio::error::get_system_category()); - io_service_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); return; } } @@ -277,7 +298,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor, else if (descriptor_data->registered_events_ == 0) { op->ec_ = boost::asio::error::operation_not_supported; - io_service_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); return; } else @@ -295,7 +316,7 @@ void epoll_reactor::start_op(int op_type, socket_type descriptor, } descriptor_data->op_queue_[op_type].push(op); - io_service_.work_started(); + scheduler_.work_started(); } void epoll_reactor::cancel_ops(socket_type, @@ -319,7 +340,7 @@ void epoll_reactor::cancel_ops(socket_type, descriptor_lock.unlock(); - io_service_.post_deferred_completions(ops); + scheduler_.post_deferred_completions(ops); } void epoll_reactor::deregister_descriptor(socket_type descriptor, @@ -359,7 +380,11 @@ void epoll_reactor::deregister_descriptor(socket_type descriptor, descriptor_lock.unlock(); - io_service_.post_deferred_completions(ops); + BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(( + context(), static_cast<uintmax_t>(descriptor), + reinterpret_cast<uintmax_t>(descriptor_data))); + + scheduler_.post_deferred_completions(ops); // Leave descriptor_data set so that it will be freed by the subsequent // call to cleanup_descriptor_data. @@ -394,6 +419,10 @@ void epoll_reactor::deregister_internal_descriptor(socket_type descriptor, descriptor_lock.unlock(); + BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(( + context(), static_cast<uintmax_t>(descriptor), + reinterpret_cast<uintmax_t>(descriptor_data))); + // Leave descriptor_data set so that it will be freed by the subsequent // call to cleanup_descriptor_data. } @@ -415,28 +444,62 @@ void epoll_reactor::cleanup_descriptor_data( } } -void epoll_reactor::run(bool block, op_queue<operation>& ops) +void epoll_reactor::run(long usec, op_queue<operation>& ops) { - // This code relies on the fact that the task_io_service queues the reactor - // task behind all descriptor operations generated by this function. This - // means, that by the time we reach this point, any previously returned - // descriptor operations have already been dequeued. Therefore it is now safe - // for us to reuse and return them for the task_io_service to queue again. + // This code relies on the fact that the scheduler queues the reactor task + // behind all descriptor operations generated by this function. This means, + // that by the time we reach this point, any previously returned descriptor + // operations have already been dequeued. Therefore it is now safe for us to + // reuse and return them for the scheduler to queue again. - // Calculate a timeout only if timerfd is not used. + // Calculate timeout. Check the timer queues only if timerfd is not in use. int timeout; - if (timer_fd_ != -1) - timeout = block ? -1 : 0; + if (usec == 0) + timeout = 0; else { - mutex::scoped_lock lock(mutex_); - timeout = block ? get_timeout() : 0; + timeout = (usec < 0) ? -1 : ((usec - 1) / 1000 + 1); + if (timer_fd_ == -1) + { + mutex::scoped_lock lock(mutex_); + timeout = get_timeout(timeout); + } } // Block on the epoll descriptor. epoll_event events[128]; int num_events = epoll_wait(epoll_fd_, events, 128, timeout); +#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + // Trace the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = events[i].data.ptr; + if (ptr == &interrupter_) + { + // Ignore. + } +# if defined(BOOST_ASIO_HAS_TIMERFD) + else if (ptr == &timer_fd_) + { + // Ignore. + } +# endif // defined(BOOST_ASIO_HAS_TIMERFD) + else + { + unsigned event_mask = 0; + if ((events[i].events & EPOLLIN) != 0) + event_mask |= BOOST_ASIO_HANDLER_REACTOR_READ_EVENT; + if ((events[i].events & EPOLLOUT)) + event_mask |= BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT; + if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0) + event_mask |= BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT; + BOOST_ASIO_HANDLER_REACTOR_EVENTS((context(), + reinterpret_cast<uintmax_t>(ptr), event_mask)); + } + } +#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + #if defined(BOOST_ASIO_HAS_TIMERFD) bool check_timers = (timer_fd_ == -1); #else // defined(BOOST_ASIO_HAS_TIMERFD) @@ -470,7 +533,7 @@ void epoll_reactor::run(bool block, op_queue<operation>& ops) else { // The descriptor operation doesn't count as work in and of itself, so we - // don't call work_started() here. This still allows the io_service to + // don't call work_started() here. This still allows the scheduler to // stop if the only remaining operations are descriptor operations. descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr); if (!ops.is_enqueued(descriptor_data)) @@ -562,7 +625,8 @@ int epoll_reactor::do_timerfd_create() epoll_reactor::descriptor_state* epoll_reactor::allocate_descriptor_state() { mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); - return registered_descriptors_.alloc(); + return registered_descriptors_.alloc(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_IO, scheduler_.concurrency_hint())); } void epoll_reactor::free_descriptor_state(epoll_reactor::descriptor_state* s) @@ -598,11 +662,13 @@ void epoll_reactor::update_timeout() interrupt(); } -int epoll_reactor::get_timeout() +int epoll_reactor::get_timeout(int msec) { // By default we will wait no longer than 5 minutes. This will ensure that // any changes to the system clock are detected after no longer than this. - return timer_queues_.wait_duration_msec(5 * 60 * 1000); + const int max_msec = 5 * 60 * 1000; + return timer_queues_.wait_duration_msec( + (msec < 0 || max_msec < msec) ? max_msec : msec); } #if defined(BOOST_ASIO_HAS_TIMERFD) @@ -632,19 +698,18 @@ struct epoll_reactor::perform_io_cleanup_on_block_exit { // Post the remaining completed operations for invocation. if (!ops_.empty()) - reactor_->io_service_.post_deferred_completions(ops_); + reactor_->scheduler_.post_deferred_completions(ops_); // A user-initiated operation has completed, but there's no need to // explicitly call work_finished() here. Instead, we'll take advantage of - // the fact that the task_io_service will call work_finished() once we - // return. + // the fact that the scheduler will call work_finished() once we return. } else { // No user-initiated operations have completed, so we need to compensate - // for the work_finished() call that the task_io_service will make once - // this operation returns. - reactor_->io_service_.work_started(); + // for the work_finished() call that the scheduler will make once this + // operation returns. + reactor_->scheduler_.compensating_work_started(); } } @@ -653,8 +718,9 @@ struct epoll_reactor::perform_io_cleanup_on_block_exit operation* first_op_; }; -epoll_reactor::descriptor_state::descriptor_state() - : operation(&epoll_reactor::descriptor_state::do_complete) +epoll_reactor::descriptor_state::descriptor_state(bool locking) + : operation(&epoll_reactor::descriptor_state::do_complete), + mutex_(locking) { } @@ -671,12 +737,18 @@ operation* epoll_reactor::descriptor_state::perform_io(uint32_t events) { if (events & (flag[j] | EPOLLERR | EPOLLHUP)) { + try_speculative_[j] = true; while (reactor_op* op = op_queue_[j].front()) { - if (op->perform()) + if (reactor_op::status status = op->perform()) { op_queue_[j].pop(); io_cleanup.ops_.push(op); + if (status == reactor_op::done_and_exhausted) + { + try_speculative_[j] = false; + break; + } } else break; @@ -692,7 +764,7 @@ operation* epoll_reactor::descriptor_state::perform_io(uint32_t events) } void epoll_reactor::descriptor_state::do_complete( - io_service_impl* owner, operation* base, + void* owner, operation* base, const boost::system::error_code& ec, std::size_t bytes_transferred) { if (owner) @@ -701,7 +773,7 @@ void epoll_reactor::descriptor_state::do_complete( uint32_t events = static_cast<uint32_t>(bytes_transferred); if (operation* op = descriptor_data->perform_io(events)) { - op->complete(*owner, ec, 0); + op->complete(owner, ec, 0); } } } diff --git a/boost/asio/detail/impl/handler_tracking.ipp b/boost/asio/detail/impl/handler_tracking.ipp index 259b5ab62b..aa6b9b2917 100644 --- a/boost/asio/detail/impl/handler_tracking.ipp +++ b/boost/asio/detail/impl/handler_tracking.ipp @@ -17,7 +17,11 @@ #include <boost/asio/detail/config.hpp> -#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) +#if defined(BOOST_ASIO_CUSTOM_HANDLER_TRACKING) + +// The handler tracking implementation is provided by the user-specified header. + +#elif defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) #include <cstdarg> #include <cstdio> @@ -25,17 +29,15 @@ #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) # include <boost/asio/time_traits.hpp> -#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) -# if defined(BOOST_ASIO_HAS_STD_CHRONO) -# include <chrono> -# elif defined(BOOST_ASIO_HAS_BOOST_CHRONO) -# include <boost/chrono/system_clocks.hpp> -# endif +#elif defined(BOOST_ASIO_HAS_CHRONO) +# include <boost/asio/detail/chrono.hpp> # include <boost/asio/detail/chrono_time_traits.hpp> # include <boost/asio/wait_traits.hpp> #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) -#if !defined(BOOST_ASIO_WINDOWS) +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include <boost/asio/detail/socket_types.hpp> +#elif !defined(BOOST_ASIO_WINDOWS) # include <unistd.h> #endif // !defined(BOOST_ASIO_WINDOWS) @@ -56,16 +58,11 @@ struct handler_tracking_timestamp boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); boost::posix_time::time_duration now = boost::posix_time::microsec_clock::universal_time() - epoch; -#elif defined(BOOST_ASIO_HAS_STD_CHRONO) - typedef chrono_time_traits<std::chrono::system_clock, - boost::asio::wait_traits<std::chrono::system_clock> > traits_helper; - traits_helper::posix_time_duration now( - std::chrono::system_clock::now().time_since_epoch()); -#elif defined(BOOST_ASIO_HAS_BOOST_CHRONO) - typedef chrono_time_traits<boost::chrono::system_clock, - boost::asio::wait_traits<boost::chrono::system_clock> > traits_helper; +#elif defined(BOOST_ASIO_HAS_CHRONO) + typedef chrono_time_traits<chrono::system_clock, + boost::asio::wait_traits<chrono::system_clock> > traits_helper; traits_helper::posix_time_duration now( - boost::chrono::system_clock::now().time_since_epoch()); + chrono::system_clock::now().time_since_epoch()); #endif seconds = static_cast<uint64_t>(now.total_seconds()); microseconds = static_cast<uint64_t>(now.total_microseconds() % 1000000); @@ -96,13 +93,15 @@ void handler_tracking::init() state->current_completion_ = new tss_ptr<completion>; } -void handler_tracking::creation(handler_tracking::tracked_handler* h, - const char* object_type, void* object, const char* op_name) +void handler_tracking::creation(execution_context&, + handler_tracking::tracked_handler& h, + const char* object_type, void* object, + uintmax_t /*native_handle*/, const char* op_name) { static tracking_state* state = get_state(); static_mutex::scoped_lock lock(state->mutex_); - h->id_ = state->next_id_++; + h.id_ = state->next_id_++; lock.unlock(); handler_tracking_timestamp timestamp; @@ -118,11 +117,12 @@ void handler_tracking::creation(handler_tracking::tracked_handler* h, "@asio|%llu.%06llu|%llu*%llu|%.20s@%p.%.50s\n", #endif // defined(BOOST_ASIO_WINDOWS) timestamp.seconds, timestamp.microseconds, - current_id, h->id_, object_type, object, op_name); + current_id, h.id_, object_type, object, op_name); } -handler_tracking::completion::completion(handler_tracking::tracked_handler* h) - : id_(h->id_), +handler_tracking::completion::completion( + const handler_tracking::tracked_handler& h) + : id_(h.id_), invoked_(false), next_(*get_state()->current_completion_) { @@ -250,8 +250,9 @@ void handler_tracking::completion::invocation_end() } } -void handler_tracking::operation(const char* object_type, - void* object, const char* op_name) +void handler_tracking::operation(execution_context&, + const char* object_type, void* object, + uintmax_t /*native_handle*/, const char* op_name) { static tracking_state* state = get_state(); @@ -271,6 +272,54 @@ void handler_tracking::operation(const char* object_type, current_id, object_type, object, op_name); } +void handler_tracking::reactor_registration(execution_context& /*context*/, + uintmax_t /*native_handle*/, uintmax_t /*registration*/) +{ +} + +void handler_tracking::reactor_deregistration(execution_context& /*context*/, + uintmax_t /*native_handle*/, uintmax_t /*registration*/) +{ +} + +void handler_tracking::reactor_events(execution_context& /*context*/, + uintmax_t /*native_handle*/, unsigned /*events*/) +{ +} + +void handler_tracking::reactor_operation( + const tracked_handler& h, const char* op_name, + const boost::system::error_code& ec) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(BOOST_ASIO_WINDOWS) + "@asio|%I64u.%06I64u|.%I64u|%s,ec=%.20s:%d\n", +#else // defined(BOOST_ASIO_WINDOWS) + "@asio|%llu.%06llu|.%llu|%s,ec=%.20s:%d\n", +#endif // defined(BOOST_ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + h.id_, op_name, ec.category().name(), ec.value()); +} + +void handler_tracking::reactor_operation( + const tracked_handler& h, const char* op_name, + const boost::system::error_code& ec, std::size_t bytes_transferred) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(BOOST_ASIO_WINDOWS) + "@asio|%I64u.%06I64u|.%I64u|%s,ec=%.20s:%d,bytes_transferred=%I64u\n", +#else // defined(BOOST_ASIO_WINDOWS) + "@asio|%llu.%06llu|.%llu|%s,ec=%.20s:%d,bytes_transferred=%llu\n", +#endif // defined(BOOST_ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + h.id_, op_name, ec.category().name(), ec.value(), + static_cast<uint64_t>(bytes_transferred)); +} + void handler_tracking::write_line(const char* format, ...) { using namespace std; // For sprintf (or equivalent). @@ -287,7 +336,11 @@ void handler_tracking::write_line(const char* format, ...) va_end(args); -#if defined(BOOST_ASIO_WINDOWS) +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + wchar_t wline[256] = L""; + mbstowcs_s(0, wline, sizeof(wline) / sizeof(wchar_t), line, length); + ::OutputDebugStringW(wline); +#elif defined(BOOST_ASIO_WINDOWS) HANDLE stderr_handle = ::GetStdHandle(STD_ERROR_HANDLE); DWORD bytes_written = 0; ::WriteFile(stderr_handle, line, length, &bytes_written, 0); diff --git a/boost/asio/detail/impl/kqueue_reactor.hpp b/boost/asio/detail/impl/kqueue_reactor.hpp index 93cbca26a2..83bfa95765 100644 --- a/boost/asio/detail/impl/kqueue_reactor.hpp +++ b/boost/asio/detail/impl/kqueue_reactor.hpp @@ -44,16 +44,16 @@ void kqueue_reactor::schedule_timer(timer_queue<Time_Traits>& queue, const typename Time_Traits::time_type& time, typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock lock(mutex_); if (shutdown_) { - io_service_.post_immediate_completion(op, false); + scheduler_.post_immediate_completion(op, false); return; } bool earliest = queue.enqueue_timer(time, timer, op); - io_service_.work_started(); + scheduler_.work_started(); if (earliest) interrupt(); } @@ -63,14 +63,27 @@ std::size_t kqueue_reactor::cancel_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock lock(mutex_); op_queue<operation> ops; std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); lock.unlock(); - io_service_.post_deferred_completions(ops); + scheduler_.post_deferred_completions(ops); return n; } +template <typename Time_Traits> +void kqueue_reactor::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source) +{ + mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + } // namespace detail } // namespace asio } // namespace boost diff --git a/boost/asio/detail/impl/kqueue_reactor.ipp b/boost/asio/detail/impl/kqueue_reactor.ipp index 8057606ce6..c492646a0b 100644 --- a/boost/asio/detail/impl/kqueue_reactor.ipp +++ b/boost/asio/detail/impl/kqueue_reactor.ipp @@ -21,6 +21,7 @@ #if defined(BOOST_ASIO_HAS_KQUEUE) #include <boost/asio/detail/kqueue_reactor.hpp> +#include <boost/asio/detail/scheduler.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> @@ -39,13 +40,15 @@ namespace boost { namespace asio { namespace detail { -kqueue_reactor::kqueue_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base<kqueue_reactor>(io_service), - io_service_(use_service<io_service_impl>(io_service)), - mutex_(), +kqueue_reactor::kqueue_reactor(boost::asio::execution_context& ctx) + : execution_context_service_base<kqueue_reactor>(ctx), + scheduler_(use_service<scheduler>(ctx)), + mutex_(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_REGISTRATION, scheduler_.concurrency_hint())), kqueue_fd_(do_kqueue_create()), interrupter_(), - shutdown_(false) + shutdown_(false), + registered_descriptors_mutex_(mutex_.enabled()) { struct kevent events[1]; BOOST_ASIO_KQUEUE_EV_SET(&events[0], interrupter_.read_descriptor(), @@ -63,7 +66,7 @@ kqueue_reactor::~kqueue_reactor() close(kqueue_fd_); } -void kqueue_reactor::shutdown_service() +void kqueue_reactor::shutdown() { mutex::scoped_lock lock(mutex_); shutdown_ = true; @@ -81,12 +84,13 @@ void kqueue_reactor::shutdown_service() timer_queues_.get_all_timers(ops); - io_service_.abandon_operations(ops); + scheduler_.abandon_operations(ops); } -void kqueue_reactor::fork_service(boost::asio::io_service::fork_event fork_ev) +void kqueue_reactor::notify_fork( + boost::asio::execution_context::fork_event fork_ev) { - if (fork_ev == boost::asio::io_service::fork_child) + if (fork_ev == boost::asio::execution_context::fork_child) { // The kqueue descriptor is automatically closed in the child. kqueue_fd_ = -1; @@ -128,7 +132,7 @@ void kqueue_reactor::fork_service(boost::asio::io_service::fork_event fork_ev) void kqueue_reactor::init_task() { - io_service_.init_task(); + scheduler_.init_task(); } int kqueue_reactor::register_descriptor(socket_type descriptor, @@ -136,6 +140,10 @@ int kqueue_reactor::register_descriptor(socket_type descriptor, { descriptor_data = allocate_descriptor_state(); + BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(( + context(), static_cast<uintmax_t>(descriptor), + reinterpret_cast<uintmax_t>(descriptor_data))); + mutex::scoped_lock lock(descriptor_data->mutex_); descriptor_data->descriptor_ = descriptor; @@ -151,6 +159,10 @@ int kqueue_reactor::register_internal_descriptor( { descriptor_data = allocate_descriptor_state(); + BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(( + context(), static_cast<uintmax_t>(descriptor), + reinterpret_cast<uintmax_t>(descriptor_data))); + mutex::scoped_lock lock(descriptor_data->mutex_); descriptor_data->descriptor_ = descriptor; @@ -205,7 +217,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor, if (op->perform()) { descriptor_lock.unlock(); - io_service_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); return; } @@ -224,7 +236,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor, { op->ec_ = boost::system::error_code(errno, boost::asio::error::get_system_category()); - io_service_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); return; } } @@ -244,7 +256,7 @@ void kqueue_reactor::start_op(int op_type, socket_type descriptor, } descriptor_data->op_queue_[op_type].push(op); - io_service_.work_started(); + scheduler_.work_started(); } void kqueue_reactor::cancel_ops(socket_type, @@ -268,7 +280,7 @@ void kqueue_reactor::cancel_ops(socket_type, descriptor_lock.unlock(); - io_service_.post_deferred_completions(ops); + scheduler_.post_deferred_completions(ops); } void kqueue_reactor::deregister_descriptor(socket_type descriptor, @@ -312,7 +324,11 @@ void kqueue_reactor::deregister_descriptor(socket_type descriptor, descriptor_lock.unlock(); - io_service_.post_deferred_completions(ops); + BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(( + context(), static_cast<uintmax_t>(descriptor), + reinterpret_cast<uintmax_t>(descriptor_data))); + + scheduler_.post_deferred_completions(ops); // Leave descriptor_data set so that it will be freed by the subsequent // call to cleanup_descriptor_data. @@ -351,6 +367,10 @@ void kqueue_reactor::deregister_internal_descriptor(socket_type descriptor, descriptor_lock.unlock(); + BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(( + context(), static_cast<uintmax_t>(descriptor), + reinterpret_cast<uintmax_t>(descriptor_data))); + // Leave descriptor_data set so that it will be freed by the subsequent // call to cleanup_descriptor_data. } @@ -372,13 +392,13 @@ void kqueue_reactor::cleanup_descriptor_data( } } -void kqueue_reactor::run(bool block, op_queue<operation>& ops) +void kqueue_reactor::run(long usec, op_queue<operation>& ops) { mutex::scoped_lock lock(mutex_); // Determine how long to block while waiting for events. timespec timeout_buf = { 0, 0 }; - timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf; + timespec* timeout = usec ? get_timeout(usec, timeout_buf) : &timeout_buf; lock.unlock(); @@ -386,6 +406,31 @@ void kqueue_reactor::run(bool block, op_queue<operation>& ops) struct kevent events[128]; int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout); +#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + // Trace the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = reinterpret_cast<void*>(events[i].udata); + if (ptr != &interrupter_) + { + unsigned event_mask = 0; + switch (events[i].filter) + { + case EVFILT_READ: + event_mask |= BOOST_ASIO_HANDLER_REACTOR_READ_EVENT; + break; + case EVFILT_WRITE: + event_mask |= BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT; + break; + } + if ((events[i].flags & (EV_ERROR | EV_OOBAND)) != 0) + event_mask |= BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT; + BOOST_ASIO_HANDLER_REACTOR_EVENTS((context(), + reinterpret_cast<uintmax_t>(ptr), event_mask)); + } + } +#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + // Dispatch the waiting events. for (int i = 0; i < num_events; ++i) { @@ -476,7 +521,8 @@ int kqueue_reactor::do_kqueue_create() kqueue_reactor::descriptor_state* kqueue_reactor::allocate_descriptor_state() { mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); - return registered_descriptors_.alloc(); + return registered_descriptors_.alloc(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_IO, scheduler_.concurrency_hint())); } void kqueue_reactor::free_descriptor_state(kqueue_reactor::descriptor_state* s) @@ -497,11 +543,13 @@ void kqueue_reactor::do_remove_timer_queue(timer_queue_base& queue) timer_queues_.erase(&queue); } -timespec* kqueue_reactor::get_timeout(timespec& ts) +timespec* kqueue_reactor::get_timeout(long usec, timespec& ts) { // By default we will wait no longer than 5 minutes. This will ensure that // any changes to the system clock are detected after no longer than this. - long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + const long max_usec = 5 * 60 * 1000 * 1000; + usec = timer_queues_.wait_duration_usec( + (usec < 0 || max_usec < usec) ? max_usec : usec); ts.tv_sec = usec / 1000000; ts.tv_nsec = (usec % 1000000) * 1000; return &ts; diff --git a/boost/asio/detail/impl/null_event.ipp b/boost/asio/detail/impl/null_event.ipp new file mode 100644 index 0000000000..fb9f2e2ed2 --- /dev/null +++ b/boost/asio/detail/impl/null_event.ipp @@ -0,0 +1,76 @@ +// +// detail/impl/null_event.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_NULL_EVENT_IPP +#define BOOST_ASIO_DETAIL_IMPL_NULL_EVENT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include <thread> +#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# include <boost/asio/detail/socket_types.hpp> +#else +# include <unistd.h> +# if defined(__hpux) +# include <sys/time.h> +# endif +# if !defined(__hpux) || defined(__SELECT) +# include <sys/select.h> +# endif +#endif + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +void null_event::do_wait() +{ +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + std::this_thread::sleep_until((std::chrono::steady_clock::time_point::max)()); +#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + ::Sleep(INFINITE); +#else + ::pause(); +#endif +} + +void null_event::do_wait_for_usec(long usec) +{ +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + std::this_thread::sleep_for(std::chrono::microseconds(usec)); +#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + ::Sleep(usec / 1000); +#elif defined(__hpux) && defined(__SELECT) + timespec ts; + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + ::pselect(0, 0, 0, 0, &ts, 0); +#else + timeval tv; + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; + ::select(0, 0, 0, 0, &tv); +#endif +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_IMPL_NULL_EVENT_IPP diff --git a/boost/asio/detail/impl/posix_event.ipp b/boost/asio/detail/impl/posix_event.ipp index 3b465ca3cd..4ff246f301 100644 --- a/boost/asio/detail/impl/posix_event.ipp +++ b/boost/asio/detail/impl/posix_event.ipp @@ -32,7 +32,19 @@ namespace detail { posix_event::posix_event() : state_(0) { +#if (defined(__MACH__) && defined(__APPLE__)) \ + || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) int error = ::pthread_cond_init(&cond_, 0); +#else // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) + ::pthread_condattr_t attr; + ::pthread_condattr_init(&attr); + int error = ::pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + if (error == 0) + error = ::pthread_cond_init(&cond_, &attr); +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) + boost::system::error_code ec(error, boost::asio::error::get_system_category()); boost::asio::detail::throw_error(ec, "event"); diff --git a/boost/asio/detail/impl/posix_thread.ipp b/boost/asio/detail/impl/posix_thread.ipp index 66cb18da33..66a6792a4a 100644 --- a/boost/asio/detail/impl/posix_thread.ipp +++ b/boost/asio/detail/impl/posix_thread.ipp @@ -44,6 +44,16 @@ void posix_thread::join() } } +std::size_t posix_thread::hardware_concurrency() +{ +#if defined(_SC_NPROCESSORS_ONLN) + long result = sysconf(_SC_NPROCESSORS_ONLN); + if (result > 0) + return result; +#endif // defined(_SC_NPROCESSORS_ONLN) + return 0; +} + void posix_thread::start_thread(func_base* arg) { int error = ::pthread_create(&thread_, 0, diff --git a/boost/asio/detail/impl/reactive_descriptor_service.ipp b/boost/asio/detail/impl/reactive_descriptor_service.ipp index a0300c47d0..ffb623839f 100644 --- a/boost/asio/detail/impl/reactive_descriptor_service.ipp +++ b/boost/asio/detail/impl/reactive_descriptor_service.ipp @@ -31,13 +31,14 @@ namespace asio { namespace detail { reactive_descriptor_service::reactive_descriptor_service( - boost::asio::io_service& io_service) - : reactor_(boost::asio::use_service<reactor>(io_service)) + boost::asio::io_context& io_context) + : service_base<reactive_descriptor_service>(io_context), + reactor_(boost::asio::use_service<reactor>(io_context)) { reactor_.init_task(); } -void reactive_descriptor_service::shutdown_service() +void reactive_descriptor_service::shutdown() { } @@ -84,7 +85,8 @@ void reactive_descriptor_service::destroy( { if (is_open(impl)) { - BOOST_ASIO_HANDLER_OPERATION(("descriptor", &impl, "close")); + BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), + "descriptor", &impl, impl.descriptor_, "close")); reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, (impl.state_ & descriptor_ops::possible_dup) == 0); @@ -126,7 +128,8 @@ boost::system::error_code reactive_descriptor_service::close( { if (is_open(impl)) { - BOOST_ASIO_HANDLER_OPERATION(("descriptor", &impl, "close")); + BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), + "descriptor", &impl, impl.descriptor_, "close")); reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, (impl.state_ & descriptor_ops::possible_dup) == 0); @@ -159,7 +162,8 @@ reactive_descriptor_service::release( if (is_open(impl)) { - BOOST_ASIO_HANDLER_OPERATION(("descriptor", &impl, "release")); + BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), + "descriptor", &impl, impl.descriptor_, "release")); reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, false); reactor_.cleanup_descriptor_data(impl.reactor_data_); @@ -179,7 +183,8 @@ boost::system::error_code reactive_descriptor_service::cancel( return ec; } - BOOST_ASIO_HANDLER_OPERATION(("descriptor", &impl, "cancel")); + BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), + "descriptor", &impl, impl.descriptor_, "cancel")); reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_); ec = boost::system::error_code(); diff --git a/boost/asio/detail/impl/reactive_serial_port_service.ipp b/boost/asio/detail/impl/reactive_serial_port_service.ipp index ffa8857ab6..ffd2a2b558 100644 --- a/boost/asio/detail/impl/reactive_serial_port_service.ipp +++ b/boost/asio/detail/impl/reactive_serial_port_service.ipp @@ -31,14 +31,15 @@ namespace asio { namespace detail { reactive_serial_port_service::reactive_serial_port_service( - boost::asio::io_service& io_service) - : descriptor_service_(io_service) + boost::asio::io_context& io_context) + : service_base<reactive_serial_port_service>(io_context), + descriptor_service_(io_context) { } -void reactive_serial_port_service::shutdown_service() +void reactive_serial_port_service::shutdown() { - descriptor_service_.shutdown_service(); + descriptor_service_.shutdown(); } boost::system::error_code reactive_serial_port_service::open( @@ -73,7 +74,7 @@ boost::system::error_code reactive_serial_port_service::open( s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec); if (s >= 0) { -#if defined(_BSD_SOURCE) +#if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) ::cfmakeraw(&ios); #else ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK diff --git a/boost/asio/detail/impl/reactive_socket_service_base.ipp b/boost/asio/detail/impl/reactive_socket_service_base.ipp index 3594ae0528..23dbbb583c 100644 --- a/boost/asio/detail/impl/reactive_socket_service_base.ipp +++ b/boost/asio/detail/impl/reactive_socket_service_base.ipp @@ -29,13 +29,14 @@ namespace asio { namespace detail { reactive_socket_service_base::reactive_socket_service_base( - boost::asio::io_service& io_service) - : reactor_(use_service<reactor>(io_service)) + boost::asio::io_context& io_context) + : io_context_(io_context), + reactor_(use_service<reactor>(io_context)) { reactor_.init_task(); } -void reactive_socket_service_base::shutdown_service() +void reactive_socket_service_base::base_shutdown() { } @@ -82,7 +83,8 @@ void reactive_socket_service_base::destroy( { if (impl.socket_ != invalid_socket) { - BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "close")); + BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "close")); reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, (impl.state_ & socket_ops::possible_dup) == 0); @@ -100,7 +102,8 @@ boost::system::error_code reactive_socket_service_base::close( { if (is_open(impl)) { - BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "close")); + BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "close")); reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, (impl.state_ & socket_ops::possible_dup) == 0); @@ -127,6 +130,27 @@ boost::system::error_code reactive_socket_service_base::close( return ec; } +socket_type reactive_socket_service_base::release( + reactive_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return invalid_socket; + } + + BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "release")); + + reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, false); + reactor_.cleanup_descriptor_data(impl.reactor_data_); + socket_type sock = impl.socket_; + construct(impl); + ec = boost::system::error_code(); + return sock; +} + boost::system::error_code reactive_socket_service_base::cancel( reactive_socket_service_base::base_implementation_type& impl, boost::system::error_code& ec) @@ -137,7 +161,8 @@ boost::system::error_code reactive_socket_service_base::cancel( return ec; } - BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "cancel")); + BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "cancel")); reactor_.cancel_ops(impl.socket_, impl.reactor_data_); ec = boost::system::error_code(); diff --git a/boost/asio/detail/impl/resolver_service_base.ipp b/boost/asio/detail/impl/resolver_service_base.ipp index 4ef66cde15..1dbbd20c3f 100644 --- a/boost/asio/detail/impl/resolver_service_base.ipp +++ b/boost/asio/detail/impl/resolver_service_base.ipp @@ -24,62 +24,62 @@ namespace boost { namespace asio { namespace detail { -class resolver_service_base::work_io_service_runner +class resolver_service_base::work_io_context_runner { public: - work_io_service_runner(boost::asio::io_service& io_service) - : io_service_(io_service) {} - void operator()() { io_service_.run(); } + work_io_context_runner(boost::asio::io_context& io_context) + : io_context_(io_context) {} + void operator()() { io_context_.run(); } private: - boost::asio::io_service& io_service_; + boost::asio::io_context& io_context_; }; resolver_service_base::resolver_service_base( - boost::asio::io_service& io_service) - : io_service_impl_(boost::asio::use_service<io_service_impl>(io_service)), - work_io_service_(new boost::asio::io_service), - work_io_service_impl_(boost::asio::use_service< - io_service_impl>(*work_io_service_)), - work_(new boost::asio::io_service::work(*work_io_service_)), + boost::asio::io_context& io_context) + : io_context_impl_(boost::asio::use_service<io_context_impl>(io_context)), + work_io_context_(new boost::asio::io_context(-1)), + work_io_context_impl_(boost::asio::use_service< + io_context_impl>(*work_io_context_)), + work_(boost::asio::make_work_guard(*work_io_context_)), work_thread_(0) { } resolver_service_base::~resolver_service_base() { - shutdown_service(); + base_shutdown(); } -void resolver_service_base::shutdown_service() +void resolver_service_base::base_shutdown() { work_.reset(); - if (work_io_service_.get()) + if (work_io_context_.get()) { - work_io_service_->stop(); + work_io_context_->stop(); if (work_thread_.get()) { work_thread_->join(); work_thread_.reset(); } - work_io_service_.reset(); + work_io_context_.reset(); } } -void resolver_service_base::fork_service( - boost::asio::io_service::fork_event fork_ev) +void resolver_service_base::base_notify_fork( + boost::asio::io_context::fork_event fork_ev) { if (work_thread_.get()) { - if (fork_ev == boost::asio::io_service::fork_prepare) + if (fork_ev == boost::asio::io_context::fork_prepare) { - work_io_service_->stop(); + work_io_context_->stop(); work_thread_->join(); } else { - work_io_service_->reset(); + work_io_context_->restart(); work_thread_.reset(new boost::asio::detail::thread( - work_io_service_runner(*work_io_service_))); + work_io_context_runner(*work_io_context_))); } } } @@ -93,24 +93,48 @@ void resolver_service_base::construct( void resolver_service_base::destroy( resolver_service_base::implementation_type& impl) { - BOOST_ASIO_HANDLER_OPERATION(("resolver", &impl, "cancel")); + BOOST_ASIO_HANDLER_OPERATION((io_context_impl_.context(), + "resolver", &impl, 0, "cancel")); impl.reset(); } +void resolver_service_base::move_construct(implementation_type& impl, + implementation_type& other_impl) +{ + impl = BOOST_ASIO_MOVE_CAST(implementation_type)(other_impl); +} + +void resolver_service_base::move_assign(implementation_type& impl, + resolver_service_base&, implementation_type& other_impl) +{ + destroy(impl); + impl = BOOST_ASIO_MOVE_CAST(implementation_type)(other_impl); +} + void resolver_service_base::cancel( resolver_service_base::implementation_type& impl) { - BOOST_ASIO_HANDLER_OPERATION(("resolver", &impl, "cancel")); + BOOST_ASIO_HANDLER_OPERATION((io_context_impl_.context(), + "resolver", &impl, 0, "cancel")); impl.reset(static_cast<void*>(0), socket_ops::noop_deleter()); } -void resolver_service_base::start_resolve_op(operation* op) +void resolver_service_base::start_resolve_op(resolve_op* op) { - start_work_thread(); - io_service_impl_.work_started(); - work_io_service_impl_.post_immediate_completion(op, false); + if (BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER, + io_context_impl_.concurrency_hint())) + { + start_work_thread(); + io_context_impl_.work_started(); + work_io_context_impl_.post_immediate_completion(op, false); + } + else + { + op->ec_ = boost::asio::error::operation_not_supported; + io_context_impl_.post_immediate_completion(op, false); + } } void resolver_service_base::start_work_thread() @@ -119,7 +143,7 @@ void resolver_service_base::start_work_thread() if (!work_thread_.get()) { work_thread_.reset(new boost::asio::detail::thread( - work_io_service_runner(*work_io_service_))); + work_io_context_runner(*work_io_context_))); } } diff --git a/boost/asio/detail/impl/task_io_service.ipp b/boost/asio/detail/impl/scheduler.ipp index bc83fd4757..7af3907016 100644 --- a/boost/asio/detail/impl/task_io_service.ipp +++ b/boost/asio/detail/impl/scheduler.ipp @@ -1,6 +1,6 @@ // -// detail/impl/task_io_service.ipp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/impl/scheduler.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,8 +8,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP -#define BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP +#ifndef BOOST_ASIO_DETAIL_IMPL_SCHEDULER_IPP +#define BOOST_ASIO_DETAIL_IMPL_SCHEDULER_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once @@ -17,13 +17,12 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_HAS_IOCP) - +#include <boost/asio/detail/concurrency_hint.hpp> #include <boost/asio/detail/event.hpp> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/reactor.hpp> -#include <boost/asio/detail/task_io_service.hpp> -#include <boost/asio/detail/task_io_service_thread_info.hpp> +#include <boost/asio/detail/scheduler.hpp> +#include <boost/asio/detail/scheduler_thread_info.hpp> #include <boost/asio/detail/push_options.hpp> @@ -31,14 +30,14 @@ namespace boost { namespace asio { namespace detail { -struct task_io_service::task_cleanup +struct scheduler::task_cleanup { ~task_cleanup() { if (this_thread_->private_outstanding_work > 0) { boost::asio::detail::increment( - task_io_service_->outstanding_work_, + scheduler_->outstanding_work_, this_thread_->private_outstanding_work); } this_thread_->private_outstanding_work = 0; @@ -46,29 +45,29 @@ struct task_io_service::task_cleanup // Enqueue the completed operations and reinsert the task at the end of // the operation queue. lock_->lock(); - task_io_service_->task_interrupted_ = true; - task_io_service_->op_queue_.push(this_thread_->private_op_queue); - task_io_service_->op_queue_.push(&task_io_service_->task_operation_); + scheduler_->task_interrupted_ = true; + scheduler_->op_queue_.push(this_thread_->private_op_queue); + scheduler_->op_queue_.push(&scheduler_->task_operation_); } - task_io_service* task_io_service_; + scheduler* scheduler_; mutex::scoped_lock* lock_; thread_info* this_thread_; }; -struct task_io_service::work_cleanup +struct scheduler::work_cleanup { ~work_cleanup() { if (this_thread_->private_outstanding_work > 1) { boost::asio::detail::increment( - task_io_service_->outstanding_work_, + scheduler_->outstanding_work_, this_thread_->private_outstanding_work - 1); } else if (this_thread_->private_outstanding_work < 1) { - task_io_service_->work_finished(); + scheduler_->work_finished(); } this_thread_->private_outstanding_work = 0; @@ -76,31 +75,37 @@ struct task_io_service::work_cleanup if (!this_thread_->private_op_queue.empty()) { lock_->lock(); - task_io_service_->op_queue_.push(this_thread_->private_op_queue); + scheduler_->op_queue_.push(this_thread_->private_op_queue); } #endif // defined(BOOST_ASIO_HAS_THREADS) } - task_io_service* task_io_service_; + scheduler* scheduler_; mutex::scoped_lock* lock_; thread_info* this_thread_; }; -task_io_service::task_io_service( - boost::asio::io_service& io_service, std::size_t concurrency_hint) - : boost::asio::detail::service_base<task_io_service>(io_service), - one_thread_(concurrency_hint == 1), - mutex_(), +scheduler::scheduler( + boost::asio::execution_context& ctx, int concurrency_hint) + : boost::asio::detail::execution_context_service_base<scheduler>(ctx), + one_thread_(concurrency_hint == 1 + || !BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING( + SCHEDULER, concurrency_hint) + || !BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_IO, concurrency_hint)), + mutex_(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING( + SCHEDULER, concurrency_hint)), task_(0), task_interrupted_(true), outstanding_work_(0), stopped_(false), - shutdown_(false) + shutdown_(false), + concurrency_hint_(concurrency_hint) { BOOST_ASIO_HANDLER_TRACKING_INIT; } -void task_io_service::shutdown_service() +void scheduler::shutdown() { mutex::scoped_lock lock(mutex_); shutdown_ = true; @@ -119,18 +124,18 @@ void task_io_service::shutdown_service() task_ = 0; } -void task_io_service::init_task() +void scheduler::init_task() { mutex::scoped_lock lock(mutex_); if (!shutdown_ && !task_) { - task_ = &use_service<reactor>(this->get_io_service()); + task_ = &use_service<reactor>(this->context()); op_queue_.push(&task_operation_); wake_one_thread_and_unlock(lock); } } -std::size_t task_io_service::run(boost::system::error_code& ec) +std::size_t scheduler::run(boost::system::error_code& ec) { ec = boost::system::error_code(); if (outstanding_work_ == 0) @@ -152,7 +157,7 @@ std::size_t task_io_service::run(boost::system::error_code& ec) return n; } -std::size_t task_io_service::run_one(boost::system::error_code& ec) +std::size_t scheduler::run_one(boost::system::error_code& ec) { ec = boost::system::error_code(); if (outstanding_work_ == 0) @@ -170,7 +175,25 @@ std::size_t task_io_service::run_one(boost::system::error_code& ec) return do_run_one(lock, this_thread, ec); } -std::size_t task_io_service::poll(boost::system::error_code& ec) +std::size_t scheduler::wait_one(long usec, boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + thread_info this_thread; + this_thread.private_outstanding_work = 0; + thread_call_stack::context ctx(this, this_thread); + + mutex::scoped_lock lock(mutex_); + + return do_wait_one(lock, this_thread, usec, ec); +} + +std::size_t scheduler::poll(boost::system::error_code& ec) { ec = boost::system::error_code(); if (outstanding_work_ == 0) @@ -190,8 +213,8 @@ std::size_t task_io_service::poll(boost::system::error_code& ec) // that are already on a thread-private queue need to be put on to the main // queue now. if (one_thread_) - if (thread_info* outer_thread_info = ctx.next_by_key()) - op_queue_.push(outer_thread_info->private_op_queue); + if (thread_info* outer_info = static_cast<thread_info*>(ctx.next_by_key())) + op_queue_.push(outer_info->private_op_queue); #endif // defined(BOOST_ASIO_HAS_THREADS) std::size_t n = 0; @@ -201,7 +224,7 @@ std::size_t task_io_service::poll(boost::system::error_code& ec) return n; } -std::size_t task_io_service::poll_one(boost::system::error_code& ec) +std::size_t scheduler::poll_one(boost::system::error_code& ec) { ec = boost::system::error_code(); if (outstanding_work_ == 0) @@ -221,41 +244,47 @@ std::size_t task_io_service::poll_one(boost::system::error_code& ec) // that are already on a thread-private queue need to be put on to the main // queue now. if (one_thread_) - if (thread_info* outer_thread_info = ctx.next_by_key()) - op_queue_.push(outer_thread_info->private_op_queue); + if (thread_info* outer_info = static_cast<thread_info*>(ctx.next_by_key())) + op_queue_.push(outer_info->private_op_queue); #endif // defined(BOOST_ASIO_HAS_THREADS) return do_poll_one(lock, this_thread, ec); } -void task_io_service::stop() +void scheduler::stop() { mutex::scoped_lock lock(mutex_); stop_all_threads(lock); } -bool task_io_service::stopped() const +bool scheduler::stopped() const { mutex::scoped_lock lock(mutex_); return stopped_; } -void task_io_service::reset() +void scheduler::restart() { mutex::scoped_lock lock(mutex_); stopped_ = false; } -void task_io_service::post_immediate_completion( - task_io_service::operation* op, bool is_continuation) +void scheduler::compensating_work_started() +{ + thread_info_base* this_thread = thread_call_stack::contains(this); + ++static_cast<thread_info*>(this_thread)->private_outstanding_work; +} + +void scheduler::post_immediate_completion( + scheduler::operation* op, bool is_continuation) { #if defined(BOOST_ASIO_HAS_THREADS) if (one_thread_ || is_continuation) { - if (thread_info* this_thread = thread_call_stack::contains(this)) + if (thread_info_base* this_thread = thread_call_stack::contains(this)) { - ++this_thread->private_outstanding_work; - this_thread->private_op_queue.push(op); + ++static_cast<thread_info*>(this_thread)->private_outstanding_work; + static_cast<thread_info*>(this_thread)->private_op_queue.push(op); return; } } @@ -269,14 +298,14 @@ void task_io_service::post_immediate_completion( wake_one_thread_and_unlock(lock); } -void task_io_service::post_deferred_completion(task_io_service::operation* op) +void scheduler::post_deferred_completion(scheduler::operation* op) { #if defined(BOOST_ASIO_HAS_THREADS) if (one_thread_) { - if (thread_info* this_thread = thread_call_stack::contains(this)) + if (thread_info_base* this_thread = thread_call_stack::contains(this)) { - this_thread->private_op_queue.push(op); + static_cast<thread_info*>(this_thread)->private_op_queue.push(op); return; } } @@ -287,17 +316,17 @@ void task_io_service::post_deferred_completion(task_io_service::operation* op) wake_one_thread_and_unlock(lock); } -void task_io_service::post_deferred_completions( - op_queue<task_io_service::operation>& ops) +void scheduler::post_deferred_completions( + op_queue<scheduler::operation>& ops) { if (!ops.empty()) { #if defined(BOOST_ASIO_HAS_THREADS) if (one_thread_) { - if (thread_info* this_thread = thread_call_stack::contains(this)) + if (thread_info_base* this_thread = thread_call_stack::contains(this)) { - this_thread->private_op_queue.push(ops); + static_cast<thread_info*>(this_thread)->private_op_queue.push(ops); return; } } @@ -309,8 +338,8 @@ void task_io_service::post_deferred_completions( } } -void task_io_service::do_dispatch( - task_io_service::operation* op) +void scheduler::do_dispatch( + scheduler::operation* op) { work_started(); mutex::scoped_lock lock(mutex_); @@ -318,15 +347,15 @@ void task_io_service::do_dispatch( wake_one_thread_and_unlock(lock); } -void task_io_service::abandon_operations( - op_queue<task_io_service::operation>& ops) +void scheduler::abandon_operations( + op_queue<scheduler::operation>& ops) { - op_queue<task_io_service::operation> ops2; + op_queue<scheduler::operation> ops2; ops2.push(ops); } -std::size_t task_io_service::do_run_one(mutex::scoped_lock& lock, - task_io_service::thread_info& this_thread, +std::size_t scheduler::do_run_one(mutex::scoped_lock& lock, + scheduler::thread_info& this_thread, const boost::system::error_code& ec) { while (!stopped_) @@ -353,7 +382,7 @@ std::size_t task_io_service::do_run_one(mutex::scoped_lock& lock, // Run the task. May throw an exception. Only block if the operation // queue is empty and we're not polling, otherwise we want to return // as soon as possible. - task_->run(!more_handlers, this_thread.private_op_queue); + task_->run(more_handlers ? 0 : -1, this_thread.private_op_queue); } else { @@ -369,7 +398,7 @@ std::size_t task_io_service::do_run_one(mutex::scoped_lock& lock, (void)on_exit; // Complete the operation. May throw an exception. Deletes the object. - o->complete(*this, ec, task_result); + o->complete(this, ec, task_result); return 1; } @@ -384,8 +413,78 @@ std::size_t task_io_service::do_run_one(mutex::scoped_lock& lock, return 0; } -std::size_t task_io_service::do_poll_one(mutex::scoped_lock& lock, - task_io_service::thread_info& this_thread, +std::size_t scheduler::do_wait_one(mutex::scoped_lock& lock, + scheduler::thread_info& this_thread, long usec, + const boost::system::error_code& ec) +{ + if (stopped_) + return 0; + + operation* o = op_queue_.front(); + if (o == 0) + { + wakeup_event_.clear(lock); + wakeup_event_.wait_for_usec(lock, usec); + usec = 0; // Wait at most once. + o = op_queue_.front(); + } + + if (o == &task_operation_) + { + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + task_interrupted_ = more_handlers; + + if (more_handlers && !one_thread_) + wakeup_event_.unlock_and_signal_one(lock); + else + lock.unlock(); + + { + task_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // Run the task. May throw an exception. Only block if the operation + // queue is empty and we're not polling, otherwise we want to return + // as soon as possible. + task_->run(more_handlers ? 0 : usec, this_thread.private_op_queue); + } + + o = op_queue_.front(); + if (o == &task_operation_) + { + if (!one_thread_) + wakeup_event_.maybe_unlock_and_signal_one(lock); + return 0; + } + } + + if (o == 0) + return 0; + + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + std::size_t task_result = o->task_result_; + + if (more_handlers && !one_thread_) + wake_one_thread_and_unlock(lock); + else + lock.unlock(); + + // Ensure the count of outstanding work is decremented on block exit. + work_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // Complete the operation. May throw an exception. Deletes the object. + o->complete(this, ec, task_result); + + return 1; +} + +std::size_t scheduler::do_poll_one(mutex::scoped_lock& lock, + scheduler::thread_info& this_thread, const boost::system::error_code& ec) { if (stopped_) @@ -404,7 +503,7 @@ std::size_t task_io_service::do_poll_one(mutex::scoped_lock& lock, // Run the task. May throw an exception. Only block if the operation // queue is empty and we're not polling, otherwise we want to return // as soon as possible. - task_->run(false, this_thread.private_op_queue); + task_->run(0, this_thread.private_op_queue); } o = op_queue_.front(); @@ -433,12 +532,12 @@ std::size_t task_io_service::do_poll_one(mutex::scoped_lock& lock, (void)on_exit; // Complete the operation. May throw an exception. Deletes the object. - o->complete(*this, ec, task_result); + o->complete(this, ec, task_result); return 1; } -void task_io_service::stop_all_threads( +void scheduler::stop_all_threads( mutex::scoped_lock& lock) { stopped_ = true; @@ -451,7 +550,7 @@ void task_io_service::stop_all_threads( } } -void task_io_service::wake_one_thread_and_unlock( +void scheduler::wake_one_thread_and_unlock( mutex::scoped_lock& lock) { if (!wakeup_event_.maybe_unlock_and_signal_one(lock)) @@ -471,6 +570,4 @@ void task_io_service::wake_one_thread_and_unlock( #include <boost/asio/detail/pop_options.hpp> -#endif // !defined(BOOST_ASIO_HAS_IOCP) - -#endif // BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP +#endif // BOOST_ASIO_DETAIL_IMPL_SCHEDULER_IPP diff --git a/boost/asio/detail/impl/select_reactor.hpp b/boost/asio/detail/impl/select_reactor.hpp index d3f28f5e61..207a045f6c 100644 --- a/boost/asio/detail/impl/select_reactor.hpp +++ b/boost/asio/detail/impl/select_reactor.hpp @@ -51,12 +51,12 @@ void select_reactor::schedule_timer(timer_queue<Time_Traits>& queue, if (shutdown_) { - io_service_.post_immediate_completion(op, false); + scheduler_.post_immediate_completion(op, false); return; } bool earliest = queue.enqueue_timer(time, timer, op); - io_service_.work_started(); + scheduler_.work_started(); if (earliest) interrupter_.interrupt(); } @@ -70,10 +70,23 @@ std::size_t select_reactor::cancel_timer(timer_queue<Time_Traits>& queue, op_queue<operation> ops; std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); lock.unlock(); - io_service_.post_deferred_completions(ops); + scheduler_.post_deferred_completions(ops); return n; } +template <typename Time_Traits> +void select_reactor::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + } // namespace detail } // namespace asio } // namespace boost diff --git a/boost/asio/detail/impl/select_reactor.ipp b/boost/asio/detail/impl/select_reactor.ipp index 869f73492b..44fab64269 100644 --- a/boost/asio/detail/impl/select_reactor.ipp +++ b/boost/asio/detail/impl/select_reactor.ipp @@ -23,7 +23,6 @@ && !defined(BOOST_ASIO_HAS_KQUEUE) \ && !defined(BOOST_ASIO_WINDOWS_RUNTIME)) -#include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fd_set_adapter.hpp> #include <boost/asio/detail/select_reactor.hpp> #include <boost/asio/detail/signal_blocker.hpp> @@ -35,9 +34,28 @@ namespace boost { namespace asio { namespace detail { -select_reactor::select_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base<select_reactor>(io_service), - io_service_(use_service<io_service_impl>(io_service)), +#if defined(BOOST_ASIO_HAS_IOCP) +class select_reactor::thread_function +{ +public: + explicit thread_function(select_reactor* r) + : this_(r) + { + } + + void operator()() + { + this_->run_thread(); + } + +private: + select_reactor* this_; +}; +#endif // defined(BOOST_ASIO_HAS_IOCP) + +select_reactor::select_reactor(boost::asio::execution_context& ctx) + : execution_context_service_base<select_reactor>(ctx), + scheduler_(use_service<scheduler_type>(ctx)), mutex_(), interrupter_(), #if defined(BOOST_ASIO_HAS_IOCP) @@ -48,17 +66,16 @@ select_reactor::select_reactor(boost::asio::io_service& io_service) { #if defined(BOOST_ASIO_HAS_IOCP) boost::asio::detail::signal_blocker sb; - thread_ = new boost::asio::detail::thread( - bind_handler(&select_reactor::call_run_thread, this)); + thread_ = new boost::asio::detail::thread(thread_function(this)); #endif // defined(BOOST_ASIO_HAS_IOCP) } select_reactor::~select_reactor() { - shutdown_service(); + shutdown(); } -void select_reactor::shutdown_service() +void select_reactor::shutdown() { boost::asio::detail::mutex::scoped_lock lock(mutex_); shutdown_ = true; @@ -84,18 +101,19 @@ void select_reactor::shutdown_service() timer_queues_.get_all_timers(ops); - io_service_.abandon_operations(ops); + scheduler_.abandon_operations(ops); } -void select_reactor::fork_service(boost::asio::io_service::fork_event fork_ev) +void select_reactor::notify_fork( + boost::asio::execution_context::fork_event fork_ev) { - if (fork_ev == boost::asio::io_service::fork_child) + if (fork_ev == boost::asio::execution_context::fork_child) interrupter_.recreate(); } void select_reactor::init_task() { - io_service_.init_task(); + scheduler_.init_task(); } int select_reactor::register_descriptor(socket_type, @@ -135,7 +153,7 @@ void select_reactor::start_op(int op_type, socket_type descriptor, } bool first = op_queue_[op_type].enqueue_operation(descriptor, op); - io_service_.work_started(); + scheduler_.work_started(); if (first) interrupter_.interrupt(); } @@ -168,7 +186,7 @@ void select_reactor::cleanup_descriptor_data( { } -void select_reactor::run(bool block, op_queue<operation>& ops) +void select_reactor::run(long usec, op_queue<operation>& ops) { boost::asio::detail::mutex::scoped_lock lock(mutex_); @@ -205,12 +223,12 @@ void select_reactor::run(bool block, op_queue<operation>& ops) // We can return immediately if there's no work to do and the reactor is // not supposed to block. - if (!block && !have_work_to_do) + if (!usec && !have_work_to_do) return; // Determine how long to block while waiting for events. timeval tv_buf = { 0, 0 }; - timeval* tv = block ? get_timeout(tv_buf) : &tv_buf; + timeval* tv = usec ? get_timeout(usec, tv_buf) : &tv_buf; lock.unlock(); @@ -259,15 +277,10 @@ void select_reactor::run_thread() lock.unlock(); op_queue<operation> ops; run(true, ops); - io_service_.post_deferred_completions(ops); + scheduler_.post_deferred_completions(ops); lock.lock(); } } - -void select_reactor::call_run_thread(select_reactor* reactor) -{ - reactor->run_thread(); -} #endif // defined(BOOST_ASIO_HAS_IOCP) void select_reactor::do_add_timer_queue(timer_queue_base& queue) @@ -282,11 +295,13 @@ void select_reactor::do_remove_timer_queue(timer_queue_base& queue) timer_queues_.erase(&queue); } -timeval* select_reactor::get_timeout(timeval& tv) +timeval* select_reactor::get_timeout(long usec, timeval& tv) { // By default we will wait no longer than 5 minutes. This will ensure that // any changes to the system clock are detected after no longer than this. - long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + const long max_usec = 5 * 60 * 1000 * 1000; + usec = timer_queues_.wait_duration_usec( + (usec < 0 || max_usec < usec) ? max_usec : usec); tv.tv_sec = usec / 1000000; tv.tv_usec = usec % 1000000; return &tv; @@ -300,7 +315,7 @@ void select_reactor::cancel_ops_unlocked(socket_type descriptor, for (int i = 0; i < max_ops; ++i) need_interrupt = op_queue_[i].cancel_operations( descriptor, ops, ec) || need_interrupt; - io_service_.post_deferred_completions(ops); + scheduler_.post_deferred_completions(ops); if (need_interrupt) interrupter_.interrupt(); } diff --git a/boost/asio/detail/impl/service_registry.hpp b/boost/asio/detail/impl/service_registry.hpp index 7ffdd029f7..11ad4cf5cc 100644 --- a/boost/asio/detail/impl/service_registry.hpp +++ b/boost/asio/detail/impl/service_registry.hpp @@ -21,64 +21,70 @@ namespace boost { namespace asio { namespace detail { -template <typename Service, typename Arg> -service_registry::service_registry( - boost::asio::io_service& o, Service*, Arg arg) - : owner_(o), - first_service_(new Service(o, arg)) -{ - boost::asio::io_service::service::key key; - init_key(key, Service::id); - first_service_->key_ = key; - first_service_->next_ = 0; -} - template <typename Service> -Service& service_registry::first_service() +Service& service_registry::use_service() { - return *static_cast<Service*>(first_service_); + execution_context::service::key key; + init_key<Service>(key, 0); + factory_type factory = &service_registry::create<Service, execution_context>; + return *static_cast<Service*>(do_use_service(key, factory, &owner_)); } template <typename Service> -Service& service_registry::use_service() +Service& service_registry::use_service(io_context& owner) { - boost::asio::io_service::service::key key; - init_key(key, Service::id); - factory_type factory = &service_registry::create<Service>; - return *static_cast<Service*>(do_use_service(key, factory)); + execution_context::service::key key; + init_key<Service>(key, 0); + factory_type factory = &service_registry::create<Service, io_context>; + return *static_cast<Service*>(do_use_service(key, factory, &owner)); } template <typename Service> void service_registry::add_service(Service* new_service) { - boost::asio::io_service::service::key key; - init_key(key, Service::id); + execution_context::service::key key; + init_key<Service>(key, 0); return do_add_service(key, new_service); } template <typename Service> bool service_registry::has_service() const { - boost::asio::io_service::service::key key; - init_key(key, Service::id); + execution_context::service::key key; + init_key<Service>(key, 0); return do_has_service(key); } +template <typename Service> +inline void service_registry::init_key( + execution_context::service::key& key, ...) +{ + init_key_from_id(key, Service::id); +} + #if !defined(BOOST_ASIO_NO_TYPEID) template <typename Service> -void service_registry::init_key(boost::asio::io_service::service::key& key, - const boost::asio::detail::service_id<Service>& /*id*/) +void service_registry::init_key(execution_context::service::key& key, + typename enable_if< + is_base_of<typename Service::key_type, Service>::value>::type*) { key.type_info_ = &typeid(typeid_wrapper<Service>); key.id_ = 0; } -#endif // !defined(BOOST_ASIO_NO_TYPEID) template <typename Service> -boost::asio::io_service::service* service_registry::create( - boost::asio::io_service& owner) +void service_registry::init_key_from_id(execution_context::service::key& key, + const service_id<Service>& /*id*/) +{ + key.type_info_ = &typeid(typeid_wrapper<Service>); + key.id_ = 0; +} +#endif // !defined(BOOST_ASIO_NO_TYPEID) + +template <typename Service, typename Owner> +execution_context::service* service_registry::create(void* owner) { - return new Service(owner); + return new Service(*static_cast<Owner*>(owner)); } } // namespace detail diff --git a/boost/asio/detail/impl/service_registry.ipp b/boost/asio/detail/impl/service_registry.ipp index 25ac8eccc6..75c3f45625 100644 --- a/boost/asio/detail/impl/service_registry.ipp +++ b/boost/asio/detail/impl/service_registry.ipp @@ -26,36 +26,45 @@ namespace boost { namespace asio { namespace detail { +service_registry::service_registry(execution_context& owner) + : owner_(owner), + first_service_(0) +{ +} + service_registry::~service_registry() { - // Shutdown all services. This must be done in a separate loop before the - // services are destroyed since the destructors of user-defined handler - // objects may try to access other service objects. - boost::asio::io_service::service* service = first_service_; +} + +void service_registry::shutdown_services() +{ + execution_context::service* service = first_service_; while (service) { - service->shutdown_service(); + service->shutdown(); service = service->next_; } +} - // Destroy all services. +void service_registry::destroy_services() +{ while (first_service_) { - boost::asio::io_service::service* next_service = first_service_->next_; + execution_context::service* next_service = first_service_->next_; destroy(first_service_); first_service_ = next_service; } } -void service_registry::notify_fork(boost::asio::io_service::fork_event fork_ev) +void service_registry::notify_fork(execution_context::fork_event fork_ev) { // Make a copy of all of the services while holding the lock. We don't want // to hold the lock while calling into each service, as it may try to call // back into this class. - std::vector<boost::asio::io_service::service*> services; + std::vector<execution_context::service*> services; { boost::asio::detail::mutex::scoped_lock lock(mutex_); - boost::asio::io_service::service* service = first_service_; + execution_context::service* service = first_service_; while (service) { services.push_back(service); @@ -68,24 +77,24 @@ void service_registry::notify_fork(boost::asio::io_service::fork_event fork_ev) // services in the vector. For the other events we want to go in the other // direction. std::size_t num_services = services.size(); - if (fork_ev == boost::asio::io_service::fork_prepare) + if (fork_ev == execution_context::fork_prepare) for (std::size_t i = 0; i < num_services; ++i) - services[i]->fork_service(fork_ev); + services[i]->notify_fork(fork_ev); else for (std::size_t i = num_services; i > 0; --i) - services[i - 1]->fork_service(fork_ev); + services[i - 1]->notify_fork(fork_ev); } -void service_registry::init_key(boost::asio::io_service::service::key& key, - const boost::asio::io_service::id& id) +void service_registry::init_key_from_id(execution_context::service::key& key, + const execution_context::id& id) { key.type_info_ = 0; key.id_ = &id; } bool service_registry::keys_match( - const boost::asio::io_service::service::key& key1, - const boost::asio::io_service::service::key& key2) + const execution_context::service::key& key1, + const execution_context::service::key& key2) { if (key1.id_ && key2.id_) if (key1.id_ == key2.id_) @@ -96,19 +105,19 @@ bool service_registry::keys_match( return false; } -void service_registry::destroy(boost::asio::io_service::service* service) +void service_registry::destroy(execution_context::service* service) { delete service; } -boost::asio::io_service::service* service_registry::do_use_service( - const boost::asio::io_service::service::key& key, - factory_type factory) +execution_context::service* service_registry::do_use_service( + const execution_context::service::key& key, + factory_type factory, void* owner) { boost::asio::detail::mutex::scoped_lock lock(mutex_); // First see if there is an existing service object with the given key. - boost::asio::io_service::service* service = first_service_; + execution_context::service* service = first_service_; while (service) { if (keys_match(service->key_, key)) @@ -120,7 +129,7 @@ boost::asio::io_service::service* service_registry::do_use_service( // at this time to allow for nested calls into this function from the new // service's constructor. lock.unlock(); - auto_service_ptr new_service = { factory(owner_) }; + auto_service_ptr new_service = { factory(owner) }; new_service.ptr_->key_ = key; lock.lock(); @@ -142,16 +151,16 @@ boost::asio::io_service::service* service_registry::do_use_service( } void service_registry::do_add_service( - const boost::asio::io_service::service::key& key, - boost::asio::io_service::service* new_service) + const execution_context::service::key& key, + execution_context::service* new_service) { - if (&owner_ != &new_service->get_io_service()) + if (&owner_ != &new_service->context()) boost::asio::detail::throw_exception(invalid_service_owner()); boost::asio::detail::mutex::scoped_lock lock(mutex_); // Check if there is an existing service object with the given key. - boost::asio::io_service::service* service = first_service_; + execution_context::service* service = first_service_; while (service) { if (keys_match(service->key_, key)) @@ -166,11 +175,11 @@ void service_registry::do_add_service( } bool service_registry::do_has_service( - const boost::asio::io_service::service::key& key) const + const execution_context::service::key& key) const { boost::asio::detail::mutex::scoped_lock lock(mutex_); - boost::asio::io_service::service* service = first_service_; + execution_context::service* service = first_service_; while (service) { if (keys_match(service->key_, key)) diff --git a/boost/asio/detail/impl/signal_set_service.ipp b/boost/asio/detail/impl/signal_set_service.ipp index 95ea8bee21..376d311471 100644 --- a/boost/asio/detail/impl/signal_set_service.ipp +++ b/boost/asio/detail/impl/signal_set_service.ipp @@ -18,10 +18,12 @@ #include <boost/asio/detail/config.hpp> #include <cstring> +#include <stdexcept> #include <boost/asio/detail/reactor.hpp> #include <boost/asio/detail/signal_blocker.hpp> #include <boost/asio/detail/signal_set_service.hpp> #include <boost/asio/detail/static_mutex.hpp> +#include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/detail/push_options.hpp> @@ -92,7 +94,7 @@ public: { } - static bool do_perform(reactor_op*) + static status do_perform(reactor_op*) { signal_state* state = get_signal_state(); @@ -102,10 +104,10 @@ public: if (signal_number >= 0 && signal_number < max_signal_number) signal_set_service::deliver_signal(signal_number); - return false; + return not_done; } - static void do_complete(io_service_impl* /*owner*/, operation* base, + static void do_complete(void* /*owner*/, operation* base, const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/) { @@ -118,12 +120,13 @@ public: // && !defined(__CYGWIN__) signal_set_service::signal_set_service( - boost::asio::io_service& io_service) - : io_service_(boost::asio::use_service<io_service_impl>(io_service)), + boost::asio::io_context& io_context) + : service_base<signal_set_service>(io_context), + io_context_(boost::asio::use_service<io_context_impl>(io_context)), #if !defined(BOOST_ASIO_WINDOWS) \ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ && !defined(__CYGWIN__) - reactor_(boost::asio::use_service<reactor>(io_service)), + reactor_(boost::asio::use_service<reactor>(io_context)), #endif // !defined(BOOST_ASIO_WINDOWS) // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) // && !defined(__CYGWIN__) @@ -151,7 +154,7 @@ signal_set_service::~signal_set_service() remove_service(this); } -void signal_set_service::shutdown_service() +void signal_set_service::shutdown() { remove_service(this); @@ -167,11 +170,11 @@ void signal_set_service::shutdown_service() } } - io_service_.abandon_operations(ops); + io_context_.abandon_operations(ops); } -void signal_set_service::fork_service( - boost::asio::io_service::fork_event fork_ev) +void signal_set_service::notify_fork( + boost::asio::io_context::fork_event fork_ev) { #if !defined(BOOST_ASIO_WINDOWS) \ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ @@ -181,7 +184,7 @@ void signal_set_service::fork_service( switch (fork_ev) { - case boost::asio::io_service::fork_prepare: + case boost::asio::io_context::fork_prepare: { int read_descriptor = state->read_descriptor_; state->fork_prepared_ = true; @@ -190,7 +193,7 @@ void signal_set_service::fork_service( reactor_.cleanup_descriptor_data(reactor_data_); } break; - case boost::asio::io_service::fork_parent: + case boost::asio::io_context::fork_parent: if (state->fork_prepared_) { int read_descriptor = state->read_descriptor_; @@ -200,7 +203,7 @@ void signal_set_service::fork_service( read_descriptor, reactor_data_, new pipe_read_op); } break; - case boost::asio::io_service::fork_child: + case boost::asio::io_context::fork_child: if (state->fork_prepared_) { boost::asio::detail::signal_blocker blocker; @@ -439,7 +442,8 @@ boost::system::error_code signal_set_service::cancel( signal_set_service::implementation_type& impl, boost::system::error_code& ec) { - BOOST_ASIO_HANDLER_OPERATION(("signal_set", &impl, "cancel")); + BOOST_ASIO_HANDLER_OPERATION((io_context_.context(), + "signal_set", &impl, 0, "cancel")); op_queue<operation> ops; { @@ -454,7 +458,7 @@ boost::system::error_code signal_set_service::cancel( } } - io_service_.post_deferred_completions(ops); + io_context_.post_deferred_completions(ops); ec = boost::system::error_code(); return ec; @@ -490,7 +494,7 @@ void signal_set_service::deliver_signal(int signal_number) reg = reg->next_in_table_; } - service->io_service_.post_deferred_completions(ops); + service->io_context_.post_deferred_completions(ops); service = service->next_; } @@ -507,6 +511,22 @@ void signal_set_service::add_service(signal_set_service* service) open_descriptors(); #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + // If an io_context object is thread-unsafe then it must be the only + // io_context used to create signal_set objects. + if (state->service_list_ != 0) + { + if (!BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER, + service->io_context_.concurrency_hint()) + || !BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER, + state->service_list_->io_context_.concurrency_hint())) + { + std::logic_error ex( + "Thread-unsafe io_context objects require " + "exclusive access to signal handling."); + boost::asio::detail::throw_exception(ex); + } + } + // Insert service into linked list of all services. service->next_ = state->service_list_; service->prev_ = 0; @@ -620,7 +640,7 @@ void signal_set_service::close_descriptors() void signal_set_service::start_wait_op( signal_set_service::implementation_type& impl, signal_op* op) { - io_service_.work_started(); + io_context_.work_started(); signal_state* state = get_signal_state(); static_mutex::scoped_lock lock(state->mutex_); @@ -632,7 +652,7 @@ void signal_set_service::start_wait_op( { --reg->undelivered_; op->signal_number_ = reg->signal_number_; - io_service_.post_deferred_completion(op); + io_context_.post_deferred_completion(op); return; } diff --git a/boost/asio/detail/impl/socket_ops.ipp b/boost/asio/detail/impl/socket_ops.ipp index c9683f4a09..94be0f280c 100644 --- a/boost/asio/detail/impl/socket_ops.ipp +++ b/boost/asio/detail/impl/socket_ops.ipp @@ -169,7 +169,7 @@ socket_type sync_accept(socket_type s, state_type state, return invalid_socket; // Wait for socket to become ready. - if (socket_ops::poll_read(s, 0, ec) < 0) + if (socket_ops::poll_read(s, 0, -1, ec) < 0) return invalid_socket; } } @@ -242,8 +242,6 @@ bool non_blocking_accept(socket_type s, if (ec == boost::asio::error::would_block || ec == boost::asio::error::try_again) { - if (state & user_set_non_blocking) - return true; // Fall through to retry operation. } else if (ec == boost::asio::error::connection_aborted) @@ -506,7 +504,7 @@ void sync_connect(socket_type s, const socket_addr_type* addr, } // Wait for socket to become ready. - if (socket_ops::poll_connect(s, ec) < 0) + if (socket_ops::poll_connect(s, -1, ec) < 0) return; // Get the error code from the connect operation. @@ -773,6 +771,8 @@ signed_size_type recv(socket_type s, buf* bufs, size_t count, ec = boost::asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) ec = boost::asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + ec.assign(0, ec.category()); if (result != 0) return socket_error_retval; ec = boost::system::error_code(); @@ -828,7 +828,7 @@ size_t sync_recv(socket_type s, state_type state, buf* bufs, return 0; // Wait for socket to become ready. - if (socket_ops::poll_read(s, 0, ec) < 0) + if (socket_ops::poll_read(s, 0, -1, ec) < 0) return 0; } } @@ -851,6 +851,10 @@ void complete_iocp_recv(state_type state, { ec = boost::asio::error::connection_refused; } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + ec.assign(0, ec.category()); + } // Check for connection closed. else if (!ec && bytes_transferred == 0 @@ -921,6 +925,8 @@ signed_size_type recvfrom(socket_type s, buf* bufs, size_t count, ec = boost::asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) ec = boost::asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + ec.assign(0, ec.category()); if (result != 0) return socket_error_retval; ec = boost::system::error_code(); @@ -967,7 +973,7 @@ size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, return 0; // Wait for socket to become ready. - if (socket_ops::poll_read(s, 0, ec) < 0) + if (socket_ops::poll_read(s, 0, -1, ec) < 0) return 0; } } @@ -990,6 +996,10 @@ void complete_iocp_recvfrom( { ec = boost::asio::error::connection_refused; } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + ec.assign(0, ec.category()); + } } #else // defined(BOOST_ASIO_HAS_IOCP) @@ -1080,7 +1090,7 @@ size_t sync_recvmsg(socket_type s, state_type state, return 0; // Wait for socket to become ready. - if (socket_ops::poll_read(s, 0, ec) < 0) + if (socket_ops::poll_read(s, 0, -1, ec) < 0) return 0; } } @@ -1103,6 +1113,10 @@ void complete_iocp_recvmsg( { ec = boost::asio::error::connection_refused; } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + ec.assign(0, ec.category()); + } } #else // defined(BOOST_ASIO_HAS_IOCP) @@ -1207,7 +1221,7 @@ size_t sync_send(socket_type s, state_type state, const buf* bufs, return 0; // Wait for socket to become ready. - if (socket_ops::poll_write(s, 0, ec) < 0) + if (socket_ops::poll_write(s, 0, -1, ec) < 0) return 0; } } @@ -1331,7 +1345,7 @@ size_t sync_sendto(socket_type s, state_type state, const buf* bufs, return 0; // Wait for socket to become ready. - if (socket_ops::poll_write(s, 0, ec) < 0) + if (socket_ops::poll_write(s, 0, -1, ec) < 0) return 0; } } @@ -1785,7 +1799,8 @@ int select(int nfds, fd_set* readfds, fd_set* writefds, #endif } -int poll_read(socket_type s, state_type state, boost::system::error_code& ec) +int poll_read(socket_type s, state_type state, + int msec, boost::system::error_code& ec) { if (s == invalid_socket) { @@ -1799,10 +1814,22 @@ int poll_read(socket_type s, state_type state, boost::system::error_code& ec) fd_set fds; FD_ZERO(&fds); FD_SET(s, &fds); - timeval zero_timeout; - zero_timeout.tv_sec = 0; - zero_timeout.tv_usec = 0; - timeval* timeout = (state & user_set_non_blocking) ? &zero_timeout : 0; + timeval timeout_obj; + timeval* timeout; + if (state & user_set_non_blocking) + { + timeout_obj.tv_sec = 0; + timeout_obj.tv_usec = 0; + timeout = &timeout_obj; + } + else if (msec >= 0) + { + timeout_obj.tv_sec = msec / 1000; + timeout_obj.tv_usec = (msec % 1000) * 1000; + timeout = &timeout_obj; + } + else + timeout = 0; clear_last_error(); int result = error_wrapper(::select(s + 1, &fds, 0, 0, timeout), ec); #else // defined(BOOST_ASIO_WINDOWS) @@ -1812,7 +1839,7 @@ int poll_read(socket_type s, state_type state, boost::system::error_code& ec) fds.fd = s; fds.events = POLLIN; fds.revents = 0; - int timeout = (state & user_set_non_blocking) ? 0 : -1; + int timeout = (state & user_set_non_blocking) ? 0 : msec; clear_last_error(); int result = error_wrapper(::poll(&fds, 1, timeout), ec); #endif // defined(BOOST_ASIO_WINDOWS) @@ -1826,7 +1853,8 @@ int poll_read(socket_type s, state_type state, boost::system::error_code& ec) return result; } -int poll_write(socket_type s, state_type state, boost::system::error_code& ec) +int poll_write(socket_type s, state_type state, + int msec, boost::system::error_code& ec) { if (s == invalid_socket) { @@ -1840,10 +1868,22 @@ int poll_write(socket_type s, state_type state, boost::system::error_code& ec) fd_set fds; FD_ZERO(&fds); FD_SET(s, &fds); - timeval zero_timeout; - zero_timeout.tv_sec = 0; - zero_timeout.tv_usec = 0; - timeval* timeout = (state & user_set_non_blocking) ? &zero_timeout : 0; + timeval timeout_obj; + timeval* timeout; + if (state & user_set_non_blocking) + { + timeout_obj.tv_sec = 0; + timeout_obj.tv_usec = 0; + timeout = &timeout_obj; + } + else if (msec >= 0) + { + timeout_obj.tv_sec = msec / 1000; + timeout_obj.tv_usec = (msec % 1000) * 1000; + timeout = &timeout_obj; + } + else + timeout = 0; clear_last_error(); int result = error_wrapper(::select(s + 1, 0, &fds, 0, timeout), ec); #else // defined(BOOST_ASIO_WINDOWS) @@ -1853,7 +1893,7 @@ int poll_write(socket_type s, state_type state, boost::system::error_code& ec) fds.fd = s; fds.events = POLLOUT; fds.revents = 0; - int timeout = (state & user_set_non_blocking) ? 0 : -1; + int timeout = (state & user_set_non_blocking) ? 0 : msec; clear_last_error(); int result = error_wrapper(::poll(&fds, 1, timeout), ec); #endif // defined(BOOST_ASIO_WINDOWS) @@ -1867,7 +1907,61 @@ int poll_write(socket_type s, state_type state, boost::system::error_code& ec) return result; } -int poll_connect(socket_type s, boost::system::error_code& ec) +int poll_error(socket_type s, state_type state, + int msec, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + timeval timeout_obj; + timeval* timeout; + if (state & user_set_non_blocking) + { + timeout_obj.tv_sec = 0; + timeout_obj.tv_usec = 0; + timeout = &timeout_obj; + } + else if (msec >= 0) + { + timeout_obj.tv_sec = msec / 1000; + timeout_obj.tv_usec = (msec % 1000) * 1000; + timeout = &timeout_obj; + } + else + timeout = 0; + clear_last_error(); + int result = error_wrapper(::select(s + 1, 0, 0, &fds, timeout), ec); +#else // defined(BOOST_ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLPRI | POLLERR | POLLHUP; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : msec; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, timeout), ec); +#endif // defined(BOOST_ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + if (result == 0) + ec = (state & user_set_non_blocking) + ? boost::asio::error::would_block : boost::system::error_code(); + else if (result > 0) + ec = boost::system::error_code(); + return result; +} + +int poll_connect(socket_type s, int msec, boost::system::error_code& ec) { if (s == invalid_socket) { @@ -1884,9 +1978,19 @@ int poll_connect(socket_type s, boost::system::error_code& ec) fd_set except_fds; FD_ZERO(&except_fds); FD_SET(s, &except_fds); + timeval timeout_obj; + timeval* timeout; + if (msec >= 0) + { + timeout_obj.tv_sec = msec / 1000; + timeout_obj.tv_usec = (msec % 1000) * 1000; + timeout = &timeout_obj; + } + else + timeout = 0; clear_last_error(); int result = error_wrapper(::select( - s + 1, 0, &write_fds, &except_fds, 0), ec); + s + 1, 0, &write_fds, &except_fds, timeout), ec); if (result >= 0) ec = boost::system::error_code(); return result; @@ -1898,7 +2002,7 @@ int poll_connect(socket_type s, boost::system::error_code& ec) fds.events = POLLOUT; fds.revents = 0; clear_last_error(); - int result = error_wrapper(::poll(&fds, 1, -1), ec); + int result = error_wrapper(::poll(&fds, 1, msec), ec); if (result >= 0) ec = boost::system::error_code(); return result; @@ -3346,7 +3450,6 @@ boost::system::error_code getnameinfo(const socket_addr_type* addr, using namespace std; // For memcpy. sockaddr_storage_type tmp_addr; memcpy(&tmp_addr, addr, addrlen); - tmp_addr.ss_len = addrlen; addr = reinterpret_cast<socket_addr_type*>(&tmp_addr); clear_last_error(); return getnameinfo_emulation(addr, addrlen, diff --git a/boost/asio/detail/impl/strand_executor_service.hpp b/boost/asio/detail/impl/strand_executor_service.hpp new file mode 100644 index 0000000000..6821c2ec64 --- /dev/null +++ b/boost/asio/detail/impl/strand_executor_service.hpp @@ -0,0 +1,181 @@ +// +// detail/impl/strand_executor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP +#define BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/call_stack.hpp> +#include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/recycling_allocator.hpp> +#include <boost/asio/executor_work_guard.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +template <typename Executor> +class strand_executor_service::invoker +{ +public: + invoker(const implementation_type& impl, Executor& ex) + : impl_(impl), + work_(ex) + { + } + + invoker(const invoker& other) + : impl_(other.impl_), + work_(other.work_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + invoker(invoker&& other) + : impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)), + work_(BOOST_ASIO_MOVE_CAST(executor_work_guard<Executor>)(other.work_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + struct on_invoker_exit + { + invoker* this_; + + ~on_invoker_exit() + { + this_->impl_->mutex_->lock(); + this_->impl_->ready_queue_.push(this_->impl_->waiting_queue_); + bool more_handlers = this_->impl_->locked_ = + !this_->impl_->ready_queue_.empty(); + this_->impl_->mutex_->unlock(); + + if (more_handlers) + { + Executor ex(this_->work_.get_executor()); + recycling_allocator<void> allocator; + ex.post(BOOST_ASIO_MOVE_CAST(invoker)(*this_), allocator); + } + } + }; + + void operator()() + { + // Indicate that this strand is executing on the current thread. + call_stack<strand_impl>::context ctx(impl_.get()); + + // Ensure the next handler, if any, is scheduled on block exit. + on_invoker_exit on_exit = { this }; + (void)on_exit; + + // Run all ready handlers. No lock is required since the ready queue is + // accessed only within the strand. + boost::system::error_code ec; + while (scheduler_operation* o = impl_->ready_queue_.front()) + { + impl_->ready_queue_.pop(); + o->complete(impl_.get(), ec, 0); + } + } + +private: + implementation_type impl_; + executor_work_guard<Executor> work_; +}; + +template <typename Executor, typename Function, typename Allocator> +void strand_executor_service::dispatch(const implementation_type& impl, + Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a) +{ + typedef typename decay<Function>::type function_type; + + // If we are already in the strand then the function can run immediately. + if (call_stack<strand_impl>::contains(impl.get())) + { + // Make a local, non-const copy of the function. + function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(function)); + + fenced_block b(fenced_block::full); + boost_asio_handler_invoke_helpers::invoke(tmp, tmp); + return; + } + + // Allocate and construct an operation to wrap the function. + typedef executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(function), a); + + BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, + "strand_executor", impl.get(), 0, "dispatch")); + + // Add the function to the strand and schedule the strand if required. + bool first = enqueue(impl, p.p); + p.v = p.p = 0; + if (first) + ex.dispatch(invoker<Executor>(impl, ex), a); +} + +// Request invocation of the given function and return immediately. +template <typename Executor, typename Function, typename Allocator> +void strand_executor_service::post(const implementation_type& impl, + Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a) +{ + typedef typename decay<Function>::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(function), a); + + BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, + "strand_executor", impl.get(), 0, "post")); + + // Add the function to the strand and schedule the strand if required. + bool first = enqueue(impl, p.p); + p.v = p.p = 0; + if (first) + ex.post(invoker<Executor>(impl, ex), a); +} + +// Request invocation of the given function and return immediately. +template <typename Executor, typename Function, typename Allocator> +void strand_executor_service::defer(const implementation_type& impl, + Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a) +{ + typedef typename decay<Function>::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(function), a); + + BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, + "strand_executor", impl.get(), 0, "defer")); + + // Add the function to the strand and schedule the strand if required. + bool first = enqueue(impl, p.p); + p.v = p.p = 0; + if (first) + ex.defer(invoker<Executor>(impl, ex), a); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP diff --git a/boost/asio/detail/impl/strand_executor_service.ipp b/boost/asio/detail/impl/strand_executor_service.ipp new file mode 100644 index 0000000000..353304ae27 --- /dev/null +++ b/boost/asio/detail/impl/strand_executor_service.ipp @@ -0,0 +1,126 @@ +// +// detail/impl/strand_executor_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/strand_executor_service.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +strand_executor_service::strand_executor_service(execution_context& ctx) + : execution_context_service_base<strand_executor_service>(ctx), + mutex_(), + salt_(0), + impl_list_(0) +{ +} + +void strand_executor_service::shutdown() +{ + op_queue<scheduler_operation> ops; + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + strand_impl* impl = impl_list_; + while (impl) + { + ops.push(impl->waiting_queue_); + ops.push(impl->ready_queue_); + impl = impl->next_; + } +} + +strand_executor_service::implementation_type +strand_executor_service::create_implementation() +{ + implementation_type new_impl(new strand_impl); + new_impl->locked_ = false; + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // Select a mutex from the pool of shared mutexes. + std::size_t salt = salt_++; + std::size_t mutex_index = reinterpret_cast<std::size_t>(new_impl.get()); + mutex_index += (reinterpret_cast<std::size_t>(new_impl.get()) >> 3); + mutex_index ^= salt + 0x9e3779b9 + (mutex_index << 6) + (mutex_index >> 2); + mutex_index = mutex_index % num_mutexes; + if (!mutexes_[mutex_index].get()) + mutexes_[mutex_index].reset(new mutex); + new_impl->mutex_ = mutexes_[mutex_index].get(); + + // Insert implementation into linked list of all implementations. + new_impl->next_ = impl_list_; + new_impl->prev_ = 0; + if (impl_list_) + impl_list_->prev_ = new_impl.get(); + impl_list_ = new_impl.get(); + new_impl->service_ = this; + + return new_impl; +} + +strand_executor_service::strand_impl::~strand_impl() +{ + boost::asio::detail::mutex::scoped_lock lock(service_->mutex_); + + // Remove implementation from linked list of all implementations. + if (service_->impl_list_ == this) + service_->impl_list_ = next_; + if (prev_) + prev_->next_ = next_; + if (next_) + next_->prev_= prev_; +} + +bool strand_executor_service::enqueue(const implementation_type& impl, + scheduler_operation* op) +{ + impl->mutex_->lock(); + if (impl->locked_) + { + // Some other function already holds the strand lock. Enqueue for later. + impl->waiting_queue_.push(op); + impl->mutex_->unlock(); + return false; + } + else + { + // The function is acquiring the strand lock and so is responsible for + // scheduling the strand. + impl->locked_ = true; + impl->mutex_->unlock(); + impl->ready_queue_.push(op); + return true; + } +} + +bool strand_executor_service::running_in_this_thread( + const implementation_type& impl) +{ + return !!call_stack<strand_impl>::contains(impl.get()); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP diff --git a/boost/asio/detail/impl/strand_service.hpp b/boost/asio/detail/impl/strand_service.hpp index 4167f686d1..df21099971 100644 --- a/boost/asio/detail/impl/strand_service.hpp +++ b/boost/asio/detail/impl/strand_service.hpp @@ -15,12 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/call_stack.hpp> #include <boost/asio/detail/completion_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/push_options.hpp> @@ -36,7 +36,7 @@ inline strand_service::strand_impl::strand_impl() struct strand_service::on_dispatch_exit { - io_service_impl* io_service_; + io_context_impl* io_context_; strand_impl* impl_; ~on_dispatch_exit() @@ -47,7 +47,7 @@ struct strand_service::on_dispatch_exit impl_->mutex_.unlock(); if (more_handlers) - io_service_->post_immediate_completion(impl_, false); + io_context_->post_immediate_completion(impl_, false); } }; @@ -66,11 +66,11 @@ void strand_service::dispatch(strand_service::implementation_type& impl, // Allocate and construct an operation to wrap the handler. typedef completion_handler<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "strand", impl, "dispatch")); + BOOST_ASIO_HANDLER_CREATION((this->context(), + *p.p, "strand", impl, 0, "dispatch")); bool dispatch_immediately = do_dispatch(impl, p.p); operation* o = p.p; @@ -82,15 +82,15 @@ void strand_service::dispatch(strand_service::implementation_type& impl, call_stack<strand_impl>::context ctx(impl); // Ensure the next handler, if any, is scheduled on block exit. - on_dispatch_exit on_exit = { &io_service_, impl }; + on_dispatch_exit on_exit = { &io_context_, impl }; (void)on_exit; completion_handler<Handler>::do_complete( - &io_service_, o, boost::system::error_code(), 0); + &io_context_, o, boost::system::error_code(), 0); } } -// Request the io_service to invoke the given handler and return immediately. +// Request the io_context to invoke the given handler and return immediately. template <typename Handler> void strand_service::post(strand_service::implementation_type& impl, Handler& handler) @@ -101,11 +101,11 @@ void strand_service::post(strand_service::implementation_type& impl, // Allocate and construct an operation to wrap the handler. typedef completion_handler<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "strand", impl, "post")); + BOOST_ASIO_HANDLER_CREATION((this->context(), + *p.p, "strand", impl, 0, "post")); do_post(impl, p.p, is_continuation); p.v = p.p = 0; diff --git a/boost/asio/detail/impl/strand_service.ipp b/boost/asio/detail/impl/strand_service.ipp index 54ecde2cc7..e92355d837 100644 --- a/boost/asio/detail/impl/strand_service.ipp +++ b/boost/asio/detail/impl/strand_service.ipp @@ -27,7 +27,7 @@ namespace detail { struct strand_service::on_do_complete_exit { - io_service_impl* owner_; + io_context_impl* owner_; strand_impl* impl_; ~on_do_complete_exit() @@ -42,15 +42,15 @@ struct strand_service::on_do_complete_exit } }; -strand_service::strand_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base<strand_service>(io_service), - io_service_(boost::asio::use_service<io_service_impl>(io_service)), +strand_service::strand_service(boost::asio::io_context& io_context) + : boost::asio::detail::service_base<strand_service>(io_context), + io_context_(boost::asio::use_service<io_context_impl>(io_context)), mutex_(), salt_(0) { } -void strand_service::shutdown_service() +void strand_service::shutdown() { op_queue<operation> ops; @@ -93,9 +93,9 @@ bool strand_service::running_in_this_thread( bool strand_service::do_dispatch(implementation_type& impl, operation* op) { - // If we are running inside the io_service, and no other handler already + // If we are running inside the io_context, and no other handler already // holds the strand lock, then the handler can run immediately. - bool can_dispatch = io_service_.can_dispatch(); + bool can_dispatch = io_context_.can_dispatch(); impl->mutex_.lock(); if (can_dispatch && !impl->locked_) { @@ -118,7 +118,7 @@ bool strand_service::do_dispatch(implementation_type& impl, operation* op) impl->locked_ = true; impl->mutex_.unlock(); impl->ready_queue_.push(op); - io_service_.post_immediate_completion(impl, false); + io_context_.post_immediate_completion(impl, false); } return false; @@ -141,11 +141,11 @@ void strand_service::do_post(implementation_type& impl, impl->locked_ = true; impl->mutex_.unlock(); impl->ready_queue_.push(op); - io_service_.post_immediate_completion(impl, is_continuation); + io_context_.post_immediate_completion(impl, is_continuation); } } -void strand_service::do_complete(io_service_impl* owner, operation* base, +void strand_service::do_complete(void* owner, operation* base, const boost::system::error_code& ec, std::size_t /*bytes_transferred*/) { if (owner) @@ -156,15 +156,16 @@ void strand_service::do_complete(io_service_impl* owner, operation* base, call_stack<strand_impl>::context ctx(impl); // Ensure the next handler, if any, is scheduled on block exit. - on_do_complete_exit on_exit = { owner, impl }; - (void)on_exit; + on_do_complete_exit on_exit; + on_exit.owner_ = static_cast<io_context_impl*>(owner); + on_exit.impl_ = impl; // Run all ready handlers. No lock is required since the ready queue is // accessed only within the strand. while (operation* o = impl->ready_queue_.front()) { impl->ready_queue_.pop(); - o->complete(*owner, ec, 0); + o->complete(owner, ec, 0); } } } diff --git a/boost/asio/detail/impl/task_io_service.hpp b/boost/asio/detail/impl/task_io_service.hpp deleted file mode 100644 index 09b4ba6985..0000000000 --- a/boost/asio/detail/impl/task_io_service.hpp +++ /dev/null @@ -1,80 +0,0 @@ -// -// detail/impl/task_io_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2017 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) -// - -#ifndef BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP -#define BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include <boost/asio/detail/addressof.hpp> -#include <boost/asio/detail/completion_handler.hpp> -#include <boost/asio/detail/fenced_block.hpp> -#include <boost/asio/detail/handler_alloc_helpers.hpp> -#include <boost/asio/detail/handler_cont_helpers.hpp> -#include <boost/asio/detail/handler_invoke_helpers.hpp> - -#include <boost/asio/detail/push_options.hpp> - -namespace boost { -namespace asio { -namespace detail { - -template <typename Handler> -void task_io_service::dispatch(Handler& handler) -{ - if (thread_call_stack::contains(this)) - { - fenced_block b(fenced_block::full); - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - else - { - // Allocate and construct an operation to wrap the handler. - typedef completion_handler<Handler> op; - typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; - p.p = new (p.v) op(handler); - - BOOST_ASIO_HANDLER_CREATION((p.p, "io_service", this, "dispatch")); - - do_dispatch(p.p); - p.v = p.p = 0; - } -} - -template <typename Handler> -void task_io_service::post(Handler& handler) -{ - bool is_continuation = - boost_asio_handler_cont_helpers::is_continuation(handler); - - // Allocate and construct an operation to wrap the handler. - typedef completion_handler<Handler> op; - typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; - p.p = new (p.v) op(handler); - - BOOST_ASIO_HANDLER_CREATION((p.p, "io_service", this, "post")); - - post_immediate_completion(p.p, is_continuation); - p.v = p.p = 0; -} - -} // namespace detail -} // namespace asio -} // namespace boost - -#include <boost/asio/detail/pop_options.hpp> - -#endif // BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP diff --git a/boost/asio/detail/impl/timer_queue_ptime.ipp b/boost/asio/detail/impl/timer_queue_ptime.ipp index 0216d20ba5..885ee7d06e 100644 --- a/boost/asio/detail/impl/timer_queue_ptime.ipp +++ b/boost/asio/detail/impl/timer_queue_ptime.ipp @@ -16,12 +16,13 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + #include <boost/asio/detail/timer_queue_ptime.hpp> #include <boost/asio/detail/push_options.hpp> -#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) - namespace boost { namespace asio { namespace detail { @@ -75,12 +76,18 @@ std::size_t timer_queue<time_traits<boost::posix_time::ptime> >::cancel_timer( return impl_.cancel_timer(timer, ops, max_cancelled); } +void timer_queue<time_traits<boost::posix_time::ptime> >::move_timer( + per_timer_data& target, per_timer_data& source) +{ + impl_.move_timer(target, source); +} + } // namespace detail } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) - #include <boost/asio/detail/pop_options.hpp> +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + #endif // BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP diff --git a/boost/asio/detail/impl/win_event.ipp b/boost/asio/detail/impl/win_event.ipp index 2519d3165d..4e084de2ba 100644 --- a/boost/asio/detail/impl/win_event.ipp +++ b/boost/asio/detail/impl/win_event.ipp @@ -33,7 +33,8 @@ win_event::win_event() : state_(0) { #if defined(BOOST_ASIO_WINDOWS_APP) - events_[0] = ::CreateEventExW(0, 0, CREATE_EVENT_MANUAL_RESET, 0); + events_[0] = ::CreateEventExW(0, 0, + CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); #else // defined(BOOST_ASIO_WINDOWS_APP) events_[0] = ::CreateEventW(0, true, false, 0); #endif // defined(BOOST_ASIO_WINDOWS_APP) @@ -46,7 +47,7 @@ win_event::win_event() } #if defined(BOOST_ASIO_WINDOWS_APP) - events_[1] = ::CreateEventExW(0, 0, 0, 0); + events_[1] = ::CreateEventExW(0, 0, 0, EVENT_ALL_ACCESS); #else // defined(BOOST_ASIO_WINDOWS_APP) events_[1] = ::CreateEventW(0, false, false, 0); #endif // defined(BOOST_ASIO_WINDOWS_APP) diff --git a/boost/asio/detail/impl/win_iocp_handle_service.ipp b/boost/asio/detail/impl/win_iocp_handle_service.ipp index ea513bc1dd..4f35a1c0a8 100644 --- a/boost/asio/detail/impl/win_iocp_handle_service.ipp +++ b/boost/asio/detail/impl/win_iocp_handle_service.ipp @@ -67,14 +67,15 @@ public: }; win_iocp_handle_service::win_iocp_handle_service( - boost::asio::io_service& io_service) - : iocp_service_(boost::asio::use_service<win_iocp_io_service>(io_service)), + boost::asio::io_context& io_context) + : service_base<win_iocp_handle_service>(io_context), + iocp_service_(boost::asio::use_service<win_iocp_io_context>(io_context)), mutex_(), impl_list_(0) { } -void win_iocp_handle_service::shutdown_service() +void win_iocp_handle_service::shutdown() { // Close all implementations, causing all operations to complete. boost::asio::detail::mutex::scoped_lock lock(mutex_); @@ -200,7 +201,8 @@ boost::system::error_code win_iocp_handle_service::close( { if (is_open(impl)) { - BOOST_ASIO_HANDLER_OPERATION(("handle", &impl, "close")); + BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle", + &impl, reinterpret_cast<uintmax_t>(impl.handle_), "close")); if (!::CloseHandle(impl.handle_)) { @@ -234,7 +236,8 @@ boost::system::error_code win_iocp_handle_service::cancel( return ec; } - BOOST_ASIO_HANDLER_OPERATION(("handle", &impl, "cancel")); + BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle", + &impl, reinterpret_cast<uintmax_t>(impl.handle_), "cancel")); if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) @@ -304,7 +307,7 @@ size_t win_iocp_handle_service::do_write( } // A request to write 0 bytes on a handle is a no-op. - if (boost::asio::buffer_size(buffer) == 0) + if (buffer.size() == 0) { ec = boost::system::error_code(); return 0; @@ -319,9 +322,8 @@ size_t win_iocp_handle_service::do_write( // Write the data. overlapped.Offset = offset & 0xFFFFFFFF; overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::WriteFile(impl.handle_, - boost::asio::buffer_cast<LPCVOID>(buffer), - static_cast<DWORD>(boost::asio::buffer_size(buffer)), 0, &overlapped); + BOOL ok = ::WriteFile(impl.handle_, buffer.data(), + static_cast<DWORD>(buffer.size()), 0, &overlapped); if (!ok) { DWORD last_error = ::GetLastError(); @@ -360,7 +362,7 @@ void win_iocp_handle_service::start_write_op( { iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); } - else if (boost::asio::buffer_size(buffer) == 0) + else if (buffer.size() == 0) { // A request to write 0 bytes on a handle is a no-op. iocp_service_.on_completion(op); @@ -370,9 +372,8 @@ void win_iocp_handle_service::start_write_op( DWORD bytes_transferred = 0; op->Offset = offset & 0xFFFFFFFF; op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::WriteFile(impl.handle_, - boost::asio::buffer_cast<LPCVOID>(buffer), - static_cast<DWORD>(boost::asio::buffer_size(buffer)), + BOOL ok = ::WriteFile(impl.handle_, buffer.data(), + static_cast<DWORD>(buffer.size()), &bytes_transferred, op); DWORD last_error = ::GetLastError(); if (!ok && last_error != ERROR_IO_PENDING @@ -398,7 +399,7 @@ size_t win_iocp_handle_service::do_read( } // A request to read 0 bytes on a stream handle is a no-op. - if (boost::asio::buffer_size(buffer) == 0) + if (buffer.size() == 0) { ec = boost::system::error_code(); return 0; @@ -413,9 +414,8 @@ size_t win_iocp_handle_service::do_read( // Read some data. overlapped.Offset = offset & 0xFFFFFFFF; overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::ReadFile(impl.handle_, - boost::asio::buffer_cast<LPVOID>(buffer), - static_cast<DWORD>(boost::asio::buffer_size(buffer)), 0, &overlapped); + BOOL ok = ::ReadFile(impl.handle_, buffer.data(), + static_cast<DWORD>(buffer.size()), 0, &overlapped); if (!ok) { DWORD last_error = ::GetLastError(); @@ -468,7 +468,7 @@ void win_iocp_handle_service::start_read_op( { iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); } - else if (boost::asio::buffer_size(buffer) == 0) + else if (buffer.size() == 0) { // A request to read 0 bytes on a handle is a no-op. iocp_service_.on_completion(op); @@ -478,9 +478,8 @@ void win_iocp_handle_service::start_read_op( DWORD bytes_transferred = 0; op->Offset = offset & 0xFFFFFFFF; op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::ReadFile(impl.handle_, - boost::asio::buffer_cast<LPVOID>(buffer), - static_cast<DWORD>(boost::asio::buffer_size(buffer)), + BOOL ok = ::ReadFile(impl.handle_, buffer.data(), + static_cast<DWORD>(buffer.size()), &bytes_transferred, op); DWORD last_error = ::GetLastError(); if (!ok && last_error != ERROR_IO_PENDING @@ -508,7 +507,8 @@ void win_iocp_handle_service::close_for_destruction(implementation_type& impl) { if (is_open(impl)) { - BOOST_ASIO_HANDLER_OPERATION(("handle", &impl, "close")); + BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle", + &impl, reinterpret_cast<uintmax_t>(impl.handle_), "close")); ::CloseHandle(impl.handle_); impl.handle_ = INVALID_HANDLE_VALUE; diff --git a/boost/asio/detail/impl/win_iocp_io_service.hpp b/boost/asio/detail/impl/win_iocp_io_context.hpp index e3505cb852..948b0c93d4 100644 --- a/boost/asio/detail/impl/win_iocp_io_service.hpp +++ b/boost/asio/detail/impl/win_iocp_io_context.hpp @@ -1,5 +1,5 @@ // -// detail/impl/win_iocp_io_service.hpp +// detail/impl/win_iocp_io_context.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -8,8 +8,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP -#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once @@ -19,11 +19,11 @@ #if defined(BOOST_ASIO_HAS_IOCP) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/completion_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/push_options.hpp> @@ -31,62 +31,22 @@ namespace boost { namespace asio { namespace detail { -template <typename Handler> -void win_iocp_io_service::dispatch(Handler& handler) -{ - if (thread_call_stack::contains(this)) - { - fenced_block b(fenced_block::full); - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - else - { - // Allocate and construct an operation to wrap the handler. - typedef completion_handler<Handler> op; - typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; - p.p = new (p.v) op(handler); - - BOOST_ASIO_HANDLER_CREATION((p.p, "io_service", this, "dispatch")); - - post_immediate_completion(p.p, false); - p.v = p.p = 0; - } -} - -template <typename Handler> -void win_iocp_io_service::post(Handler& handler) -{ - // Allocate and construct an operation to wrap the handler. - typedef completion_handler<Handler> op; - typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; - p.p = new (p.v) op(handler); - - BOOST_ASIO_HANDLER_CREATION((p.p, "io_service", this, "post")); - - post_immediate_completion(p.p, false); - p.v = p.p = 0; -} - template <typename Time_Traits> -void win_iocp_io_service::add_timer_queue( +void win_iocp_io_context::add_timer_queue( timer_queue<Time_Traits>& queue) { do_add_timer_queue(queue); } template <typename Time_Traits> -void win_iocp_io_service::remove_timer_queue( +void win_iocp_io_context::remove_timer_queue( timer_queue<Time_Traits>& queue) { do_remove_timer_queue(queue); } template <typename Time_Traits> -void win_iocp_io_service::schedule_timer(timer_queue<Time_Traits>& queue, +void win_iocp_io_context::schedule_timer(timer_queue<Time_Traits>& queue, const typename Time_Traits::time_type& time, typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op) { @@ -106,7 +66,7 @@ void win_iocp_io_service::schedule_timer(timer_queue<Time_Traits>& queue, } template <typename Time_Traits> -std::size_t win_iocp_io_service::cancel_timer(timer_queue<Time_Traits>& queue, +std::size_t win_iocp_io_context::cancel_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled) { @@ -121,6 +81,19 @@ std::size_t win_iocp_io_service::cancel_timer(timer_queue<Time_Traits>& queue, return n; } +template <typename Time_Traits> +void win_iocp_io_context::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from) +{ + boost::asio::detail::mutex::scoped_lock lock(dispatch_mutex_); + op_queue<operation> ops; + queue.cancel_timer(to, ops); + queue.move_timer(to, from); + lock.unlock(); + post_deferred_completions(ops); +} + } // namespace detail } // namespace asio } // namespace boost @@ -129,4 +102,4 @@ std::size_t win_iocp_io_service::cancel_timer(timer_queue<Time_Traits>& queue, #endif // defined(BOOST_ASIO_HAS_IOCP) -#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP diff --git a/boost/asio/detail/impl/win_iocp_io_service.ipp b/boost/asio/detail/impl/win_iocp_io_context.ipp index a5bfcbbdea..9071836aa9 100644 --- a/boost/asio/detail/impl/win_iocp_io_service.ipp +++ b/boost/asio/detail/impl/win_iocp_io_context.ipp @@ -1,5 +1,5 @@ // -// detail/impl/win_iocp_io_service.ipp +// detail/impl/win_iocp_io_context.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -8,8 +8,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP -#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once @@ -20,13 +20,12 @@ #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> #include <boost/asio/detail/cstdint.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/throw_error.hpp> -#include <boost/asio/detail/win_iocp_io_service.hpp> +#include <boost/asio/detail/win_iocp_io_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -34,51 +33,51 @@ namespace boost { namespace asio { namespace detail { -struct win_iocp_io_service::work_finished_on_block_exit +struct win_iocp_io_context::work_finished_on_block_exit { ~work_finished_on_block_exit() { - io_service_->work_finished(); + io_context_->work_finished(); } - win_iocp_io_service* io_service_; + win_iocp_io_context* io_context_; }; -struct win_iocp_io_service::timer_thread_function +struct win_iocp_io_context::timer_thread_function { void operator()() { - while (::InterlockedExchangeAdd(&io_service_->shutdown_, 0) == 0) + while (::InterlockedExchangeAdd(&io_context_->shutdown_, 0) == 0) { - if (::WaitForSingleObject(io_service_->waitable_timer_.handle, + if (::WaitForSingleObject(io_context_->waitable_timer_.handle, INFINITE) == WAIT_OBJECT_0) { - ::InterlockedExchange(&io_service_->dispatch_required_, 1); - ::PostQueuedCompletionStatus(io_service_->iocp_.handle, + ::InterlockedExchange(&io_context_->dispatch_required_, 1); + ::PostQueuedCompletionStatus(io_context_->iocp_.handle, 0, wake_for_dispatch, 0); } } } - win_iocp_io_service* io_service_; + win_iocp_io_context* io_context_; }; -win_iocp_io_service::win_iocp_io_service( - boost::asio::io_service& io_service, size_t concurrency_hint) - : boost::asio::detail::service_base<win_iocp_io_service>(io_service), +win_iocp_io_context::win_iocp_io_context( + boost::asio::execution_context& ctx, int concurrency_hint) + : execution_context_service_base<win_iocp_io_context>(ctx), iocp_(), outstanding_work_(0), stopped_(0), stop_event_posted_(0), shutdown_(0), gqcs_timeout_(get_gqcs_timeout()), - dispatch_required_(0) + dispatch_required_(0), + concurrency_hint_(concurrency_hint) { BOOST_ASIO_HANDLER_TRACKING_INIT; iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, - static_cast<DWORD>(concurrency_hint < DWORD(~0) - ? concurrency_hint : DWORD(~0))); + static_cast<DWORD>(concurrency_hint >= 0 ? concurrency_hint : DWORD(~0))); if (!iocp_.handle) { DWORD last_error = ::GetLastError(); @@ -88,7 +87,7 @@ win_iocp_io_service::win_iocp_io_service( } } -void win_iocp_io_service::shutdown_service() +void win_iocp_io_context::shutdown() { ::InterlockedExchange(&shutdown_, 1); @@ -132,7 +131,7 @@ void win_iocp_io_service::shutdown_service() timer_thread_->join(); } -boost::system::error_code win_iocp_io_service::register_handle( +boost::system::error_code win_iocp_io_context::register_handle( HANDLE handle, boost::system::error_code& ec) { if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0) @@ -148,7 +147,7 @@ boost::system::error_code win_iocp_io_service::register_handle( return ec; } -size_t win_iocp_io_service::run(boost::system::error_code& ec) +size_t win_iocp_io_context::run(boost::system::error_code& ec) { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) { @@ -161,13 +160,13 @@ size_t win_iocp_io_service::run(boost::system::error_code& ec) thread_call_stack::context ctx(this, this_thread); size_t n = 0; - while (do_one(true, ec)) + while (do_one(INFINITE, ec)) if (n != (std::numeric_limits<size_t>::max)()) ++n; return n; } -size_t win_iocp_io_service::run_one(boost::system::error_code& ec) +size_t win_iocp_io_context::run_one(boost::system::error_code& ec) { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) { @@ -179,10 +178,25 @@ size_t win_iocp_io_service::run_one(boost::system::error_code& ec) win_iocp_thread_info this_thread; thread_call_stack::context ctx(this, this_thread); - return do_one(true, ec); + return do_one(INFINITE, ec); } -size_t win_iocp_io_service::poll(boost::system::error_code& ec) +size_t win_iocp_io_context::wait_one(long usec, boost::system::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); + + return do_one(usec < 0 ? INFINITE : ((usec - 1) / 1000 + 1), ec); +} + +size_t win_iocp_io_context::poll(boost::system::error_code& ec) { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) { @@ -195,13 +209,13 @@ size_t win_iocp_io_service::poll(boost::system::error_code& ec) thread_call_stack::context ctx(this, this_thread); size_t n = 0; - while (do_one(false, ec)) + while (do_one(0, ec)) if (n != (std::numeric_limits<size_t>::max)()) ++n; return n; } -size_t win_iocp_io_service::poll_one(boost::system::error_code& ec) +size_t win_iocp_io_context::poll_one(boost::system::error_code& ec) { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) { @@ -213,10 +227,10 @@ size_t win_iocp_io_service::poll_one(boost::system::error_code& ec) win_iocp_thread_info this_thread; thread_call_stack::context ctx(this, this_thread); - return do_one(false, ec); + return do_one(0, ec); } -void win_iocp_io_service::stop() +void win_iocp_io_context::stop() { if (::InterlockedExchange(&stopped_, 1) == 0) { @@ -233,7 +247,7 @@ void win_iocp_io_service::stop() } } -void win_iocp_io_service::post_deferred_completion(win_iocp_operation* op) +void win_iocp_io_context::post_deferred_completion(win_iocp_operation* op) { // Flag the operation as ready. op->ready_ = 1; @@ -248,7 +262,7 @@ void win_iocp_io_service::post_deferred_completion(win_iocp_operation* op) } } -void win_iocp_io_service::post_deferred_completions( +void win_iocp_io_context::post_deferred_completions( op_queue<win_iocp_operation>& ops) { while (win_iocp_operation* op = ops.front()) @@ -270,7 +284,7 @@ void win_iocp_io_service::post_deferred_completions( } } -void win_iocp_io_service::abandon_operations( +void win_iocp_io_context::abandon_operations( op_queue<win_iocp_operation>& ops) { while (win_iocp_operation* op = ops.front()) @@ -281,7 +295,7 @@ void win_iocp_io_service::abandon_operations( } } -void win_iocp_io_service::on_pending(win_iocp_operation* op) +void win_iocp_io_context::on_pending(win_iocp_operation* op) { if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) { @@ -297,7 +311,7 @@ void win_iocp_io_service::on_pending(win_iocp_operation* op) } } -void win_iocp_io_service::on_completion(win_iocp_operation* op, +void win_iocp_io_context::on_completion(win_iocp_operation* op, DWORD last_error, DWORD bytes_transferred) { // Flag that the operation is ready for invocation. @@ -320,7 +334,7 @@ void win_iocp_io_service::on_completion(win_iocp_operation* op, } } -void win_iocp_io_service::on_completion(win_iocp_operation* op, +void win_iocp_io_context::on_completion(win_iocp_operation* op, const boost::system::error_code& ec, DWORD bytes_transferred) { // Flag that the operation is ready for invocation. @@ -342,7 +356,7 @@ void win_iocp_io_service::on_completion(win_iocp_operation* op, } } -size_t win_iocp_io_service::do_one(bool block, boost::system::error_code& ec) +size_t win_iocp_io_context::do_one(DWORD msec, boost::system::error_code& ec) { for (;;) { @@ -364,8 +378,9 @@ size_t win_iocp_io_service::do_one(bool block, boost::system::error_code& ec) dword_ptr_t completion_key = 0; LPOVERLAPPED overlapped = 0; ::SetLastError(0); - BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, - &completion_key, &overlapped, block ? gqcs_timeout_ : 0); + BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, + &bytes_transferred, &completion_key, &overlapped, + msec < gqcs_timeout_ ? msec : gqcs_timeout_); DWORD last_error = ::GetLastError(); if (overlapped) @@ -402,7 +417,7 @@ size_t win_iocp_io_service::do_one(bool block, boost::system::error_code& ec) work_finished_on_block_exit on_exit = { this }; (void)on_exit; - op->complete(*this, result_ec, bytes_transferred); + op->complete(this, result_ec, bytes_transferred); ec = boost::system::error_code(); return 1; } @@ -416,8 +431,9 @@ size_t win_iocp_io_service::do_one(bool block, boost::system::error_code& ec) return 0; } - // If we're not polling we need to keep going until we get a real handler. - if (block) + // If we're waiting indefinitely we need to keep going until we get a + // real handler. + if (msec == INFINITE) continue; ec = boost::system::error_code(); @@ -456,7 +472,7 @@ size_t win_iocp_io_service::do_one(bool block, boost::system::error_code& ec) } } -DWORD win_iocp_io_service::get_gqcs_timeout() +DWORD win_iocp_io_context::get_gqcs_timeout() { OSVERSIONINFOEX osvi; ZeroMemory(&osvi, sizeof(osvi)); @@ -472,7 +488,7 @@ DWORD win_iocp_io_service::get_gqcs_timeout() return default_gqcs_timeout; } -void win_iocp_io_service::do_add_timer_queue(timer_queue_base& queue) +void win_iocp_io_context::do_add_timer_queue(timer_queue_base& queue) { mutex::scoped_lock lock(dispatch_mutex_); @@ -503,14 +519,14 @@ void win_iocp_io_service::do_add_timer_queue(timer_queue_base& queue) } } -void win_iocp_io_service::do_remove_timer_queue(timer_queue_base& queue) +void win_iocp_io_context::do_remove_timer_queue(timer_queue_base& queue) { mutex::scoped_lock lock(dispatch_mutex_); timer_queues_.erase(&queue); } -void win_iocp_io_service::update_timeout() +void win_iocp_io_context::update_timeout() { if (timer_thread_.get()) { @@ -537,4 +553,4 @@ void win_iocp_io_service::update_timeout() #endif // defined(BOOST_ASIO_HAS_IOCP) -#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP diff --git a/boost/asio/detail/impl/win_iocp_serial_port_service.ipp b/boost/asio/detail/impl/win_iocp_serial_port_service.ipp index 32ba34684b..c0d2dbbd59 100644 --- a/boost/asio/detail/impl/win_iocp_serial_port_service.ipp +++ b/boost/asio/detail/impl/win_iocp_serial_port_service.ipp @@ -30,12 +30,13 @@ namespace asio { namespace detail { win_iocp_serial_port_service::win_iocp_serial_port_service( - boost::asio::io_service& io_service) - : handle_service_(io_service) + boost::asio::io_context& io_context) + : service_base<win_iocp_serial_port_service>(io_context), + handle_service_(io_context) { } -void win_iocp_serial_port_service::shutdown_service() +void win_iocp_serial_port_service::shutdown() { } diff --git a/boost/asio/detail/impl/win_iocp_socket_service_base.ipp b/boost/asio/detail/impl/win_iocp_socket_service_base.ipp index 93f5ed0713..e9a5049345 100644 --- a/boost/asio/detail/impl/win_iocp_socket_service_base.ipp +++ b/boost/asio/detail/impl/win_iocp_socket_service_base.ipp @@ -28,24 +28,24 @@ namespace asio { namespace detail { win_iocp_socket_service_base::win_iocp_socket_service_base( - boost::asio::io_service& io_service) - : io_service_(io_service), - iocp_service_(use_service<win_iocp_io_service>(io_service)), + boost::asio::io_context& io_context) + : io_context_(io_context), + iocp_service_(use_service<win_iocp_io_context>(io_context)), reactor_(0), connect_ex_(0), + nt_set_info_(0), mutex_(), impl_list_(0) { } -void win_iocp_socket_service_base::shutdown_service() +void win_iocp_socket_service_base::base_shutdown() { // Close all implementations, causing all operations to complete. boost::asio::detail::mutex::scoped_lock lock(mutex_); base_implementation_type* impl = impl_list_; while (impl) { - boost::system::error_code ignored_ec; close_for_destruction(*impl); impl = impl->next_; } @@ -167,12 +167,13 @@ boost::system::error_code win_iocp_socket_service_base::close( { if (is_open(impl)) { - BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "close")); + BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), + "socket", &impl, impl.socket_, "close")); // Check if the reactor was created, in which case we need to close the // socket on the reactor as well to cancel any operations that might be // running there. - reactor* r = static_cast<reactor*>( + select_reactor* r = static_cast<select_reactor*>( interlocked_compare_exchange_pointer( reinterpret_cast<void**>(&reactor_), 0, 0)); if (r) @@ -198,6 +199,39 @@ boost::system::error_code win_iocp_socket_service_base::close( return ec; } +socket_type win_iocp_socket_service_base::release( + win_iocp_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + return invalid_socket; + + cancel(impl, ec); + if (ec) + return invalid_socket; + + nt_set_info_fn fn = get_nt_set_info(); + if (fn == 0) + { + ec = boost::asio::error::operation_not_supported; + return invalid_socket; + } + + HANDLE sock_as_handle = reinterpret_cast<HANDLE>(impl.socket_); + ULONG_PTR iosb[2] = { 0, 0 }; + void* info[2] = { 0, 0 }; + if (fn(sock_as_handle, iosb, &info, sizeof(info), + 61 /* FileReplaceCompletionInformation */)) + { + ec = boost::asio::error::operation_not_supported; + return invalid_socket; + } + + socket_type tmp = impl.socket_; + impl.socket_ = invalid_socket; + return tmp; +} + boost::system::error_code win_iocp_socket_service_base::cancel( win_iocp_socket_service_base::base_implementation_type& impl, boost::system::error_code& ec) @@ -208,7 +242,8 @@ boost::system::error_code win_iocp_socket_service_base::cancel( return ec; } - BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "cancel")); + BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), + "socket", &impl, impl.socket_, "cancel")); if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) @@ -279,7 +314,7 @@ boost::system::error_code win_iocp_socket_service_base::cancel( // Cancel any operations started via the reactor. if (!ec) { - reactor* r = static_cast<reactor*>( + select_reactor* r = static_cast<select_reactor*>( interlocked_compare_exchange_pointer( reinterpret_cast<void**>(&reactor_), 0, 0)); if (r) @@ -445,7 +480,7 @@ void win_iocp_socket_service_base::start_null_buffers_receive_op( { start_reactor_op(impl, (flags & socket_base::message_out_of_band) - ? reactor::except_op : reactor::read_op, + ? select_reactor::except_op : select_reactor::read_op, op); } } @@ -537,7 +572,7 @@ void win_iocp_socket_service_base::start_reactor_op( win_iocp_socket_service_base::base_implementation_type& impl, int op_type, reactor_op* op) { - reactor& r = get_reactor(); + select_reactor& r = get_reactor(); update_cancellation_thread_id(impl); if (is_open(impl)) @@ -598,7 +633,7 @@ void win_iocp_socket_service_base::start_connect_op( } // Otherwise, fall back to a reactor-based implementation. - reactor& r = get_reactor(); + select_reactor& r = get_reactor(); update_cancellation_thread_id(impl); if ((impl.state_ & socket_ops::non_blocking) != 0 @@ -611,7 +646,7 @@ void win_iocp_socket_service_base::start_connect_op( || op->ec_ == boost::asio::error::would_block) { op->ec_ = boost::system::error_code(); - r.start_op(reactor::connect_op, impl.socket_, + r.start_op(select_reactor::connect_op, impl.socket_, impl.reactor_data_, op, false, false); return; } @@ -626,12 +661,13 @@ void win_iocp_socket_service_base::close_for_destruction( { if (is_open(impl)) { - BOOST_ASIO_HANDLER_OPERATION(("socket", &impl, "close")); + BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), + "socket", &impl, impl.socket_, "close")); // Check if the reactor was created, in which case we need to close the // socket on the reactor as well to cancel any operations that might be // running there. - reactor* r = static_cast<reactor*>( + select_reactor* r = static_cast<select_reactor*>( interlocked_compare_exchange_pointer( reinterpret_cast<void**>(&reactor_), 0, 0)); if (r) @@ -665,14 +701,14 @@ void win_iocp_socket_service_base::update_cancellation_thread_id( #endif // defined(BOOST_ASIO_ENABLE_CANCELIO) } -reactor& win_iocp_socket_service_base::get_reactor() +select_reactor& win_iocp_socket_service_base::get_reactor() { - reactor* r = static_cast<reactor*>( + select_reactor* r = static_cast<select_reactor*>( interlocked_compare_exchange_pointer( reinterpret_cast<void**>(&reactor_), 0, 0)); if (!r) { - r = &(use_service<reactor>(io_service_)); + r = &(use_service<select_reactor>(io_context_)); interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r); } return *r; @@ -713,6 +749,24 @@ win_iocp_socket_service_base::get_connect_ex( #endif // defined(BOOST_ASIO_DISABLE_CONNECTEX) } +win_iocp_socket_service_base::nt_set_info_fn +win_iocp_socket_service_base::get_nt_set_info() +{ + void* ptr = interlocked_compare_exchange_pointer(&nt_set_info_, 0, 0); + if (!ptr) + { + if (HMODULE h = ::GetModuleHandleA("NTDLL.DLL")) + ptr = reinterpret_cast<void*>(GetProcAddress(h, "NtSetInformationFile")); + + // On failure, set nt_set_info_ to a special value to indicate that the + // NtSetInformationFile function is unavailable. That way we won't bother + // trying to look it up again. + interlocked_exchange_pointer(&nt_set_info_, ptr ? ptr : this); + } + + return reinterpret_cast<nt_set_info_fn>(ptr == this ? 0 : ptr); +} + void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer( void** dest, void* exch, void* cmp) { diff --git a/boost/asio/detail/impl/win_object_handle_service.ipp b/boost/asio/detail/impl/win_object_handle_service.ipp index a940161cba..31718a012b 100644 --- a/boost/asio/detail/impl/win_object_handle_service.ipp +++ b/boost/asio/detail/impl/win_object_handle_service.ipp @@ -29,15 +29,16 @@ namespace asio { namespace detail { win_object_handle_service::win_object_handle_service( - boost::asio::io_service& io_service) - : io_service_(boost::asio::use_service<io_service_impl>(io_service)), + boost::asio::io_context& io_context) + : service_base<win_object_handle_service>(io_context), + io_context_(boost::asio::use_service<io_context_impl>(io_context)), mutex_(), impl_list_(0), shutdown_(false) { } -void win_object_handle_service::shutdown_service() +void win_object_handle_service::shutdown() { mutex::scoped_lock lock(mutex_); @@ -52,7 +53,7 @@ void win_object_handle_service::shutdown_service() lock.unlock(); - io_service_.abandon_operations(ops); + io_context_.abandon_operations(ops); } void win_object_handle_service::construct( @@ -178,7 +179,8 @@ void win_object_handle_service::destroy( if (is_open(impl)) { - BOOST_ASIO_HANDLER_OPERATION(("object_handle", &impl, "close")); + BOOST_ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle", + &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close")); HANDLE wait_handle = impl.wait_handle_; impl.wait_handle_ = INVALID_HANDLE_VALUE; @@ -202,7 +204,7 @@ void win_object_handle_service::destroy( ::CloseHandle(impl.handle_); impl.handle_ = INVALID_HANDLE_VALUE; - io_service_.post_deferred_completions(ops); + io_context_.post_deferred_completions(ops); } } @@ -227,7 +229,8 @@ boost::system::error_code win_object_handle_service::close( { if (is_open(impl)) { - BOOST_ASIO_HANDLER_OPERATION(("object_handle", &impl, "close")); + BOOST_ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle", + &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close")); mutex::scoped_lock lock(mutex_); @@ -262,7 +265,7 @@ boost::system::error_code win_object_handle_service::close( boost::asio::error::get_system_category()); } - io_service_.post_deferred_completions(completed_ops); + io_context_.post_deferred_completions(completed_ops); } else { @@ -278,7 +281,8 @@ boost::system::error_code win_object_handle_service::cancel( { if (is_open(impl)) { - BOOST_ASIO_HANDLER_OPERATION(("object_handle", &impl, "cancel")); + BOOST_ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle", + &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "cancel")); mutex::scoped_lock lock(mutex_); @@ -303,7 +307,7 @@ boost::system::error_code win_object_handle_service::cancel( ec = boost::system::error_code(); - io_service_.post_deferred_completions(completed_ops); + io_context_.post_deferred_completions(completed_ops); } else { @@ -337,7 +341,7 @@ void win_object_handle_service::wait( void win_object_handle_service::start_wait_op( win_object_handle_service::implementation_type& impl, wait_op* op) { - io_service_.work_started(); + io_context_.work_started(); if (is_open(impl)) { @@ -355,13 +359,13 @@ void win_object_handle_service::start_wait_op( else { lock.unlock(); - io_service_.post_deferred_completion(op); + io_context_.post_deferred_completion(op); } } else { op->ec_ = boost::asio::error::bad_descriptor; - io_service_.post_deferred_completion(op); + io_context_.post_deferred_completion(op); } } @@ -388,7 +392,7 @@ void win_object_handle_service::register_wait_callback( } lock.unlock(); - io_service_.post_deferred_completions(completed_ops); + io_context_.post_deferred_completions(completed_ops); } } @@ -430,9 +434,9 @@ void win_object_handle_service::wait_callback(PVOID param, BOOLEAN) } } - io_service_impl& ios = impl->owner_->io_service_; + io_context_impl& ioc = impl->owner_->io_context_; lock.unlock(); - ios.post_deferred_completions(completed_ops); + ioc.post_deferred_completions(completed_ops); } } diff --git a/boost/asio/detail/impl/win_thread.ipp b/boost/asio/detail/impl/win_thread.ipp index e2d9384007..c90c3f3986 100644 --- a/boost/asio/detail/impl/win_thread.ipp +++ b/boost/asio/detail/impl/win_thread.ipp @@ -56,6 +56,13 @@ void win_thread::join() } } +std::size_t win_thread::hardware_concurrency() +{ + SYSTEM_INFO system_info; + ::GetSystemInfo(&system_info); + return system_info.dwNumberOfProcessors; +} + void win_thread::start_thread(func_base* arg, unsigned int stack_size) { ::HANDLE entry_event = 0; diff --git a/boost/asio/detail/impl/win_tss_ptr.ipp b/boost/asio/detail/impl/win_tss_ptr.ipp index 3390066695..105cf3022c 100644 --- a/boost/asio/detail/impl/win_tss_ptr.ipp +++ b/boost/asio/detail/impl/win_tss_ptr.ipp @@ -32,9 +32,9 @@ namespace detail { DWORD win_tss_ptr_create() { #if defined(UNDER_CE) - enum { out_of_indexes = 0xFFFFFFFF }; + const DWORD out_of_indexes = 0xFFFFFFFF; #else - enum { out_of_indexes = TLS_OUT_OF_INDEXES }; + const DWORD out_of_indexes = TLS_OUT_OF_INDEXES; #endif DWORD tss_key = ::TlsAlloc(); diff --git a/boost/asio/detail/impl/winrt_ssocket_service_base.ipp b/boost/asio/detail/impl/winrt_ssocket_service_base.ipp index f5990a97ad..a7a340b70b 100644 --- a/boost/asio/detail/impl/winrt_ssocket_service_base.ipp +++ b/boost/asio/detail/impl/winrt_ssocket_service_base.ipp @@ -31,15 +31,15 @@ namespace asio { namespace detail { winrt_ssocket_service_base::winrt_ssocket_service_base( - boost::asio::io_service& io_service) - : io_service_(use_service<io_service_impl>(io_service)), - async_manager_(use_service<winrt_async_manager>(io_service)), + boost::asio::io_context& io_context) + : io_context_(use_service<io_context_impl>(io_context)), + async_manager_(use_service<winrt_async_manager>(io_context)), mutex_(), impl_list_(0) { } -void winrt_ssocket_service_base::shutdown_service() +void winrt_ssocket_service_base::base_shutdown() { // Close all implementations, causing all operations to complete. boost::asio::detail::mutex::scoped_lock lock(mutex_); @@ -149,6 +149,23 @@ boost::system::error_code winrt_ssocket_service_base::close( return ec; } +winrt_ssocket_service_base::native_handle_type +winrt_ssocket_service_base::release( + winrt_ssocket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + return nullptr; + + cancel(impl, ec); + if (ec) + return nullptr; + + native_handle_type tmp = impl.socket_; + impl.socket_ = nullptr; + return tmp; +} + std::size_t winrt_ssocket_service_base::do_get_endpoint( const base_implementation_type& impl, bool local, void* addr, std::size_t addr_len, boost::system::error_code& ec) const @@ -382,7 +399,7 @@ void winrt_ssocket_service_base::start_connect_op( if (!is_open(impl)) { op->ec_ = boost::asio::error::bad_descriptor; - io_service_.post_immediate_completion(op, is_continuation); + io_context_.post_immediate_completion(op, is_continuation); return; } @@ -411,7 +428,7 @@ void winrt_ssocket_service_base::start_connect_op( if (op->ec_) { - io_service_.post_immediate_completion(op, is_continuation); + io_context_.post_immediate_completion(op, is_continuation); return; } @@ -426,7 +443,7 @@ void winrt_ssocket_service_base::start_connect_op( { op->ec_ = boost::system::error_code( e->HResult, boost::system::system_category()); - io_service_.post_immediate_completion(op, is_continuation); + io_context_.post_immediate_completion(op, is_continuation); } } @@ -450,7 +467,7 @@ std::size_t winrt_ssocket_service_base::do_send( try { buffer_sequence_adapter<boost::asio::const_buffer, - boost::asio::const_buffers_1> bufs(boost::asio::buffer(data)); + boost::asio::const_buffer> bufs(boost::asio::buffer(data)); if (bufs.all_empty()) { @@ -477,25 +494,25 @@ void winrt_ssocket_service_base::start_send_op( if (flags) { op->ec_ = boost::asio::error::operation_not_supported; - io_service_.post_immediate_completion(op, is_continuation); + io_context_.post_immediate_completion(op, is_continuation); return; } if (!is_open(impl)) { op->ec_ = boost::asio::error::bad_descriptor; - io_service_.post_immediate_completion(op, is_continuation); + io_context_.post_immediate_completion(op, is_continuation); return; } try { buffer_sequence_adapter<boost::asio::const_buffer, - boost::asio::const_buffers_1> bufs(boost::asio::buffer(data)); + boost::asio::const_buffer> bufs(boost::asio::buffer(data)); if (bufs.all_empty()) { - io_service_.post_immediate_completion(op, is_continuation); + io_context_.post_immediate_completion(op, is_continuation); return; } @@ -506,7 +523,7 @@ void winrt_ssocket_service_base::start_send_op( { op->ec_ = boost::system::error_code(e->HResult, boost::system::system_category()); - io_service_.post_immediate_completion(op, is_continuation); + io_context_.post_immediate_completion(op, is_continuation); } } @@ -530,7 +547,7 @@ std::size_t winrt_ssocket_service_base::do_receive( try { buffer_sequence_adapter<boost::asio::mutable_buffer, - boost::asio::mutable_buffers_1> bufs(boost::asio::buffer(data)); + boost::asio::mutable_buffer> bufs(boost::asio::buffer(data)); if (bufs.all_empty()) { @@ -568,25 +585,25 @@ void winrt_ssocket_service_base::start_receive_op( if (flags) { op->ec_ = boost::asio::error::operation_not_supported; - io_service_.post_immediate_completion(op, is_continuation); + io_context_.post_immediate_completion(op, is_continuation); return; } if (!is_open(impl)) { op->ec_ = boost::asio::error::bad_descriptor; - io_service_.post_immediate_completion(op, is_continuation); + io_context_.post_immediate_completion(op, is_continuation); return; } try { buffer_sequence_adapter<boost::asio::mutable_buffer, - boost::asio::mutable_buffers_1> bufs(boost::asio::buffer(data)); + boost::asio::mutable_buffer> bufs(boost::asio::buffer(data)); if (bufs.all_empty()) { - io_service_.post_immediate_completion(op, is_continuation); + io_context_.post_immediate_completion(op, is_continuation); return; } @@ -599,7 +616,7 @@ void winrt_ssocket_service_base::start_receive_op( { op->ec_ = boost::system::error_code(e->HResult, boost::system::system_category()); - io_service_.post_immediate_completion(op, is_continuation); + io_context_.post_immediate_completion(op, is_continuation); } } diff --git a/boost/asio/detail/impl/winrt_timer_scheduler.hpp b/boost/asio/detail/impl/winrt_timer_scheduler.hpp index 8d93e57962..b1522b4673 100644 --- a/boost/asio/detail/impl/winrt_timer_scheduler.hpp +++ b/boost/asio/detail/impl/winrt_timer_scheduler.hpp @@ -47,12 +47,12 @@ void winrt_timer_scheduler::schedule_timer(timer_queue<Time_Traits>& queue, if (shutdown_) { - io_service_.post_immediate_completion(op, false); + io_context_.post_immediate_completion(op, false); return; } bool earliest = queue.enqueue_timer(time, timer, op); - io_service_.work_started(); + io_context_.work_started(); if (earliest) event_.signal(lock); } @@ -66,10 +66,23 @@ std::size_t winrt_timer_scheduler::cancel_timer(timer_queue<Time_Traits>& queue, op_queue<operation> ops; std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); lock.unlock(); - io_service_.post_deferred_completions(ops); + io_context_.post_deferred_completions(ops); return n; } +template <typename Time_Traits> +void winrt_timer_scheduler::move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue<operation> ops; + queue.cancel_timer(to, ops); + queue.move_timer(to, from); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + } // namespace detail } // namespace asio } // namespace boost diff --git a/boost/asio/detail/impl/winrt_timer_scheduler.ipp b/boost/asio/detail/impl/winrt_timer_scheduler.ipp index 914849d822..2e8145b6b8 100644 --- a/boost/asio/detail/impl/winrt_timer_scheduler.ipp +++ b/boost/asio/detail/impl/winrt_timer_scheduler.ipp @@ -29,9 +29,9 @@ namespace asio { namespace detail { winrt_timer_scheduler::winrt_timer_scheduler( - boost::asio::io_service& io_service) - : boost::asio::detail::service_base<winrt_timer_scheduler>(io_service), - io_service_(use_service<io_service_impl>(io_service)), + boost::asio::io_context& io_context) + : boost::asio::detail::service_base<winrt_timer_scheduler>(io_context), + io_context_(use_service<io_context_impl>(io_context)), mutex_(), event_(), timer_queues_(), @@ -45,10 +45,10 @@ winrt_timer_scheduler::winrt_timer_scheduler( winrt_timer_scheduler::~winrt_timer_scheduler() { - shutdown_service(); + shutdown(); } -void winrt_timer_scheduler::shutdown_service() +void winrt_timer_scheduler::shutdown() { boost::asio::detail::mutex::scoped_lock lock(mutex_); shutdown_ = true; @@ -65,10 +65,10 @@ void winrt_timer_scheduler::shutdown_service() op_queue<operation> ops; timer_queues_.get_all_timers(ops); - io_service_.abandon_operations(ops); + io_context_.abandon_operations(ops); } -void winrt_timer_scheduler::fork_service(boost::asio::io_service::fork_event) +void winrt_timer_scheduler::notify_fork(boost::asio::io_context::fork_event) { } @@ -90,7 +90,7 @@ void winrt_timer_scheduler::run_thread() if (!ops.empty()) { lock.unlock(); - io_service_.post_deferred_completions(ops); + io_context_.post_deferred_completions(ops); lock.lock(); } } diff --git a/boost/asio/detail/io_control.hpp b/boost/asio/detail/io_control.hpp index 6c7527d1cf..d235fa1fda 100644 --- a/boost/asio/detail/io_control.hpp +++ b/boost/asio/detail/io_control.hpp @@ -26,56 +26,6 @@ namespace asio { namespace detail { namespace io_control { -// IO control command for non-blocking I/O. -class non_blocking_io -{ -public: - // Default constructor. - non_blocking_io() - : value_(0) - { - } - - // Construct with a specific command value. - non_blocking_io(bool value) - : value_(value ? 1 : 0) - { - } - - // Get the name of the IO control command. - int name() const - { - return static_cast<int>(BOOST_ASIO_OS_DEF(FIONBIO)); - } - - // Set the value of the I/O control command. - void set(bool value) - { - value_ = value ? 1 : 0; - } - - // Get the current value of the I/O control command. - bool get() const - { - return value_ != 0; - } - - // Get the address of the command data. - detail::ioctl_arg_type* data() - { - return &value_; - } - - // Get the address of the command data. - const detail::ioctl_arg_type* data() const - { - return &value_; - } - -private: - detail::ioctl_arg_type value_; -}; - // I/O control command for getting number of bytes available. class bytes_readable { diff --git a/boost/asio/detail/is_buffer_sequence.hpp b/boost/asio/detail/is_buffer_sequence.hpp new file mode 100644 index 0000000000..c788c55d28 --- /dev/null +++ b/boost/asio/detail/is_buffer_sequence.hpp @@ -0,0 +1,241 @@ +// +// detail/is_buffer_sequence.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP +#define BOOST_ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/type_traits.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +class mutable_buffer; +class const_buffer; + +namespace detail { + +struct buffer_sequence_memfns_base +{ + void begin(); + void end(); + void size(); + void max_size(); + void capacity(); + void data(); + void prepare(); + void commit(); + void consume(); +}; + +template <typename T> +struct buffer_sequence_memfns_derived + : T, buffer_sequence_memfns_base +{ +}; + +template <typename T, T> +struct buffer_sequence_memfns_check +{ +}; + +template <typename> +char (&begin_memfn_helper(...))[2]; + +template <typename T> +char begin_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::begin>*); + +template <typename> +char (&end_memfn_helper(...))[2]; + +template <typename T> +char end_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::end>*); + +template <typename> +char (&size_memfn_helper(...))[2]; + +template <typename T> +char size_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::size>*); + +template <typename> +char (&max_size_memfn_helper(...))[2]; + +template <typename T> +char max_size_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::max_size>*); + +template <typename> +char (&capacity_memfn_helper(...))[2]; + +template <typename T> +char capacity_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::capacity>*); + +template <typename> +char (&data_memfn_helper(...))[2]; + +template <typename T> +char data_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::data>*); + +template <typename> +char (&prepare_memfn_helper(...))[2]; + +template <typename T> +char prepare_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::data>*); + +template <typename> +char (&commit_memfn_helper(...))[2]; + +template <typename T> +char commit_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::commit>*); + +template <typename> +char (&consume_memfn_helper(...))[2]; + +template <typename T> +char consume_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived<T>::consume>*); + +template <typename, typename> +char (&buffer_element_type_helper(...))[2]; + +#if defined(BOOST_ASIO_HAS_DECL_TYPE) + +template <typename T, typename Buffer> +char buffer_element_type_helper(T* t, + typename enable_if<is_convertible< + decltype(*buffer_sequence_begin(*t)), + Buffer>::value>::type*); + +#else // defined(BOOST_ASIO_HAS_DECL_TYPE) + +template <typename T, typename Buffer> +char buffer_element_type_helper( + typename T::const_iterator*, + typename enable_if<is_convertible< + typename T::value_type, Buffer>::value>::type*); + +#endif // defined(BOOST_ASIO_HAS_DECL_TYPE) + +template <typename> +char (&const_buffers_type_typedef_helper(...))[2]; + +template <typename T> +char const_buffers_type_typedef_helper( + typename T::const_buffers_type*); + +template <typename> +char (&mutable_buffers_type_typedef_helper(...))[2]; + +template <typename T> +char mutable_buffers_type_typedef_helper( + typename T::mutable_buffers_type*); + +template <typename T, typename Buffer> +struct is_buffer_sequence_class + : integral_constant<bool, + sizeof(begin_memfn_helper<T>(0)) != 1 && + sizeof(end_memfn_helper<T>(0)) != 1 && + sizeof(buffer_element_type_helper<T, Buffer>(0, 0)) == 1> +{ +}; + +template <typename T, typename Buffer> +struct is_buffer_sequence + : conditional<is_class<T>::value, + is_buffer_sequence_class<T, Buffer>, + false_type>::type +{ +}; + +template <> +struct is_buffer_sequence<mutable_buffer, mutable_buffer> + : true_type +{ +}; + +template <> +struct is_buffer_sequence<mutable_buffer, const_buffer> + : true_type +{ +}; + +template <> +struct is_buffer_sequence<const_buffer, const_buffer> + : true_type +{ +}; + +template <> +struct is_buffer_sequence<const_buffer, mutable_buffer> + : false_type +{ +}; + +template <typename T> +struct is_dynamic_buffer_class + : integral_constant<bool, + sizeof(size_memfn_helper<T>(0)) != 1 && + sizeof(max_size_memfn_helper<T>(0)) != 1 && + sizeof(capacity_memfn_helper<T>(0)) != 1 && + sizeof(data_memfn_helper<T>(0)) != 1 && + sizeof(consume_memfn_helper<T>(0)) != 1 && + sizeof(prepare_memfn_helper<T>(0)) != 1 && + sizeof(commit_memfn_helper<T>(0)) != 1 && + sizeof(const_buffers_type_typedef_helper<T>(0)) == 1 && + sizeof(mutable_buffers_type_typedef_helper<T>(0)) == 1> +{ +}; + +template <typename T> +struct is_dynamic_buffer + : conditional<is_class<T>::value, + is_dynamic_buffer_class<T>, + false_type>::type +{ +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP diff --git a/boost/asio/detail/is_executor.hpp b/boost/asio/detail/is_executor.hpp new file mode 100644 index 0000000000..43db5d0120 --- /dev/null +++ b/boost/asio/detail/is_executor.hpp @@ -0,0 +1,128 @@ +// +// detail/is_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_IS_EXECUTOR_HPP +#define BOOST_ASIO_DETAIL_IS_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/type_traits.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +struct executor_memfns_base +{ + void context(); + void on_work_started(); + void on_work_finished(); + void dispatch(); + void post(); + void defer(); +}; + +template <typename T> +struct executor_memfns_derived + : T, executor_memfns_base +{ +}; + +template <typename T, T> +struct executor_memfns_check +{ +}; + +template <typename> +char (&context_memfn_helper(...))[2]; + +template <typename T> +char context_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived<T>::context>*); + +template <typename> +char (&on_work_started_memfn_helper(...))[2]; + +template <typename T> +char on_work_started_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived<T>::on_work_started>*); + +template <typename> +char (&on_work_finished_memfn_helper(...))[2]; + +template <typename T> +char on_work_finished_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived<T>::on_work_finished>*); + +template <typename> +char (&dispatch_memfn_helper(...))[2]; + +template <typename T> +char dispatch_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived<T>::dispatch>*); + +template <typename> +char (&post_memfn_helper(...))[2]; + +template <typename T> +char post_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived<T>::post>*); + +template <typename> +char (&defer_memfn_helper(...))[2]; + +template <typename T> +char defer_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived<T>::defer>*); + +template <typename T> +struct is_executor_class + : integral_constant<bool, + sizeof(context_memfn_helper<T>(0)) != 1 && + sizeof(on_work_started_memfn_helper<T>(0)) != 1 && + sizeof(on_work_finished_memfn_helper<T>(0)) != 1 && + sizeof(dispatch_memfn_helper<T>(0)) != 1 && + sizeof(post_memfn_helper<T>(0)) != 1 && + sizeof(defer_memfn_helper<T>(0)) != 1> +{ +}; + +template <typename T> +struct is_executor + : conditional<is_class<T>::value, + is_executor_class<T>, + false_type>::type +{ +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_IS_EXECUTOR_HPP diff --git a/boost/asio/detail/kqueue_reactor.hpp b/boost/asio/detail/kqueue_reactor.hpp index c6182b4d55..492b7ff016 100644 --- a/boost/asio/detail/kqueue_reactor.hpp +++ b/boost/asio/detail/kqueue_reactor.hpp @@ -35,7 +35,7 @@ #include <boost/asio/detail/timer_queue_set.hpp> #include <boost/asio/detail/wait_op.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/execution_context.hpp> // Older versions of Mac OS X may not define EV_OOBAND. #if !defined(EV_OOBAND) @@ -48,9 +48,15 @@ namespace boost { namespace asio { namespace detail { +class scheduler; + class kqueue_reactor - : public boost::asio::detail::service_base<kqueue_reactor> + : public execution_context_service_base<kqueue_reactor> { +private: + // The mutex type used by this reactor. + typedef conditionally_enabled_mutex mutex; + public: enum op_types { read_op = 0, write_op = 1, connect_op = 1, except_op = 2, max_ops = 3 }; @@ -58,6 +64,8 @@ public: // Per-descriptor queues. struct descriptor_state { + descriptor_state(bool locking) : mutex_(locking) {} + friend class kqueue_reactor; friend class object_pool_access; @@ -75,17 +83,17 @@ public: typedef descriptor_state* per_descriptor_data; // Constructor. - BOOST_ASIO_DECL kqueue_reactor(boost::asio::io_service& io_service); + BOOST_ASIO_DECL kqueue_reactor(boost::asio::execution_context& ctx); // Destructor. BOOST_ASIO_DECL ~kqueue_reactor(); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void shutdown(); // Recreate internal descriptors following a fork. - BOOST_ASIO_DECL void fork_service( - boost::asio::io_service::fork_event fork_ev); + BOOST_ASIO_DECL void notify_fork( + boost::asio::execution_context::fork_event fork_ev); // Initialise the task. BOOST_ASIO_DECL void init_task(); @@ -109,7 +117,7 @@ public: // Post a reactor operation for immediate completion. void post_immediate_completion(reactor_op* op, bool is_continuation) { - io_service_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); } // Start a new operation. The reactor operation will be performed when the @@ -163,8 +171,14 @@ public: typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source); + // Run the kqueue loop. - BOOST_ASIO_DECL void run(bool block, op_queue<operation>& ops); + BOOST_ASIO_DECL void run(long usec, op_queue<operation>& ops); // Interrupt the kqueue loop. BOOST_ASIO_DECL void interrupt(); @@ -187,10 +201,10 @@ private: BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); // Get the timeout value for the kevent call. - BOOST_ASIO_DECL timespec* get_timeout(timespec& ts); + BOOST_ASIO_DECL timespec* get_timeout(long usec, timespec& ts); - // The io_service implementation used to post completions. - io_service_impl& io_service_; + // The scheduler used to post completions. + scheduler& scheduler_; // Mutex to protect access to internal data. mutex mutex_; diff --git a/boost/asio/detail/macos_fenced_block.hpp b/boost/asio/detail/macos_fenced_block.hpp index 5ab7f91c5e..20a995ebec 100644 --- a/boost/asio/detail/macos_fenced_block.hpp +++ b/boost/asio/detail/macos_fenced_block.hpp @@ -20,6 +20,7 @@ #if defined(__MACH__) && defined(__APPLE__) #include <libkern/OSAtomic.h> +#include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> diff --git a/boost/asio/detail/memory.hpp b/boost/asio/detail/memory.hpp index 479b57a3d1..c0a205e169 100644 --- a/boost/asio/detail/memory.hpp +++ b/boost/asio/detail/memory.hpp @@ -18,14 +18,55 @@ #include <boost/asio/detail/config.hpp> #include <memory> +#if !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) +# include <boost/shared_ptr.hpp> +# include <boost/weak_ptr.hpp> +#endif // !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) + +#if !defined(BOOST_ASIO_HAS_STD_ADDRESSOF) +# include <boost/utility/addressof.hpp> +#endif // !defined(BOOST_ASIO_HAS_STD_ADDRESSOF) + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_HAS_STD_SHARED_PTR) +using std::shared_ptr; +using std::weak_ptr; +#else // defined(BOOST_ASIO_HAS_STD_SHARED_PTR) +using boost::shared_ptr; +using boost::weak_ptr; +#endif // defined(BOOST_ASIO_HAS_STD_SHARED_PTR) + +#if defined(BOOST_ASIO_HAS_STD_ADDRESSOF) +using std::addressof; +#else // defined(BOOST_ASIO_HAS_STD_ADDRESSOF) +using boost::addressof; +#endif // defined(BOOST_ASIO_HAS_STD_ADDRESSOF) + +} // namespace detail + #if defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) +using std::allocator_arg_t; +# define BOOST_ASIO_USES_ALLOCATOR(t) \ + namespace std { \ + template <typename Allocator> \ + struct uses_allocator<t, Allocator> : true_type {}; \ + } \ + /**/ # define BOOST_ASIO_REBIND_ALLOC(alloc, t) \ typename std::allocator_traits<alloc>::template rebind_alloc<t> /**/ #else // defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) +struct allocator_arg_t {}; +# define BOOST_ASIO_USES_ALLOCATOR(t) # define BOOST_ASIO_REBIND_ALLOC(alloc, t) \ typename alloc::template rebind<t>::other /**/ #endif // defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) +} // namespace asio +} // namespace boost + #endif // BOOST_ASIO_DETAIL_MEMORY_HPP diff --git a/boost/asio/detail/null_event.hpp b/boost/asio/detail/null_event.hpp index 28ba5ede55..3bc74afb68 100644 --- a/boost/asio/detail/null_event.hpp +++ b/boost/asio/detail/null_event.hpp @@ -16,9 +16,6 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> - -#if !defined(BOOST_ASIO_HAS_THREADS) - #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> @@ -76,7 +73,20 @@ public: template <typename Lock> void wait(Lock&) { + do_wait(); } + + // Timed wait for the event to become signalled. + template <typename Lock> + bool wait_for_usec(Lock&, long usec) + { + do_wait_for_usec(usec); + return true; + } + +private: + BOOST_ASIO_DECL static void do_wait(); + BOOST_ASIO_DECL static void do_wait_for_usec(long usec); }; } // namespace detail @@ -85,6 +95,8 @@ public: #include <boost/asio/detail/pop_options.hpp> -#endif // !defined(BOOST_ASIO_HAS_THREADS) +#if defined(BOOST_ASIO_HEADER_ONLY) +# include <boost/asio/detail/impl/null_event.ipp> +#endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_DETAIL_NULL_EVENT_HPP diff --git a/boost/asio/detail/null_fenced_block.hpp b/boost/asio/detail/null_fenced_block.hpp index 27029b9e31..6d2b22f8cf 100644 --- a/boost/asio/detail/null_fenced_block.hpp +++ b/boost/asio/detail/null_fenced_block.hpp @@ -15,6 +15,8 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include <boost/asio/detail/noncopyable.hpp> + #include <boost/asio/detail/push_options.hpp> namespace boost { diff --git a/boost/asio/detail/null_global.hpp b/boost/asio/detail/null_global.hpp new file mode 100644 index 0000000000..fa24b5cbaf --- /dev/null +++ b/boost/asio/detail/null_global.hpp @@ -0,0 +1,61 @@ +// +// detail/null_global.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_NULL_GLOBAL_HPP +#define BOOST_ASIO_DETAIL_NULL_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +template <typename T> +struct null_global_impl +{ + null_global_impl() + : ptr_(0) + { + } + + // Destructor automatically cleans up the global. + ~null_global_impl() + { + delete ptr_; + } + + static null_global_impl instance_; + T* ptr_; +}; + +template <typename T> +null_global_impl<T> null_global_impl<T>::instance_; + +template <typename T> +T& null_global() +{ + if (null_global_impl<T>::instance_.ptr_ == 0) + null_global_impl<T>::instance_.ptr_ = new T; + return *null_global_impl<T>::instance_.ptr_; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_NULL_GLOBAL_HPP diff --git a/boost/asio/detail/null_reactor.hpp b/boost/asio/detail/null_reactor.hpp index 2cfce63a4c..30a07390a7 100644 --- a/boost/asio/detail/null_reactor.hpp +++ b/boost/asio/detail/null_reactor.hpp @@ -17,9 +17,10 @@ #include <boost/asio/detail/config.hpp> -#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +#if defined(BOOST_ASIO_HAS_IOCP) || defined(BOOST_ASIO_WINDOWS_RUNTIME) -#include <boost/asio/io_service.hpp> +#include <boost/asio/detail/scheduler_operation.hpp> +#include <boost/asio/execution_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -28,12 +29,12 @@ namespace asio { namespace detail { class null_reactor - : public boost::asio::detail::service_base<null_reactor> + : public execution_context_service_base<null_reactor> { public: // Constructor. - null_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base<null_reactor>(io_service) + null_reactor(boost::asio::execution_context& ctx) + : execution_context_service_base<null_reactor>(ctx) { } @@ -43,12 +44,12 @@ public: } // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { } // No-op because should never be called. - void run(bool /*block*/, op_queue<operation>& /*ops*/) + void run(long /*usec*/, op_queue<scheduler_operation>& /*ops*/) { } @@ -64,6 +65,6 @@ public: #include <boost/asio/detail/pop_options.hpp> -#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) +#endif // defined(BOOST_ASIO_HAS_IOCP) || defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_NULL_REACTOR_HPP diff --git a/boost/asio/detail/null_socket_service.hpp b/boost/asio/detail/null_socket_service.hpp index bf06ebb545..73a11cf9e8 100644 --- a/boost/asio/detail/null_socket_service.hpp +++ b/boost/asio/detail/null_socket_service.hpp @@ -21,7 +21,7 @@ #include <boost/asio/buffer.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/socket_base.hpp> #include <boost/asio/detail/bind_handler.hpp> @@ -32,7 +32,8 @@ namespace asio { namespace detail { template <typename Protocol> -class null_socket_service +class null_socket_service : + public service_base<null_socket_service<Protocol> > { public: // The protocol type. @@ -50,13 +51,14 @@ public: }; // Constructor. - null_socket_service(boost::asio::io_service& io_service) - : io_service_(io_service) + null_socket_service(boost::asio::io_context& io_context) + : service_base<null_socket_service<Protocol> >(io_context), + io_context_(io_context) { } // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { } @@ -119,6 +121,14 @@ public: return ec; } + // Release ownership of the socket. + native_handle_type release(implementation_type&, + boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return 0; + } + // Get the native socket representation. native_handle_type native_handle(implementation_type&) { @@ -269,7 +279,7 @@ public: { boost::system::error_code ec = boost::asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_service_.post(detail::bind_handler(handler, ec, bytes_transferred)); + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); } // Start an asynchronous wait until data can be sent without blocking. @@ -279,7 +289,7 @@ public: { boost::system::error_code ec = boost::asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_service_.post(detail::bind_handler(handler, ec, bytes_transferred)); + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); } // Receive some data from the peer. Returns the number of bytes received. @@ -307,7 +317,7 @@ public: { boost::system::error_code ec = boost::asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_service_.post(detail::bind_handler(handler, ec, bytes_transferred)); + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); } // Wait until data can be received without blocking. @@ -317,7 +327,7 @@ public: { boost::system::error_code ec = boost::asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_service_.post(detail::bind_handler(handler, ec, bytes_transferred)); + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); } // Receive some data with associated flags. Returns the number of bytes @@ -349,7 +359,7 @@ public: { boost::system::error_code ec = boost::asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_service_.post(detail::bind_handler(handler, ec, bytes_transferred)); + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); } // Wait until data can be received without blocking. @@ -360,7 +370,7 @@ public: { boost::system::error_code ec = boost::asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_service_.post(detail::bind_handler(handler, ec, bytes_transferred)); + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); } // Send a datagram to the specified endpoint. Returns the number of bytes @@ -392,7 +402,7 @@ public: { boost::system::error_code ec = boost::asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_service_.post(detail::bind_handler(handler, ec, bytes_transferred)); + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); } // Start an asynchronous wait until data can be sent without blocking. @@ -402,7 +412,7 @@ public: { boost::system::error_code ec = boost::asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_service_.post(detail::bind_handler(handler, ec, bytes_transferred)); + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); } // Receive a datagram with the endpoint of the sender. Returns the number of @@ -435,7 +445,7 @@ public: { boost::system::error_code ec = boost::asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_service_.post(detail::bind_handler(handler, ec, bytes_transferred)); + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); } // Wait until data can be received without blocking. @@ -446,7 +456,7 @@ public: { boost::system::error_code ec = boost::asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_service_.post(detail::bind_handler(handler, ec, bytes_transferred)); + io_context_.post(detail::bind_handler(handler, ec, bytes_transferred)); } // Accept a new connection. @@ -465,7 +475,7 @@ public: endpoint_type*, Handler& handler) { boost::system::error_code ec = boost::asio::error::operation_not_supported; - io_service_.post(detail::bind_handler(handler, ec)); + io_context_.post(detail::bind_handler(handler, ec)); } // Connect the socket to the specified endpoint. @@ -482,11 +492,11 @@ public: const endpoint_type&, Handler& handler) { boost::system::error_code ec = boost::asio::error::operation_not_supported; - io_service_.post(detail::bind_handler(handler, ec)); + io_context_.post(detail::bind_handler(handler, ec)); } private: - boost::asio::io_service& io_service_; + boost::asio::io_context& io_context_; }; } // namespace detail diff --git a/boost/asio/detail/null_thread.hpp b/boost/asio/detail/null_thread.hpp index 5e9b458638..bdb9912be3 100644 --- a/boost/asio/detail/null_thread.hpp +++ b/boost/asio/detail/null_thread.hpp @@ -50,6 +50,12 @@ public: void join() { } + + // Get number of CPUs. + static std::size_t hardware_concurrency() + { + return 1; + } }; } // namespace detail diff --git a/boost/asio/detail/object_pool.hpp b/boost/asio/detail/object_pool.hpp index 692efed09d..3affeb8dab 100644 --- a/boost/asio/detail/object_pool.hpp +++ b/boost/asio/detail/object_pool.hpp @@ -35,6 +35,12 @@ public: return new Object; } + template <typename Object, typename Arg> + static Object* create(Arg arg) + { + return new Object(arg); + } + template <typename Object> static void destroy(Object* o) { @@ -97,6 +103,25 @@ public: return o; } + // Allocate a new object with an argument. + template <typename Arg> + Object* alloc(Arg arg) + { + Object* o = free_list_; + if (o) + free_list_ = object_pool_access::next(free_list_); + else + o = object_pool_access::create<Object>(arg); + + object_pool_access::next(o) = live_list_; + object_pool_access::prev(o) = 0; + if (live_list_) + object_pool_access::prev(live_list_) = o; + live_list_ = o; + + return o; + } + // Free an object. Moves it to the free list. No destructors are run. void free(Object* o) { diff --git a/boost/asio/detail/operation.hpp b/boost/asio/detail/operation.hpp index a186a1f4d8..be62d12514 100644 --- a/boost/asio/detail/operation.hpp +++ b/boost/asio/detail/operation.hpp @@ -20,7 +20,7 @@ #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_operation.hpp> #else -# include <boost/asio/detail/task_io_service_operation.hpp> +# include <boost/asio/detail/scheduler_operation.hpp> #endif namespace boost { @@ -30,7 +30,7 @@ namespace detail { #if defined(BOOST_ASIO_HAS_IOCP) typedef win_iocp_operation operation; #else -typedef task_io_service_operation operation; +typedef scheduler_operation operation; #endif } // namespace detail diff --git a/boost/asio/detail/pop_options.hpp b/boost/asio/detail/pop_options.hpp index 29213ede7b..7126d75040 100644 --- a/boost/asio/detail/pop_options.hpp +++ b/boost/asio/detail/pop_options.hpp @@ -67,6 +67,10 @@ # pragma GCC visibility pop # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# if (__GNUC__ >= 7) +# pragma GCC diagnostic pop +# endif // (__GNUC__ >= 7) + #elif defined(__KCC) // Kai C++ diff --git a/boost/asio/detail/posix_event.hpp b/boost/asio/detail/posix_event.hpp index 4eae96e2a8..970f298638 100644 --- a/boost/asio/detail/posix_event.hpp +++ b/boost/asio/detail/posix_event.hpp @@ -108,6 +108,39 @@ public: } } + // Timed wait for the event to become signalled. + template <typename Lock> + bool wait_for_usec(Lock& lock, long usec) + { + BOOST_ASIO_ASSERT(lock.locked()); + if ((state_ & 1) == 0) + { + state_ += 2; + timespec ts; +#if (defined(__MACH__) && defined(__APPLE__)) \ + || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + ::pthread_cond_timedwait_relative_np( + &cond_, &lock.mutex().mutex_, &ts); // Ignore EINVAL. +#else // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) + if (::clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + { + ts.tv_sec += usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + ts.tv_sec += ts.tv_nsec / 1000000000; + ts.tv_nsec = ts.tv_nsec % 1000000000; + ::pthread_cond_timedwait(&cond_, + &lock.mutex().mutex_, &ts); // Ignore EINVAL. + } +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) + state_ -= 2; + } + return (state_ & 1) != 0; + } + private: ::pthread_cond_t cond_; std::size_t state_; diff --git a/boost/asio/detail/posix_global.hpp b/boost/asio/detail/posix_global.hpp new file mode 100644 index 0000000000..463809fc29 --- /dev/null +++ b/boost/asio/detail/posix_global.hpp @@ -0,0 +1,82 @@ +// +// detail/posix_global.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_POSIX_GLOBAL_HPP +#define BOOST_ASIO_DETAIL_POSIX_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_HAS_PTHREADS) + +#include <exception> +#include <pthread.h> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +template <typename T> +struct posix_global_impl +{ + // Helper function to perform initialisation. + static void do_init() + { + instance_.static_ptr_ = instance_.ptr_ = new T; + } + + // Destructor automatically cleans up the global. + ~posix_global_impl() + { + delete static_ptr_; + } + + static ::pthread_once_t init_once_; + static T* static_ptr_; + static posix_global_impl instance_; + T* ptr_; +}; + +template <typename T> +::pthread_once_t posix_global_impl<T>::init_once_ = PTHREAD_ONCE_INIT; + +template <typename T> +T* posix_global_impl<T>::static_ptr_ = 0; + +template <typename T> +posix_global_impl<T> posix_global_impl<T>::instance_; + +template <typename T> +T& posix_global() +{ + int result = ::pthread_once( + &posix_global_impl<T>::init_once_, + &posix_global_impl<T>::do_init); + + if (result != 0) + std::terminate(); + + return *posix_global_impl<T>::instance_.ptr_; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // defined(BOOST_ASIO_HAS_PTHREADS) + +#endif // BOOST_ASIO_DETAIL_POSIX_GLOBAL_HPP diff --git a/boost/asio/detail/posix_thread.hpp b/boost/asio/detail/posix_thread.hpp index ddf5ba46f3..985e14028f 100644 --- a/boost/asio/detail/posix_thread.hpp +++ b/boost/asio/detail/posix_thread.hpp @@ -19,6 +19,7 @@ #if defined(BOOST_ASIO_HAS_PTHREADS) +#include <cstddef> #include <pthread.h> #include <boost/asio/detail/noncopyable.hpp> @@ -51,6 +52,9 @@ public: // Wait for the thread to exit. BOOST_ASIO_DECL void join(); + // Get number of CPUs. + BOOST_ASIO_DECL static std::size_t hardware_concurrency(); + private: friend void* boost_asio_detail_posix_thread_function(void* arg); diff --git a/boost/asio/detail/push_options.hpp b/boost/asio/detail/push_options.hpp index ae189c0519..08e541d0d1 100644 --- a/boost/asio/detail/push_options.hpp +++ b/boost/asio/detail/push_options.hpp @@ -71,6 +71,11 @@ # pragma GCC visibility push (default) # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# if (__GNUC__ >= 7) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +# endif // (__GNUC__ >= 7) + #elif defined(__KCC) // Kai C++ @@ -135,6 +140,10 @@ # pragma warning (disable:4512) # pragma warning (disable:4610) # pragma warning (disable:4675) +# if (_MSC_VER < 1600) +// Visual Studio 2008 generates spurious warnings about unused parameters. +# pragma warning (disable:4100) +# endif // (_MSC_VER < 1600) # if defined(_M_IX86) && defined(_Wp64) // The /Wp64 option is broken. If you want to check 64 bit portability, use a // 64 bit compiler! diff --git a/boost/asio/detail/reactive_descriptor_service.hpp b/boost/asio/detail/reactive_descriptor_service.hpp index 3d6d1e98c8..f413edbc7b 100644 --- a/boost/asio/detail/reactive_descriptor_service.hpp +++ b/boost/asio/detail/reactive_descriptor_service.hpp @@ -22,17 +22,19 @@ && !defined(__CYGWIN__) #include <boost/asio/buffer.hpp> -#include <boost/asio/io_service.hpp> -#include <boost/asio/detail/addressof.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/descriptor_ops.hpp> #include <boost/asio/detail/descriptor_read_op.hpp> #include <boost/asio/detail/descriptor_write_op.hpp> #include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/reactive_null_buffers_op.hpp> +#include <boost/asio/detail/reactive_wait_op.hpp> #include <boost/asio/detail/reactor.hpp> +#include <boost/asio/posix/descriptor_base.hpp> #include <boost/asio/detail/push_options.hpp> @@ -40,7 +42,8 @@ namespace boost { namespace asio { namespace detail { -class reactive_descriptor_service +class reactive_descriptor_service : + public service_base<reactive_descriptor_service> { public: // The native type of a descriptor. @@ -74,10 +77,10 @@ public: // Constructor. BOOST_ASIO_DECL reactive_descriptor_service( - boost::asio::io_service& io_service); + boost::asio::io_context& io_context); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void shutdown(); // Construct a new descriptor implementation. BOOST_ASIO_DECL void construct(implementation_type& impl); @@ -162,6 +165,71 @@ public: return ec; } + // Wait for the descriptor to become ready to read, ready to write, or to have + // pending error conditions. + boost::system::error_code wait(implementation_type& impl, + posix::descriptor_base::wait_type w, boost::system::error_code& ec) + { + switch (w) + { + case posix::descriptor_base::wait_read: + descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec); + break; + case posix::descriptor_base::wait_write: + descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec); + break; + case posix::descriptor_base::wait_error: + descriptor_ops::poll_error(impl.descriptor_, impl.state_, ec); + break; + default: + ec = boost::asio::error::invalid_argument; + break; + } + + return ec; + } + + // Asynchronously wait for the descriptor to become ready to read, ready to + // write, or to have pending error conditions. + template <typename Handler> + void async_wait(implementation_type& impl, + posix::descriptor_base::wait_type w, Handler& handler) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_wait_op<Handler> op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_wait")); + + int op_type; + switch (w) + { + case posix::descriptor_base::wait_read: + op_type = reactor::read_op; + break; + case posix::descriptor_base::wait_write: + op_type = reactor::write_op; + break; + case posix::descriptor_base::wait_error: + op_type = reactor::except_op; + break; + default: + p.p->ec_ = boost::asio::error::invalid_argument; + reactor_.post_immediate_completion(p.p, is_continuation); + p.v = p.p = 0; + return; + } + + start_op(impl, op_type, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + // Write some data to the descriptor. template <typename ConstBufferSequence> size_t write_some(implementation_type& impl, @@ -196,11 +264,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef descriptor_write_op<ConstBufferSequence, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.descriptor_, buffers, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "descriptor", &impl, "async_write_some")); + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_write_some")); start_op(impl, reactor::write_op, p.p, is_continuation, true, buffer_sequence_adapter<boost::asio::const_buffer, @@ -219,12 +287,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef reactive_null_buffers_op<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "descriptor", - &impl, "async_write_some(null_buffers)")); + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_write_some(null_buffers)")); start_op(impl, reactor::write_op, p.p, is_continuation, false, false); p.v = p.p = 0; @@ -264,11 +331,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef descriptor_read_op<MutableBufferSequence, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.descriptor_, buffers, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "descriptor", &impl, "async_read_some")); + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_read_some")); start_op(impl, reactor::read_op, p.p, is_continuation, true, buffer_sequence_adapter<boost::asio::mutable_buffer, @@ -287,12 +354,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef reactive_null_buffers_op<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "descriptor", - &impl, "async_read_some(null_buffers)")); + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_read_some(null_buffers)")); start_op(impl, reactor::read_op, p.p, is_continuation, false, false); p.v = p.p = 0; diff --git a/boost/asio/detail/reactive_null_buffers_op.hpp b/boost/asio/detail/reactive_null_buffers_op.hpp index 4b1c7fedbf..0983b8a52e 100644 --- a/boost/asio/detail/reactive_null_buffers_op.hpp +++ b/boost/asio/detail/reactive_null_buffers_op.hpp @@ -16,10 +16,10 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/push_options.hpp> @@ -39,22 +39,24 @@ public: &reactive_null_buffers_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static bool do_perform(reactor_op*) + static status do_perform(reactor_op*) { - return true; + return done; } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. reactive_null_buffers_op* o(static_cast<reactive_null_buffers_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_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 @@ -72,7 +74,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/reactive_serial_port_service.hpp b/boost/asio/detail/reactive_serial_port_service.hpp index 4976fbd08e..225f0828f5 100644 --- a/boost/asio/detail/reactive_serial_port_service.hpp +++ b/boost/asio/detail/reactive_serial_port_service.hpp @@ -23,7 +23,7 @@ #include <string> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/serial_port_base.hpp> #include <boost/asio/detail/descriptor_ops.hpp> #include <boost/asio/detail/reactive_descriptor_service.hpp> @@ -35,7 +35,8 @@ namespace asio { namespace detail { // Extend reactive_descriptor_service to provide serial port support. -class reactive_serial_port_service +class reactive_serial_port_service : + public service_base<reactive_serial_port_service> { public: // The native type of a serial port. @@ -45,10 +46,10 @@ public: typedef reactive_descriptor_service::implementation_type implementation_type; BOOST_ASIO_DECL reactive_serial_port_service( - boost::asio::io_service& io_service); + boost::asio::io_context& io_context); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void shutdown(); // Construct a new serial port implementation. void construct(implementation_type& impl) @@ -190,8 +191,8 @@ private: static boost::system::error_code store_option(const void* option, termios& storage, boost::system::error_code& ec) { - return static_cast<const SettableSerialPortOption*>(option)->store( - storage, ec); + static_cast<const SettableSerialPortOption*>(option)->store(storage, ec); + return ec; } // Helper function to set a serial port option. @@ -208,7 +209,8 @@ private: static boost::system::error_code load_option(void* option, const termios& storage, boost::system::error_code& ec) { - return static_cast<GettableSerialPortOption*>(option)->load(storage, ec); + static_cast<GettableSerialPortOption*>(option)->load(storage, ec); + return ec; } // Helper function to get a serial port option. diff --git a/boost/asio/detail/reactive_socket_accept_op.hpp b/boost/asio/detail/reactive_socket_accept_op.hpp index fec6bddb55..ca996b2ab5 100644 --- a/boost/asio/detail/reactive_socket_accept_op.hpp +++ b/boost/asio/detail/reactive_socket_accept_op.hpp @@ -16,10 +16,10 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_holder.hpp> #include <boost/asio/detail/socket_ops.hpp> @@ -42,40 +42,48 @@ public: state_(state), peer_(peer), protocol_(protocol), - peer_endpoint_(peer_endpoint) + peer_endpoint_(peer_endpoint), + addrlen_(peer_endpoint ? peer_endpoint->capacity() : 0) { } - static bool do_perform(reactor_op* base) + static status do_perform(reactor_op* base) { reactive_socket_accept_op_base* o( static_cast<reactive_socket_accept_op_base*>(base)); - std::size_t addrlen = o->peer_endpoint_ ? o->peer_endpoint_->capacity() : 0; socket_type new_socket = invalid_socket; - bool result = socket_ops::non_blocking_accept(o->socket_, - o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0, - o->peer_endpoint_ ? &addrlen : 0, o->ec_, new_socket); + status result = socket_ops::non_blocking_accept(o->socket_, + o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0, + o->peer_endpoint_ ? &o->addrlen_ : 0, o->ec_, new_socket) + ? done : not_done; + o->new_socket_.reset(new_socket); - // On success, assign new connection to peer socket object. - if (new_socket != invalid_socket) - { - socket_holder new_socket_holder(new_socket); - if (o->peer_endpoint_) - o->peer_endpoint_->resize(addrlen); - if (!o->peer_.assign(o->protocol_, new_socket, o->ec_)) - new_socket_holder.release(); - } + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_accept", o->ec_)); return result; } + void do_assign() + { + if (new_socket_.get() != invalid_socket) + { + if (peer_endpoint_) + peer_endpoint_->resize(addrlen_); + peer_.assign(protocol_, new_socket_.get(), ec_); + if (!ec_) + new_socket_.release(); + } + } + private: socket_type socket_; socket_ops::state_type state_; + socket_holder new_socket_; Socket& peer_; Protocol protocol_; typename Protocol::endpoint* peer_endpoint_; + std::size_t addrlen_; }; template <typename Socket, typename Protocol, typename Handler> @@ -92,17 +100,23 @@ public: protocol, peer_endpoint, &reactive_socket_accept_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. reactive_socket_accept_op* o(static_cast<reactive_socket_accept_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + // On success, assign new connection to peer socket object. + if (owner) + o->do_assign(); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_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 @@ -120,7 +134,72 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +#if defined(BOOST_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: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_move_accept_op); + + reactive_socket_move_accept_op(io_context& ioc, socket_type socket, + socket_ops::state_type state, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, Handler& handler) + : Protocol::socket(ioc), + reactive_socket_accept_op_base<typename Protocol::socket, Protocol>( + socket, state, *this, protocol, peer_endpoint, + &reactive_socket_move_accept_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::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 = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + // On success, assign new connection to peer socket object. + if (owner) + o->do_assign(); + + BOOST_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, + boost::system::error_code, typename Protocol::socket> + handler(0, BOOST_ASIO_MOVE_CAST(Handler)(o->handler_), o->ec_, + BOOST_ASIO_MOVE_CAST(typename Protocol::socket)(*o)); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } @@ -129,6 +208,8 @@ private: Handler handler_; }; +#endif // defined(BOOST_ASIO_HAS_MOVE) + } // namespace detail } // namespace asio } // namespace boost diff --git a/boost/asio/detail/reactive_socket_connect_op.hpp b/boost/asio/detail/reactive_socket_connect_op.hpp index 809d63b7ae..410da203ad 100644 --- a/boost/asio/detail/reactive_socket_connect_op.hpp +++ b/boost/asio/detail/reactive_socket_connect_op.hpp @@ -16,10 +16,10 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> @@ -38,12 +38,17 @@ public: { } - static bool do_perform(reactor_op* base) + static status do_perform(reactor_op* base) { reactive_socket_connect_op_base* o( static_cast<reactive_socket_connect_op_base*>(base)); - return socket_ops::non_blocking_connect(o->socket_, o->ec_); + status result = socket_ops::non_blocking_connect( + o->socket_, o->ec_) ? done : not_done; + + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_connect", o->ec_)); + + return result; } private: @@ -61,9 +66,10 @@ public: &reactive_socket_connect_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/) { @@ -71,8 +77,9 @@ public: reactive_socket_connect_op* o (static_cast<reactive_socket_connect_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_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 @@ -90,7 +97,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/reactive_socket_recv_op.hpp b/boost/asio/detail/reactive_socket_recv_op.hpp index 751160c48f..ea7d84a0c5 100644 --- a/boost/asio/detail/reactive_socket_recv_op.hpp +++ b/boost/asio/detail/reactive_socket_recv_op.hpp @@ -16,10 +16,10 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> @@ -44,7 +44,7 @@ public: { } - static bool do_perform(reactor_op* base) + static status do_perform(reactor_op* base) { reactive_socket_recv_op_base* o( static_cast<reactive_socket_recv_op_base*>(base)); @@ -52,10 +52,20 @@ public: buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence> bufs(o->buffers_); - return socket_ops::non_blocking_recv(o->socket_, + status result = socket_ops::non_blocking_recv(o->socket_, bufs.buffers(), bufs.count(), o->flags_, (o->state_ & socket_ops::stream_oriented) != 0, - o->ec_, o->bytes_transferred_); + o->ec_, o->bytes_transferred_) ? done : not_done; + + if (result == done) + if ((o->state_ & socket_ops::stream_oriented) != 0) + if (o->bytes_transferred_ == 0) + result = done_and_exhausted; + + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recv", + o->ec_, o->bytes_transferred_)); + + return result; } private: @@ -79,17 +89,19 @@ public: buffers, flags, &reactive_socket_recv_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. reactive_socket_recv_op* o(static_cast<reactive_socket_recv_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_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 @@ -107,7 +119,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/reactive_socket_recvfrom_op.hpp b/boost/asio/detail/reactive_socket_recvfrom_op.hpp index 14829a0d75..9631465f24 100644 --- a/boost/asio/detail/reactive_socket_recvfrom_op.hpp +++ b/boost/asio/detail/reactive_socket_recvfrom_op.hpp @@ -16,10 +16,10 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> @@ -45,7 +45,7 @@ public: { } - static bool do_perform(reactor_op* base) + static status do_perform(reactor_op* base) { reactive_socket_recvfrom_op_base* o( static_cast<reactive_socket_recvfrom_op_base*>(base)); @@ -54,14 +54,17 @@ public: MutableBufferSequence> bufs(o->buffers_); std::size_t addr_len = o->sender_endpoint_.capacity(); - bool result = socket_ops::non_blocking_recvfrom(o->socket_, + status result = socket_ops::non_blocking_recvfrom(o->socket_, bufs.buffers(), bufs.count(), o->flags_, o->sender_endpoint_.data(), &addr_len, - o->ec_, o->bytes_transferred_); + o->ec_, o->bytes_transferred_) ? done : not_done; if (result && !o->ec_) o->sender_endpoint_.resize(addr_len); + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvfrom", + o->ec_, o->bytes_transferred_)); + return result; } @@ -88,9 +91,10 @@ public: &reactive_socket_recvfrom_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/) { @@ -98,8 +102,9 @@ public: reactive_socket_recvfrom_op* o( static_cast<reactive_socket_recvfrom_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_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 @@ -117,7 +122,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/reactive_socket_recvmsg_op.hpp b/boost/asio/detail/reactive_socket_recvmsg_op.hpp index fed5d01098..c48b1aba7e 100644 --- a/boost/asio/detail/reactive_socket_recvmsg_op.hpp +++ b/boost/asio/detail/reactive_socket_recvmsg_op.hpp @@ -16,10 +16,10 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/socket_base.hpp> @@ -45,7 +45,7 @@ public: { } - static bool do_perform(reactor_op* base) + static status do_perform(reactor_op* base) { reactive_socket_recvmsg_op_base* o( static_cast<reactive_socket_recvmsg_op_base*>(base)); @@ -53,10 +53,15 @@ public: buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence> bufs(o->buffers_); - return socket_ops::non_blocking_recvmsg(o->socket_, + status result = socket_ops::non_blocking_recvmsg(o->socket_, bufs.buffers(), bufs.count(), o->in_flags_, o->out_flags_, - o->ec_, o->bytes_transferred_); + o->ec_, o->bytes_transferred_) ? done : not_done; + + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvmsg", + o->ec_, o->bytes_transferred_)); + + return result; } private: @@ -80,9 +85,10 @@ public: in_flags, out_flags, &reactive_socket_recvmsg_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/) { @@ -90,8 +96,9 @@ public: reactive_socket_recvmsg_op* o( static_cast<reactive_socket_recvmsg_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_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 @@ -109,7 +116,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/reactive_socket_send_op.hpp b/boost/asio/detail/reactive_socket_send_op.hpp index 776117b6f7..01bb58f9ae 100644 --- a/boost/asio/detail/reactive_socket_send_op.hpp +++ b/boost/asio/detail/reactive_socket_send_op.hpp @@ -16,10 +16,10 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> @@ -34,16 +34,17 @@ class reactive_socket_send_op_base : public reactor_op { public: reactive_socket_send_op_base(socket_type socket, - const ConstBufferSequence& buffers, + socket_ops::state_type state, const ConstBufferSequence& buffers, socket_base::message_flags flags, func_type complete_func) : reactor_op(&reactive_socket_send_op_base::do_perform, complete_func), socket_(socket), + state_(state), buffers_(buffers), flags_(flags) { } - static bool do_perform(reactor_op* base) + static status do_perform(reactor_op* base) { reactive_socket_send_op_base* o( static_cast<reactive_socket_send_op_base*>(base)); @@ -51,13 +52,24 @@ public: buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence> bufs(o->buffers_); - return socket_ops::non_blocking_send(o->socket_, + status result = socket_ops::non_blocking_send(o->socket_, bufs.buffers(), bufs.count(), o->flags_, - o->ec_, o->bytes_transferred_); + o->ec_, o->bytes_transferred_) ? done : not_done; + + if (result == done) + if ((o->state_ & socket_ops::stream_oriented) != 0) + if (o->bytes_transferred_ < bufs.total_size()) + result = done_and_exhausted; + + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_send", + o->ec_, o->bytes_transferred_)); + + return result; } private: socket_type socket_; + socket_ops::state_type state_; ConstBufferSequence buffers_; socket_base::message_flags flags_; }; @@ -70,23 +82,25 @@ public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op); reactive_socket_send_op(socket_type socket, - const ConstBufferSequence& buffers, + socket_ops::state_type state, const ConstBufferSequence& buffers, socket_base::message_flags flags, Handler& handler) : reactive_socket_send_op_base<ConstBufferSequence>(socket, - buffers, flags, &reactive_socket_send_op::do_complete), + state, buffers, flags, &reactive_socket_send_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. reactive_socket_send_op* o(static_cast<reactive_socket_send_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_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 @@ -104,7 +118,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/reactive_socket_sendto_op.hpp b/boost/asio/detail/reactive_socket_sendto_op.hpp index 134c767c86..47a2656e22 100644 --- a/boost/asio/detail/reactive_socket_sendto_op.hpp +++ b/boost/asio/detail/reactive_socket_sendto_op.hpp @@ -16,10 +16,10 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> @@ -44,7 +44,7 @@ public: { } - static bool do_perform(reactor_op* base) + static status do_perform(reactor_op* base) { reactive_socket_sendto_op_base* o( static_cast<reactive_socket_sendto_op_base*>(base)); @@ -52,10 +52,15 @@ public: buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence> bufs(o->buffers_); - return socket_ops::non_blocking_sendto(o->socket_, + status result = socket_ops::non_blocking_sendto(o->socket_, bufs.buffers(), bufs.count(), o->flags_, o->destination_.data(), o->destination_.size(), - o->ec_, o->bytes_transferred_); + o->ec_, o->bytes_transferred_) ? done : not_done; + + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_sendto", + o->ec_, o->bytes_transferred_)); + + return result; } private: @@ -79,17 +84,19 @@ public: buffers, endpoint, flags, &reactive_socket_sendto_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. reactive_socket_sendto_op* o(static_cast<reactive_socket_sendto_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_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 @@ -107,7 +114,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/reactive_socket_service.hpp b/boost/asio/detail/reactive_socket_service.hpp index d5a6e08eab..186cf35336 100644 --- a/boost/asio/detail/reactive_socket_service.hpp +++ b/boost/asio/detail/reactive_socket_service.hpp @@ -21,10 +21,10 @@ #include <boost/asio/buffer.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/socket_base.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/reactive_null_buffers_op.hpp> #include <boost/asio/detail/reactive_socket_accept_op.hpp> @@ -46,6 +46,7 @@ namespace detail { template <typename Protocol> class reactive_socket_service : + public service_base<reactive_socket_service<Protocol> >, public reactive_socket_service_base { public: @@ -73,11 +74,18 @@ public: }; // Constructor. - reactive_socket_service(boost::asio::io_service& io_service) - : reactive_socket_service_base(io_service) + reactive_socket_service(boost::asio::io_context& io_context) + : service_base<reactive_socket_service<Protocol> >(io_context), + reactive_socket_service_base(io_context) { } + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + this->base_shutdown(); + } + // Move-construct a new socket implementation. void move_construct(implementation_type& impl, implementation_type& other_impl) @@ -196,6 +204,14 @@ public: return endpoint; } + // Disable sends or receives on the socket. + boost::system::error_code shutdown(base_implementation_type& impl, + socket_base::shutdown_type what, boost::system::error_code& ec) + { + socket_ops::shutdown(impl.socket_, what, ec); + return ec; + } + // Send a datagram to the specified endpoint. Returns the number of bytes // sent. template <typename ConstBufferSequence> @@ -217,7 +233,7 @@ public: boost::system::error_code& ec) { // Wait for socket to become ready. - socket_ops::poll_write(impl.socket_, impl.state_, ec); + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); return 0; } @@ -237,11 +253,11 @@ public: typedef reactive_socket_sendto_op<ConstBufferSequence, endpoint_type, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.socket_, buffers, destination, flags, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send_to")); + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send_to")); start_op(impl, reactor::write_op, p.p, is_continuation, true, false); p.v = p.p = 0; @@ -258,12 +274,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef reactive_null_buffers_op<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", - &impl, "async_send_to(null_buffers)")); + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send_to(null_buffers)")); start_op(impl, reactor::write_op, p.p, is_continuation, false, false); p.v = p.p = 0; @@ -297,7 +312,7 @@ public: boost::system::error_code& ec) { // Wait for socket to become ready. - socket_ops::poll_read(impl.socket_, impl.state_, ec); + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); @@ -320,14 +335,13 @@ public: typedef reactive_socket_recvfrom_op<MutableBufferSequence, endpoint_type, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; int protocol = impl.protocol_.type(); p.p = new (p.v) op(impl.socket_, protocol, buffers, sender_endpoint, flags, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", - &impl, "async_receive_from")); + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_from")); start_op(impl, (flags & socket_base::message_out_of_band) @@ -348,12 +362,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef reactive_null_buffers_op<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", - &impl, "async_receive_from(null_buffers)")); + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_from(null_buffers)")); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); @@ -387,15 +400,44 @@ public: { if (peer_endpoint) peer_endpoint->resize(addr_len); - if (!peer.assign(impl.protocol_, new_socket.get(), ec)) + peer.assign(impl.protocol_, new_socket.get(), ec); + if (!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. +#if defined(BOOST_ASIO_HAS_MOVE) + // Accept a new connection. + typename Protocol::socket accept(implementation_type& impl, + io_context* peer_io_context, endpoint_type* peer_endpoint, + boost::system::error_code& ec) + { + typename Protocol::socket peer( + peer_io_context ? *peer_io_context : io_context_); + + 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); + peer.assign(impl.protocol_, new_socket.get(), ec); + if (!ec) + new_socket.release(); + } + + return peer; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // 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) @@ -406,17 +448,43 @@ public: // Allocate and construct an operation to wrap the handler. typedef reactive_socket_accept_op<Socket, Protocol, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.socket_, impl.state_, peer, impl.protocol_, peer_endpoint, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_accept")); + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_accept")); start_accept_op(impl, p.p, is_continuation, peer.is_open()); p.v = p.p = 0; } +#if defined(BOOST_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, + boost::asio::io_context* peer_io_context, + endpoint_type* peer_endpoint, Handler& handler) + { + bool is_continuation = + boost_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 = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(peer_io_context ? *peer_io_context : io_context_, + impl.socket_, impl.state_, impl.protocol_, peer_endpoint, handler); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_accept")); + + start_accept_op(impl, p.p, is_continuation, false); + p.v = p.p = 0; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + // Connect the socket to the specified endpoint. boost::system::error_code connect(implementation_type& impl, const endpoint_type& peer_endpoint, boost::system::error_code& ec) @@ -437,11 +505,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef reactive_socket_connect_op<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.socket_, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_connect")); + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_connect")); start_connect_op(impl, p.p, is_continuation, peer_endpoint.data(), peer_endpoint.size()); diff --git a/boost/asio/detail/reactive_socket_service_base.hpp b/boost/asio/detail/reactive_socket_service_base.hpp index fb2aa5d028..17c694a3cd 100644 --- a/boost/asio/detail/reactive_socket_service_base.hpp +++ b/boost/asio/detail/reactive_socket_service_base.hpp @@ -22,14 +22,15 @@ #include <boost/asio/buffer.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/socket_base.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactive_null_buffers_op.hpp> #include <boost/asio/detail/reactive_socket_recv_op.hpp> #include <boost/asio/detail/reactive_socket_recvmsg_op.hpp> #include <boost/asio/detail/reactive_socket_send_op.hpp> +#include <boost/asio/detail/reactive_wait_op.hpp> #include <boost/asio/detail/reactor.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_holder.hpp> @@ -63,10 +64,10 @@ public: // Constructor. BOOST_ASIO_DECL reactive_socket_service_base( - boost::asio::io_service& io_service); + boost::asio::io_context& io_context); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void base_shutdown(); // Construct a new socket implementation. BOOST_ASIO_DECL void construct(base_implementation_type& impl); @@ -93,6 +94,10 @@ public: BOOST_ASIO_DECL boost::system::error_code close( base_implementation_type& impl, boost::system::error_code& ec); + // Release ownership of the socket. + BOOST_ASIO_DECL socket_type release( + base_implementation_type& impl, boost::system::error_code& ec); + // Get the native socket representation. native_handle_type native_handle(base_implementation_type& impl) { @@ -163,14 +168,71 @@ public: return ec; } - // Disable sends or receives on the socket. - boost::system::error_code shutdown(base_implementation_type& impl, - socket_base::shutdown_type what, boost::system::error_code& ec) + // Wait for the socket to become ready to read, ready to write, or to have + // pending error conditions. + boost::system::error_code wait(base_implementation_type& impl, + socket_base::wait_type w, boost::system::error_code& ec) { - socket_ops::shutdown(impl.socket_, what, ec); + switch (w) + { + case socket_base::wait_read: + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_write: + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_error: + socket_ops::poll_error(impl.socket_, impl.state_, -1, ec); + break; + default: + ec = boost::asio::error::invalid_argument; + break; + } + return ec; } + // Asynchronously wait for the socket to become ready to read, ready to + // write, or to have pending error conditions. + template <typename Handler> + void async_wait(base_implementation_type& impl, + socket_base::wait_type w, Handler& handler) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_wait_op<Handler> op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_wait")); + + int op_type; + switch (w) + { + case socket_base::wait_read: + op_type = reactor::read_op; + break; + case socket_base::wait_write: + op_type = reactor::write_op; + break; + case socket_base::wait_error: + op_type = reactor::except_op; + break; + default: + p.p->ec_ = boost::asio::error::invalid_argument; + reactor_.post_immediate_completion(p.p, is_continuation); + p.v = p.p = 0; + return; + } + + start_op(impl, op_type, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + // Send the given data to the peer. template <typename ConstBufferSequence> size_t send(base_implementation_type& impl, @@ -189,7 +251,7 @@ public: socket_base::message_flags, boost::system::error_code& ec) { // Wait for socket to become ready. - socket_ops::poll_write(impl.socket_, impl.state_, ec); + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); return 0; } @@ -207,11 +269,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef reactive_socket_send_op<ConstBufferSequence, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; - p.p = new (p.v) op(impl.socket_, buffers, flags, handler); + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send")); + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send")); start_op(impl, reactor::write_op, p.p, is_continuation, true, ((impl.state_ & socket_ops::stream_oriented) @@ -231,12 +293,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef reactive_null_buffers_op<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", - &impl, "async_send(null_buffers)")); + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send(null_buffers)")); start_op(impl, reactor::write_op, p.p, is_continuation, false, false); p.v = p.p = 0; @@ -260,7 +321,7 @@ public: socket_base::message_flags, boost::system::error_code& ec) { // Wait for socket to become ready. - socket_ops::poll_read(impl.socket_, impl.state_, ec); + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); return 0; } @@ -278,11 +339,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef reactive_socket_recv_op<MutableBufferSequence, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_receive")); + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive")); start_op(impl, (flags & socket_base::message_out_of_band) @@ -306,12 +367,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef reactive_null_buffers_op<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", - &impl, "async_receive(null_buffers)")); + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive(null_buffers)")); start_op(impl, (flags & socket_base::message_out_of_band) @@ -341,7 +401,7 @@ public: socket_base::message_flags& out_flags, boost::system::error_code& ec) { // Wait for socket to become ready. - socket_ops::poll_read(impl.socket_, impl.state_, ec); + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); // Clear out_flags, since we cannot give it any other sensible value when // performing a null_buffers operation. @@ -363,12 +423,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef reactive_socket_recvmsg_op<MutableBufferSequence, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.socket_, buffers, in_flags, out_flags, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", - &impl, "async_receive_with_flags")); + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags")); start_op(impl, (in_flags & socket_base::message_out_of_band) @@ -390,12 +449,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef reactive_null_buffers_op<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, - "async_receive_with_flags(null_buffers)")); + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags(null_buffers)")); // Clear out_flags, since we cannot give it any other sensible value when // performing a null_buffers operation. @@ -432,6 +490,9 @@ protected: reactor_op* op, bool is_continuation, const socket_addr_type* addr, size_t addrlen); + // The io_context that owns this socket service. + io_context& io_context_; + // The selector that performs event demultiplexing for the service. reactor& reactor_; }; diff --git a/boost/asio/detail/reactive_wait_op.hpp b/boost/asio/detail/reactive_wait_op.hpp new file mode 100644 index 0000000000..9bc4e2c1c5 --- /dev/null +++ b/boost/asio/detail/reactive_wait_op.hpp @@ -0,0 +1,92 @@ +// +// detail/reactive_wait_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_WAIT_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_WAIT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/handler_alloc_helpers.hpp> +#include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> +#include <boost/asio/detail/reactor_op.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +template <typename Handler> +class reactive_wait_op : public reactor_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_wait_op); + + reactive_wait_op(Handler& handler) + : reactor_op(&reactive_wait_op::do_perform, + &reactive_wait_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static status do_perform(reactor_op*) + { + return done; + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_wait_op* o(static_cast<reactive_wait_op*>(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + BOOST_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::binder1<Handler, boost::system::error_code> + handler(o->handler_, o->ec_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_REACTIVE_WAIT_OP_HPP diff --git a/boost/asio/detail/reactor.hpp b/boost/asio/detail/reactor.hpp index 1a4ace8776..e65df12863 100644 --- a/boost/asio/detail/reactor.hpp +++ b/boost/asio/detail/reactor.hpp @@ -23,7 +23,7 @@ # include <boost/asio/detail/kqueue_reactor.hpp> #elif defined(BOOST_ASIO_HAS_DEV_POLL) # include <boost/asio/detail/dev_poll_reactor.hpp> -#elif defined(BOOST_ASIO_WINDOWS_RUNTIME) +#elif defined(BOOST_ASIO_HAS_IOCP) || defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/null_reactor.hpp> #else # include <boost/asio/detail/select_reactor.hpp> diff --git a/boost/asio/detail/reactor_fwd.hpp b/boost/asio/detail/reactor_fwd.hpp index 6b2e49f5a4..d14ed4cf9c 100644 --- a/boost/asio/detail/reactor_fwd.hpp +++ b/boost/asio/detail/reactor_fwd.hpp @@ -21,7 +21,7 @@ namespace boost { namespace asio { namespace detail { -#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +#if defined(BOOST_ASIO_HAS_IOCP) || defined(BOOST_ASIO_WINDOWS_RUNTIME) typedef class null_reactor reactor; #elif defined(BOOST_ASIO_HAS_IOCP) typedef class select_reactor reactor; diff --git a/boost/asio/detail/reactor_op.hpp b/boost/asio/detail/reactor_op.hpp index c5964dea37..c2540545d5 100644 --- a/boost/asio/detail/reactor_op.hpp +++ b/boost/asio/detail/reactor_op.hpp @@ -34,14 +34,18 @@ public: // The number of bytes transferred, to be passed to the completion handler. std::size_t bytes_transferred_; + // Status returned by perform function. May be used to decide whether it is + // worth performing more operations on the descriptor immediately. + enum status { not_done, done, done_and_exhausted }; + // Perform the operation. Returns true if it is finished. - bool perform() + status perform() { return perform_func_(this); } protected: - typedef bool (*perform_func_type)(reactor_op*); + typedef status (*perform_func_type)(reactor_op*); reactor_op(perform_func_type perform_func, func_type complete_func) : operation(complete_func), diff --git a/boost/asio/detail/recycling_allocator.hpp b/boost/asio/detail/recycling_allocator.hpp new file mode 100644 index 0000000000..050e8bdfa0 --- /dev/null +++ b/boost/asio/detail/recycling_allocator.hpp @@ -0,0 +1,106 @@ +// +// detail/recycling_allocator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP +#define BOOST_ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/memory.hpp> +#include <boost/asio/detail/thread_context.hpp> +#include <boost/asio/detail/thread_info_base.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +template <typename T> +class recycling_allocator +{ +public: + typedef T value_type; + + template <typename U> + struct rebind + { + typedef recycling_allocator<U> other; + }; + + recycling_allocator() + { + } + + template <typename U> + recycling_allocator(const recycling_allocator<U>&) + { + } + + T* allocate(std::size_t n) + { + typedef thread_context::thread_call_stack call_stack; + void* p = thread_info_base::allocate(call_stack::top(), sizeof(T) * n); + return static_cast<T*>(p); + } + + void deallocate(T* p, std::size_t n) + { + typedef thread_context::thread_call_stack call_stack; + thread_info_base::deallocate(call_stack::top(), p, sizeof(T) * n); + } +}; + +template <> +class recycling_allocator<void> +{ +public: + typedef void value_type; + + template <typename U> + struct rebind + { + typedef recycling_allocator<U> other; + }; + + recycling_allocator() + { + } + + template <typename U> + recycling_allocator(const recycling_allocator<U>&) + { + } +}; + +template <typename Allocator> +struct get_recycling_allocator +{ + typedef Allocator type; + static type get(const Allocator& a) { return a; } +}; + +template <typename T> +struct get_recycling_allocator<std::allocator<T> > +{ + typedef recycling_allocator<T> type; + static type get(const std::allocator<T>&) { return type(); } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP diff --git a/boost/asio/detail/resolve_endpoint_op.hpp b/boost/asio/detail/resolve_endpoint_op.hpp index 0b7060ad6b..4a2c06798a 100644 --- a/boost/asio/detail/resolve_endpoint_op.hpp +++ b/boost/asio/detail/resolve_endpoint_op.hpp @@ -17,14 +17,14 @@ #include <boost/asio/detail/config.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> -#include <boost/asio/ip/basic_resolver_iterator.hpp> -#include <boost/asio/detail/addressof.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/basic_resolver_results.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> -#include <boost/asio/detail/operation.hpp> +#include <boost/asio/detail/memory.hpp> +#include <boost/asio/detail/resolve_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/push_options.hpp> @@ -34,35 +34,37 @@ namespace asio { namespace detail { template <typename Protocol, typename Handler> -class resolve_endpoint_op : public operation +class resolve_endpoint_op : public resolve_op { public: BOOST_ASIO_DEFINE_HANDLER_PTR(resolve_endpoint_op); typedef typename Protocol::endpoint endpoint_type; - typedef boost::asio::ip::basic_resolver_iterator<Protocol> iterator_type; + typedef boost::asio::ip::basic_resolver_results<Protocol> results_type; resolve_endpoint_op(socket_ops::weak_cancel_token_type cancel_token, - const endpoint_type& endpoint, io_service_impl& ios, Handler& handler) - : operation(&resolve_endpoint_op::do_complete), + const endpoint_type& endpoint, io_context_impl& ioc, Handler& handler) + : resolve_op(&resolve_endpoint_op::do_complete), cancel_token_(cancel_token), endpoint_(endpoint), - io_service_impl_(ios), + io_context_impl_(ioc), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the operation object. resolve_endpoint_op* o(static_cast<resolve_endpoint_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - if (owner && owner != &o->io_service_impl_) + if (owner && owner != &o->io_context_impl_) { - // The operation is being run on the worker io_service. Time to perform + // The operation is being run on the worker io_context. Time to perform // the resolver operation. // Perform the blocking endpoint resolution operation. @@ -71,18 +73,18 @@ public: socket_ops::background_getnameinfo(o->cancel_token_, o->endpoint_.data(), o->endpoint_.size(), host_name, NI_MAXHOST, service_name, NI_MAXSERV, o->endpoint_.protocol().type(), o->ec_); - o->iter_ = iterator_type::create(o->endpoint_, host_name, service_name); + o->results_ = results_type::create(o->endpoint_, host_name, service_name); - // Pass operation back to main io_service for completion. - o->io_service_impl_.post_deferred_completion(o); + // Pass operation back to main io_context for completion. + o->io_context_impl_.post_deferred_completion(o); p.v = p.p = 0; } else { - // The operation has been returned to the main io_service. The completion + // The operation has been returned to the main io_context. The completion // handler is ready to be delivered. - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_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, @@ -90,8 +92,8 @@ public: // 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::binder2<Handler, boost::system::error_code, iterator_type> - handler(o->handler_, o->ec_, o->iter_); + detail::binder2<Handler, boost::system::error_code, results_type> + handler(o->handler_, o->ec_, o->results_); p.h = boost::asio::detail::addressof(handler.handler_); p.reset(); @@ -99,7 +101,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } @@ -108,10 +110,9 @@ public: private: socket_ops::weak_cancel_token_type cancel_token_; endpoint_type endpoint_; - io_service_impl& io_service_impl_; + io_context_impl& io_context_impl_; Handler handler_; - boost::system::error_code ec_; - iterator_type iter_; + results_type results_; }; } // namespace detail diff --git a/boost/asio/detail/resolve_op.hpp b/boost/asio/detail/resolve_op.hpp index 435e27026f..99f9772f97 100644 --- a/boost/asio/detail/resolve_op.hpp +++ b/boost/asio/detail/resolve_op.hpp @@ -17,16 +17,7 @@ #include <boost/asio/detail/config.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> -#include <boost/asio/ip/basic_resolver_iterator.hpp> -#include <boost/asio/ip/basic_resolver_query.hpp> -#include <boost/asio/detail/addressof.hpp> -#include <boost/asio/detail/bind_handler.hpp> -#include <boost/asio/detail/fenced_block.hpp> -#include <boost/asio/detail/handler_alloc_helpers.hpp> -#include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/operation.hpp> -#include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/push_options.hpp> @@ -34,94 +25,17 @@ namespace boost { namespace asio { namespace detail { -template <typename Protocol, typename Handler> class resolve_op : public operation { public: - BOOST_ASIO_DEFINE_HANDLER_PTR(resolve_op); - - typedef boost::asio::ip::basic_resolver_query<Protocol> query_type; - typedef boost::asio::ip::basic_resolver_iterator<Protocol> iterator_type; - - resolve_op(socket_ops::weak_cancel_token_type cancel_token, - const query_type& query, io_service_impl& ios, Handler& handler) - : operation(&resolve_op::do_complete), - cancel_token_(cancel_token), - query_(query), - io_service_impl_(ios), - handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), - addrinfo_(0) - { - } + // The error code to be passed to the completion handler. + boost::system::error_code ec_; - ~resolve_op() +protected: + resolve_op(func_type complete_func) + : operation(complete_func) { - if (addrinfo_) - socket_ops::freeaddrinfo(addrinfo_); } - - static void do_complete(io_service_impl* owner, operation* base, - const boost::system::error_code& /*ec*/, - std::size_t /*bytes_transferred*/) - { - // Take ownership of the operation object. - resolve_op* o(static_cast<resolve_op*>(base)); - ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; - - if (owner && owner != &o->io_service_impl_) - { - // The operation is being run on the worker io_service. Time to perform - // the resolver operation. - - // Perform the blocking host resolution operation. - socket_ops::background_getaddrinfo(o->cancel_token_, - o->query_.host_name().c_str(), o->query_.service_name().c_str(), - o->query_.hints(), &o->addrinfo_, o->ec_); - - // Pass operation back to main io_service for completion. - o->io_service_impl_.post_deferred_completion(o); - p.v = p.p = 0; - } - else - { - // The operation has been returned to the main io_service. The completion - // handler is ready to be delivered. - - BOOST_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::binder2<Handler, boost::system::error_code, iterator_type> - handler(o->handler_, o->ec_, iterator_type()); - p.h = boost::asio::detail::addressof(handler.handler_); - if (o->addrinfo_) - { - handler.arg2_ = iterator_type::create(o->addrinfo_, - o->query_.host_name(), o->query_.service_name()); - } - p.reset(); - - if (owner) - { - fenced_block b(fenced_block::half); - BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); - BOOST_ASIO_HANDLER_INVOCATION_END; - } - } - } - -private: - socket_ops::weak_cancel_token_type cancel_token_; - query_type query_; - io_service_impl& io_service_impl_; - Handler handler_; - boost::system::error_code ec_; - boost::asio::detail::addrinfo_type* addrinfo_; }; } // namespace detail diff --git a/boost/asio/detail/resolve_query_op.hpp b/boost/asio/detail/resolve_query_op.hpp new file mode 100644 index 0000000000..6e5c431941 --- /dev/null +++ b/boost/asio/detail/resolve_query_op.hpp @@ -0,0 +1,136 @@ +// +// detail/resolve_query_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_RESOLVE_QUERY_OP_HPP +#define BOOST_ASIO_DETAIL_RESOLVE_QUERY_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/error.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/basic_resolver_query.hpp> +#include <boost/asio/ip/basic_resolver_results.hpp> +#include <boost/asio/detail/bind_handler.hpp> +#include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/handler_alloc_helpers.hpp> +#include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> +#include <boost/asio/detail/resolve_op.hpp> +#include <boost/asio/detail/socket_ops.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +template <typename Protocol, typename Handler> +class resolve_query_op : public resolve_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(resolve_query_op); + + typedef boost::asio::ip::basic_resolver_query<Protocol> query_type; + typedef boost::asio::ip::basic_resolver_results<Protocol> results_type; + + resolve_query_op(socket_ops::weak_cancel_token_type cancel_token, + const query_type& query, io_context_impl& ioc, Handler& handler) + : resolve_op(&resolve_query_op::do_complete), + cancel_token_(cancel_token), + query_(query), + io_context_impl_(ioc), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + addrinfo_(0) + { + handler_work<Handler>::start(handler_); + } + + ~resolve_query_op() + { + if (addrinfo_) + socket_ops::freeaddrinfo(addrinfo_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the operation object. + resolve_query_op* o(static_cast<resolve_query_op*>(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + + if (owner && owner != &o->io_context_impl_) + { + // The operation is being run on the worker io_context. Time to perform + // the resolver operation. + + // Perform the blocking host resolution operation. + socket_ops::background_getaddrinfo(o->cancel_token_, + o->query_.host_name().c_str(), o->query_.service_name().c_str(), + o->query_.hints(), &o->addrinfo_, o->ec_); + + // Pass operation back to main io_context for completion. + o->io_context_impl_.post_deferred_completion(o); + p.v = p.p = 0; + } + else + { + // The operation has been returned to the main io_context. The completion + // handler is ready to be delivered. + + // Take ownership of the operation's outstanding work. + handler_work<Handler> w(o->handler_); + + BOOST_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::binder2<Handler, boost::system::error_code, results_type> + handler(o->handler_, o->ec_, results_type()); + p.h = boost::asio::detail::addressof(handler.handler_); + if (o->addrinfo_) + { + handler.arg2_ = results_type::create(o->addrinfo_, + o->query_.host_name(), o->query_.service_name()); + } + p.reset(); + + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + query_type query_; + io_context_impl& io_context_impl_; + Handler handler_; + boost::asio::detail::addrinfo_type* addrinfo_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_RESOLVE_QUERY_OP_HPP diff --git a/boost/asio/detail/resolver_service.hpp b/boost/asio/detail/resolver_service.hpp index f73742e9b0..bda1139eb7 100644 --- a/boost/asio/detail/resolver_service.hpp +++ b/boost/asio/detail/resolver_service.hpp @@ -19,11 +19,12 @@ #if !defined(BOOST_ASIO_WINDOWS_RUNTIME) -#include <boost/asio/ip/basic_resolver_iterator.hpp> #include <boost/asio/ip/basic_resolver_query.hpp> -#include <boost/asio/detail/addressof.hpp> +#include <boost/asio/ip/basic_resolver_results.hpp> +#include <boost/asio/detail/concurrency_hint.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/resolve_endpoint_op.hpp> -#include <boost/asio/detail/resolve_op.hpp> +#include <boost/asio/detail/resolve_query_op.hpp> #include <boost/asio/detail/resolver_service_base.hpp> #include <boost/asio/detail/push_options.hpp> @@ -33,7 +34,9 @@ namespace asio { namespace detail { template <typename Protocol> -class resolver_service : public resolver_service_base +class resolver_service : + public service_base<resolver_service<Protocol> >, + public resolver_service_base { public: // The implementation type of the resolver. A cancellation token is used to @@ -46,17 +49,30 @@ public: // The query type. typedef boost::asio::ip::basic_resolver_query<Protocol> query_type; - // The iterator type. - typedef boost::asio::ip::basic_resolver_iterator<Protocol> iterator_type; + // The results type. + typedef boost::asio::ip::basic_resolver_results<Protocol> results_type; // Constructor. - resolver_service(boost::asio::io_service& io_service) - : resolver_service_base(io_service) + resolver_service(boost::asio::io_context& io_context) + : service_base<resolver_service<Protocol> >(io_context), + resolver_service_base(io_context) { } + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + this->base_shutdown(); + } + + // Perform any fork-related housekeeping. + void notify_fork(boost::asio::io_context::fork_event fork_ev) + { + this->base_notify_fork(fork_ev); + } + // Resolve a query to a list of entries. - iterator_type resolve(implementation_type&, const query_type& query, + results_type resolve(implementation_type&, const query_type& query, boost::system::error_code& ec) { boost::asio::detail::addrinfo_type* address_info = 0; @@ -65,7 +81,7 @@ public: query.service_name().c_str(), query.hints(), &address_info, ec); auto_addrinfo auto_address_info(address_info); - return ec ? iterator_type() : iterator_type::create( + return ec ? results_type() : results_type::create( address_info, query.host_name(), query.service_name()); } @@ -75,20 +91,20 @@ public: const query_type& query, Handler& handler) { // Allocate and construct an operation to wrap the handler. - typedef resolve_op<Protocol, Handler> op; + typedef resolve_query_op<Protocol, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; - p.p = new (p.v) op(impl, query, io_service_impl_, handler); + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl, query, io_context_impl_, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "resolver", &impl, "async_resolve")); + BOOST_ASIO_HANDLER_CREATION((io_context_impl_.context(), + *p.p, "resolver", &impl, 0, "async_resolve")); start_resolve_op(p.p); p.v = p.p = 0; } // Resolve an endpoint to a list of entries. - iterator_type resolve(implementation_type&, + results_type resolve(implementation_type&, const endpoint_type& endpoint, boost::system::error_code& ec) { char host_name[NI_MAXHOST]; @@ -97,7 +113,7 @@ public: host_name, NI_MAXHOST, service_name, NI_MAXSERV, endpoint.protocol().type(), ec); - return ec ? iterator_type() : iterator_type::create( + return ec ? results_type() : results_type::create( endpoint, host_name, service_name); } @@ -109,11 +125,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef resolve_endpoint_op<Protocol, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; - p.p = new (p.v) op(impl, endpoint, io_service_impl_, handler); + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl, endpoint, io_context_impl_, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "resolver", &impl, "async_resolve")); + BOOST_ASIO_HANDLER_CREATION((io_context_impl_.context(), + *p.p, "resolver", &impl, 0, "async_resolve")); start_resolve_op(p.p); p.v = p.p = 0; diff --git a/boost/asio/detail/resolver_service_base.hpp b/boost/asio/detail/resolver_service_base.hpp index 1a4180c166..818e20b02b 100644 --- a/boost/asio/detail/resolver_service_base.hpp +++ b/boost/asio/detail/resolver_service_base.hpp @@ -17,10 +17,11 @@ #include <boost/asio/detail/config.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/executor_work_guard.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/noncopyable.hpp> -#include <boost/asio/detail/operation.hpp> +#include <boost/asio/detail/resolve_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/scoped_ptr.hpp> @@ -40,17 +41,17 @@ public: typedef socket_ops::shared_cancel_token_type implementation_type; // Constructor. - BOOST_ASIO_DECL resolver_service_base(boost::asio::io_service& io_service); + BOOST_ASIO_DECL resolver_service_base(boost::asio::io_context& io_context); // Destructor. BOOST_ASIO_DECL ~resolver_service_base(); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void base_shutdown(); // Perform any fork-related housekeeping. - BOOST_ASIO_DECL void fork_service( - boost::asio::io_service::fork_event fork_ev); + BOOST_ASIO_DECL void base_notify_fork( + boost::asio::io_context::fork_event fork_ev); // Construct a new resolver implementation. BOOST_ASIO_DECL void construct(implementation_type& impl); @@ -58,12 +59,21 @@ public: // Destroy a resolver implementation. BOOST_ASIO_DECL void destroy(implementation_type&); + // Move-construct a new resolver implementation. + BOOST_ASIO_DECL void move_construct(implementation_type& impl, + implementation_type& other_impl); + + // Move-assign from another resolver implementation. + BOOST_ASIO_DECL void move_assign(implementation_type& impl, + resolver_service_base& other_service, + implementation_type& other_impl); + // Cancel pending asynchronous operations. BOOST_ASIO_DECL void cancel(implementation_type& impl); protected: // Helper function to start an asynchronous resolve operation. - BOOST_ASIO_DECL void start_resolve_op(operation* op); + BOOST_ASIO_DECL void start_resolve_op(resolve_op* op); #if !defined(BOOST_ASIO_WINDOWS_RUNTIME) // Helper class to perform exception-safe cleanup of addrinfo objects. @@ -92,29 +102,30 @@ protected: }; #endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) - // Helper class to run the work io_service in a thread. - class work_io_service_runner; + // Helper class to run the work io_context in a thread. + class work_io_context_runner; // Start the work thread if it's not already running. BOOST_ASIO_DECL void start_work_thread(); - // The io_service implementation used to post completions. - io_service_impl& io_service_impl_; + // The io_context implementation used to post completions. + io_context_impl& io_context_impl_; private: // Mutex to protect access to internal data. boost::asio::detail::mutex mutex_; - // Private io_service used for performing asynchronous host resolution. - boost::asio::detail::scoped_ptr<boost::asio::io_service> work_io_service_; + // Private io_context used for performing asynchronous host resolution. + boost::asio::detail::scoped_ptr<boost::asio::io_context> work_io_context_; - // The work io_service implementation used to post completions. - io_service_impl& work_io_service_impl_; + // The work io_context implementation used to post completions. + io_context_impl& work_io_context_impl_; - // Work for the private io_service to perform. - boost::asio::detail::scoped_ptr<boost::asio::io_service::work> work_; + // Work for the private io_context to perform. + boost::asio::executor_work_guard< + boost::asio::io_context::executor_type> work_; - // Thread used for running the work io_service's run loop. + // Thread used for running the work io_context's run loop. boost::asio::detail::scoped_ptr<boost::asio::detail::thread> work_thread_; }; diff --git a/boost/asio/detail/task_io_service.hpp b/boost/asio/detail/scheduler.hpp index 5184ea5a58..1d64a062c8 100644 --- a/boost/asio/detail/task_io_service.hpp +++ b/boost/asio/detail/scheduler.hpp @@ -1,6 +1,6 @@ // -// detail/task_io_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,8 +8,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP -#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP +#ifndef BOOST_ASIO_DETAIL_SCHEDULER_HPP +#define BOOST_ASIO_DETAIL_SCHEDULER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once @@ -17,17 +17,15 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_HAS_IOCP) - #include <boost/system/error_code.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/execution_context.hpp> #include <boost/asio/detail/atomic_count.hpp> -#include <boost/asio/detail/call_stack.hpp> -#include <boost/asio/detail/event.hpp> -#include <boost/asio/detail/mutex.hpp> +#include <boost/asio/detail/conditionally_enabled_event.hpp> +#include <boost/asio/detail/conditionally_enabled_mutex.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/reactor_fwd.hpp> -#include <boost/asio/detail/task_io_service_operation.hpp> +#include <boost/asio/detail/scheduler_operation.hpp> +#include <boost/asio/detail/thread_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -35,21 +33,22 @@ namespace boost { namespace asio { namespace detail { -struct task_io_service_thread_info; +struct scheduler_thread_info; -class task_io_service - : public boost::asio::detail::service_base<task_io_service> +class scheduler + : public execution_context_service_base<scheduler>, + public thread_context { public: - typedef task_io_service_operation operation; + typedef scheduler_operation operation; // Constructor. Specifies the number of concurrent threads that are likely to - // run the io_service. If set to 1 certain optimisation are performed. - BOOST_ASIO_DECL task_io_service(boost::asio::io_service& io_service, - std::size_t concurrency_hint = 0); + // run the scheduler. If set to 1 certain optimisation are performed. + BOOST_ASIO_DECL scheduler(boost::asio::execution_context& ctx, + int concurrency_hint = 0); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void shutdown(); // Initialise the task, if required. BOOST_ASIO_DECL void init_task(); @@ -60,6 +59,10 @@ public: // Run until interrupted or one operation is performed. BOOST_ASIO_DECL std::size_t run_one(boost::system::error_code& ec); + // Run until timeout, interrupted, or one operation is performed. + BOOST_ASIO_DECL std::size_t wait_one( + long usec, boost::system::error_code& ec); + // Poll for operations without blocking. BOOST_ASIO_DECL std::size_t poll(boost::system::error_code& ec); @@ -69,11 +72,11 @@ public: // Interrupt the event processing loop. BOOST_ASIO_DECL void stop(); - // Determine whether the io_service is stopped. + // Determine whether the scheduler is stopped. BOOST_ASIO_DECL bool stopped() const; - // Reset in preparation for a subsequent run invocation. - BOOST_ASIO_DECL void reset(); + // Restart in preparation for a subsequent run invocation. + BOOST_ASIO_DECL void restart(); // Notify that some work has started. void work_started() @@ -81,6 +84,10 @@ public: ++outstanding_work_; } + // Used to compensate for a forthcoming work_finished call. Must be called + // from within a scheduler-owned thread. + BOOST_ASIO_DECL void compensating_work_started(); + // Notify that some work has finished. void work_finished() { @@ -94,14 +101,6 @@ public: return thread_call_stack::contains(this) != 0; } - // Request invocation of the given handler. - template <typename Handler> - void dispatch(Handler& handler); - - // Request invocation of the given handler and return immediately. - template <typename Handler> - void post(Handler& handler); - // Request invocation of the given operation and return immediately. Assumes // that work_started() has not yet been called for the operation. BOOST_ASIO_DECL void post_immediate_completion( @@ -115,22 +114,38 @@ public: // that work_started() was previously called for each operation. BOOST_ASIO_DECL void post_deferred_completions(op_queue<operation>& ops); - // Process unfinished operations as part of a shutdown_service operation. - // Assumes that work_started() was previously called for the operations. + // Enqueue the given operation following a failed attempt to dispatch the + // operation for immediate invocation. + BOOST_ASIO_DECL void do_dispatch(operation* op); + + // Process unfinished operations as part of a shutdownoperation. Assumes that + // work_started() was previously called for the operations. BOOST_ASIO_DECL void abandon_operations(op_queue<operation>& ops); + // Get the concurrency hint that was used to initialise the scheduler. + int concurrency_hint() const + { + return concurrency_hint_; + } + private: - // Structure containing thread-specific data. - typedef task_io_service_thread_info thread_info; + // The mutex type used by this scheduler. + typedef conditionally_enabled_mutex mutex; - // Enqueue the given operation following a failed attempt to dispatch the - // operation for immediate invocation. - BOOST_ASIO_DECL void do_dispatch(operation* op); + // The event type used by this scheduler. + typedef conditionally_enabled_event event; + + // Structure containing thread-specific data. + typedef scheduler_thread_info thread_info; // Run at most one operation. May block. BOOST_ASIO_DECL std::size_t do_run_one(mutex::scoped_lock& lock, thread_info& this_thread, const boost::system::error_code& ec); + // Run at most one operation with a timeout. May block. + BOOST_ASIO_DECL std::size_t do_wait_one(mutex::scoped_lock& lock, + thread_info& this_thread, long usec, const boost::system::error_code& ec); + // Poll for at most one operation. BOOST_ASIO_DECL std::size_t do_poll_one(mutex::scoped_lock& lock, thread_info& this_thread, const boost::system::error_code& ec); @@ -183,8 +198,8 @@ private: // Flag to indicate that the dispatcher has been shut down. bool shutdown_; - // Per-thread call stack to track the state of each thread in the io_service. - typedef call_stack<task_io_service, thread_info> thread_call_stack; + // The concurrency hint used to initialise the scheduler. + const int concurrency_hint_; }; } // namespace detail @@ -193,11 +208,8 @@ private: #include <boost/asio/detail/pop_options.hpp> -#include <boost/asio/detail/impl/task_io_service.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) -# include <boost/asio/detail/impl/task_io_service.ipp> +# include <boost/asio/detail/impl/scheduler.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) -#endif // !defined(BOOST_ASIO_HAS_IOCP) - -#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP +#endif // BOOST_ASIO_DETAIL_SCHEDULER_HPP diff --git a/boost/asio/detail/task_io_service_operation.hpp b/boost/asio/detail/scheduler_operation.hpp index 91bee25cb4..54a8a7a206 100644 --- a/boost/asio/detail/task_io_service_operation.hpp +++ b/boost/asio/detail/scheduler_operation.hpp @@ -1,6 +1,6 @@ // -// detail/task_io_service_operation.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/scheduler_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,8 +8,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP -#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP +#ifndef BOOST_ASIO_DETAIL_SCHEDULER_OPERATION_HPP +#define BOOST_ASIO_DETAIL_SCHEDULER_OPERATION_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once @@ -25,17 +25,19 @@ namespace boost { namespace asio { namespace detail { -class task_io_service; +class scheduler; // Base class for all operations. A function pointer is used instead of virtual // functions to avoid the associated overhead. -class task_io_service_operation BOOST_ASIO_INHERIT_TRACKED_HANDLER +class scheduler_operation BOOST_ASIO_INHERIT_TRACKED_HANDLER { public: - void complete(task_io_service& owner, - const boost::system::error_code& ec, std::size_t bytes_transferred) + typedef scheduler_operation operation_type; + + void complete(void* owner, const boost::system::error_code& ec, + std::size_t bytes_transferred) { - func_(&owner, this, ec, bytes_transferred); + func_(owner, this, ec, bytes_transferred); } void destroy() @@ -44,11 +46,11 @@ public: } protected: - typedef void (*func_type)(task_io_service*, - task_io_service_operation*, + typedef void (*func_type)(void*, + scheduler_operation*, const boost::system::error_code&, std::size_t); - task_io_service_operation(func_type func) + scheduler_operation(func_type func) : next_(0), func_(func), task_result_(0) @@ -56,16 +58,16 @@ protected: } // Prevents deletion through this type. - ~task_io_service_operation() + ~scheduler_operation() { } private: friend class op_queue_access; - task_io_service_operation* next_; + scheduler_operation* next_; func_type func_; protected: - friend class task_io_service; + friend class scheduler; unsigned int task_result_; // Passed into bytes transferred. }; @@ -75,4 +77,4 @@ protected: #include <boost/asio/detail/pop_options.hpp> -#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP +#endif // BOOST_ASIO_DETAIL_SCHEDULER_OPERATION_HPP diff --git a/boost/asio/detail/task_io_service_thread_info.hpp b/boost/asio/detail/scheduler_thread_info.hpp index 0af044c009..79d64783c2 100644 --- a/boost/asio/detail/task_io_service_thread_info.hpp +++ b/boost/asio/detail/scheduler_thread_info.hpp @@ -1,6 +1,6 @@ // -// detail/task_io_service_thread_info.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/scheduler_thread_info.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,8 +8,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_DETAIL_TASK_IO_SERVICE_THREAD_INFO_HPP -#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_THREAD_INFO_HPP +#ifndef BOOST_ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP +#define BOOST_ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once @@ -24,12 +24,12 @@ namespace boost { namespace asio { namespace detail { -class task_io_service; -class task_io_service_operation; +class scheduler; +class scheduler_operation; -struct task_io_service_thread_info : public thread_info_base +struct scheduler_thread_info : public thread_info_base { - op_queue<task_io_service_operation> private_op_queue; + op_queue<scheduler_operation> private_op_queue; long private_outstanding_work; }; @@ -39,4 +39,4 @@ struct task_io_service_thread_info : public thread_info_base #include <boost/asio/detail/pop_options.hpp> -#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_THREAD_INFO_HPP +#endif // BOOST_ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP diff --git a/boost/asio/detail/scoped_ptr.hpp b/boost/asio/detail/scoped_ptr.hpp index fd471631e1..80ced171cd 100644 --- a/boost/asio/detail/scoped_ptr.hpp +++ b/boost/asio/detail/scoped_ptr.hpp @@ -64,6 +64,14 @@ public: p_ = p; } + // Release ownership of the pointer. + T* release() + { + T* tmp = p_; + p_ = 0; + return tmp; + } + private: // Disallow copying and assignment. scoped_ptr(const scoped_ptr&); diff --git a/boost/asio/detail/select_reactor.hpp b/boost/asio/detail/select_reactor.hpp index d6f75242e5..030c092250 100644 --- a/boost/asio/detail/select_reactor.hpp +++ b/boost/asio/detail/select_reactor.hpp @@ -35,7 +35,7 @@ #include <boost/asio/detail/timer_queue_base.hpp> #include <boost/asio/detail/timer_queue_set.hpp> #include <boost/asio/detail/wait_op.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/execution_context.hpp> #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/thread.hpp> @@ -48,7 +48,7 @@ namespace asio { namespace detail { class select_reactor - : public boost::asio::detail::service_base<select_reactor> + : public execution_context_service_base<select_reactor> { public: #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) @@ -65,17 +65,17 @@ public: }; // Constructor. - BOOST_ASIO_DECL select_reactor(boost::asio::io_service& io_service); + BOOST_ASIO_DECL select_reactor(boost::asio::execution_context& ctx); // Destructor. BOOST_ASIO_DECL ~select_reactor(); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void shutdown(); // Recreate internal descriptors following a fork. - BOOST_ASIO_DECL void fork_service( - boost::asio::io_service::fork_event fork_ev); + BOOST_ASIO_DECL void notify_fork( + boost::asio::execution_context::fork_event fork_ev); // Initialise the task, but only if the reactor is not in its own thread. BOOST_ASIO_DECL void init_task(); @@ -93,7 +93,7 @@ public: // Post a reactor operation for immediate completion. void post_immediate_completion(reactor_op* op, bool is_continuation) { - io_service_.post_immediate_completion(op, is_continuation); + scheduler_.post_immediate_completion(op, is_continuation); } // Start a new operation. The reactor operation will be performed when the @@ -149,8 +149,14 @@ public: typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& target, + typename timer_queue<Time_Traits>::per_timer_data& source); + // Run select once until interrupted or events are ready to be dispatched. - BOOST_ASIO_DECL void run(bool block, op_queue<operation>& ops); + BOOST_ASIO_DECL void run(long usec, op_queue<operation>& ops); // Interrupt the select loop. BOOST_ASIO_DECL void interrupt(); @@ -159,9 +165,6 @@ private: #if defined(BOOST_ASIO_HAS_IOCP) // Run the select loop in the thread. BOOST_ASIO_DECL void run_thread(); - - // Entry point for the select loop thread. - BOOST_ASIO_DECL static void call_run_thread(select_reactor* reactor); #endif // defined(BOOST_ASIO_HAS_IOCP) // Helper function to add a new timer queue. @@ -171,15 +174,20 @@ private: BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); // Get the timeout value for the select call. - BOOST_ASIO_DECL timeval* get_timeout(timeval& tv); + BOOST_ASIO_DECL timeval* get_timeout(long usec, timeval& tv); // Cancel all operations associated with the given descriptor. This function // does not acquire the select_reactor's mutex. BOOST_ASIO_DECL void cancel_ops_unlocked(socket_type descriptor, const boost::system::error_code& ec); - // The io_service implementation used to post completions. - io_service_impl& io_service_; + // The scheduler implementation used to post completions. +# if defined(BOOST_ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_type; +# else // defined(BOOST_ASIO_HAS_IOCP) + typedef class scheduler scheduler_type; +# endif // defined(BOOST_ASIO_HAS_IOCP) + scheduler_type& scheduler_; // Mutex to protect access to internal data. boost::asio::detail::mutex mutex_; @@ -197,6 +205,10 @@ private: timer_queue_set timer_queues_; #if defined(BOOST_ASIO_HAS_IOCP) + // Helper class to run the reactor loop in a thread. + class thread_function; + friend class thread_function; + // Does the reactor loop thread need to stop. bool stop_thread_; diff --git a/boost/asio/detail/service_registry.hpp b/boost/asio/detail/service_registry.hpp index b5fa85bd01..7218848e4c 100644 --- a/boost/asio/detail/service_registry.hpp +++ b/boost/asio/detail/service_registry.hpp @@ -19,12 +19,16 @@ #include <typeinfo> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/noncopyable.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/detail/type_traits.hpp> +#include <boost/asio/execution_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { + +class io_context; + namespace detail { template <typename T> @@ -34,27 +38,34 @@ class service_registry : private noncopyable { public: - // Constructor. Adds the initial service. - template <typename Service, typename Arg> - service_registry(boost::asio::io_service& o, - Service* initial_service, Arg arg); + // Constructor. + BOOST_ASIO_DECL service_registry(execution_context& owner); // Destructor. BOOST_ASIO_DECL ~service_registry(); + // Shutdown all services. + BOOST_ASIO_DECL void shutdown_services(); + + // Destroy all services. + BOOST_ASIO_DECL void destroy_services(); + // Notify all services of a fork event. - BOOST_ASIO_DECL void notify_fork(boost::asio::io_service::fork_event fork_ev); + BOOST_ASIO_DECL void notify_fork(execution_context::fork_event fork_ev); - // Get the first service object cast to the specified type. Called during - // io_service construction and so performs no locking or type checking. + // Get the service object corresponding to the specified service type. Will + // create a new service object automatically if no such object already + // exists. Ownership of the service object is not transferred to the caller. template <typename Service> - Service& first_service(); + Service& use_service(); // Get the service object corresponding to the specified service type. Will // create a new service object automatically if no such object already // exists. Ownership of the service object is not transferred to the caller. + // This overload is used for backwards compatibility with services that + // inherit from io_context::service. template <typename Service> - Service& use_service(); + Service& use_service(io_context& owner); // Add a service object. Throws on error, in which case ownership of the // object is retained by the caller. @@ -66,70 +77,79 @@ public: bool has_service() const; private: + // Initalise a service's key when the key_type typedef is not available. + template <typename Service> + static void init_key(execution_context::service::key& key, ...); + +#if !defined(BOOST_ASIO_NO_TYPEID) + // Initalise a service's key when the key_type typedef is available. + template <typename Service> + static void init_key(execution_context::service::key& key, + typename enable_if< + is_base_of<typename Service::key_type, Service>::value>::type*); +#endif // !defined(BOOST_ASIO_NO_TYPEID) + // Initialise a service's key based on its id. - BOOST_ASIO_DECL static void init_key( - boost::asio::io_service::service::key& key, - const boost::asio::io_service::id& id); + BOOST_ASIO_DECL static void init_key_from_id( + execution_context::service::key& key, + const execution_context::id& id); #if !defined(BOOST_ASIO_NO_TYPEID) // Initialise a service's key based on its id. template <typename Service> - static void init_key(boost::asio::io_service::service::key& key, - const boost::asio::detail::service_id<Service>& /*id*/); + static void init_key_from_id(execution_context::service::key& key, + const service_id<Service>& /*id*/); #endif // !defined(BOOST_ASIO_NO_TYPEID) // Check if a service matches the given id. BOOST_ASIO_DECL static bool keys_match( - const boost::asio::io_service::service::key& key1, - const boost::asio::io_service::service::key& key2); + const execution_context::service::key& key1, + const execution_context::service::key& key2); // The type of a factory function used for creating a service instance. - typedef boost::asio::io_service::service* - (*factory_type)(boost::asio::io_service&); + typedef execution_context::service*(*factory_type)(void*); // Factory function for creating a service instance. - template <typename Service> - static boost::asio::io_service::service* create( - boost::asio::io_service& owner); + template <typename Service, typename Owner> + static execution_context::service* create(void* owner); // Destroy a service instance. - BOOST_ASIO_DECL static void destroy( - boost::asio::io_service::service* service); + BOOST_ASIO_DECL static void destroy(execution_context::service* service); // Helper class to manage service pointers. struct auto_service_ptr; friend struct auto_service_ptr; struct auto_service_ptr { - boost::asio::io_service::service* ptr_; + execution_context::service* ptr_; ~auto_service_ptr() { destroy(ptr_); } }; // Get the service object corresponding to the specified service key. Will // create a new service object automatically if no such object already // exists. Ownership of the service object is not transferred to the caller. - BOOST_ASIO_DECL boost::asio::io_service::service* do_use_service( - const boost::asio::io_service::service::key& key, - factory_type factory); + BOOST_ASIO_DECL execution_context::service* do_use_service( + const execution_context::service::key& key, + factory_type factory, void* owner); // Add a service object. Throws on error, in which case ownership of the // object is retained by the caller. BOOST_ASIO_DECL void do_add_service( - const boost::asio::io_service::service::key& key, - boost::asio::io_service::service* new_service); + const execution_context::service::key& key, + execution_context::service* new_service); // Check whether a service object with the specified key already exists. BOOST_ASIO_DECL bool do_has_service( - const boost::asio::io_service::service::key& key) const; + const execution_context::service::key& key) const; // Mutex to protect access to internal data. mutable boost::asio::detail::mutex mutex_; // The owner of this service registry and the services it contains. - boost::asio::io_service& owner_; + execution_context& owner_; // The first service in the list of contained services. - boost::asio::io_service::service* first_service_; + execution_context::service* first_service_; }; } // namespace detail diff --git a/boost/asio/detail/shared_ptr.hpp b/boost/asio/detail/shared_ptr.hpp deleted file mode 100644 index f26c645121..0000000000 --- a/boost/asio/detail/shared_ptr.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// -// detail/shared_ptr.hpp -// ~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2017 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) -// - -#ifndef BOOST_ASIO_DETAIL_SHARED_PTR_HPP -#define BOOST_ASIO_DETAIL_SHARED_PTR_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include <boost/asio/detail/config.hpp> - -#if defined(BOOST_ASIO_HAS_STD_SHARED_PTR) -# include <memory> -#else // defined(BOOST_ASIO_HAS_STD_SHARED_PTR) -# include <boost/shared_ptr.hpp> -#endif // defined(BOOST_ASIO_HAS_STD_SHARED_PTR) - -namespace boost { -namespace asio { -namespace detail { - -#if defined(BOOST_ASIO_HAS_STD_SHARED_PTR) -using std::shared_ptr; -#else // defined(BOOST_ASIO_HAS_STD_SHARED_PTR) -using boost::shared_ptr; -#endif // defined(BOOST_ASIO_HAS_STD_SHARED_PTR) - -} // namespace detail -} // namespace asio -} // namespace boost - -#endif // BOOST_ASIO_DETAIL_SHARED_PTR_HPP diff --git a/boost/asio/detail/signal_handler.hpp b/boost/asio/detail/signal_handler.hpp index edad41b8ee..6ea723a27a 100644 --- a/boost/asio/detail/signal_handler.hpp +++ b/boost/asio/detail/signal_handler.hpp @@ -16,10 +16,12 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/detail/addressof.hpp> +#include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/handler_work.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/signal_op.hpp> #include <boost/asio/detail/push_options.hpp> @@ -38,17 +40,19 @@ public: : signal_op(&signal_handler::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(h)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. signal_handler* h(static_cast<signal_handler*>(base)); ptr p = { boost::asio::detail::addressof(h->handler_), h, h }; + handler_work<Handler> w(h->handler_); - BOOST_ASIO_HANDLER_COMPLETION((h)); + BOOST_ASIO_HANDLER_COMPLETION((*h)); // 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 @@ -66,7 +70,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/signal_set_service.hpp b/boost/asio/detail/signal_set_service.hpp index a023ebb66f..f27f8652c4 100644 --- a/boost/asio/detail/signal_set_service.hpp +++ b/boost/asio/detail/signal_set_service.hpp @@ -20,9 +20,9 @@ #include <cstddef> #include <signal.h> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> -#include <boost/asio/detail/addressof.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/signal_handler.hpp> #include <boost/asio/detail/signal_op.hpp> @@ -48,7 +48,8 @@ extern BOOST_ASIO_DECL struct signal_state* get_signal_state(); extern "C" BOOST_ASIO_DECL void boost_asio_signal_handler(int signal_number); -class signal_set_service +class signal_set_service : + public service_base<signal_set_service> { public: // Type used for tracking an individual signal registration. @@ -109,17 +110,17 @@ public: }; // Constructor. - BOOST_ASIO_DECL signal_set_service(boost::asio::io_service& io_service); + BOOST_ASIO_DECL signal_set_service(boost::asio::io_context& io_context); // Destructor. BOOST_ASIO_DECL ~signal_set_service(); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void shutdown(); // Perform fork-related housekeeping. - BOOST_ASIO_DECL void fork_service( - boost::asio::io_service::fork_event fork_ev); + BOOST_ASIO_DECL void notify_fork( + boost::asio::io_context::fork_event fork_ev); // Construct a new signal_set implementation. BOOST_ASIO_DECL void construct(implementation_type& impl); @@ -150,11 +151,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef signal_handler<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "signal_set", &impl, "async_wait")); + BOOST_ASIO_HANDLER_CREATION((io_context_.context(), + *p.p, "signal_set", &impl, 0, "async_wait")); start_wait_op(impl, p.p); p.v = p.p = 0; @@ -179,8 +180,8 @@ private: // Helper function to start a wait operation. BOOST_ASIO_DECL void start_wait_op(implementation_type& impl, signal_op* op); - // The io_service instance used for dispatching handlers. - io_service_impl& io_service_; + // The io_context instance used for dispatching handlers. + io_context_impl& io_context_; #if !defined(BOOST_ASIO_WINDOWS) \ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ diff --git a/boost/asio/detail/socket_ops.hpp b/boost/asio/detail/socket_ops.hpp index 136a3f01f7..8d39ab8737 100644 --- a/boost/asio/detail/socket_ops.hpp +++ b/boost/asio/detail/socket_ops.hpp @@ -18,9 +18,8 @@ #include <boost/asio/detail/config.hpp> #include <boost/system/error_code.hpp> -#include <boost/asio/detail/shared_ptr.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/socket_types.hpp> -#include <boost/asio/detail/weak_ptr.hpp> #include <boost/asio/detail/push_options.hpp> @@ -265,12 +264,16 @@ BOOST_ASIO_DECL int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec); BOOST_ASIO_DECL int poll_read(socket_type s, - state_type state, boost::system::error_code& ec); + state_type state, int msec, boost::system::error_code& ec); BOOST_ASIO_DECL int poll_write(socket_type s, - state_type state, boost::system::error_code& ec); + state_type state, int msec, boost::system::error_code& ec); -BOOST_ASIO_DECL int poll_connect(socket_type s, boost::system::error_code& ec); +BOOST_ASIO_DECL int poll_error(socket_type s, + state_type state, int msec, boost::system::error_code& ec); + +BOOST_ASIO_DECL int poll_connect(socket_type s, + int msec, boost::system::error_code& ec); #endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) diff --git a/boost/asio/detail/socket_types.hpp b/boost/asio/detail/socket_types.hpp index 0768f70077..ca9fc83a29 100644 --- a/boost/asio/detail/socket_types.hpp +++ b/boost/asio/detail/socket_types.hpp @@ -59,7 +59,8 @@ # include <sys/ioctl.h> # if (defined(__MACH__) && defined(__APPLE__)) \ || defined(__FreeBSD__) || defined(__NetBSD__) \ - || defined(__OpenBSD__) || defined(__linux__) + || defined(__OpenBSD__) || defined(__linux__) \ + || defined(__EMSCRIPTEN__) # include <poll.h> # elif !defined(__SYMBIAN32__) # include <sys/poll.h> @@ -152,6 +153,7 @@ typedef int signed_size_type; # define BOOST_ASIO_OS_DEF_SO_DONTROUTE 0x10 # define BOOST_ASIO_OS_DEF_SO_KEEPALIVE 0x8 # define BOOST_ASIO_OS_DEF_SO_LINGER 0x80 +# define BOOST_ASIO_OS_DEF_SO_OOBINLINE 0x100 # define BOOST_ASIO_OS_DEF_SO_SNDBUF 0x1001 # define BOOST_ASIO_OS_DEF_SO_RCVBUF 0x1002 # define BOOST_ASIO_OS_DEF_SO_SNDLOWAT 0x1003 @@ -236,6 +238,7 @@ typedef int signed_size_type; # define BOOST_ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE # define BOOST_ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE # define BOOST_ASIO_OS_DEF_SO_LINGER SO_LINGER +# define BOOST_ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE # define BOOST_ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF # define BOOST_ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF # define BOOST_ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT @@ -351,6 +354,7 @@ typedef int signed_size_type; # define BOOST_ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE # define BOOST_ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE # define BOOST_ASIO_OS_DEF_SO_LINGER SO_LINGER +# define BOOST_ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE # define BOOST_ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF # define BOOST_ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF # define BOOST_ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT diff --git a/boost/asio/detail/solaris_fenced_block.hpp b/boost/asio/detail/solaris_fenced_block.hpp index 2aef0229f1..5653a8b4c4 100644 --- a/boost/asio/detail/solaris_fenced_block.hpp +++ b/boost/asio/detail/solaris_fenced_block.hpp @@ -20,6 +20,7 @@ #if defined(__sun) #include <atomic.h> +#include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> diff --git a/boost/asio/detail/std_global.hpp b/boost/asio/detail/std_global.hpp new file mode 100644 index 0000000000..f0936e5ea9 --- /dev/null +++ b/boost/asio/detail/std_global.hpp @@ -0,0 +1,72 @@ +// +// detail/std_global.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_STD_GLOBAL_HPP +#define BOOST_ASIO_DETAIL_STD_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_HAS_STD_CALL_ONCE) + +#include <exception> +#include <mutex> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +template <typename T> +struct std_global_impl +{ + // Helper function to perform initialisation. + static void do_init() + { + instance_.ptr_ = new T; + } + + // Destructor automatically cleans up the global. + ~std_global_impl() + { + delete ptr_; + } + + static std::once_flag init_once_; + static std_global_impl instance_; + T* ptr_; +}; + +template <typename T> +std::once_flag std_global_impl<T>::init_once_; + +template <typename T> +std_global_impl<T> std_global_impl<T>::instance_; + +template <typename T> +T& std_global() +{ + std::call_once(std_global_impl<T>::init_once_, &std_global_impl<T>::do_init); + return *std_global_impl<T>::instance_.ptr_; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // defined(BOOST_ASIO_HAS_STD_CALL_ONCE) + +#endif // BOOST_ASIO_DETAIL_STD_GLOBAL_HPP diff --git a/boost/asio/detail/std_thread.hpp b/boost/asio/detail/std_thread.hpp index cd2a61dac2..35bcc1722c 100644 --- a/boost/asio/detail/std_thread.hpp +++ b/boost/asio/detail/std_thread.hpp @@ -52,6 +52,12 @@ public: thread_.join(); } + // Get number of CPUs. + static std::size_t hardware_concurrency() + { + return std::thread::hardware_concurrency(); + } + private: std::thread thread_; }; diff --git a/boost/asio/detail/strand_executor_service.hpp b/boost/asio/detail/strand_executor_service.hpp new file mode 100644 index 0000000000..38728d4610 --- /dev/null +++ b/boost/asio/detail/strand_executor_service.hpp @@ -0,0 +1,140 @@ +// +// detail/strand_executor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP +#define BOOST_ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/atomic_count.hpp> +#include <boost/asio/detail/executor_op.hpp> +#include <boost/asio/detail/memory.hpp> +#include <boost/asio/detail/mutex.hpp> +#include <boost/asio/detail/op_queue.hpp> +#include <boost/asio/detail/scheduler_operation.hpp> +#include <boost/asio/detail/scoped_ptr.hpp> +#include <boost/asio/execution_context.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +// Default service implementation for a strand. +class strand_executor_service + : public execution_context_service_base<strand_executor_service> +{ +public: + // The underlying implementation of a strand. + class strand_impl + { + public: + BOOST_ASIO_DECL ~strand_impl(); + + private: + friend class strand_executor_service; + + // Mutex to protect access to internal data. + mutex* mutex_; + + // Indicates whether the strand is currently "locked" by a handler. This + // means that there is a handler upcall in progress, or that the strand + // itself has been scheduled in order to invoke some pending handlers. + bool locked_; + + // The handlers that are waiting on the strand but should not be run until + // after the next time the strand is scheduled. This queue must only be + // modified while the mutex is locked. + op_queue<scheduler_operation> waiting_queue_; + + // The handlers that are ready to be run. Logically speaking, these are the + // handlers that hold the strand's lock. The ready queue is only modified + // from within the strand and so may be accessed without locking the mutex. + op_queue<scheduler_operation> ready_queue_; + + // Pointers to adjacent handle implementations in linked list. + strand_impl* next_; + strand_impl* prev_; + + // The strand service in where the implementation is held. + strand_executor_service* service_; + }; + + typedef shared_ptr<strand_impl> implementation_type; + + // Construct a new strand service for the specified context. + BOOST_ASIO_DECL explicit strand_executor_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown(); + + // Create a new strand_executor implementation. + BOOST_ASIO_DECL implementation_type create_implementation(); + + // Request invocation of the given function. + template <typename Executor, typename Function, typename Allocator> + static void dispatch(const implementation_type& impl, Executor& ex, + BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a); + + // Request invocation of the given function and return immediately. + template <typename Executor, typename Function, typename Allocator> + static void post(const implementation_type& impl, Executor& ex, + BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a); + + // Request invocation of the given function and return immediately. + template <typename Executor, typename Function, typename Allocator> + static void defer(const implementation_type& impl, Executor& ex, + BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a); + + // Determine whether the strand is running in the current thread. + BOOST_ASIO_DECL static bool running_in_this_thread( + const implementation_type& impl); + +private: + friend class strand_impl; + template <typename Executor> class invoker; + + // Adds a function to the strand. Returns true if it acquires the lock. + BOOST_ASIO_DECL static bool enqueue(const implementation_type& impl, + scheduler_operation* op); + + // Mutex to protect access to the service-wide state. + mutex mutex_; + + // Number of mutexes shared between all strand objects. + enum { num_mutexes = 193 }; + + // Pool of mutexes. + scoped_ptr<mutex> mutexes_[num_mutexes]; + + // Extra value used when hashing to prevent recycled memory locations from + // getting the same mutex. + std::size_t salt_; + + // The head of a linked list of all implementations. + strand_impl* impl_list_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#include <boost/asio/detail/impl/strand_executor_service.hpp> +#if defined(BOOST_ASIO_HEADER_ONLY) +# include <boost/asio/detail/impl/strand_executor_service.ipp> +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP diff --git a/boost/asio/detail/strand_service.hpp b/boost/asio/detail/strand_service.hpp index 8a94e58e36..e9d05b3ae7 100644 --- a/boost/asio/detail/strand_service.hpp +++ b/boost/asio/detail/strand_service.hpp @@ -16,7 +16,7 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/operation.hpp> @@ -75,20 +75,20 @@ public: typedef strand_impl* implementation_type; - // Construct a new strand service for the specified io_service. - BOOST_ASIO_DECL explicit strand_service(boost::asio::io_service& io_service); + // Construct a new strand service for the specified io_context. + BOOST_ASIO_DECL explicit strand_service(boost::asio::io_context& io_context); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void shutdown(); // Construct a new strand implementation. BOOST_ASIO_DECL void construct(implementation_type& impl); - // Request the io_service to invoke the given handler. + // Request the io_context to invoke the given handler. template <typename Handler> void dispatch(implementation_type& impl, Handler& handler); - // Request the io_service to invoke the given handler and return immediately. + // Request the io_context to invoke the given handler and return immediately. template <typename Handler> void post(implementation_type& impl, Handler& handler); @@ -105,12 +105,12 @@ private: BOOST_ASIO_DECL void do_post(implementation_type& impl, operation* op, bool is_continuation); - BOOST_ASIO_DECL static void do_complete(io_service_impl* owner, + BOOST_ASIO_DECL static void do_complete(void* owner, operation* base, const boost::system::error_code& ec, std::size_t bytes_transferred); - // The io_service implementation used to post completions. - io_service_impl& io_service_; + // The io_context implementation used to post completions. + io_context_impl& io_context_; // Mutex to protect access to the array of implementations. boost::asio::detail::mutex mutex_; diff --git a/boost/asio/detail/string_view.hpp b/boost/asio/detail/string_view.hpp new file mode 100644 index 0000000000..3d0a24f4c6 --- /dev/null +++ b/boost/asio/detail/string_view.hpp @@ -0,0 +1,47 @@ +// +// detail/string_view.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_STRING_VIEW_HPP +#define BOOST_ASIO_DETAIL_STRING_VIEW_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + +#if defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# include <experimental/string_view> +#else // defined(BOOST_ASIO_HAS_EXPERIMENTAL_STRING_VIEW) +# include <string_view> +#endif // defined(BOOST_ASIO_HAS_EXPERIMENTAL_STRING_VIEW) + +namespace boost { +namespace asio { + +#if defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +using std::experimental::basic_string_view; +using std::experimental::string_view; +#else // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +using std::basic_string_view; +using std::string_view; +#endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + +} // namespace asio +} // namespace boost + +# define BOOST_ASIO_STRING_VIEW_PARAM boost::asio::string_view +#else // defined(BOOST_ASIO_HAS_STD_STRING_VIEW) +# define BOOST_ASIO_STRING_VIEW_PARAM const std::string& +#endif // defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + +#endif // BOOST_ASIO_DETAIL_STRING_VIEW_HPP diff --git a/boost/asio/detail/thread.hpp b/boost/asio/detail/thread.hpp index f385fc85a1..e10040e972 100644 --- a/boost/asio/detail/thread.hpp +++ b/boost/asio/detail/thread.hpp @@ -20,8 +20,10 @@ #if !defined(BOOST_ASIO_HAS_THREADS) # include <boost/asio/detail/null_thread.hpp> #elif defined(BOOST_ASIO_WINDOWS) -# if defined(BOOST_ASIO_WINDOWS_APP) || defined(UNDER_CE) -# include <boost/asio/detail/winapi_thread.hpp> +# if defined(UNDER_CE) +# include <boost/asio/detail/wince_thread.hpp> +# elif defined(BOOST_ASIO_WINDOWS_APP) +# include <boost/asio/detail/winapp_thread.hpp> # else # include <boost/asio/detail/win_thread.hpp> # endif @@ -40,8 +42,10 @@ namespace detail { #if !defined(BOOST_ASIO_HAS_THREADS) typedef null_thread thread; #elif defined(BOOST_ASIO_WINDOWS) -# if defined(BOOST_ASIO_WINDOWS_APP) || defined(UNDER_CE) -typedef winapi_thread thread; +# if defined(UNDER_CE) +typedef wince_thread thread; +# elif defined(BOOST_ASIO_WINDOWS_APP) +typedef winapp_thread thread; # else typedef win_thread thread; # endif diff --git a/boost/asio/detail/thread_context.hpp b/boost/asio/detail/thread_context.hpp new file mode 100644 index 0000000000..8c059ccb02 --- /dev/null +++ b/boost/asio/detail/thread_context.hpp @@ -0,0 +1,44 @@ +// +// detail/thread_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_THREAD_CONTEXT_HPP +#define BOOST_ASIO_DETAIL_THREAD_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <climits> +#include <cstddef> +#include <boost/asio/detail/call_stack.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +class thread_info_base; + +// Base class for things that manage threads (scheduler, win_iocp_io_context). +class thread_context +{ +public: + // Per-thread call stack to track the state of each thread in the context. + typedef call_stack<thread_context, thread_info_base> thread_call_stack; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_THREAD_CONTEXT_HPP diff --git a/boost/asio/detail/thread_group.hpp b/boost/asio/detail/thread_group.hpp new file mode 100644 index 0000000000..2451e8f3b7 --- /dev/null +++ b/boost/asio/detail/thread_group.hpp @@ -0,0 +1,91 @@ +// +// detail/thread_group.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_THREAD_GROUP_HPP +#define BOOST_ASIO_DETAIL_THREAD_GROUP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/scoped_ptr.hpp> +#include <boost/asio/detail/thread.hpp> + +namespace boost { +namespace asio { +namespace detail { + +class thread_group +{ +public: + // Constructor initialises an empty thread group. + thread_group() + : first_(0) + { + } + + // Destructor joins any remaining threads in the group. + ~thread_group() + { + join(); + } + + // Create a new thread in the group. + template <typename Function> + void create_thread(Function f) + { + first_ = new item(f, first_); + } + + // Create new threads in the group. + template <typename Function> + void create_threads(Function f, std::size_t num_threads) + { + for (std::size_t i = 0; i < num_threads; ++i) + create_thread(f); + } + + // Wait for all threads in the group to exit. + void join() + { + while (first_) + { + first_->thread_.join(); + item* tmp = first_; + first_ = first_->next_; + delete tmp; + } + } + +private: + // Structure used to track a single thread in the group. + struct item + { + template <typename Function> + explicit item(Function f, item* next) + : thread_(f), + next_(next) + { + } + + boost::asio::detail::thread thread_; + item* next_; + }; + + // The first thread in the group. + item* first_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_THREAD_GROUP_HPP diff --git a/boost/asio/detail/thread_info_base.hpp b/boost/asio/detail/thread_info_base.hpp index 3baa8ef39f..c0dc322f41 100644 --- a/boost/asio/detail/thread_info_base.hpp +++ b/boost/asio/detail/thread_info_base.hpp @@ -42,13 +42,15 @@ public: static void* allocate(thread_info_base* this_thread, std::size_t size) { + std::size_t chunks = (size + chunk_size - 1) / chunk_size; + if (this_thread && this_thread->reusable_memory_) { void* const pointer = this_thread->reusable_memory_; this_thread->reusable_memory_ = 0; unsigned char* const mem = static_cast<unsigned char*>(pointer); - if (static_cast<std::size_t>(mem[0]) >= size) + if (static_cast<std::size_t>(mem[0]) >= chunks) { mem[size] = mem[0]; return pointer; @@ -57,16 +59,16 @@ public: ::operator delete(pointer); } - void* const pointer = ::operator new(size + 1); + void* const pointer = ::operator new(chunks * chunk_size + 1); unsigned char* const mem = static_cast<unsigned char*>(pointer); - mem[size] = (size <= UCHAR_MAX) ? static_cast<unsigned char>(size) : 0; + mem[size] = (chunks <= UCHAR_MAX) ? static_cast<unsigned char>(chunks) : 0; return pointer; } static void deallocate(thread_info_base* this_thread, void* pointer, std::size_t size) { - if (size <= UCHAR_MAX) + if (size <= chunk_size * UCHAR_MAX) { if (this_thread && this_thread->reusable_memory_ == 0) { @@ -81,6 +83,7 @@ public: } private: + enum { chunk_size = 4 }; void* reusable_memory_; }; diff --git a/boost/asio/detail/timer_queue.hpp b/boost/asio/detail/timer_queue.hpp index cb848dfb3a..f8d48babad 100644 --- a/boost/asio/detail/timer_queue.hpp +++ b/boost/asio/detail/timer_queue.hpp @@ -47,7 +47,11 @@ public: class per_timer_data { public: - per_timer_data() : next_(0), prev_(0) {} + per_timer_data() : + heap_index_((std::numeric_limits<std::size_t>::max)()), + next_(0), prev_(0) + { + } private: friend class timer_queue; @@ -189,6 +193,29 @@ public: return num_cancelled; } + // Move operations from one timer to another, empty timer. + void move_timer(per_timer_data& target, per_timer_data& source) + { + target.op_queue_.push(source.op_queue_); + + target.heap_index_ = source.heap_index_; + source.heap_index_ = (std::numeric_limits<std::size_t>::max)(); + + if (target.heap_index_ < heap_.size()) + heap_[target.heap_index_].timer_ = ⌖ + + if (timers_ == &source) + timers_ = ⌖ + if (source.prev_) + source.prev_->next_ = ⌖ + if (source.next_) + source.next_->prev_= ⌖ + target.next_ = source.next_; + target.prev_ = source.prev_; + source.next_ = 0; + source.prev_ = 0; + } + private: // Move the item at the given index up the heap to its correct position. void up_heap(std::size_t index) diff --git a/boost/asio/detail/timer_queue_ptime.hpp b/boost/asio/detail/timer_queue_ptime.hpp index 0693acca83..d1934f1375 100644 --- a/boost/asio/detail/timer_queue_ptime.hpp +++ b/boost/asio/detail/timer_queue_ptime.hpp @@ -15,13 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + #include <boost/asio/time_traits.hpp> #include <boost/asio/detail/timer_queue.hpp> #include <boost/asio/detail/push_options.hpp> -#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) - namespace boost { namespace asio { namespace detail { @@ -76,6 +78,10 @@ public: per_timer_data& timer, op_queue<operation>& ops, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Move operations from one timer to another, empty timer. + BOOST_ASIO_DECL void move_timer(per_timer_data& target, + per_timer_data& source); + private: timer_queue<forwarding_posix_time_traits> impl_; }; @@ -84,12 +90,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) - #include <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/timer_queue_ptime.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + #endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP diff --git a/boost/asio/detail/timer_scheduler.hpp b/boost/asio/detail/timer_scheduler.hpp index 49dc113d10..290d0b0680 100644 --- a/boost/asio/detail/timer_scheduler.hpp +++ b/boost/asio/detail/timer_scheduler.hpp @@ -21,7 +21,7 @@ #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/winrt_timer_scheduler.hpp> #elif defined(BOOST_ASIO_HAS_IOCP) -# include <boost/asio/detail/win_iocp_io_service.hpp> +# include <boost/asio/detail/win_iocp_io_context.hpp> #elif defined(BOOST_ASIO_HAS_EPOLL) # include <boost/asio/detail/epoll_reactor.hpp> #elif defined(BOOST_ASIO_HAS_KQUEUE) diff --git a/boost/asio/detail/timer_scheduler_fwd.hpp b/boost/asio/detail/timer_scheduler_fwd.hpp index bf732a63d3..de3d3bd350 100644 --- a/boost/asio/detail/timer_scheduler_fwd.hpp +++ b/boost/asio/detail/timer_scheduler_fwd.hpp @@ -24,7 +24,7 @@ namespace detail { #if defined(BOOST_ASIO_WINDOWS_RUNTIME) typedef class winrt_timer_scheduler timer_scheduler; #elif defined(BOOST_ASIO_HAS_IOCP) -typedef class win_iocp_io_service timer_scheduler; +typedef class win_iocp_io_context timer_scheduler; #elif defined(BOOST_ASIO_HAS_EPOLL) typedef class epoll_reactor timer_scheduler; #elif defined(BOOST_ASIO_HAS_KQUEUE) diff --git a/boost/asio/detail/type_traits.hpp b/boost/asio/detail/type_traits.hpp index 53a73a0eb1..1556e597e0 100644 --- a/boost/asio/detail/type_traits.hpp +++ b/boost/asio/detail/type_traits.hpp @@ -21,6 +21,11 @@ # include <type_traits> #else // defined(BOOST_ASIO_HAS_TYPE_TRAITS) # include <boost/type_traits/add_const.hpp> +# include <boost/type_traits/conditional.hpp> +# include <boost/type_traits/decay.hpp> +# include <boost/type_traits/integral_constant.hpp> +# include <boost/type_traits/is_base_of.hpp> +# include <boost/type_traits/is_class.hpp> # include <boost/type_traits/is_const.hpp> # include <boost/type_traits/is_convertible.hpp> # include <boost/type_traits/is_function.hpp> @@ -28,6 +33,7 @@ # include <boost/type_traits/remove_pointer.hpp> # include <boost/type_traits/remove_reference.hpp> # include <boost/utility/enable_if.hpp> +# include <boost/utility/result_of.hpp> #endif // defined(BOOST_ASIO_HAS_TYPE_TRAITS) namespace boost { @@ -35,23 +41,39 @@ namespace asio { #if defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) using std::add_const; +using std::conditional; +using std::decay; using std::enable_if; +using std::false_type; +using std::integral_constant; +using std::is_base_of; +using std::is_class; using std::is_const; using std::is_convertible; using std::is_function; using std::is_same; using std::remove_pointer; using std::remove_reference; +using std::result_of; +using std::true_type; #else // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) using boost::add_const; template <bool Condition, typename Type = void> struct enable_if : boost::enable_if_c<Condition, Type> {}; +using boost::conditional; +using boost::decay; +using boost::false_type; +using boost::integral_constant; +using boost::is_base_of; +using boost::is_class; using boost::is_const; using boost::is_convertible; using boost::is_function; using boost::is_same; using boost::remove_pointer; using boost::remove_reference; +using boost::result_of; +using boost::true_type; #endif // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) } // namespace asio diff --git a/boost/asio/detail/variadic_templates.hpp b/boost/asio/detail/variadic_templates.hpp index 6d55bc7a7c..228a6542e9 100644 --- a/boost/asio/detail/variadic_templates.hpp +++ b/boost/asio/detail/variadic_templates.hpp @@ -34,27 +34,83 @@ # define BOOST_ASIO_VARIADIC_TARGS(n) BOOST_ASIO_VARIADIC_TARGS_##n -# define BOOST_ASIO_VARIADIC_TARGS_1 x1 -# define BOOST_ASIO_VARIADIC_TARGS_2 x1, x2 -# define BOOST_ASIO_VARIADIC_TARGS_3 x1, x2, x3 -# define BOOST_ASIO_VARIADIC_TARGS_4 x1, x2, x3, x4 -# define BOOST_ASIO_VARIADIC_TARGS_5 x1, x2, x3, x4, x5 - -# define BOOST_ASIO_VARIADIC_PARAMS(n) BOOST_ASIO_VARIADIC_PARAMS_##n - -# define BOOST_ASIO_VARIADIC_PARAMS_1 T1 x1 -# define BOOST_ASIO_VARIADIC_PARAMS_2 T1 x1, T2 x2 -# define BOOST_ASIO_VARIADIC_PARAMS_3 T1 x1, T2 x2, T3 x3 -# define BOOST_ASIO_VARIADIC_PARAMS_4 T1 x1, T2 x2, T3 x3, T4 x4 -# define BOOST_ASIO_VARIADIC_PARAMS_5 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5 - -# define BOOST_ASIO_VARIADIC_ARGS(n) BOOST_ASIO_VARIADIC_ARGS_##n - -# define BOOST_ASIO_VARIADIC_ARGS_1 x1 -# define BOOST_ASIO_VARIADIC_ARGS_2 x1, x2 -# define BOOST_ASIO_VARIADIC_ARGS_3 x1, x2, x3 -# define BOOST_ASIO_VARIADIC_ARGS_4 x1, x2, x3, x4 -# define BOOST_ASIO_VARIADIC_ARGS_5 x1, x2, x3, x4, x5 +# define BOOST_ASIO_VARIADIC_TARGS_1 T1 +# define BOOST_ASIO_VARIADIC_TARGS_2 T1, T2 +# define BOOST_ASIO_VARIADIC_TARGS_3 T1, T2, T3 +# define BOOST_ASIO_VARIADIC_TARGS_4 T1, T2, T3, T4 +# define BOOST_ASIO_VARIADIC_TARGS_5 T1, T2, T3, T4, T5 + +# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS(n) \ + BOOST_ASIO_VARIADIC_BYVAL_PARAMS_##n + +# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_1 T1 x1 +# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_2 T1 x1, T2 x2 +# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_3 T1 x1, T2 x2, T3 x3 +# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_4 T1 x1, T2 x2, T3 x3, T4 x4 +# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_5 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5 + +# define BOOST_ASIO_VARIADIC_BYVAL_ARGS(n) \ + BOOST_ASIO_VARIADIC_BYVAL_ARGS_##n + +# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_1 x1 +# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_2 x1, x2 +# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_3 x1, x2, x3 +# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_4 x1, x2, x3, x4 +# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_5 x1, x2, x3, x4, x5 + +# define BOOST_ASIO_VARIADIC_MOVE_PARAMS(n) \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS_##n + +# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_1 \ + BOOST_ASIO_MOVE_ARG(T1) x1 +# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_2 \ + BOOST_ASIO_MOVE_ARG(T1) x1, BOOST_ASIO_MOVE_ARG(T2) x2 +# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_3 \ + BOOST_ASIO_MOVE_ARG(T1) x1, BOOST_ASIO_MOVE_ARG(T2) x2, \ + BOOST_ASIO_MOVE_ARG(T3) x3 +# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_4 \ + BOOST_ASIO_MOVE_ARG(T1) x1, BOOST_ASIO_MOVE_ARG(T2) x2, \ + BOOST_ASIO_MOVE_ARG(T3) x3, BOOST_ASIO_MOVE_ARG(T4) x4 +# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_5 \ + BOOST_ASIO_MOVE_ARG(T1) x1, BOOST_ASIO_MOVE_ARG(T2) x2, \ + BOOST_ASIO_MOVE_ARG(T3) x3, BOOST_ASIO_MOVE_ARG(T4) x4, \ + BOOST_ASIO_MOVE_ARG(T5) x5 + +# define BOOST_ASIO_VARIADIC_MOVE_ARGS(n) \ + BOOST_ASIO_VARIADIC_MOVE_ARGS_##n + +# define BOOST_ASIO_VARIADIC_MOVE_ARGS_1 \ + BOOST_ASIO_MOVE_CAST(T1)(x1) +# define BOOST_ASIO_VARIADIC_MOVE_ARGS_2 \ + BOOST_ASIO_MOVE_CAST(T1)(x1), BOOST_ASIO_MOVE_CAST(T2)(x2) +# define BOOST_ASIO_VARIADIC_MOVE_ARGS_3 \ + BOOST_ASIO_MOVE_CAST(T1)(x1), BOOST_ASIO_MOVE_CAST(T2)(x2), \ + BOOST_ASIO_MOVE_CAST(T3)(x3) +# define BOOST_ASIO_VARIADIC_MOVE_ARGS_4 \ + BOOST_ASIO_MOVE_CAST(T1)(x1), BOOST_ASIO_MOVE_CAST(T2)(x2), \ + BOOST_ASIO_MOVE_CAST(T3)(x3), BOOST_ASIO_MOVE_CAST(T4)(x4) +# define BOOST_ASIO_VARIADIC_MOVE_ARGS_5 \ + BOOST_ASIO_MOVE_CAST(T1)(x1), BOOST_ASIO_MOVE_CAST(T2)(x2), \ + BOOST_ASIO_MOVE_CAST(T3)(x3), BOOST_ASIO_MOVE_CAST(T4)(x4), \ + BOOST_ASIO_MOVE_CAST(T5)(x5) + +# define BOOST_ASIO_VARIADIC_DECAY(n) \ + BOOST_ASIO_VARIADIC_DECAY_##n + +# define BOOST_ASIO_VARIADIC_DECAY_1 \ + typename decay<T1>::type +# define BOOST_ASIO_VARIADIC_DECAY_2 \ + typename decay<T1>::type, typename decay<T2>::type +# define BOOST_ASIO_VARIADIC_DECAY_3 \ + typename decay<T1>::type, typename decay<T2>::type, \ + typename decay<T3>::type +# define BOOST_ASIO_VARIADIC_DECAY_4 \ + typename decay<T1>::type, typename decay<T2>::type, \ + typename decay<T3>::type, typename decay<T4>::type +# define BOOST_ASIO_VARIADIC_DECAY_5 \ + typename decay<T1>::type, typename decay<T2>::type, \ + typename decay<T3>::type, typename decay<T4>::type, \ + typename decay<T5>::type # define BOOST_ASIO_VARIADIC_GENERATE(m) m(1) m(2) m(3) m(4) m(5) diff --git a/boost/asio/detail/wait_handler.hpp b/boost/asio/detail/wait_handler.hpp index 440dae1f18..5d520e8fb1 100644 --- a/boost/asio/detail/wait_handler.hpp +++ b/boost/asio/detail/wait_handler.hpp @@ -16,12 +16,12 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/wait_op.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -39,17 +39,19 @@ public: : wait_op(&wait_handler::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(h)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. wait_handler* h(static_cast<wait_handler*>(base)); ptr p = { boost::asio::detail::addressof(h->handler_), h, h }; + handler_work<Handler> w(h->handler_); - BOOST_ASIO_HANDLER_COMPLETION((h)); + BOOST_ASIO_HANDLER_COMPLETION((*h)); // 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 @@ -67,7 +69,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/weak_ptr.hpp b/boost/asio/detail/weak_ptr.hpp deleted file mode 100644 index 1870c0e0e8..0000000000 --- a/boost/asio/detail/weak_ptr.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// -// detail/weak_ptr.hpp -// ~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2017 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) -// - -#ifndef BOOST_ASIO_DETAIL_WEAK_PTR_HPP -#define BOOST_ASIO_DETAIL_WEAK_PTR_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include <boost/asio/detail/config.hpp> - -#if defined(BOOST_ASIO_HAS_STD_SHARED_PTR) -# include <memory> -#else // defined(BOOST_ASIO_HAS_STD_SHARED_PTR) -# include <boost/weak_ptr.hpp> -#endif // defined(BOOST_ASIO_HAS_STD_SHARED_PTR) - -namespace boost { -namespace asio { -namespace detail { - -#if defined(BOOST_ASIO_HAS_STD_SHARED_PTR) -using std::weak_ptr; -#else // defined(BOOST_ASIO_HAS_STD_SHARED_PTR) -using boost::weak_ptr; -#endif // defined(BOOST_ASIO_HAS_STD_SHARED_PTR) - -} // namespace detail -} // namespace asio -} // namespace boost - -#endif // BOOST_ASIO_DETAIL_WEAK_PTR_HPP diff --git a/boost/asio/detail/win_event.hpp b/boost/asio/detail/win_event.hpp index 7a7d54fac6..4c00068010 100644 --- a/boost/asio/detail/win_event.hpp +++ b/boost/asio/detail/win_event.hpp @@ -112,6 +112,27 @@ public: } } + // Timed wait for the event to become signalled. + template <typename Lock> + bool wait_for_usec(Lock& lock, long usec) + { + BOOST_ASIO_ASSERT(lock.locked()); + if ((state_ & 1) == 0) + { + state_ += 2; + lock.unlock(); + DWORD msec = usec > 0 ? (usec < 1000 ? 1 : usec / 1000) : 0; +#if defined(BOOST_ASIO_WINDOWS_APP) + ::WaitForMultipleObjectsEx(2, events_, false, msec, false); +#else // defined(BOOST_ASIO_WINDOWS_APP) + ::WaitForMultipleObjects(2, events_, false, msec); +#endif // defined(BOOST_ASIO_WINDOWS_APP) + lock.lock(); + state_ -= 2; + } + return (state_ & 1) != 0; + } + private: HANDLE events_[2]; std::size_t state_; diff --git a/boost/asio/detail/win_fenced_block.hpp b/boost/asio/detail/win_fenced_block.hpp index dba1d5355d..c6e5601361 100644 --- a/boost/asio/detail/win_fenced_block.hpp +++ b/boost/asio/detail/win_fenced_block.hpp @@ -20,6 +20,7 @@ #if defined(BOOST_ASIO_WINDOWS) && !defined(UNDER_CE) #include <boost/asio/detail/socket_types.hpp> +#include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> diff --git a/boost/asio/detail/win_global.hpp b/boost/asio/detail/win_global.hpp new file mode 100644 index 0000000000..5a43902a7c --- /dev/null +++ b/boost/asio/detail/win_global.hpp @@ -0,0 +1,75 @@ +// +// detail/win_global.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_GLOBAL_HPP +#define BOOST_ASIO_DETAIL_WIN_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/static_mutex.hpp> +#include <boost/asio/detail/tss_ptr.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +template <typename T> +struct win_global_impl +{ + // Destructor automatically cleans up the global. + ~win_global_impl() + { + delete ptr_; + } + + static win_global_impl instance_; + static static_mutex mutex_; + static T* ptr_; + static tss_ptr<T> tss_ptr_; +}; + +template <typename T> +win_global_impl<T> win_global_impl<T>::instance_ = { 0 }; + +template <typename T> +static_mutex win_global_impl<T>::mutex_ = BOOST_ASIO_STATIC_MUTEX_INIT; + +template <typename T> +T* win_global_impl<T>::ptr_ = 0; + +template <typename T> +tss_ptr<T> win_global_impl<T>::tss_ptr_; + +template <typename T> +T& win_global() +{ + if (static_cast<T*>(win_global_impl<T>::tss_ptr_) == 0) + { + win_global_impl<T>::mutex_.init(); + static_mutex::scoped_lock lock(win_global_impl<T>::mutex_); + win_global_impl<T>::ptr_ = new T; + win_global_impl<T>::tss_ptr_ = win_global_impl<T>::ptr_; + } + + return *win_global_impl<T>::tss_ptr_; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_WIN_GLOBAL_HPP diff --git a/boost/asio/detail/win_iocp_handle_read_op.hpp b/boost/asio/detail/win_iocp_handle_read_op.hpp index fda3cc1e77..67d0ccc296 100644 --- a/boost/asio/detail/win_iocp_handle_read_op.hpp +++ b/boost/asio/detail/win_iocp_handle_read_op.hpp @@ -21,12 +21,12 @@ #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/error.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/push_options.hpp> @@ -47,9 +47,10 @@ public: buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& result_ec, std::size_t bytes_transferred) { @@ -58,8 +59,9 @@ public: // Take ownership of the operation object. win_iocp_handle_read_op* o(static_cast<win_iocp_handle_read_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_ASIO_HANDLER_COMPLETION((*o)); #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) if (owner) @@ -90,7 +92,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/win_iocp_handle_service.hpp b/boost/asio/detail/win_iocp_handle_service.hpp index 29f24f90c5..876fb68cb8 100644 --- a/boost/asio/detail/win_iocp_handle_service.hpp +++ b/boost/asio/detail/win_iocp_handle_service.hpp @@ -21,16 +21,16 @@ #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> -#include <boost/asio/detail/addressof.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/cstdint.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/win_iocp_handle_read_op.hpp> #include <boost/asio/detail/win_iocp_handle_write_op.hpp> -#include <boost/asio/detail/win_iocp_io_service.hpp> +#include <boost/asio/detail/win_iocp_io_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -38,7 +38,8 @@ namespace boost { namespace asio { namespace detail { -class win_iocp_handle_service +class win_iocp_handle_service : + public service_base<win_iocp_handle_service> { public: // The native type of a stream handle. @@ -75,10 +76,10 @@ public: implementation_type* prev_; }; - BOOST_ASIO_DECL win_iocp_handle_service(boost::asio::io_service& io_service); + BOOST_ASIO_DECL win_iocp_handle_service(boost::asio::io_context& io_context); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void shutdown(); // Construct a new handle implementation. BOOST_ASIO_DECL void construct(implementation_type& impl); @@ -149,11 +150,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef win_iocp_handle_write_op<ConstBufferSequence, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(buffers, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "handle", &impl, "async_write_some")); + BOOST_ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, + reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some")); start_write_op(impl, 0, buffer_sequence_adapter<boost::asio::const_buffer, @@ -170,11 +171,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef win_iocp_handle_write_op<ConstBufferSequence, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(buffers, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "handle", &impl, "async_write_some_at")); + BOOST_ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, + reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some_at")); start_write_op(impl, offset, buffer_sequence_adapter<boost::asio::const_buffer, @@ -211,11 +212,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef win_iocp_handle_read_op<MutableBufferSequence, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(buffers, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "handle", &impl, "async_read_some")); + BOOST_ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, + reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some")); start_read_op(impl, 0, buffer_sequence_adapter<boost::asio::mutable_buffer, @@ -233,11 +234,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef win_iocp_handle_read_op<MutableBufferSequence, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(buffers, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "handle", &impl, "async_read_some_at")); + BOOST_ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, + reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some_at")); start_read_op(impl, offset, buffer_sequence_adapter<boost::asio::mutable_buffer, @@ -300,7 +301,7 @@ private: // The IOCP service used for running asynchronous operations and dispatching // handlers. - win_iocp_io_service& iocp_service_; + win_iocp_io_context& iocp_service_; // Mutex to protect access to the linked list of implementations. mutex mutex_; diff --git a/boost/asio/detail/win_iocp_handle_write_op.hpp b/boost/asio/detail/win_iocp_handle_write_op.hpp index a53db910a8..b6b1483265 100644 --- a/boost/asio/detail/win_iocp_handle_write_op.hpp +++ b/boost/asio/detail/win_iocp_handle_write_op.hpp @@ -21,12 +21,12 @@ #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/error.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/push_options.hpp> @@ -46,16 +46,18 @@ public: buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& ec, std::size_t bytes_transferred) { // Take ownership of the operation object. win_iocp_handle_write_op* o(static_cast<win_iocp_handle_write_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_ASIO_HANDLER_COMPLETION((*o)); #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) if (owner) @@ -82,7 +84,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/win_iocp_io_service.hpp b/boost/asio/detail/win_iocp_io_context.hpp index 0abb9fe89a..c53b9eb9c3 100644 --- a/boost/asio/detail/win_iocp_io_service.hpp +++ b/boost/asio/detail/win_iocp_io_context.hpp @@ -1,5 +1,5 @@ // -// detail/win_iocp_io_service.hpp +// detail/win_iocp_io_context.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -8,8 +8,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP -#define BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once @@ -19,19 +19,19 @@ #if defined(BOOST_ASIO_HAS_IOCP) -#include <boost/asio/io_service.hpp> -#include <boost/asio/detail/call_stack.hpp> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/scoped_ptr.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/thread.hpp> +#include <boost/asio/detail/thread_context.hpp> #include <boost/asio/detail/timer_queue_base.hpp> #include <boost/asio/detail/timer_queue_set.hpp> #include <boost/asio/detail/wait_op.hpp> #include <boost/asio/detail/win_iocp_operation.hpp> #include <boost/asio/detail/win_iocp_thread_info.hpp> +#include <boost/asio/execution_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -41,18 +41,18 @@ namespace detail { class wait_op; -class win_iocp_io_service - : public boost::asio::detail::service_base<win_iocp_io_service> +class win_iocp_io_context + : public execution_context_service_base<win_iocp_io_context>, + public thread_context { public: - // Constructor. Specifies a concurrency hint that is passed through to the // underlying I/O completion port. - BOOST_ASIO_DECL win_iocp_io_service(boost::asio::io_service& io_service, - size_t concurrency_hint = 0); + BOOST_ASIO_DECL win_iocp_io_context(boost::asio::execution_context& ctx, + int concurrency_hint = -1); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void shutdown(); // Initialise the task. Nothing to do here. void init_task() @@ -69,6 +69,9 @@ public: // Run until stopped or one operation is performed. BOOST_ASIO_DECL size_t run_one(boost::system::error_code& ec); + // Run until timeout, interrupted, or one operation is performed. + BOOST_ASIO_DECL size_t wait_one(long usec, boost::system::error_code& ec); + // Poll for operations without blocking. BOOST_ASIO_DECL size_t poll(boost::system::error_code& ec); @@ -78,14 +81,14 @@ public: // Stop the event processing loop. BOOST_ASIO_DECL void stop(); - // Determine whether the io_service is stopped. + // Determine whether the io_context is stopped. bool stopped() const { return ::InterlockedExchangeAdd(&stopped_, 0) != 0; } - // Reset in preparation for a subsequent run invocation. - void reset() + // Restart in preparation for a subsequent run invocation. + void restart() { ::InterlockedExchange(&stopped_, 0); } @@ -109,14 +112,6 @@ public: return thread_call_stack::contains(this) != 0; } - // Request invocation of the given handler. - template <typename Handler> - void dispatch(Handler& handler); - - // Request invocation of the given handler and return immediately. - template <typename Handler> - void post(Handler& handler); - // Request invocation of the given operation and return immediately. Assumes // that work_started() has not yet been called for the operation. void post_immediate_completion(win_iocp_operation* op, bool) @@ -150,8 +145,15 @@ public: post_deferred_completion(op); } - // Process unfinished operations as part of a shutdown_service operation. - // Assumes that work_started() was previously called for the operations. + // Enqueue the given operation following a failed attempt to dispatch the + // operation for immediate invocation. + void do_dispatch(operation* op) + { + post_immediate_completion(op, false); + } + + // Process unfinished operations as part of a shutdown operation. Assumes + // that work_started() was previously called for the operations. BOOST_ASIO_DECL void abandon_operations(op_queue<operation>& ops); // Called after starting an overlapped I/O operation that did not complete @@ -193,6 +195,18 @@ public: typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from); + + // Get the concurrency hint that was used to initialise the io_context. + int concurrency_hint() const + { + return concurrency_hint_; + } + private: #if defined(WINVER) && (WINVER < 0x0500) typedef DWORD dword_ptr_t; @@ -205,7 +219,7 @@ private: // Dequeues at most one operation from the I/O completion port, and then // executes it. Returns the number of operations that were dequeued (i.e. // either 0 or 1). - BOOST_ASIO_DECL size_t do_one(bool block, boost::system::error_code& ec); + BOOST_ASIO_DECL size_t do_one(DWORD msec, boost::system::error_code& ec); // Helper to calculate the GetQueuedCompletionStatus timeout. BOOST_ASIO_DECL static DWORD get_gqcs_timeout(); @@ -296,9 +310,8 @@ private: // The operations that are ready to dispatch. op_queue<win_iocp_operation> completed_ops_; - // Per-thread call stack to track the state of each thread in the io_service. - typedef call_stack<win_iocp_io_service, - win_iocp_thread_info> thread_call_stack; + // The concurrency hint used to initialise the io_context. + const int concurrency_hint_; }; } // namespace detail @@ -307,11 +320,11 @@ private: #include <boost/asio/detail/pop_options.hpp> -#include <boost/asio/detail/impl/win_iocp_io_service.hpp> +#include <boost/asio/detail/impl/win_iocp_io_context.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) -# include <boost/asio/detail/impl/win_iocp_io_service.ipp> +# include <boost/asio/detail/impl/win_iocp_io_context.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_HAS_IOCP) -#endif // BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP diff --git a/boost/asio/detail/win_iocp_null_buffers_op.hpp b/boost/asio/detail/win_iocp_null_buffers_op.hpp index 905d7a664e..318331a125 100644 --- a/boost/asio/detail/win_iocp_null_buffers_op.hpp +++ b/boost/asio/detail/win_iocp_null_buffers_op.hpp @@ -19,12 +19,12 @@ #if defined(BOOST_ASIO_HAS_IOCP) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/error.hpp> @@ -48,14 +48,15 @@ public: cancel_token_(cancel_token), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static bool do_perform(reactor_op*) + static status do_perform(reactor_op*) { - return true; + return done; } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& result_ec, std::size_t bytes_transferred) { @@ -64,8 +65,9 @@ public: // Take ownership of the operation object. win_iocp_null_buffers_op* o(static_cast<win_iocp_null_buffers_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_ASIO_HANDLER_COMPLETION((*o)); // The reactor may have stored a result in the operation object. if (o->ec_) @@ -100,7 +102,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/win_iocp_operation.hpp b/boost/asio/detail/win_iocp_operation.hpp index 232930344b..fcb79a933b 100644 --- a/boost/asio/detail/win_iocp_operation.hpp +++ b/boost/asio/detail/win_iocp_operation.hpp @@ -30,7 +30,7 @@ namespace boost { namespace asio { namespace detail { -class win_iocp_io_service; +class win_iocp_io_context; // Base class for all operations. A function pointer is used instead of virtual // functions to avoid the associated overhead. @@ -39,11 +39,12 @@ class win_iocp_operation BOOST_ASIO_ALSO_INHERIT_TRACKED_HANDLER { public: - void complete(win_iocp_io_service& owner, - const boost::system::error_code& ec, + typedef win_iocp_operation operation_type; + + void complete(void* owner, const boost::system::error_code& ec, std::size_t bytes_transferred) { - func_(&owner, this, ec, bytes_transferred); + func_(owner, this, ec, bytes_transferred); } void destroy() @@ -53,7 +54,7 @@ public: protected: typedef void (*func_type)( - win_iocp_io_service*, win_iocp_operation*, + void*, win_iocp_operation*, const boost::system::error_code&, std::size_t); win_iocp_operation(func_type func) @@ -80,7 +81,7 @@ protected: private: friend class op_queue_access; - friend class win_iocp_io_service; + friend class win_iocp_io_context; win_iocp_operation* next_; func_type func_; long ready_; diff --git a/boost/asio/detail/win_iocp_overlapped_op.hpp b/boost/asio/detail/win_iocp_overlapped_op.hpp index 6d0e4bfcc2..4b26db3f43 100644 --- a/boost/asio/detail/win_iocp_overlapped_op.hpp +++ b/boost/asio/detail/win_iocp_overlapped_op.hpp @@ -20,11 +20,11 @@ #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/error.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/push_options.hpp> @@ -43,16 +43,18 @@ public: : operation(&win_iocp_overlapped_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& ec, std::size_t bytes_transferred) { // Take ownership of the operation object. win_iocp_overlapped_op* o(static_cast<win_iocp_overlapped_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_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 @@ -70,7 +72,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/win_iocp_overlapped_ptr.hpp b/boost/asio/detail/win_iocp_overlapped_ptr.hpp index 5d252c6fb1..fc51fd6c59 100644 --- a/boost/asio/detail/win_iocp_overlapped_ptr.hpp +++ b/boost/asio/detail/win_iocp_overlapped_ptr.hpp @@ -19,12 +19,12 @@ #if defined(BOOST_ASIO_HAS_IOCP) -#include <boost/asio/io_service.hpp> -#include <boost/asio/detail/addressof.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/win_iocp_overlapped_op.hpp> -#include <boost/asio/detail/win_iocp_io_service.hpp> +#include <boost/asio/detail/win_iocp_io_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -47,11 +47,11 @@ public: // Construct an win_iocp_overlapped_ptr to contain the specified handler. template <typename Handler> explicit win_iocp_overlapped_ptr( - boost::asio::io_service& io_service, BOOST_ASIO_MOVE_ARG(Handler) handler) + boost::asio::io_context& io_context, BOOST_ASIO_MOVE_ARG(Handler) handler) : ptr_(0), iocp_service_(0) { - this->reset(io_service, BOOST_ASIO_MOVE_CAST(Handler)(handler)); + this->reset(io_context, BOOST_ASIO_MOVE_CAST(Handler)(handler)); } // Destructor automatically frees the OVERLAPPED object unless released. @@ -75,22 +75,21 @@ public: // Reset to contain the specified handler, freeing any current OVERLAPPED // object. template <typename Handler> - void reset(boost::asio::io_service& io_service, Handler handler) + void reset(boost::asio::io_context& io_context, Handler handler) { typedef win_iocp_overlapped_op<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "io_service", - &io_service.impl_, "overlapped")); + BOOST_ASIO_HANDLER_CREATION((io_context, *p.p, + "io_context", &io_context.impl_, 0, "overlapped")); - io_service.impl_.work_started(); + io_context.impl_.work_started(); reset(); ptr_ = p.p; p.v = p.p = 0; - iocp_service_ = &io_service.impl_; + iocp_service_ = &io_context.impl_; } // Get the contained OVERLAPPED object. @@ -132,7 +131,7 @@ public: private: win_iocp_operation* ptr_; - win_iocp_io_service* iocp_service_; + win_iocp_io_context* iocp_service_; }; } // namespace detail diff --git a/boost/asio/detail/win_iocp_serial_port_service.hpp b/boost/asio/detail/win_iocp_serial_port_service.hpp index 6b21f96535..4b641f0c73 100644 --- a/boost/asio/detail/win_iocp_serial_port_service.hpp +++ b/boost/asio/detail/win_iocp_serial_port_service.hpp @@ -22,7 +22,7 @@ #include <string> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/win_iocp_handle_service.hpp> #include <boost/asio/detail/push_options.hpp> @@ -32,7 +32,8 @@ namespace asio { namespace detail { // Extend win_iocp_handle_service to provide serial port support. -class win_iocp_serial_port_service +class win_iocp_serial_port_service : + public service_base<win_iocp_serial_port_service> { public: // The native type of a serial port. @@ -43,10 +44,10 @@ public: // Constructor. BOOST_ASIO_DECL win_iocp_serial_port_service( - boost::asio::io_service& io_service); + boost::asio::io_context& io_context); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void shutdown(); // Construct a new serial port implementation. void construct(implementation_type& impl) @@ -185,8 +186,8 @@ private: static boost::system::error_code store_option(const void* option, ::DCB& storage, boost::system::error_code& ec) { - return static_cast<const SettableSerialPortOption*>(option)->store( - storage, ec); + static_cast<const SettableSerialPortOption*>(option)->store(storage, ec); + return ec; } // Helper function to set a serial port option. @@ -203,7 +204,8 @@ private: static boost::system::error_code load_option(void* option, const ::DCB& storage, boost::system::error_code& ec) { - return static_cast<GettableSerialPortOption*>(option)->load(storage, ec); + static_cast<GettableSerialPortOption*>(option)->load(storage, ec); + return ec; } // Helper function to get a serial port option. diff --git a/boost/asio/detail/win_iocp_socket_accept_op.hpp b/boost/asio/detail/win_iocp_socket_accept_op.hpp index d296103c54..f05be5465d 100644 --- a/boost/asio/detail/win_iocp_socket_accept_op.hpp +++ b/boost/asio/detail/win_iocp_socket_accept_op.hpp @@ -19,12 +19,12 @@ #if defined(BOOST_ASIO_HAS_IOCP) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/win_iocp_socket_service_base.hpp> @@ -55,6 +55,7 @@ public: enable_connection_aborted_(enable_connection_aborted), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } socket_holder& new_socket() @@ -72,7 +73,7 @@ public: return sizeof(sockaddr_storage_type) + 16; } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& result_ec, std::size_t /*bytes_transferred*/) { @@ -81,6 +82,7 @@ public: // Take ownership of the operation object. win_iocp_socket_accept_op* o(static_cast<win_iocp_socket_accept_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); if (owner) { @@ -121,7 +123,7 @@ public: *o->peer_endpoint_ = peer_endpoint; } - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_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 @@ -139,7 +141,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } @@ -156,6 +158,136 @@ private: Handler handler_; }; +#if defined(BOOST_ASIO_HAS_MOVE) + +template <typename Protocol, typename Handler> +class win_iocp_socket_move_accept_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_move_accept_op); + + win_iocp_socket_move_accept_op( + win_iocp_socket_service_base& socket_service, socket_type socket, + const Protocol& protocol, boost::asio::io_context& peer_io_context, + typename Protocol::endpoint* peer_endpoint, + bool enable_connection_aborted, Handler& handler) + : operation(&win_iocp_socket_move_accept_op::do_complete), + socket_service_(socket_service), + socket_(socket), + peer_(peer_io_context), + protocol_(protocol), + peer_endpoint_(peer_endpoint), + enable_connection_aborted_(enable_connection_aborted), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + socket_holder& new_socket() + { + return new_socket_; + } + + void* output_buffer() + { + return output_buffer_; + } + + DWORD address_length() + { + return sizeof(sockaddr_storage_type) + 16; + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& result_ec, + std::size_t /*bytes_transferred*/) + { + boost::system::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_move_accept_op* o( + static_cast<win_iocp_socket_move_accept_op*>(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + if (owner) + { + typename Protocol::endpoint peer_endpoint; + std::size_t addr_len = peer_endpoint.capacity(); + socket_ops::complete_iocp_accept(o->socket_, + o->output_buffer(), o->address_length(), + peer_endpoint.data(), &addr_len, + o->new_socket_.get(), ec); + + // Restart the accept operation if we got the connection_aborted error + // and the enable_connection_aborted socket option is not set. + if (ec == boost::asio::error::connection_aborted + && !o->enable_connection_aborted_) + { + o->reset(); + o->socket_service_.restart_accept_op(o->socket_, + o->new_socket_, o->protocol_.family(), + o->protocol_.type(), o->protocol_.protocol(), + o->output_buffer(), o->address_length(), o); + p.v = p.p = 0; + return; + } + + // If the socket was successfully accepted, transfer ownership of the + // socket to the peer object. + if (!ec) + { + o->peer_.assign(o->protocol_, + typename Protocol::socket::native_handle_type( + o->new_socket_.get(), peer_endpoint), ec); + if (!ec) + o->new_socket_.release(); + } + + // Pass endpoint back to caller. + if (o->peer_endpoint_) + *o->peer_endpoint_ = peer_endpoint; + } + + BOOST_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, + boost::system::error_code, typename Protocol::socket> + handler(0, BOOST_ASIO_MOVE_CAST(Handler)(o->handler_), ec, + BOOST_ASIO_MOVE_CAST(typename Protocol::socket)(o->peer_)); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + win_iocp_socket_service_base& socket_service_; + socket_type socket_; + socket_holder new_socket_; + typename Protocol::socket peer_; + Protocol protocol_; + typename Protocol::endpoint* peer_endpoint_; + unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; + bool enable_connection_aborted_; + Handler handler_; +}; + +#endif // defined(BOOST_ASIO_HAS_MOVE) + } // namespace detail } // namespace asio } // namespace boost diff --git a/boost/asio/detail/win_iocp_socket_connect_op.hpp b/boost/asio/detail/win_iocp_socket_connect_op.hpp index e987c6b6c4..829597ae9c 100644 --- a/boost/asio/detail/win_iocp_socket_connect_op.hpp +++ b/boost/asio/detail/win_iocp_socket_connect_op.hpp @@ -19,11 +19,11 @@ #if defined(BOOST_ASIO_HAS_IOCP) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/error.hpp> @@ -44,12 +44,13 @@ public: { } - static bool do_perform(reactor_op* base) + static status do_perform(reactor_op* base) { win_iocp_socket_connect_op_base* o( static_cast<win_iocp_socket_connect_op_base*>(base)); - return socket_ops::non_blocking_connect(o->socket_, o->ec_); + return socket_ops::non_blocking_connect( + o->socket_, o->ec_) ? done : not_done; } socket_type socket_; @@ -67,9 +68,10 @@ public: &win_iocp_socket_connect_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& result_ec, std::size_t /*bytes_transferred*/) { @@ -79,6 +81,7 @@ public: win_iocp_socket_connect_op* o( static_cast<win_iocp_socket_connect_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); if (owner) { @@ -88,7 +91,7 @@ public: ec = o->ec_; } - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_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 @@ -106,7 +109,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/win_iocp_socket_recv_op.hpp b/boost/asio/detail/win_iocp_socket_recv_op.hpp index 4202822d17..46f5dcd3f5 100644 --- a/boost/asio/detail/win_iocp_socket_recv_op.hpp +++ b/boost/asio/detail/win_iocp_socket_recv_op.hpp @@ -19,12 +19,12 @@ #if defined(BOOST_ASIO_HAS_IOCP) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/error.hpp> @@ -50,9 +50,10 @@ public: buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& result_ec, std::size_t bytes_transferred) { @@ -61,8 +62,9 @@ public: // Take ownership of the operation object. win_iocp_socket_recv_op* o(static_cast<win_iocp_socket_recv_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_ASIO_HANDLER_COMPLETION((*o)); #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. @@ -94,7 +96,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp b/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp index 21ca4fb331..b9437c3a60 100644 --- a/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp +++ b/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp @@ -19,12 +19,12 @@ #if defined(BOOST_ASIO_HAS_IOCP) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/error.hpp> @@ -51,6 +51,7 @@ public: buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } int& endpoint_size() @@ -58,7 +59,7 @@ public: return endpoint_size_; } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& result_ec, std::size_t bytes_transferred) { @@ -68,8 +69,9 @@ public: win_iocp_socket_recvfrom_op* o( static_cast<win_iocp_socket_recvfrom_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_ASIO_HANDLER_COMPLETION((*o)); #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. @@ -101,7 +103,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp b/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp index 5179bb2945..51747c55e8 100644 --- a/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp +++ b/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp @@ -19,12 +19,12 @@ #if defined(BOOST_ASIO_HAS_IOCP) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/error.hpp> @@ -52,9 +52,10 @@ public: out_flags_(out_flags), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& result_ec, std::size_t bytes_transferred) { @@ -64,8 +65,9 @@ public: win_iocp_socket_recvmsg_op* o( static_cast<win_iocp_socket_recvmsg_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_ASIO_HANDLER_COMPLETION((*o)); #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. @@ -95,7 +97,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/win_iocp_socket_send_op.hpp b/boost/asio/detail/win_iocp_socket_send_op.hpp index c9abc0e664..48951c2508 100644 --- a/boost/asio/detail/win_iocp_socket_send_op.hpp +++ b/boost/asio/detail/win_iocp_socket_send_op.hpp @@ -19,12 +19,12 @@ #if defined(BOOST_ASIO_HAS_IOCP) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/error.hpp> @@ -48,9 +48,10 @@ public: buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code& result_ec, std::size_t bytes_transferred) { @@ -59,8 +60,9 @@ public: // Take ownership of the operation object. win_iocp_socket_send_op* o(static_cast<win_iocp_socket_send_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_ASIO_HANDLER_COMPLETION((*o)); #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. @@ -89,7 +91,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/win_iocp_socket_service.hpp b/boost/asio/detail/win_iocp_socket_service.hpp index 179798c8d9..ed1cd1edd5 100644 --- a/boost/asio/detail/win_iocp_socket_service.hpp +++ b/boost/asio/detail/win_iocp_socket_service.hpp @@ -21,22 +21,22 @@ #include <cstring> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/socket_base.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/operation.hpp> -#include <boost/asio/detail/reactor.hpp> #include <boost/asio/detail/reactor_op.hpp> +#include <boost/asio/detail/select_reactor.hpp> #include <boost/asio/detail/socket_holder.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/socket_types.hpp> -#include <boost/asio/detail/win_iocp_io_service.hpp> +#include <boost/asio/detail/win_iocp_io_context.hpp> #include <boost/asio/detail/win_iocp_null_buffers_op.hpp> #include <boost/asio/detail/win_iocp_socket_accept_op.hpp> #include <boost/asio/detail/win_iocp_socket_connect_op.hpp> @@ -51,7 +51,9 @@ namespace asio { namespace detail { template <typename Protocol> -class win_iocp_socket_service : public win_iocp_socket_service_base +class win_iocp_socket_service : + public service_base<win_iocp_socket_service<Protocol> >, + public win_iocp_socket_service_base { public: // The protocol type. @@ -128,11 +130,18 @@ public: }; // Constructor. - win_iocp_socket_service(boost::asio::io_service& io_service) - : win_iocp_socket_service_base(io_service) + win_iocp_socket_service(boost::asio::io_context& io_context) + : service_base<win_iocp_socket_service<Protocol> >(io_context), + win_iocp_socket_service_base(io_context) { } + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + this->base_shutdown(); + } + // Move-construct a new socket implementation. void move_construct(implementation_type& impl, implementation_type& other_impl) @@ -279,6 +288,14 @@ public: return endpoint; } + // Disable sends or receives on the socket. + boost::system::error_code shutdown(base_implementation_type& impl, + socket_base::shutdown_type what, boost::system::error_code& ec) + { + socket_ops::shutdown(impl.socket_, what, ec); + return ec; + } + // Send a datagram to the specified endpoint. Returns the number of bytes // sent. template <typename ConstBufferSequence> @@ -300,7 +317,7 @@ public: boost::system::error_code& ec) { // Wait for socket to become ready. - socket_ops::poll_write(impl.socket_, impl.state_, ec); + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); return 0; } @@ -315,11 +332,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.cancel_token_, buffers, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send_to")); + BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_send_to")); buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence> bufs(buffers); @@ -338,14 +355,13 @@ public: // Allocate and construct an operation to wrap the handler. typedef win_iocp_null_buffers_op<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.cancel_token_, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", - &impl, "async_send_to(null_buffers)")); + BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_send_to(null_buffers)")); - start_reactor_op(impl, reactor::write_op, p.p); + start_reactor_op(impl, select_reactor::write_op, p.p); p.v = p.p = 0; } @@ -377,7 +393,7 @@ public: socket_base::message_flags, boost::system::error_code& ec) { // Wait for socket to become ready. - socket_ops::poll_read(impl.socket_, impl.state_, ec); + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); @@ -397,11 +413,11 @@ public: typedef win_iocp_socket_recvfrom_op< MutableBufferSequence, endpoint_type, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(sender_endp, impl.cancel_token_, buffers, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_receive_from")); + BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_receive_from")); buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence> bufs(buffers); @@ -420,12 +436,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef win_iocp_null_buffers_op<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.cancel_token_, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, - "async_receive_from(null_buffers)")); + BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_receive_from(null_buffers)")); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); @@ -456,13 +471,42 @@ public: { if (peer_endpoint) peer_endpoint->resize(addr_len); - if (!peer.assign(impl.protocol_, new_socket.get(), ec)) + peer.assign(impl.protocol_, new_socket.get(), ec); + if (!ec) new_socket.release(); } return ec; } +#if defined(BOOST_ASIO_HAS_MOVE) + // Accept a new connection. + typename Protocol::socket accept(implementation_type& impl, + io_context* peer_io_context, endpoint_type* peer_endpoint, + boost::system::error_code& ec) + { + typename Protocol::socket peer( + peer_io_context ? *peer_io_context : io_context_); + + 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); + peer.assign(impl.protocol_, new_socket.get(), ec); + if (!ec) + new_socket.release(); + } + + return peer; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + // 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> @@ -472,14 +516,14 @@ public: // Allocate and construct an operation to wrap the handler. typedef win_iocp_socket_accept_op<Socket, protocol_type, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; bool enable_connection_aborted = (impl.state_ & socket_ops::enable_connection_aborted) != 0; p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_, peer_endpoint, enable_connection_aborted, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_accept")); + BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_accept")); start_accept_op(impl, peer.is_open(), p.p->new_socket(), impl.protocol_.family(), impl.protocol_.type(), @@ -488,6 +532,35 @@ public: p.v = p.p = 0; } +#if defined(BOOST_ASIO_HAS_MOVE) + // Start an asynchronous accept. The peer and peer_endpoint objects + // must be valid until the accept's handler is invoked. + template <typename Handler> + void async_accept(implementation_type& impl, + boost::asio::io_context* peer_io_context, + endpoint_type* peer_endpoint, Handler& handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_move_accept_op<protocol_type, Handler> op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + bool enable_connection_aborted = + (impl.state_ & socket_ops::enable_connection_aborted) != 0; + p.p = new (p.v) op(*this, impl.socket_, impl.protocol_, + peer_io_context ? *peer_io_context : io_context_, + peer_endpoint, enable_connection_aborted, handler); + + BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_accept")); + + start_accept_op(impl, false, p.p->new_socket(), + impl.protocol_.family(), impl.protocol_.type(), + impl.protocol_.protocol(), p.p->output_buffer(), + p.p->address_length(), p.p); + p.v = p.p = 0; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + // Connect the socket to the specified endpoint. boost::system::error_code connect(implementation_type& impl, const endpoint_type& peer_endpoint, boost::system::error_code& ec) @@ -505,11 +578,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef win_iocp_socket_connect_op<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.socket_, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_connect")); + BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_connect")); start_connect_op(impl, impl.protocol_.family(), impl.protocol_.type(), peer_endpoint.data(), static_cast<int>(peer_endpoint.size()), p.p); diff --git a/boost/asio/detail/win_iocp_socket_service_base.hpp b/boost/asio/detail/win_iocp_socket_service_base.hpp index 8ecf219598..2af1546712 100644 --- a/boost/asio/detail/win_iocp_socket_service_base.hpp +++ b/boost/asio/detail/win_iocp_socket_service_base.hpp @@ -20,27 +20,28 @@ #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/socket_base.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/operation.hpp> -#include <boost/asio/detail/reactor.hpp> #include <boost/asio/detail/reactor_op.hpp> +#include <boost/asio/detail/select_reactor.hpp> #include <boost/asio/detail/socket_holder.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/socket_types.hpp> -#include <boost/asio/detail/win_iocp_io_service.hpp> +#include <boost/asio/detail/win_iocp_io_context.hpp> #include <boost/asio/detail/win_iocp_null_buffers_op.hpp> #include <boost/asio/detail/win_iocp_socket_connect_op.hpp> #include <boost/asio/detail/win_iocp_socket_send_op.hpp> #include <boost/asio/detail/win_iocp_socket_recv_op.hpp> #include <boost/asio/detail/win_iocp_socket_recvmsg_op.hpp> +#include <boost/asio/detail/win_iocp_wait_op.hpp> #include <boost/asio/detail/push_options.hpp> @@ -69,7 +70,7 @@ public: socket_ops::shared_cancel_token_type cancel_token_; // Per-descriptor data used by the reactor. - reactor::per_descriptor_data reactor_data_; + select_reactor::per_descriptor_data reactor_data_; #if defined(BOOST_ASIO_ENABLE_CANCELIO) // The ID of the thread from which it is safe to cancel asynchronous @@ -86,10 +87,10 @@ public: // Constructor. BOOST_ASIO_DECL win_iocp_socket_service_base( - boost::asio::io_service& io_service); + boost::asio::io_context& io_context); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void base_shutdown(); // Construct a new socket implementation. BOOST_ASIO_DECL void construct(base_implementation_type& impl); @@ -116,6 +117,10 @@ public: BOOST_ASIO_DECL boost::system::error_code close( base_implementation_type& impl, boost::system::error_code& ec); + // Release ownership of the socket. + BOOST_ASIO_DECL socket_type release( + base_implementation_type& impl, boost::system::error_code& ec); + // Cancel all operations associated with the socket. BOOST_ASIO_DECL boost::system::error_code cancel( base_implementation_type& impl, boost::system::error_code& ec); @@ -180,14 +185,68 @@ public: return ec; } - // Disable sends or receives on the socket. - boost::system::error_code shutdown(base_implementation_type& impl, - socket_base::shutdown_type what, boost::system::error_code& ec) + // Wait for the socket to become ready to read, ready to write, or to have + // pending error conditions. + boost::system::error_code wait(base_implementation_type& impl, + socket_base::wait_type w, boost::system::error_code& ec) { - socket_ops::shutdown(impl.socket_, what, ec); + switch (w) + { + case socket_base::wait_read: + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_write: + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_error: + socket_ops::poll_error(impl.socket_, impl.state_, -1, ec); + break; + default: + ec = boost::asio::error::invalid_argument; + break; + } + return ec; } + // Asynchronously wait for the socket to become ready to read, ready to + // write, or to have pending error conditions. + template <typename Handler> + void async_wait(base_implementation_type& impl, + socket_base::wait_type w, Handler& handler) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_wait_op<Handler> op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); + + BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_wait")); + + switch (w) + { + case socket_base::wait_read: + start_null_buffers_receive_op(impl, 0, p.p); + break; + case socket_base::wait_write: + start_reactor_op(impl, select_reactor::write_op, p.p); + break; + case socket_base::wait_error: + start_reactor_op(impl, select_reactor::except_op, p.p); + break; + default: + p.p->ec_ = boost::asio::error::invalid_argument; + iocp_service_.post_immediate_completion(p.p, is_continuation); + break; + } + + p.v = p.p = 0; + } + // Send the given data to the peer. Returns the number of bytes sent. template <typename ConstBufferSequence> size_t send(base_implementation_type& impl, @@ -206,7 +265,7 @@ public: socket_base::message_flags, boost::system::error_code& ec) { // Wait for socket to become ready. - socket_ops::poll_write(impl.socket_, impl.state_, ec); + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); return 0; } @@ -221,11 +280,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.cancel_token_, buffers, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send")); + BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_send")); buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence> bufs(buffers); @@ -244,14 +303,13 @@ public: // Allocate and construct an operation to wrap the handler. typedef win_iocp_null_buffers_op<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.cancel_token_, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", - &impl, "async_send(null_buffers)")); + BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_send(null_buffers)")); - start_reactor_op(impl, reactor::write_op, p.p); + start_reactor_op(impl, select_reactor::write_op, p.p); p.v = p.p = 0; } @@ -273,7 +331,7 @@ public: socket_base::message_flags, boost::system::error_code& ec) { // Wait for socket to become ready. - socket_ops::poll_read(impl.socket_, impl.state_, ec); + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); return 0; } @@ -288,11 +346,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef win_iocp_socket_recv_op<MutableBufferSequence, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.state_, impl.cancel_token_, buffers, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_receive")); + BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_receive")); buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence> bufs(buffers); @@ -311,12 +369,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef win_iocp_null_buffers_op<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.cancel_token_, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", - &impl, "async_receive(null_buffers)")); + BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_receive(null_buffers)")); start_null_buffers_receive_op(impl, flags, p.p); p.v = p.p = 0; @@ -343,7 +400,7 @@ public: socket_base::message_flags& out_flags, boost::system::error_code& ec) { // Wait for socket to become ready. - socket_ops::poll_read(impl.socket_, impl.state_, ec); + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); // Clear out_flags, since we cannot give it any other sensible value when // performing a null_buffers operation. @@ -362,12 +419,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef win_iocp_socket_recvmsg_op<MutableBufferSequence, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.cancel_token_, buffers, out_flags, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", - &impl, "async_receive_with_flags")); + BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags")); buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence> bufs(buffers); @@ -385,12 +441,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef win_iocp_null_buffers_op<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.cancel_token_, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, - "async_receive_with_flags(null_buffers)")); + BOOST_ASIO_HANDLER_CREATION((io_context_, *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags(null_buffers)")); // Reset out_flags since it can be given no sensible value at this time. out_flags = 0; @@ -464,9 +519,9 @@ protected: base_implementation_type& impl); // Helper function to get the reactor. If no reactor has been created yet, a - // new one is obtained from the io_service and a pointer to it is cached in + // new one is obtained from the io_context and a pointer to it is cached in // this service. - BOOST_ASIO_DECL reactor& get_reactor(); + BOOST_ASIO_DECL select_reactor& get_reactor(); // The type of a ConnectEx function pointer, as old SDKs may not provide it. typedef BOOL (PASCAL *connect_ex_fn)(SOCKET, @@ -478,6 +533,15 @@ protected: BOOST_ASIO_DECL connect_ex_fn get_connect_ex( base_implementation_type& impl, int type); + // The type of a NtSetInformationFile function pointer. + typedef LONG (NTAPI *nt_set_info_fn)(HANDLE, ULONG_PTR*, void*, ULONG, ULONG); + + // Helper function to get the NtSetInformationFile function pointer. If no + // NtSetInformationFile pointer has been obtained yet, one is obtained using + // GetProcAddress and the pointer is cached. Returns a null pointer if + // NtSetInformationFile is not available. + BOOST_ASIO_DECL nt_set_info_fn get_nt_set_info(); + // Helper function to emulate InterlockedCompareExchangePointer functionality // for: // - very old Platform SDKs; and @@ -490,20 +554,23 @@ protected: // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. BOOST_ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val); - // The io_service used to obtain the reactor, if required. - boost::asio::io_service& io_service_; + // The io_context used to obtain the reactor, if required. + boost::asio::io_context& io_context_; // The IOCP service used for running asynchronous operations and dispatching // handlers. - win_iocp_io_service& iocp_service_; + win_iocp_io_context& iocp_service_; // The reactor used for performing connect operations. This object is created // only if needed. - reactor* reactor_; + select_reactor* reactor_; // Pointer to ConnectEx implementation. void* connect_ex_; + // Pointer to NtSetInformationFile implementation. + void* nt_set_info_; + // Mutex to protect access to the linked list of implementations. boost::asio::detail::mutex mutex_; diff --git a/boost/asio/detail/win_iocp_wait_op.hpp b/boost/asio/detail/win_iocp_wait_op.hpp new file mode 100644 index 0000000000..c5bc4a273f --- /dev/null +++ b/boost/asio/detail/win_iocp_wait_op.hpp @@ -0,0 +1,123 @@ +// +// detail/win_iocp_wait_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include <boost/asio/detail/bind_handler.hpp> +#include <boost/asio/detail/buffer_sequence_adapter.hpp> +#include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/handler_alloc_helpers.hpp> +#include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> +#include <boost/asio/detail/reactor_op.hpp> +#include <boost/asio/detail/socket_ops.hpp> +#include <boost/asio/error.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +template <typename Handler> +class win_iocp_wait_op : public reactor_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_wait_op); + + win_iocp_wait_op(socket_ops::weak_cancel_token_type cancel_token, + Handler& handler) + : reactor_op(&win_iocp_wait_op::do_perform, + &win_iocp_wait_op::do_complete), + cancel_token_(cancel_token), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) + { + handler_work<Handler>::start(handler_); + } + + static status do_perform(reactor_op*) + { + return done; + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& result_ec, + std::size_t /*bytes_transferred*/) + { + boost::system::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_wait_op* o(static_cast<win_iocp_wait_op*>(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // The reactor may have stored a result in the operation object. + if (o->ec_) + ec = o->ec_; + + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (o->cancel_token_.expired()) + ec = boost::asio::error::operation_aborted; + else + ec = boost::asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = boost::asio::error::connection_refused; + } + + // 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::binder1<Handler, boost::system::error_code> + handler(o->handler_, ec); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP diff --git a/boost/asio/detail/win_object_handle_service.hpp b/boost/asio/detail/win_object_handle_service.hpp index 3383657304..1e94a304eb 100644 --- a/boost/asio/detail/win_object_handle_service.hpp +++ b/boost/asio/detail/win_object_handle_service.hpp @@ -20,11 +20,11 @@ #if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/wait_handler.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -32,7 +32,8 @@ namespace boost { namespace asio { namespace detail { -class win_object_handle_service +class win_object_handle_service : + public service_base<win_object_handle_service> { public: // The native type of an object handle. @@ -80,10 +81,10 @@ public: // Constructor. BOOST_ASIO_DECL win_object_handle_service( - boost::asio::io_service& io_service); + boost::asio::io_context& io_context); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void shutdown(); // Construct a new handle implementation. BOOST_ASIO_DECL void construct(implementation_type& impl); @@ -135,11 +136,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef wait_handler<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "object_handle", &impl, "async_wait")); + BOOST_ASIO_HANDLER_CREATION((io_context_.context(), *p.p, "object_handle", + &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "async_wait")); start_wait_op(impl, p.p); p.v = p.p = 0; @@ -157,8 +158,8 @@ private: static BOOST_ASIO_DECL VOID CALLBACK wait_callback( PVOID param, BOOLEAN timeout); - // The io_service implementation used to post completions. - io_service_impl& io_service_; + // The io_context implementation used to post completions. + io_context_impl& io_context_; // Mutex to protect access to internal state. mutex mutex_; diff --git a/boost/asio/detail/win_thread.hpp b/boost/asio/detail/win_thread.hpp index a138d92ee8..f063330e1d 100644 --- a/boost/asio/detail/win_thread.hpp +++ b/boost/asio/detail/win_thread.hpp @@ -21,6 +21,7 @@ && !defined(BOOST_ASIO_WINDOWS_APP) \ && !defined(UNDER_CE) +#include <cstddef> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/socket_types.hpp> @@ -79,6 +80,9 @@ public: // Wait for the thread to exit. BOOST_ASIO_DECL void join(); + // Get number of CPUs. + BOOST_ASIO_DECL static std::size_t hardware_concurrency(); + private: friend BOOST_ASIO_DECL unsigned int __stdcall win_thread_function(void* arg); diff --git a/boost/asio/detail/winapi_thread.hpp b/boost/asio/detail/winapp_thread.hpp index 79aba9b519..4b57d228f6 100644 --- a/boost/asio/detail/winapi_thread.hpp +++ b/boost/asio/detail/winapp_thread.hpp @@ -1,5 +1,5 @@ // -// detail/winapi_thread.hpp +// detail/winapp_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -8,8 +8,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_DETAIL_WINAPI_THREAD_HPP -#define BOOST_ASIO_DETAIL_WINAPI_THREAD_HPP +#ifndef BOOST_ASIO_DETAIL_WINAPP_THREAD_HPP +#define BOOST_ASIO_DETAIL_WINAPP_THREAD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once @@ -17,8 +17,7 @@ #include <boost/asio/detail/config.hpp> -#if defined(BOOST_ASIO_WINDOWS) -#if defined(BOOST_ASIO_WINDOWS_APP) || defined(UNDER_CE) +#if defined(BOOST_ASIO_WINDOWS) && defined(BOOST_ASIO_WINDOWS_APP) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/scoped_ptr.hpp> @@ -32,19 +31,19 @@ namespace boost { namespace asio { namespace detail { -DWORD WINAPI winapi_thread_function(LPVOID arg); +DWORD WINAPI winapp_thread_function(LPVOID arg); -class winapi_thread +class winapp_thread : private noncopyable { public: // Constructor. template <typename Function> - winapi_thread(Function f, unsigned int = 0) + winapp_thread(Function f, unsigned int = 0) { scoped_ptr<func_base> arg(new func<Function>(f)); DWORD thread_id = 0; - thread_ = ::CreateThread(0, 0, winapi_thread_function, + thread_ = ::CreateThread(0, 0, winapp_thread_function, arg.get(), 0, &thread_id); if (!thread_) { @@ -57,7 +56,7 @@ public: } // Destructor. - ~winapi_thread() + ~winapp_thread() { ::CloseHandle(thread_); } @@ -65,15 +64,19 @@ public: // Wait for the thread to exit. void join() { -#if defined(BOOST_ASIO_WINDOWS_APP) ::WaitForSingleObjectEx(thread_, INFINITE, false); -#else // defined(BOOST_ASIO_WINDOWS_APP) - ::WaitForSingleObject(thread_, INFINITE); -#endif // defined(BOOST_ASIO_WINDOWS_APP) + } + + // Get number of CPUs. + static std::size_t hardware_concurrency() + { + SYSTEM_INFO system_info; + ::GetNativeSystemInfo(&system_info); + return system_info.dwNumberOfProcessors; } private: - friend DWORD WINAPI winapi_thread_function(LPVOID arg); + friend DWORD WINAPI winapp_thread_function(LPVOID arg); class func_base { @@ -104,10 +107,10 @@ private: ::HANDLE thread_; }; -inline DWORD WINAPI winapi_thread_function(LPVOID arg) +inline DWORD WINAPI winapp_thread_function(LPVOID arg) { - scoped_ptr<winapi_thread::func_base> func( - static_cast<winapi_thread::func_base*>(arg)); + scoped_ptr<winapp_thread::func_base> func( + static_cast<winapp_thread::func_base*>(arg)); func->run(); return 0; } @@ -118,7 +121,6 @@ inline DWORD WINAPI winapi_thread_function(LPVOID arg) #include <boost/asio/detail/pop_options.hpp> -#endif // defined(BOOST_ASIO_WINDOWS_APP) || defined(UNDER_CE) -#endif // defined(BOOST_ASIO_WINDOWS) +#endif // defined(BOOST_ASIO_WINDOWS) && defined(BOOST_ASIO_WINDOWS_APP) -#endif // BOOST_ASIO_DETAIL_WINAPI_THREAD_HPP +#endif // BOOST_ASIO_DETAIL_WINAPP_THREAD_HPP diff --git a/boost/asio/detail/wince_thread.hpp b/boost/asio/detail/wince_thread.hpp new file mode 100644 index 0000000000..bc14d71207 --- /dev/null +++ b/boost/asio/detail/wince_thread.hpp @@ -0,0 +1,126 @@ +// +// detail/wince_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_WINCE_THREAD_HPP +#define BOOST_ASIO_DETAIL_WINCE_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + +#include <boost/asio/detail/noncopyable.hpp> +#include <boost/asio/detail/scoped_ptr.hpp> +#include <boost/asio/detail/socket_types.hpp> +#include <boost/asio/detail/throw_error.hpp> +#include <boost/asio/error.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +DWORD WINAPI wince_thread_function(LPVOID arg); + +class wince_thread + : private noncopyable +{ +public: + // Constructor. + template <typename Function> + wince_thread(Function f, unsigned int = 0) + { + scoped_ptr<func_base> arg(new func<Function>(f)); + DWORD thread_id = 0; + thread_ = ::CreateThread(0, 0, wince_thread_function, + arg.get(), 0, &thread_id); + if (!thread_) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread"); + } + arg.release(); + } + + // Destructor. + ~wince_thread() + { + ::CloseHandle(thread_); + } + + // Wait for the thread to exit. + void join() + { + ::WaitForSingleObject(thread_, INFINITE); + } + + // Get number of CPUs. + static std::size_t hardware_concurrency() + { + SYSTEM_INFO system_info; + ::GetSystemInfo(&system_info); + return system_info.dwNumberOfProcessors; + } + +private: + friend DWORD WINAPI wince_thread_function(LPVOID arg); + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + }; + + template <typename Function> + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + ::HANDLE thread_; +}; + +inline DWORD WINAPI wince_thread_function(LPVOID arg) +{ + scoped_ptr<wince_thread::func_base> func( + static_cast<wince_thread::func_base*>(arg)); + func->run(); + return 0; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + +#endif // BOOST_ASIO_DETAIL_WINCE_THREAD_HPP diff --git a/boost/asio/detail/winrt_async_manager.hpp b/boost/asio/detail/winrt_async_manager.hpp index d6d823d689..7af5357633 100644 --- a/boost/asio/detail/winrt_async_manager.hpp +++ b/boost/asio/detail/winrt_async_manager.hpp @@ -23,7 +23,7 @@ #include <boost/asio/detail/atomic_count.hpp> #include <boost/asio/detail/winrt_async_op.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -36,9 +36,9 @@ class winrt_async_manager { public: // Constructor. - winrt_async_manager(boost::asio::io_service& io_service) - : boost::asio::detail::service_base<winrt_async_manager>(io_service), - io_service_(use_service<io_service_impl>(io_service)), + winrt_async_manager(boost::asio::io_context& io_context) + : boost::asio::detail::service_base<winrt_async_manager>(io_context), + io_context_(use_service<io_context_impl>(io_context)), outstanding_ops_(1) { } @@ -49,7 +49,7 @@ public: } // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { if (--outstanding_ops_ > 0) { @@ -186,12 +186,12 @@ public: boost::system::system_category()); break; } - io_service_.post_deferred_completion(handler); + io_context_.post_deferred_completion(handler); if (--outstanding_ops_ == 0) promise_.set_value(); }); - io_service_.work_started(); + io_context_.work_started(); ++outstanding_ops_; action->Completed = on_completed; } @@ -223,12 +223,12 @@ public: boost::system::system_category()); break; } - io_service_.post_deferred_completion(handler); + io_context_.post_deferred_completion(handler); if (--outstanding_ops_ == 0) promise_.set_value(); }); - io_service_.work_started(); + io_context_.work_started(); ++outstanding_ops_; operation->Completed = on_completed; } @@ -264,19 +264,19 @@ public: boost::system::system_category()); break; } - io_service_.post_deferred_completion(handler); + io_context_.post_deferred_completion(handler); if (--outstanding_ops_ == 0) promise_.set_value(); }); - io_service_.work_started(); + io_context_.work_started(); ++outstanding_ops_; operation->Completed = on_completed; } private: - // The io_service implementation used to post completed handlers. - io_service_impl& io_service_; + // The io_context implementation used to post completed handlers. + io_context_impl& io_context_; // Count of outstanding operations. atomic_count outstanding_ops_; diff --git a/boost/asio/detail/winrt_resolve_op.hpp b/boost/asio/detail/winrt_resolve_op.hpp index 12d56933b1..7a98345a09 100644 --- a/boost/asio/detail/winrt_resolve_op.hpp +++ b/boost/asio/detail/winrt_resolve_op.hpp @@ -19,13 +19,13 @@ #if defined(BOOST_ASIO_WINDOWS_RUNTIME) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/winrt_async_op.hpp> -#include <boost/asio/ip/basic_resolver_iterator.hpp> +#include <boost/asio/ip/basic_resolver_results.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> @@ -45,7 +45,7 @@ public: typedef typename Protocol::endpoint endpoint_type; typedef boost::asio::ip::basic_resolver_query<Protocol> query_type; - typedef boost::asio::ip::basic_resolver_iterator<Protocol> iterator_type; + typedef boost::asio::ip::basic_resolver_results<Protocol> results_type; winrt_resolve_op(const query_type& query, Handler& handler) : winrt_async_op< @@ -55,24 +55,25 @@ public: query_(query), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code&, std::size_t) { // Take ownership of the operation object. winrt_resolve_op* o(static_cast<winrt_resolve_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_ASIO_HANDLER_COMPLETION((*o)); - iterator_type iterator = iterator_type(); + results_type results = results_type(); if (!o->ec_) { try { - iterator = iterator_type::create( - o->result_, o->query_.hints(), + results = results_type::create(o->result_, o->query_.hints(), o->query_.host_name(), o->query_.service_name()); } catch (Platform::Exception^ e) @@ -88,8 +89,8 @@ public: // 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::binder2<Handler, boost::system::error_code, iterator_type> - handler(o->handler_, o->ec_, iterator); + detail::binder2<Handler, boost::system::error_code, results_type> + handler(o->handler_, o->ec_, results); p.h = boost::asio::detail::addressof(handler.handler_); p.reset(); @@ -97,8 +98,8 @@ public: if (owner) { fenced_block b(fenced_block::half); - BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/winrt_resolver_service.hpp b/boost/asio/detail/winrt_resolver_service.hpp index dfd1dddeb2..30e50e4f00 100644 --- a/boost/asio/detail/winrt_resolver_service.hpp +++ b/boost/asio/detail/winrt_resolver_service.hpp @@ -19,10 +19,10 @@ #if defined(BOOST_ASIO_WINDOWS_RUNTIME) -#include <boost/asio/ip/basic_resolver_iterator.hpp> #include <boost/asio/ip/basic_resolver_query.hpp> -#include <boost/asio/detail/addressof.hpp> +#include <boost/asio/ip/basic_resolver_results.hpp> #include <boost/asio/detail/bind_handler.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/winrt_async_manager.hpp> #include <boost/asio/detail/winrt_resolve_op.hpp> @@ -35,7 +35,8 @@ namespace asio { namespace detail { template <typename Protocol> -class winrt_resolver_service +class winrt_resolver_service : + public service_base<winrt_resolver_service<Protocol> > { public: // The implementation type of the resolver. A cancellation token is used to @@ -49,13 +50,14 @@ public: // The query type. typedef boost::asio::ip::basic_resolver_query<Protocol> query_type; - // The iterator type. - typedef boost::asio::ip::basic_resolver_iterator<Protocol> iterator_type; + // The results type. + typedef boost::asio::ip::basic_resolver_results<Protocol> results_type; // Constructor. - winrt_resolver_service(boost::asio::io_service& io_service) - : io_service_(use_service<io_service_impl>(io_service)), - async_manager_(use_service<winrt_async_manager>(io_service)) + winrt_resolver_service(boost::asio::io_context& io_context) + : service_base<winrt_resolver_service<Protocol> >(io_context), + io_context_(use_service<io_context_impl>(io_context)), + async_manager_(use_service<winrt_async_manager>(io_context)) { } @@ -65,12 +67,12 @@ public: } // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { } // Perform any fork-related housekeeping. - void fork_service(boost::asio::io_service::fork_event) + void notify_fork(boost::asio::io_context::fork_event) { } @@ -79,6 +81,18 @@ public: { } + // Move-construct a new resolver implementation. + void move_construct(implementation_type&, + implementation_type&) + { + } + + // Move-assign from another resolver implementation. + void move_assign(implementation_type&, + winrt_resolver_service&, implementation_type&) + { + } + // Destroy a resolver implementation. void destroy(implementation_type&) { @@ -90,7 +104,7 @@ public: } // Resolve a query to a list of entries. - iterator_type resolve(implementation_type&, + results_type resolve(implementation_type&, const query_type& query, boost::system::error_code& ec) { try @@ -102,9 +116,9 @@ public: winrt_utils::string(query.service_name())), ec); if (ec) - return iterator_type(); + return results_type(); - return iterator_type::create( + return results_type::create( endpoint_pairs, query.hints(), query.host_name(), query.service_name()); } @@ -112,13 +126,13 @@ public: { ec = boost::system::error_code(e->HResult, boost::system::system_category()); - return iterator_type(); + return results_type(); } } // Asynchronously resolve a query to a list of entries. template <typename Handler> - void async_resolve(implementation_type&, + void async_resolve(implementation_type& impl, const query_type& query, Handler& handler) { bool is_continuation = @@ -127,11 +141,12 @@ public: // Allocate and construct an operation to wrap the handler. typedef winrt_resolve_op<Protocol, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(query, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "resolver", &impl, "async_resolve")); + BOOST_ASIO_HANDLER_CREATION((io_context_.context(), + *p.p, "resolver", &impl, 0, "async_resolve")); + (void)impl; try { @@ -145,17 +160,17 @@ public: { p.p->ec_ = boost::system::error_code( e->HResult, boost::system::system_category()); - io_service_.post_immediate_completion(p.p, is_continuation); + io_context_.post_immediate_completion(p.p, is_continuation); p.v = p.p = 0; } } // Resolve an endpoint to a list of entries. - iterator_type resolve(implementation_type&, + results_type resolve(implementation_type&, const endpoint_type&, boost::system::error_code& ec) { ec = boost::asio::error::operation_not_supported; - return iterator_type(); + return results_type(); } // Asynchronously resolve an endpoint to a list of entries. @@ -164,13 +179,13 @@ public: const endpoint_type&, Handler& handler) { boost::system::error_code ec = boost::asio::error::operation_not_supported; - const iterator_type iterator; - io_service_.get_io_service().post( - detail::bind_handler(handler, ec, iterator)); + const results_type results; + io_context_.get_io_context().post( + detail::bind_handler(handler, ec, results)); } private: - io_service_impl& io_service_; + io_context_impl& io_context_; winrt_async_manager& async_manager_; }; diff --git a/boost/asio/detail/winrt_socket_connect_op.hpp b/boost/asio/detail/winrt_socket_connect_op.hpp index 548f7d631a..6fc1ab0c7f 100644 --- a/boost/asio/detail/winrt_socket_connect_op.hpp +++ b/boost/asio/detail/winrt_socket_connect_op.hpp @@ -19,12 +19,12 @@ #if defined(BOOST_ASIO_WINDOWS_RUNTIME) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/winrt_async_op.hpp> #include <boost/asio/error.hpp> @@ -45,16 +45,18 @@ public: : winrt_async_op<void>(&winrt_socket_connect_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code&, std::size_t) { // Take ownership of the operation object. winrt_socket_connect_op* o(static_cast<winrt_socket_connect_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_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 @@ -71,8 +73,8 @@ public: if (owner) { fenced_block b(fenced_block::half); - BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/winrt_socket_recv_op.hpp b/boost/asio/detail/winrt_socket_recv_op.hpp index 2cbbb3c8d8..137ed5a118 100644 --- a/boost/asio/detail/winrt_socket_recv_op.hpp +++ b/boost/asio/detail/winrt_socket_recv_op.hpp @@ -19,12 +19,12 @@ #if defined(BOOST_ASIO_WINDOWS_RUNTIME) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/winrt_async_op.hpp> #include <boost/asio/error.hpp> @@ -47,16 +47,18 @@ public: buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code&, std::size_t) { // Take ownership of the operation object. winrt_socket_recv_op* o(static_cast<winrt_socket_recv_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_ASIO_HANDLER_COMPLETION((*o)); #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. @@ -91,7 +93,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/winrt_socket_send_op.hpp b/boost/asio/detail/winrt_socket_send_op.hpp index 591d9536c3..301c4127a6 100644 --- a/boost/asio/detail/winrt_socket_send_op.hpp +++ b/boost/asio/detail/winrt_socket_send_op.hpp @@ -19,12 +19,12 @@ #if defined(BOOST_ASIO_WINDOWS_RUNTIME) -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/winrt_async_op.hpp> #include <boost/asio/error.hpp> @@ -46,16 +46,18 @@ public: buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { + handler_work<Handler>::start(handler_); } - static void do_complete(io_service_impl* owner, operation* base, + static void do_complete(void* owner, operation* base, const boost::system::error_code&, std::size_t) { // Take ownership of the operation object. winrt_socket_send_op* o(static_cast<winrt_socket_send_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work<Handler> w(o->handler_); - BOOST_ASIO_HANDLER_COMPLETION((o)); + BOOST_ASIO_HANDLER_COMPLETION((*o)); #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. @@ -82,7 +84,7 @@ public: { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); - boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + w.complete(handler, handler.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } diff --git a/boost/asio/detail/winrt_ssocket_service.hpp b/boost/asio/detail/winrt_ssocket_service.hpp index b9b1910e78..a1e15db545 100644 --- a/boost/asio/detail/winrt_ssocket_service.hpp +++ b/boost/asio/detail/winrt_ssocket_service.hpp @@ -20,8 +20,8 @@ #if defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> -#include <boost/asio/detail/addressof.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/winrt_socket_connect_op.hpp> #include <boost/asio/detail/winrt_ssocket_service_base.hpp> #include <boost/asio/detail/winrt_utils.hpp> @@ -34,6 +34,7 @@ namespace detail { template <typename Protocol> class winrt_ssocket_service : + public service_base<winrt_ssocket_service<Protocol> >, public winrt_ssocket_service_base { public: @@ -61,11 +62,18 @@ public: }; // Constructor. - winrt_ssocket_service(boost::asio::io_service& io_service) - : winrt_ssocket_service_base(io_service) + winrt_ssocket_service(boost::asio::io_context& io_context) + : service_base<winrt_ssocket_service<Protocol> >(io_context), + winrt_ssocket_service_base(io_context) { } + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + this->base_shutdown(); + } + // Move-construct a new socket implementation. void move_construct(implementation_type& impl, implementation_type& other_impl) @@ -213,11 +221,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef winrt_socket_connect_op<Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_connect")); + BOOST_ASIO_HANDLER_CREATION((io_context_.context(), + *p.p, "socket", &impl, 0, "async_connect")); start_connect_op(impl, peer_endpoint.data(), p.p, is_continuation); p.v = p.p = 0; diff --git a/boost/asio/detail/winrt_ssocket_service_base.hpp b/boost/asio/detail/winrt_ssocket_service_base.hpp index 88e5674576..c18722466f 100644 --- a/boost/asio/detail/winrt_ssocket_service_base.hpp +++ b/boost/asio/detail/winrt_ssocket_service_base.hpp @@ -21,10 +21,10 @@ #include <boost/asio/buffer.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/socket_base.hpp> -#include <boost/asio/detail/addressof.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/winrt_async_manager.hpp> #include <boost/asio/detail/winrt_socket_recv_op.hpp> @@ -63,10 +63,10 @@ public: // Constructor. BOOST_ASIO_DECL winrt_ssocket_service_base( - boost::asio::io_service& io_service); + boost::asio::io_context& io_context); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void base_shutdown(); // Construct a new socket implementation. BOOST_ASIO_DECL void construct(base_implementation_type&); @@ -93,6 +93,10 @@ public: BOOST_ASIO_DECL boost::system::error_code close( base_implementation_type& impl, boost::system::error_code& ec); + // Release ownership of the socket. + BOOST_ASIO_DECL native_handle_type release( + base_implementation_type& impl, boost::system::error_code& ec); + // Get the native socket representation. native_handle_type native_handle(base_implementation_type& impl) { @@ -200,11 +204,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef winrt_socket_send_op<ConstBufferSequence, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(buffers, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_send")); + BOOST_ASIO_HANDLER_CREATION((io_context_.context(), + *p.p, "socket", &impl, 0, "async_send")); start_send_op(impl, buffer_sequence_adapter<boost::asio::const_buffer, @@ -220,7 +224,7 @@ public: { boost::system::error_code ec = boost::asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_service_.get_io_service().post( + io_context_.get_io_context().post( detail::bind_handler(handler, ec, bytes_transferred)); } @@ -256,11 +260,11 @@ public: // Allocate and construct an operation to wrap the handler. typedef winrt_socket_recv_op<MutableBufferSequence, Handler> op; typename op::ptr p = { boost::asio::detail::addressof(handler), - boost_asio_handler_alloc_helpers::allocate( - sizeof(op), handler), 0 }; + op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(buffers, handler); - BOOST_ASIO_HANDLER_CREATION((p.p, "socket", &impl, "async_receive")); + BOOST_ASIO_HANDLER_CREATION((io_context_.context(), + *p.p, "socket", &impl, 0, "async_receive")); start_receive_op(impl, buffer_sequence_adapter<boost::asio::mutable_buffer, @@ -276,7 +280,7 @@ public: { boost::system::error_code ec = boost::asio::error::operation_not_supported; const std::size_t bytes_transferred = 0; - io_service_.get_io_service().post( + io_context_.get_io_context().post( detail::bind_handler(handler, ec, bytes_transferred)); } @@ -329,8 +333,8 @@ protected: winrt_async_op<Windows::Storage::Streams::IBuffer^>* op, bool is_continuation); - // The io_service implementation used for delivering completions. - io_service_impl& io_service_; + // The io_context implementation used for delivering completions. + io_context_impl& io_context_; // The manager that keeps track of outstanding operations. winrt_async_manager& async_manager_; diff --git a/boost/asio/detail/winrt_timer_scheduler.hpp b/boost/asio/detail/winrt_timer_scheduler.hpp index 8b119b2724..9dd9d050ce 100644 --- a/boost/asio/detail/winrt_timer_scheduler.hpp +++ b/boost/asio/detail/winrt_timer_scheduler.hpp @@ -28,7 +28,7 @@ #include <boost/asio/detail/timer_queue_base.hpp> #include <boost/asio/detail/timer_queue_set.hpp> #include <boost/asio/detail/wait_op.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/thread.hpp> @@ -45,17 +45,17 @@ class winrt_timer_scheduler { public: // Constructor. - BOOST_ASIO_DECL winrt_timer_scheduler(boost::asio::io_service& io_service); + BOOST_ASIO_DECL winrt_timer_scheduler(boost::asio::io_context& io_context); // Destructor. BOOST_ASIO_DECL ~winrt_timer_scheduler(); // Destroy all user-defined handler objects owned by the service. - BOOST_ASIO_DECL void shutdown_service(); + BOOST_ASIO_DECL void shutdown(); // Recreate internal descriptors following a fork. - BOOST_ASIO_DECL void fork_service( - boost::asio::io_service::fork_event fork_ev); + BOOST_ASIO_DECL void notify_fork( + boost::asio::io_context::fork_event fork_ev); // Initialise the task. No effect as this class uses its own thread. BOOST_ASIO_DECL void init_task(); @@ -82,6 +82,12 @@ public: typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); + // Move the timer operations associated with the given timer. + template <typename Time_Traits> + void move_timer(timer_queue<Time_Traits>& queue, + typename timer_queue<Time_Traits>::per_timer_data& to, + typename timer_queue<Time_Traits>::per_timer_data& from); + private: // Run the select loop in the thread. BOOST_ASIO_DECL void run_thread(); @@ -95,8 +101,8 @@ private: // Helper function to remove a timer queue. BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); - // The io_service implementation used to post completions. - io_service_impl& io_service_; + // The io_context implementation used to post completions. + io_context_impl& io_context_; // Mutex used to protect internal variables. boost::asio::detail::mutex mutex_; diff --git a/boost/asio/detail/winrt_utils.hpp b/boost/asio/detail/winrt_utils.hpp index 351aa62f23..0aebacbbb9 100644 --- a/boost/asio/detail/winrt_utils.hpp +++ b/boost/asio/detail/winrt_utils.hpp @@ -23,13 +23,12 @@ #include <cstdlib> #include <future> #include <locale> -#include <memory> #include <robuffer.h> #include <windows.storage.streams.h> #include <wrl/implements.h> #include <boost/asio/buffer.hpp> #include <boost/system/error_code.hpp> -#include <boost/asio/detail/addressof.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/push_options.hpp> @@ -84,7 +83,8 @@ inline Windows::Storage::Streams::IBuffer^ buffer_dup( const ConstBufferSequence& buffers) { using Microsoft::WRL::ComPtr; - std::size_t size = boost::asio::buffer_size(buffers); + using boost::asio::buffer_size; + std::size_t size = buffer_size(buffers); auto b = ref new Windows::Storage::Streams::Buffer(size); ComPtr<IInspectable> insp = reinterpret_cast<IInspectable*>(b); ComPtr<Windows::Storage::Streams::IBufferByteAccess> bacc; diff --git a/boost/asio/detail/work_dispatcher.hpp b/boost/asio/detail/work_dispatcher.hpp new file mode 100644 index 0000000000..7ccacd5546 --- /dev/null +++ b/boost/asio/detail/work_dispatcher.hpp @@ -0,0 +1,74 @@ +// +// detail/work_dispatcher.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DETAIL_WORK_DISPATCHER_HPP +#define BOOST_ASIO_DETAIL_WORK_DISPATCHER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/associated_executor.hpp> +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/executor_work_guard.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace detail { + +template <typename Handler> +class work_dispatcher +{ +public: + work_dispatcher(Handler& handler) + : work_((get_associated_executor)(handler)), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + work_dispatcher(const work_dispatcher& other) + : work_(other.work_), + handler_(other.handler_) + { + } + + work_dispatcher(work_dispatcher&& other) + : work_(BOOST_ASIO_MOVE_CAST(executor_work_guard< + typename associated_executor<Handler>::type>)(other.work_)), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()() + { + typename associated_allocator<Handler>::type alloc( + (get_associated_allocator)(handler_)); + work_.get_executor().dispatch( + BOOST_ASIO_MOVE_CAST(Handler)(handler_), alloc); + work_.reset(); + } + +private: + executor_work_guard<typename associated_executor<Handler>::type> work_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_DETAIL_WORK_DISPATCHER_HPP diff --git a/boost/asio/dispatch.hpp b/boost/asio/dispatch.hpp new file mode 100644 index 0000000000..c2ea0c8999 --- /dev/null +++ b/boost/asio/dispatch.hpp @@ -0,0 +1,110 @@ +// +// dispatch.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_DISPATCH_HPP +#define BOOST_ASIO_DISPATCH_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/async_result.hpp> +#include <boost/asio/detail/type_traits.hpp> +#include <boost/asio/execution_context.hpp> +#include <boost/asio/is_executor.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +/// Submits a completion token or function object for execution. +/** + * This function submits an object for execution using the object's associated + * executor. The function object is queued for execution, and is never called + * from the current thread prior to returning from <tt>dispatch()</tt>. + * + * This function has the following effects: + * + * @li Constructs a function object handler of type @c Handler, initialized + * with <tt>handler(forward<CompletionToken>(token))</tt>. + * + * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, + * initializing the object as <tt>result(handler)</tt>. + * + * @li Obtains the handler's associated executor object @c ex by performing + * <tt>get_associated_executor(handler)</tt>. + * + * @li Obtains the handler's associated allocator object @c alloc by performing + * <tt>get_associated_allocator(handler)</tt>. + * + * @li Performs <tt>ex.dispatch(std::move(handler), alloc)</tt>. + * + * @li Returns <tt>result.get()</tt>. + */ +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( + BOOST_ASIO_MOVE_ARG(CompletionToken) token); + +/// Submits a completion token or function object for execution. +/** + * This function submits an object for execution using the specified executor. + * The function object is queued for execution, and is never called from the + * current thread prior to returning from <tt>dispatch()</tt>. + * + * This function has the following effects: + * + * @li Constructs a function object handler of type @c Handler, initialized + * with <tt>handler(forward<CompletionToken>(token))</tt>. + * + * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, + * initializing the object as <tt>result(handler)</tt>. + * + * @li Obtains the handler's associated executor object @c ex1 by performing + * <tt>get_associated_executor(handler)</tt>. + * + * @li Creates a work object @c w by performing <tt>make_work(ex1)</tt>. + * + * @li Obtains the handler's associated allocator object @c alloc by performing + * <tt>get_associated_allocator(handler)</tt>. + * + * @li Constructs a function object @c f with a function call operator that + * performs <tt>ex1.dispatch(std::move(handler), alloc)</tt> followed by + * <tt>w.reset()</tt>. + * + * @li Performs <tt>Executor(ex).dispatch(std::move(f), alloc)</tt>. + * + * @li Returns <tt>result.get()</tt>. + */ +template <typename Executor, typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( + const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_executor<Executor>::value>::type* = 0); + +/// Submits a completion token or function object for execution. +/** + * @returns <tt>dispatch(ctx.get_executor(), + * forward<CompletionToken>(token))</tt>. + */ +template <typename ExecutionContext, typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( + ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_convertible< + ExecutionContext&, execution_context&>::value>::type* = 0); + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#include <boost/asio/impl/dispatch.hpp> + +#endif // BOOST_ASIO_DISPATCH_HPP diff --git a/boost/asio/error.hpp b/boost/asio/error.hpp index dd338fb156..8f1f74cb91 100644 --- a/boost/asio/error.hpp +++ b/boost/asio/error.hpp @@ -327,6 +327,22 @@ inline boost::system::error_code make_error_code(misc_errors e) } } // namespace error +namespace stream_errc { + // Simulates the proposed stream_errc scoped enum. + using error::eof; + using error::not_found; +} // namespace stream_errc +namespace socket_errc { + // Simulates the proposed socket_errc scoped enum. + using error::already_open; + using error::not_found; +} // namespace socket_errc +namespace resolver_errc { + // Simulates the proposed resolver_errc scoped enum. + using error::host_not_found; + const error::netdb_errors try_again = error::host_not_found_try_again; + using error::service_not_found; +} // namespace resolver_errc } // namespace asio } // namespace boost diff --git a/boost/asio/execution_context.hpp b/boost/asio/execution_context.hpp new file mode 100644 index 0000000000..9feb30c45d --- /dev/null +++ b/boost/asio/execution_context.hpp @@ -0,0 +1,413 @@ +// +// execution_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_EXECUTION_CONTEXT_HPP +#define BOOST_ASIO_EXECUTION_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <cstddef> +#include <stdexcept> +#include <typeinfo> +#include <boost/asio/detail/noncopyable.hpp> +#include <boost/asio/detail/variadic_templates.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +class execution_context; +class io_context; + +#if !defined(GENERATING_DOCUMENTATION) +template <typename Service> Service& use_service(execution_context&); +template <typename Service> Service& use_service(io_context&); +template <typename Service> void add_service(execution_context&, Service*); +template <typename Service> bool has_service(execution_context&); +#endif // !defined(GENERATING_DOCUMENTATION) + +namespace detail { class service_registry; } + +/// A context for function object execution. +/** + * An execution context represents a place where function objects will be + * executed. An @c io_context is an example of an execution context. + * + * @par The execution_context class and services + * + * Class execution_context implements an extensible, type-safe, polymorphic set + * of services, indexed by service type. + * + * Services exist to manage the resources that are shared across an execution + * context. For example, timers may be implemented in terms of a single timer + * queue, and this queue would be stored in a service. + * + * Access to the services of an execution_context is via three function + * templates, use_service(), add_service() and has_service(). + * + * In a call to @c use_service<Service>(), the type argument chooses a service, + * making available all members of the named type. If @c Service is not present + * in an execution_context, an object of type @c Service is created and added + * to the execution_context. A C++ program can check if an execution_context + * implements a particular service with the function template @c + * has_service<Service>(). + * + * Service objects may be explicitly added to an execution_context using the + * function template @c add_service<Service>(). If the @c Service is already + * present, the service_already_exists exception is thrown. If the owner of the + * service is not the same object as the execution_context parameter, the + * invalid_service_owner exception is thrown. + * + * Once a service reference is obtained from an execution_context object by + * calling use_service(), that reference remains usable as long as the owning + * execution_context object exists. + * + * All service implementations have execution_context::service as a public base + * class. Custom services may be implemented by deriving from this class and + * then added to an execution_context using the facilities described above. + * + * @par The execution_context as a base class + * + * Class execution_context may be used only as a base class for concrete + * execution context types. The @c io_context is an example of such a derived + * type. + * + * On destruction, a class that is derived from execution_context must perform + * <tt>execution_context::shutdown()</tt> followed by + * <tt>execution_context::destroy()</tt>. + * + * This destruction sequence permits programs to simplify their resource + * management by using @c shared_ptr<>. Where an object's lifetime is tied to + * the lifetime of a connection (or some other sequence of asynchronous + * operations), a @c shared_ptr to the object would be bound into the handlers + * for all asynchronous operations associated with it. This works as follows: + * + * @li When a single connection ends, all associated asynchronous operations + * complete. The corresponding handler objects are destroyed, and all @c + * shared_ptr references to the objects are destroyed. + * + * @li To shut down the whole program, the io_context function stop() is called + * to terminate any run() calls as soon as possible. The io_context destructor + * calls @c shutdown() and @c destroy() to destroy all pending handlers, + * causing all @c shared_ptr references to all connection objects to be + * destroyed. + */ +class execution_context + : private noncopyable +{ +public: + class id; + class service; + +protected: + /// Constructor. + BOOST_ASIO_DECL execution_context(); + + /// Destructor. + BOOST_ASIO_DECL ~execution_context(); + + /// Shuts down all services in the context. + /** + * This function is implemented as follows: + * + * @li For each service object @c svc in the execution_context set, in + * reverse order of the beginning of service object lifetime, performs @c + * svc->shutdown(). + */ + BOOST_ASIO_DECL void shutdown(); + + /// Destroys all services in the context. + /** + * This function is implemented as follows: + * + * @li For each service object @c svc in the execution_context set, in + * reverse order * of the beginning of service object lifetime, performs + * <tt>delete static_cast<execution_context::service*>(svc)</tt>. + */ + BOOST_ASIO_DECL void destroy(); + +public: + /// Fork-related event notifications. + enum fork_event + { + /// Notify the context that the process is about to fork. + fork_prepare, + + /// Notify the context that the process has forked and is the parent. + fork_parent, + + /// Notify the context that the process has forked and is the child. + fork_child + }; + + /// Notify the execution_context of a fork-related event. + /** + * This function is used to inform the execution_context that the process is + * about to fork, or has just forked. This allows the execution_context, and + * the services it contains, to perform any necessary housekeeping to ensure + * correct operation following a fork. + * + * This function must not be called while any other execution_context + * function, or any function associated with the execution_context's derived + * class, is being called in another thread. It is, however, safe to call + * this function from within a completion handler, provided no other thread + * is accessing the execution_context or its derived class. + * + * @param event A fork-related event. + * + * @throws boost::system::system_error Thrown on failure. If the notification + * fails the execution_context object should no longer be used and should be + * destroyed. + * + * @par Example + * The following code illustrates how to incorporate the notify_fork() + * function: + * @code my_execution_context.notify_fork(execution_context::fork_prepare); + * if (fork() == 0) + * { + * // This is the child process. + * my_execution_context.notify_fork(execution_context::fork_child); + * } + * else + * { + * // This is the parent process. + * my_execution_context.notify_fork(execution_context::fork_parent); + * } @endcode + * + * @note For each service object @c svc in the execution_context set, + * performs <tt>svc->notify_fork();</tt>. When processing the fork_prepare + * event, services are visited in reverse order of the beginning of service + * object lifetime. Otherwise, services are visited in order of the beginning + * of service object lifetime. + */ + BOOST_ASIO_DECL void notify_fork(fork_event event); + + /// Obtain the service object corresponding to the given type. + /** + * This function is used to locate a service object that corresponds to the + * given service type. If there is no existing implementation of the service, + * then the execution_context will create a new instance of the service. + * + * @param e The execution_context object that owns the service. + * + * @return The service interface implementing the specified service type. + * Ownership of the service interface is not transferred to the caller. + */ + template <typename Service> + friend Service& use_service(execution_context& e); + + /// Obtain the service object corresponding to the given type. + /** + * This function is used to locate a service object that corresponds to the + * given service type. If there is no existing implementation of the service, + * then the io_context will create a new instance of the service. + * + * @param ioc The io_context object that owns the service. + * + * @return The service interface implementing the specified service type. + * Ownership of the service interface is not transferred to the caller. + * + * @note This overload is preserved for backwards compatibility with services + * that inherit from io_context::service. + */ + template <typename Service> + friend Service& use_service(io_context& ioc); + +#if defined(GENERATING_DOCUMENTATION) + + /// Creates a service object and adds it to the execution_context. + /** + * This function is used to add a service to the execution_context. + * + * @param e The execution_context object that owns the service. + * + * @param args Zero or more arguments to be passed to the service + * constructor. + * + * @throws boost::asio::service_already_exists Thrown if a service of the + * given type is already present in the execution_context. + */ + template <typename Service, typename... Args> + friend Service& make_service(execution_context& e, Args&&... args); + +#elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename Service, typename... Args> + friend Service& make_service(execution_context& e, + BOOST_ASIO_MOVE_ARG(Args)... args); + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename Service> + friend Service& make_service(execution_context& e); + +#define BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF(n) \ + template <typename Service, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + friend Service& make_service(execution_context& e, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)); \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF) +#undef BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + /// (Deprecated: Use make_service().) Add a service object to the + /// execution_context. + /** + * This function is used to add a service to the execution_context. + * + * @param e The execution_context object that owns the service. + * + * @param svc The service object. On success, ownership of the service object + * is transferred to the execution_context. When the execution_context object + * is destroyed, it will destroy the service object by performing: @code + * delete static_cast<execution_context::service*>(svc) @endcode + * + * @throws boost::asio::service_already_exists Thrown if a service of the + * given type is already present in the execution_context. + * + * @throws boost::asio::invalid_service_owner Thrown if the service's owning + * execution_context is not the execution_context object specified by the + * @c e parameter. + */ + template <typename Service> + friend void add_service(execution_context& e, Service* svc); + + /// Determine if an execution_context contains a specified service type. + /** + * This function is used to determine whether the execution_context contains a + * service object corresponding to the given service type. + * + * @param e The execution_context object that owns the service. + * + * @return A boolean indicating whether the execution_context contains the + * service. + */ + template <typename Service> + friend bool has_service(execution_context& e); + +private: + // The service registry. + boost::asio::detail::service_registry* service_registry_; +}; + +/// Class used to uniquely identify a service. +class execution_context::id + : private noncopyable +{ +public: + /// Constructor. + id() {} +}; + +/// Base class for all io_context services. +class execution_context::service + : private noncopyable +{ +public: + /// Get the context object that owns the service. + execution_context& context(); + +protected: + /// Constructor. + /** + * @param owner The execution_context object that owns the service. + */ + BOOST_ASIO_DECL service(execution_context& owner); + + /// Destructor. + BOOST_ASIO_DECL virtual ~service(); + +private: + /// Destroy all user-defined handler objects owned by the service. + virtual void shutdown() = 0; + + /// Handle notification of a fork-related event to perform any necessary + /// housekeeping. + /** + * This function is not a pure virtual so that services only have to + * implement it if necessary. The default implementation does nothing. + */ + BOOST_ASIO_DECL virtual void notify_fork( + execution_context::fork_event event); + + friend class boost::asio::detail::service_registry; + struct key + { + key() : type_info_(0), id_(0) {} + const std::type_info* type_info_; + const execution_context::id* id_; + } key_; + + execution_context& owner_; + service* next_; +}; + +/// Exception thrown when trying to add a duplicate service to an +/// execution_context. +class service_already_exists + : public std::logic_error +{ +public: + BOOST_ASIO_DECL service_already_exists(); +}; + +/// Exception thrown when trying to add a service object to an +/// execution_context where the service has a different owner. +class invalid_service_owner + : public std::logic_error +{ +public: + BOOST_ASIO_DECL invalid_service_owner(); +}; + +namespace detail { + +// Special derived service id type to keep classes header-file only. +template <typename Type> +class service_id + : public execution_context::id +{ +}; + +// Special service base class to keep classes header-file only. +template <typename Type> +class execution_context_service_base + : public execution_context::service +{ +public: + static service_id<Type> id; + + // Constructor. + execution_context_service_base(execution_context& e) + : execution_context::service(e) + { + } +}; + +template <typename Type> +service_id<Type> execution_context_service_base<Type>::id; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#include <boost/asio/impl/execution_context.hpp> +#if defined(BOOST_ASIO_HEADER_ONLY) +# include <boost/asio/impl/execution_context.ipp> +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_EXECUTION_CONTEXT_HPP diff --git a/boost/asio/executor.hpp b/boost/asio/executor.hpp new file mode 100644 index 0000000000..f519842361 --- /dev/null +++ b/boost/asio/executor.hpp @@ -0,0 +1,343 @@ +// +// executor.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_EXECUTOR_HPP +#define BOOST_ASIO_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <typeinfo> +#include <boost/asio/detail/cstddef.hpp> +#include <boost/asio/detail/memory.hpp> +#include <boost/asio/detail/throw_exception.hpp> +#include <boost/asio/execution_context.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +/// Exception thrown when trying to access an empty polymorphic executor. +class bad_executor + : public std::exception +{ +public: + /// Constructor. + BOOST_ASIO_DECL bad_executor() BOOST_ASIO_NOEXCEPT; + + /// Obtain message associated with exception. + BOOST_ASIO_DECL virtual const char* what() const + BOOST_ASIO_NOEXCEPT_OR_NOTHROW; +}; + +/// Polymorphic wrapper for executors. +class executor +{ +public: + /// Default constructor. + executor() BOOST_ASIO_NOEXCEPT + : impl_(0) + { + } + + /// Construct from nullptr. + executor(nullptr_t) BOOST_ASIO_NOEXCEPT + : impl_(0) + { + } + + /// Copy constructor. + executor(const executor& other) BOOST_ASIO_NOEXCEPT + : impl_(other.clone()) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move constructor. + executor(executor&& other) BOOST_ASIO_NOEXCEPT + : impl_(other.impl_) + { + other.impl_ = 0; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Construct a polymorphic wrapper for the specified executor. + template <typename Executor> + executor(Executor e); + + /// Allocator-aware constructor to create a polymorphic wrapper for the + /// specified executor. + template <typename Executor, typename Allocator> + executor(allocator_arg_t, const Allocator& a, Executor e); + + /// Destructor. + ~executor() + { + destroy(); + } + + /// Assignment operator. + executor& operator=(const executor& other) BOOST_ASIO_NOEXCEPT + { + destroy(); + impl_ = other.clone(); + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + // Move assignment operator. + executor& operator=(executor&& other) BOOST_ASIO_NOEXCEPT + { + destroy(); + impl_ = other.impl_; + other.impl_ = 0; + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Assignment operator for nullptr_t. + executor& operator=(nullptr_t) BOOST_ASIO_NOEXCEPT + { + destroy(); + impl_ = 0; + return *this; + } + + /// Assignment operator to create a polymorphic wrapper for the specified + /// executor. + template <typename Executor> + executor& operator=(BOOST_ASIO_MOVE_ARG(Executor) e) BOOST_ASIO_NOEXCEPT + { + executor tmp(BOOST_ASIO_MOVE_CAST(Executor)(e)); + destroy(); + impl_ = tmp.impl_; + tmp.impl_ = 0; + return *this; + } + + /// Obtain the underlying execution context. + execution_context& context() const BOOST_ASIO_NOEXCEPT + { + return get_impl()->context(); + } + + /// Inform the executor that it has some outstanding work to do. + void on_work_started() const BOOST_ASIO_NOEXCEPT + { + get_impl()->on_work_started(); + } + + /// Inform the executor that some work is no longer outstanding. + void on_work_finished() const BOOST_ASIO_NOEXCEPT + { + get_impl()->on_work_finished(); + } + + /// Request the executor to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object is executed according to the rules of the + * target executor object. + * + * @param f The function object to be called. The executor will make a copy + * of the handler object as required. The function signature of the function + * object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Request the executor to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object is executed according to the rules of the + * target executor object. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Request the executor to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object is executed according to the rules of the + * target executor object. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + struct unspecified_bool_type_t {}; + typedef void (*unspecified_bool_type)(unspecified_bool_type_t); + static void unspecified_bool_true(unspecified_bool_type_t) {} + + /// Operator to test if the executor contains a valid target. + operator unspecified_bool_type() const BOOST_ASIO_NOEXCEPT + { + return impl_ ? &executor::unspecified_bool_true : 0; + } + + /// Obtain type information for the target executor object. + /** + * @returns If @c *this has a target type of type @c T, <tt>typeid(T)</tt>; + * otherwise, <tt>typeid(void)</tt>. + */ +#if !defined(BOOST_ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION) + const std::type_info& target_type() const BOOST_ASIO_NOEXCEPT + { + return impl_ ? impl_->target_type() : typeid(void); + } +#else // !defined(BOOST_ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION) + const void* target_type() const BOOST_ASIO_NOEXCEPT + { + return impl_ ? impl_->target_type() : 0; + } +#endif // !defined(BOOST_ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION) + + /// Obtain a pointer to the target executor object. + /** + * @returns If <tt>target_type() == typeid(T)</tt>, a pointer to the stored + * executor target; otherwise, a null pointer. + */ + template <typename Executor> + Executor* target() BOOST_ASIO_NOEXCEPT; + + /// Obtain a pointer to the target executor object. + /** + * @returns If <tt>target_type() == typeid(T)</tt>, a pointer to the stored + * executor target; otherwise, a null pointer. + */ + template <typename Executor> + const Executor* target() const BOOST_ASIO_NOEXCEPT; + + /// Compare two executors for equality. + friend bool operator==(const executor& a, + const executor& b) BOOST_ASIO_NOEXCEPT + { + if (a.impl_ == b.impl_) + return true; + if (!a.impl_ || !b.impl_) + return false; + return a.impl_->equals(b.impl_); + } + + /// Compare two executors for inequality. + friend bool operator!=(const executor& a, + const executor& b) BOOST_ASIO_NOEXCEPT + { + return !(a == b); + } + +private: +#if !defined(GENERATING_DOCUMENTATION) + class function; + template <typename, typename> class impl; + +#if !defined(BOOST_ASIO_NO_TYPEID) + typedef const std::type_info& type_id_result_type; +#else // !defined(BOOST_ASIO_NO_TYPEID) + typedef const void* type_id_result_type; +#endif // !defined(BOOST_ASIO_NO_TYPEID) + + template <typename T> + static type_id_result_type type_id() + { +#if !defined(BOOST_ASIO_NO_TYPEID) + return typeid(T); +#else // !defined(BOOST_ASIO_NO_TYPEID) + static int unique_id; + return &unique_id; +#endif // !defined(BOOST_ASIO_NO_TYPEID) + } + + // Base class for all polymorphic executor implementations. + class impl_base + { + public: + virtual impl_base* clone() const BOOST_ASIO_NOEXCEPT = 0; + virtual void destroy() BOOST_ASIO_NOEXCEPT = 0; + virtual execution_context& context() BOOST_ASIO_NOEXCEPT = 0; + virtual void on_work_started() BOOST_ASIO_NOEXCEPT = 0; + virtual void on_work_finished() BOOST_ASIO_NOEXCEPT = 0; + virtual void dispatch(BOOST_ASIO_MOVE_ARG(function)) = 0; + virtual void post(BOOST_ASIO_MOVE_ARG(function)) = 0; + virtual void defer(BOOST_ASIO_MOVE_ARG(function)) = 0; + virtual type_id_result_type target_type() const BOOST_ASIO_NOEXCEPT = 0; + virtual void* target() BOOST_ASIO_NOEXCEPT = 0; + virtual const void* target() const BOOST_ASIO_NOEXCEPT = 0; + virtual bool equals(const impl_base* e) const BOOST_ASIO_NOEXCEPT = 0; + + protected: + impl_base(bool fast_dispatch) : fast_dispatch_(fast_dispatch) {} + virtual ~impl_base() {} + + private: + friend class executor; + const bool fast_dispatch_; + }; + + // Helper function to check and return the implementation pointer. + impl_base* get_impl() const + { + if (!impl_) + { + bad_executor ex; + boost::asio::detail::throw_exception(ex); + } + return impl_; + } + + // Helper function to clone another implementation. + impl_base* clone() const BOOST_ASIO_NOEXCEPT + { + return impl_ ? impl_->clone() : 0; + } + + // Helper function to destroy an implementation. + void destroy() BOOST_ASIO_NOEXCEPT + { + if (impl_) + impl_->destroy(); + } + + impl_base* impl_; +#endif // !defined(GENERATING_DOCUMENTATION) +}; + +} // namespace asio +} // namespace boost + +BOOST_ASIO_USES_ALLOCATOR(boost::asio::executor) + +#include <boost/asio/detail/pop_options.hpp> + +#include <boost/asio/impl/executor.hpp> +#if defined(BOOST_ASIO_HEADER_ONLY) +# include <boost/asio/impl/executor.ipp> +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_EXECUTOR_HPP diff --git a/boost/asio/executor_work_guard.hpp b/boost/asio/executor_work_guard.hpp new file mode 100644 index 0000000000..a5e2276b88 --- /dev/null +++ b/boost/asio/executor_work_guard.hpp @@ -0,0 +1,171 @@ +// +// executor_work_guard.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_EXECUTOR_WORK_GUARD_HPP +#define BOOST_ASIO_EXECUTOR_WORK_GUARD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/associated_executor.hpp> +#include <boost/asio/detail/type_traits.hpp> +#include <boost/asio/is_executor.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +/// An object of type @c executor_work_guard controls ownership of executor work +/// within a scope. +template <typename Executor> +class executor_work_guard +{ +public: + /// The underlying executor type. + typedef Executor executor_type; + + /// Constructs a @c executor_work_guard object for the specified executor. + /** + * Stores a copy of @c e and calls <tt>on_work_started()</tt> on it. + */ + explicit executor_work_guard(const executor_type& e) BOOST_ASIO_NOEXCEPT + : executor_(e), + owns_(true) + { + executor_.on_work_started(); + } + + /// Copy constructor. + executor_work_guard(const executor_work_guard& other) BOOST_ASIO_NOEXCEPT + : executor_(other.executor_), + owns_(other.owns_) + { + if (owns_) + executor_.on_work_started(); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move constructor. + executor_work_guard(executor_work_guard&& other) + : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)), + owns_(other.owns_) + { + other.owns_ = false; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destructor. + /** + * Unless the object has already been reset, or is in a moved-from state, + * calls <tt>on_work_finished()</tt> on the stored executor. + */ + ~executor_work_guard() + { + if (owns_) + executor_.on_work_finished(); + } + + /// Obtain the associated executor. + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return executor_; + } + + /// Whether the executor_work_guard object owns some outstanding work. + bool owns_work() const BOOST_ASIO_NOEXCEPT + { + return owns_; + } + + /// Indicate that the work is no longer outstanding. + /* + * Unless the object has already been reset, or is in a moved-from state, + * calls <tt>on_work_finished()</tt> on the stored executor. + */ + void reset() BOOST_ASIO_NOEXCEPT + { + if (owns_) + { + executor_.on_work_finished(); + owns_ = false; + } + } + +private: + // Disallow assignment. + executor_work_guard& operator=(const executor_work_guard&); + + executor_type executor_; + bool owns_; +}; + +/// Create an @ref executor_work_guard object. +template <typename Executor> +inline executor_work_guard<Executor> make_work_guard(const Executor& ex, + typename enable_if<is_executor<Executor>::value>::type* = 0) +{ + return executor_work_guard<Executor>(ex); +} + +/// Create an @ref executor_work_guard object. +template <typename ExecutionContext> +inline executor_work_guard<typename ExecutionContext::executor_type> +make_work_guard(ExecutionContext& ctx, + typename enable_if< + is_convertible<ExecutionContext&, execution_context&>::value>::type* = 0) +{ + return executor_work_guard<typename ExecutionContext::executor_type>( + ctx.get_executor()); +} + +/// Create an @ref executor_work_guard object. +template <typename T> +inline executor_work_guard<typename associated_executor<T>::type> +make_work_guard(const T& t, + typename enable_if<!is_executor<T>::value && + !is_convertible<T&, execution_context&>::value>::type* = 0) +{ + return executor_work_guard<typename associated_executor<T>::type>( + associated_executor<T>::get(t)); +} + +/// Create an @ref executor_work_guard object. +template <typename T, typename Executor> +inline executor_work_guard<typename associated_executor<T, Executor>::type> +make_work_guard(const T& t, const Executor& ex, + typename enable_if<is_executor<Executor>::value>::type* = 0) +{ + return executor_work_guard<typename associated_executor<T, Executor>::type>( + associated_executor<T, Executor>::get(t, ex)); +} + +/// Create an @ref executor_work_guard object. +template <typename T, typename ExecutionContext> +inline executor_work_guard<typename associated_executor<T, + typename ExecutionContext::executor_type>::type> +make_work_guard(const T& t, ExecutionContext& ctx, + typename enable_if<!is_executor<T>::value && + !is_convertible<T&, execution_context&>::value>::type* = 0) +{ + return executor_work_guard<typename associated_executor<T, + typename ExecutionContext::executor_type>::type>( + associated_executor<T, typename ExecutionContext::executor_type>::get( + t, ctx.get_executor())); +} + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_EXECUTOR_WORK_GUARD_HPP diff --git a/boost/asio/generic/detail/impl/endpoint.ipp b/boost/asio/generic/detail/impl/endpoint.ipp index 3c2da4a608..7fa67628d1 100644 --- a/boost/asio/generic/detail/impl/endpoint.ipp +++ b/boost/asio/generic/detail/impl/endpoint.ipp @@ -95,7 +95,8 @@ void endpoint::init(const void* sock_addr, using namespace std; // For memset and memcpy. memset(&data_.generic, 0, sizeof(boost::asio::detail::sockaddr_storage_type)); - memcpy(&data_.generic, sock_addr, sock_addr_size); + if (sock_addr_size > 0) + memcpy(&data_.generic, sock_addr, sock_addr_size); size_ = sock_addr_size; protocol_ = sock_protocol; diff --git a/boost/asio/handler_invoke_hook.hpp b/boost/asio/handler_invoke_hook.hpp index 6605d87499..f698c2f863 100644 --- a/boost/asio/handler_invoke_hook.hpp +++ b/boost/asio/handler_invoke_hook.hpp @@ -27,12 +27,12 @@ namespace asio { * @brief Default invoke function for handlers. * * Completion handlers for asynchronous operations are invoked by the - * io_service associated with the corresponding object (e.g. a socket or + * io_context associated with the corresponding object (e.g. a socket or * deadline_timer). Certain guarantees are made on when the handler may be * invoked, in particular that a handler can only be invoked from a thread that - * is currently calling @c run() on the corresponding io_service object. + * is currently calling @c run() on the corresponding io_context object. * Handlers may subsequently be invoked through other objects (such as - * io_service::strand objects) that provide additional guarantees. + * io_context::strand objects) that provide additional guarantees. * * When asynchronous operations are composed from other asynchronous * operations, all intermediate handlers should be invoked using the same diff --git a/boost/asio/handler_type.hpp b/boost/asio/handler_type.hpp index 11e97e3ea0..97187574b6 100644 --- a/boost/asio/handler_type.hpp +++ b/boost/asio/handler_type.hpp @@ -16,99 +16,37 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { -/// Default handler type traits provided for all handlers. +/// (Deprecated: Use two-parameter version of async_result.) Default handler +/// type traits provided for all completion token types. /** * The handler_type traits class is used for determining the concrete handler * type to be used for an asynchronous operation. It allows the handler type to * be determined at the point where the specific completion handler signature * is known. * - * This template may be specialised for user-defined handler types. + * This template may be specialised for user-defined completion token types. */ -template <typename Handler, typename Signature> +template <typename CompletionToken, typename Signature, typename = void> struct handler_type { /// The handler type for the specific signature. - typedef Handler type; + typedef typename conditional< + is_same<CompletionToken, typename decay<CompletionToken>::type>::value, + decay<CompletionToken>, + handler_type<typename decay<CompletionToken>::type, Signature> + >::type::type type; }; -#if !defined(GENERATING_DOCUMENTATION) - -template <typename Handler, typename Signature> -struct handler_type<const Handler, Signature> - : handler_type<Handler, Signature> {}; - -template <typename Handler, typename Signature> -struct handler_type<volatile Handler, Signature> - : handler_type<Handler, Signature> {}; - -template <typename Handler, typename Signature> -struct handler_type<const volatile Handler, Signature> - : handler_type<Handler, Signature> {}; - -template <typename Handler, typename Signature> -struct handler_type<const Handler&, Signature> - : handler_type<Handler, Signature> {}; - -template <typename Handler, typename Signature> -struct handler_type<volatile Handler&, Signature> - : handler_type<Handler, Signature> {}; - -template <typename Handler, typename Signature> -struct handler_type<const volatile Handler&, Signature> - : handler_type<Handler, Signature> {}; - -template <typename Handler, typename Signature> -struct handler_type<Handler&, Signature> - : handler_type<Handler, Signature> {}; - -#if defined(BOOST_ASIO_HAS_MOVE) -template <typename Handler, typename Signature> -struct handler_type<Handler&&, Signature> - : handler_type<Handler, Signature> {}; -#endif // defined(BOOST_ASIO_HAS_MOVE) - -template <typename ReturnType, typename Signature> -struct handler_type<ReturnType(), Signature> - : handler_type<ReturnType(*)(), Signature> {}; - -template <typename ReturnType, typename Arg1, typename Signature> -struct handler_type<ReturnType(Arg1), Signature> - : handler_type<ReturnType(*)(Arg1), Signature> {}; - -template <typename ReturnType, typename Arg1, typename Arg2, typename Signature> -struct handler_type<ReturnType(Arg1, Arg2), Signature> - : handler_type<ReturnType(*)(Arg1, Arg2), Signature> {}; - -template <typename ReturnType, typename Arg1, typename Arg2, typename Arg3, - typename Signature> -struct handler_type<ReturnType(Arg1, Arg2, Arg3), Signature> - : handler_type<ReturnType(*)(Arg1, Arg2, Arg3), Signature> {}; - -template <typename ReturnType, typename Arg1, typename Arg2, typename Arg3, - typename Arg4, typename Signature> -struct handler_type<ReturnType(Arg1, Arg2, Arg3, Arg4), Signature> - : handler_type<ReturnType(*)(Arg1, Arg2, Arg3, Arg4), Signature> {}; - -template <typename ReturnType, typename Arg1, typename Arg2, typename Arg3, - typename Arg4, typename Arg5, typename Signature> -struct handler_type<ReturnType(Arg1, Arg2, Arg3, Arg4, Arg5), Signature> - : handler_type<ReturnType(*)(Arg1, Arg2, Arg3, Arg4, Arg5), Signature> {}; - -#endif // !defined(GENERATING_DOCUMENTATION) - } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> -#define BOOST_ASIO_HANDLER_TYPE(h, sig) \ - typename handler_type<h, sig>::type - #endif // BOOST_ASIO_HANDLER_TYPE_HPP diff --git a/boost/asio/high_resolution_timer.hpp b/boost/asio/high_resolution_timer.hpp index 5d6cef0296..3cd57714ee 100644 --- a/boost/asio/high_resolution_timer.hpp +++ b/boost/asio/high_resolution_timer.hpp @@ -17,22 +17,14 @@ #include <boost/asio/detail/config.hpp> -#if defined(BOOST_ASIO_HAS_STD_CHRONO) \ - || defined(BOOST_ASIO_HAS_BOOST_CHRONO) \ - || defined(GENERATING_DOCUMENTATION) - -#if defined(BOOST_ASIO_HAS_STD_CHRONO) -# include <chrono> -#elif defined(BOOST_ASIO_HAS_BOOST_CHRONO) -# include <boost/chrono/system_clocks.hpp> -#endif +#if defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) #include <boost/asio/basic_waitable_timer.hpp> +#include <boost/asio/detail/chrono.hpp> namespace boost { namespace asio { -#if defined(GENERATING_DOCUMENTATION) /// Typedef for a timer based on the high resolution clock. /** * This typedef uses the C++11 @c <chrono> standard library facility, if @@ -45,21 +37,10 @@ namespace asio { typedef basic_waitable_timer< chrono::high_resolution_clock> high_resolution_timer; -#elif defined(BOOST_ASIO_HAS_STD_CHRONO) -typedef basic_waitable_timer< - std::chrono::high_resolution_clock> - high_resolution_timer; -#elif defined(BOOST_ASIO_HAS_BOOST_CHRONO) -typedef basic_waitable_timer< - boost::chrono::high_resolution_clock> - high_resolution_timer; -#endif } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_STD_CHRONO) - // || defined(BOOST_ASIO_HAS_BOOST_CHRONO) - // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_HIGH_RESOLUTION_TIMER_HPP diff --git a/boost/asio/impl/buffered_read_stream.hpp b/boost/asio/impl/buffered_read_stream.hpp index 082ed0338b..0813db4fce 100644 --- a/boost/asio/impl/buffered_read_stream.hpp +++ b/boost/asio/impl/buffered_read_stream.hpp @@ -15,6 +15,8 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/associated_executor.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> @@ -138,6 +140,36 @@ namespace detail } } // namespace detail +#if !defined(GENERATING_DOCUMENTATION) + +template <typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::buffered_fill_handler<ReadHandler>, Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get(const detail::buffered_fill_handler<ReadHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename ReadHandler, typename Executor> +struct associated_executor< + detail::buffered_fill_handler<ReadHandler>, Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get(const detail::buffered_fill_handler<ReadHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + template <typename Stream> template <typename ReadHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, @@ -149,9 +181,8 @@ buffered_read_stream<Stream>::async_fill( // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); std::size_t previous_size = storage_.size(); storage_.resize(storage_.capacity()); @@ -161,7 +192,7 @@ buffered_read_stream<Stream>::async_fill( storage_.size() - previous_size), detail::buffered_fill_handler<BOOST_ASIO_HANDLER_TYPE( ReadHandler, void (boost::system::error_code, std::size_t))>( - storage_, previous_size, init.handler)); + storage_, previous_size, init.completion_handler)); return init.result.get(); } @@ -171,7 +202,8 @@ template <typename MutableBufferSequence> std::size_t buffered_read_stream<Stream>::read_some( const MutableBufferSequence& buffers) { - if (boost::asio::buffer_size(buffers) == 0) + using boost::asio::buffer_size; + if (buffer_size(buffers) == 0) return 0; if (storage_.empty()) @@ -187,7 +219,8 @@ std::size_t buffered_read_stream<Stream>::read_some( { ec = boost::system::error_code(); - if (boost::asio::buffer_size(buffers) == 0) + using boost::asio::buffer_size; + if (buffer_size(buffers) == 0) return 0; if (storage_.empty() && !this->fill(ec)) @@ -206,7 +239,7 @@ namespace detail const MutableBufferSequence& buffers, ReadHandler& handler) : storage_(storage), buffers_(buffers), - handler_(handler) + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) { } @@ -296,6 +329,44 @@ namespace detail } } // namespace detail +#if !defined(GENERATING_DOCUMENTATION) + +template <typename MutableBufferSequence, + typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::buffered_read_some_handler< + MutableBufferSequence, ReadHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename MutableBufferSequence, + typename ReadHandler, typename Executor> +struct associated_executor< + detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::buffered_read_some_handler< + MutableBufferSequence, ReadHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + template <typename Stream> template <typename MutableBufferSequence, typename ReadHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, @@ -308,24 +379,24 @@ buffered_read_stream<Stream>::async_read_some( // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); - if (boost::asio::buffer_size(buffers) == 0 || !storage_.empty()) + using boost::asio::buffer_size; + if (buffer_size(buffers) == 0 || !storage_.empty()) { - next_layer_.async_read_some(boost::asio::mutable_buffers_1(0, 0), + next_layer_.async_read_some(BOOST_ASIO_MUTABLE_BUFFER(0, 0), detail::buffered_read_some_handler< MutableBufferSequence, BOOST_ASIO_HANDLER_TYPE( ReadHandler, void (boost::system::error_code, std::size_t))>( - storage_, buffers, init.handler)); + storage_, buffers, init.completion_handler)); } else { this->async_fill(detail::buffered_read_some_handler< MutableBufferSequence, BOOST_ASIO_HANDLER_TYPE( ReadHandler, void (boost::system::error_code, std::size_t))>( - storage_, buffers, init.handler)); + storage_, buffers, init.completion_handler)); } return init.result.get(); diff --git a/boost/asio/impl/buffered_write_stream.hpp b/boost/asio/impl/buffered_write_stream.hpp index 22585eb6ce..baaa694538 100644 --- a/boost/asio/impl/buffered_write_stream.hpp +++ b/boost/asio/impl/buffered_write_stream.hpp @@ -15,6 +15,8 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/associated_executor.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> @@ -53,7 +55,7 @@ namespace detail buffered_flush_handler(detail::buffered_stream_storage& storage, WriteHandler& handler) : storage_(storage), - handler_(handler) + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) { } @@ -122,7 +124,37 @@ namespace detail boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } -} +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template <typename WriteHandler, typename Allocator> +struct associated_allocator< + detail::buffered_flush_handler<WriteHandler>, Allocator> +{ + typedef typename associated_allocator<WriteHandler, Allocator>::type type; + + static type get(const detail::buffered_flush_handler<WriteHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename WriteHandler, typename Executor> +struct associated_executor< + detail::buffered_flush_handler<WriteHandler>, Executor> +{ + typedef typename associated_executor<WriteHandler, Executor>::type type; + + static type get(const detail::buffered_flush_handler<WriteHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) template <typename Stream> template <typename WriteHandler> @@ -135,14 +167,13 @@ buffered_write_stream<Stream>::async_flush( // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); async_write(next_layer_, buffer(storage_.data(), storage_.size()), detail::buffered_flush_handler<BOOST_ASIO_HANDLER_TYPE( WriteHandler, void (boost::system::error_code, std::size_t))>( - storage_, init.handler)); + storage_, init.completion_handler)); return init.result.get(); } @@ -152,7 +183,8 @@ template <typename ConstBufferSequence> std::size_t buffered_write_stream<Stream>::write_some( const ConstBufferSequence& buffers) { - if (boost::asio::buffer_size(buffers) == 0) + using boost::asio::buffer_size; + if (buffer_size(buffers) == 0) return 0; if (storage_.size() == storage_.capacity()) @@ -168,7 +200,8 @@ std::size_t buffered_write_stream<Stream>::write_some( { ec = boost::system::error_code(); - if (boost::asio::buffer_size(buffers) == 0) + using boost::asio::buffer_size; + if (buffer_size(buffers) == 0) return 0; if (storage_.size() == storage_.capacity() && !flush(ec)) @@ -187,7 +220,7 @@ namespace detail const ConstBufferSequence& buffers, WriteHandler& handler) : storage_(storage), buffers_(buffers), - handler_(handler) + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) { } @@ -216,9 +249,10 @@ namespace detail } else { + using boost::asio::buffer_size; std::size_t orig_size = storage_.size(); std::size_t space_avail = storage_.capacity() - orig_size; - std::size_t bytes_avail = boost::asio::buffer_size(buffers_); + std::size_t bytes_avail = buffer_size(buffers_); std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail; storage_.resize(orig_size + length); @@ -282,6 +316,44 @@ namespace detail } } // namespace detail +#if !defined(GENERATING_DOCUMENTATION) + +template <typename ConstBufferSequence, + typename WriteHandler, typename Allocator> +struct associated_allocator< + detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>, + Allocator> +{ + typedef typename associated_allocator<WriteHandler, Allocator>::type type; + + static type get( + const detail::buffered_write_some_handler< + ConstBufferSequence, WriteHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename ConstBufferSequence, + typename WriteHandler, typename Executor> +struct associated_executor< + detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>, + Executor> +{ + typedef typename associated_executor<WriteHandler, Executor>::type type; + + static type get( + const detail::buffered_write_some_handler< + ConstBufferSequence, WriteHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + template <typename Stream> template <typename ConstBufferSequence, typename WriteHandler> BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, @@ -294,25 +366,25 @@ buffered_write_stream<Stream>::async_write_some( // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); - if (boost::asio::buffer_size(buffers) == 0 + using boost::asio::buffer_size; + if (buffer_size(buffers) == 0 || storage_.size() < storage_.capacity()) { - next_layer_.async_write_some(boost::asio::const_buffers_1(0, 0), + next_layer_.async_write_some(BOOST_ASIO_CONST_BUFFER(0, 0), detail::buffered_write_some_handler< ConstBufferSequence, BOOST_ASIO_HANDLER_TYPE( WriteHandler, void (boost::system::error_code, std::size_t))>( - storage_, buffers, init.handler)); + storage_, buffers, init.completion_handler)); } else { this->async_flush(detail::buffered_write_some_handler< ConstBufferSequence, BOOST_ASIO_HANDLER_TYPE( WriteHandler, void (boost::system::error_code, std::size_t))>( - storage_, buffers, init.handler)); + storage_, buffers, init.completion_handler)); } return init.result.get(); @@ -323,9 +395,10 @@ template <typename ConstBufferSequence> std::size_t buffered_write_stream<Stream>::copy( const ConstBufferSequence& buffers) { + using boost::asio::buffer_size; std::size_t orig_size = storage_.size(); std::size_t space_avail = storage_.capacity() - orig_size; - std::size_t bytes_avail = boost::asio::buffer_size(buffers); + std::size_t bytes_avail = buffer_size(buffers); std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail; storage_.resize(orig_size + length); return boost::asio::buffer_copy( diff --git a/boost/asio/impl/connect.hpp b/boost/asio/impl/connect.hpp index ba587eca02..50f1809797 100644 --- a/boost/asio/impl/connect.hpp +++ b/boost/asio/impl/connect.hpp @@ -15,14 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include <algorithm> +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/associated_executor.hpp> #include <boost/asio/detail/bind_handler.hpp> -#include <boost/asio/detail/consuming_buffers.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> +#include <boost/asio/post.hpp> #include <boost/asio/detail/push_options.hpp> @@ -33,16 +36,100 @@ namespace detail { struct default_connect_condition { - template <typename Iterator> - Iterator operator()(const boost::system::error_code&, Iterator next) + template <typename Endpoint> + bool operator()(const boost::system::error_code&, const Endpoint&) { - return next; + return true; } }; + + template <typename Protocol, typename Iterator> + inline typename Protocol::endpoint deref_connect_result( + Iterator iter, boost::system::error_code& ec) + { + return ec ? typename Protocol::endpoint() : *iter; + } + + template <typename T, typename Iterator> + struct legacy_connect_condition_helper : T + { + typedef char (*fallback_func_type)(...); + operator fallback_func_type() const; + }; + + template <typename R, typename Arg1, typename Arg2, typename Iterator> + struct legacy_connect_condition_helper<R (*)(Arg1, Arg2), Iterator> + { + R operator()(Arg1, Arg2) const; + char operator()(...) const; + }; + + template <typename T, typename Iterator> + struct is_legacy_connect_condition + { + static char asio_connect_condition_check(char); + static char (&asio_connect_condition_check(Iterator))[2]; + + static const bool value = + sizeof(asio_connect_condition_check( + (*static_cast<legacy_connect_condition_helper<T, Iterator>*>(0))( + *static_cast<const boost::system::error_code*>(0), + *static_cast<const Iterator*>(0)))) != 1; + }; + + template <typename ConnectCondition, typename Iterator> + inline Iterator call_connect_condition(ConnectCondition& connect_condition, + const boost::system::error_code& ec, Iterator next, Iterator end, + typename enable_if<is_legacy_connect_condition< + ConnectCondition, Iterator>::value>::type* = 0) + { + if (next != end) + return connect_condition(ec, next); + return end; + } + + template <typename ConnectCondition, typename Iterator> + inline Iterator call_connect_condition(ConnectCondition& connect_condition, + const boost::system::error_code& ec, Iterator next, Iterator end, + typename enable_if<!is_legacy_connect_condition< + ConnectCondition, Iterator>::value>::type* = 0) + { + for (;next != end; ++next) + if (connect_condition(ec, *next)) + return next; + return end; + } +} + +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename EndpointSequence> +typename Protocol::endpoint connect( + basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, + typename enable_if<is_endpoint_sequence< + EndpointSequence>::value>::type*) +{ + boost::system::error_code ec; + typename Protocol::endpoint result = connect(s, endpoints, ec); + boost::asio::detail::throw_error(ec, "connect"); + return result; } -template <typename Protocol, typename SocketService, typename Iterator> -Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin) +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename EndpointSequence> +typename Protocol::endpoint connect( + basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, boost::system::error_code& ec, + typename enable_if<is_endpoint_sequence< + EndpointSequence>::value>::type*) +{ + return detail::deref_connect_result<Protocol>( + connect(s, endpoints.begin(), endpoints.end(), + detail::default_connect_condition(), ec), ec); +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator> +Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, + typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) { boost::system::error_code ec; Iterator result = connect(s, begin, ec); @@ -50,15 +137,17 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin) return result; } -template <typename Protocol, typename SocketService, typename Iterator> -inline Iterator connect(basic_socket<Protocol, SocketService>& s, - Iterator begin, boost::system::error_code& ec) +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator> +inline Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + Iterator begin, boost::system::error_code& ec, + typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) { return connect(s, begin, Iterator(), detail::default_connect_condition(), ec); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) -template <typename Protocol, typename SocketService, typename Iterator> -Iterator connect(basic_socket<Protocol, SocketService>& s, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator> +Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, Iterator end) { boost::system::error_code ec; @@ -67,17 +156,48 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, return result; } -template <typename Protocol, typename SocketService, typename Iterator> -inline Iterator connect(basic_socket<Protocol, SocketService>& s, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator> +inline Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, Iterator end, boost::system::error_code& ec) { return connect(s, begin, end, detail::default_connect_condition(), ec); } -template <typename Protocol, typename SocketService, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition> +typename Protocol::endpoint connect( + basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + typename enable_if<is_endpoint_sequence< + EndpointSequence>::value>::type*) +{ + boost::system::error_code ec; + typename Protocol::endpoint result = connect( + s, endpoints, connect_condition, ec); + boost::asio::detail::throw_error(ec, "connect"); + return result; +} + +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition> +typename Protocol::endpoint connect( + basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + boost::system::error_code& ec, + typename enable_if<is_endpoint_sequence< + EndpointSequence>::value>::type*) +{ + return detail::deref_connect_result<Protocol>( + connect(s, endpoints.begin(), endpoints.end(), + connect_condition, ec), ec); +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol, SocketService>& s, - Iterator begin, ConnectCondition connect_condition) +Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + Iterator begin, ConnectCondition connect_condition, + typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) { boost::system::error_code ec; Iterator result = connect(s, begin, connect_condition, ec); @@ -85,18 +205,20 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, return result; } -template <typename Protocol, typename SocketService, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, typename ConnectCondition> -inline Iterator connect(basic_socket<Protocol, SocketService>& s, +inline Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, ConnectCondition connect_condition, - boost::system::error_code& ec) + boost::system::error_code& ec, + typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) { return connect(s, begin, Iterator(), connect_condition, ec); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) -template <typename Protocol, typename SocketService, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol, SocketService>& s, +Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, Iterator end, ConnectCondition connect_condition) { boost::system::error_code ec; @@ -105,9 +227,9 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, return result; } -template <typename Protocol, typename SocketService, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, typename ConnectCondition> -Iterator connect(basic_socket<Protocol, SocketService>& s, +Iterator connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, Iterator end, ConnectCondition connect_condition, boost::system::error_code& ec) { @@ -115,7 +237,7 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, for (Iterator iter = begin; iter != end; ++iter) { - iter = connect_condition(ec, iter); + iter = (detail::call_connect_condition(connect_condition, ec, iter, end)); if (iter != end) { s.close(ec); @@ -150,8 +272,7 @@ namespace detail void check_condition(const boost::system::error_code& ec, Iterator& iter, Iterator& end) { - if (iter != end) - iter = connect_condition_(ec, static_cast<const Iterator&>(iter)); + iter = detail::call_connect_condition(connect_condition_, ec, iter, end); } private: @@ -174,26 +295,186 @@ namespace detail } }; - template <typename Protocol, typename SocketService, typename Iterator, - typename ConnectCondition, typename ComposedConnectHandler> - class connect_op : base_from_connect_condition<ConnectCondition> + template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition, + typename RangeConnectHandler> + class range_connect_op : base_from_connect_condition<ConnectCondition> + { + public: + range_connect_op(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& sock, + const EndpointSequence& endpoints, + const ConnectCondition& connect_condition, + RangeConnectHandler& handler) + : base_from_connect_condition<ConnectCondition>(connect_condition), + socket_(sock), + endpoints_(endpoints), + index_(0), + start_(0), + handler_(BOOST_ASIO_MOVE_CAST(RangeConnectHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + range_connect_op(const range_connect_op& other) + : base_from_connect_condition<ConnectCondition>(other), + socket_(other.socket_), + endpoints_(other.endpoints_), + index_(other.index_), + start_(other.start_), + handler_(other.handler_) + { + } + + range_connect_op(range_connect_op&& other) + : base_from_connect_condition<ConnectCondition>(other), + socket_(other.socket_), + endpoints_(other.endpoints_), + index_(other.index_), + start_(other.start_), + handler_(BOOST_ASIO_MOVE_CAST(RangeConnectHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(boost::system::error_code ec, int start = 0) + { + typename EndpointSequence::const_iterator begin = endpoints_.begin(); + typename EndpointSequence::const_iterator iter = begin; + std::advance(iter, index_); + typename EndpointSequence::const_iterator end = endpoints_.end(); + + switch (start_ = start) + { + case 1: + for (;;) + { + this->check_condition(ec, iter, end); + index_ = std::distance(begin, iter); + + if (iter != end) + { + socket_.close(ec); + socket_.async_connect(*iter, + BOOST_ASIO_MOVE_CAST(range_connect_op)(*this)); + return; + } + + if (start) + { + ec = boost::asio::error::not_found; + boost::asio::post(socket_.get_executor(), + detail::bind_handler( + BOOST_ASIO_MOVE_CAST(range_connect_op)(*this), ec)); + return; + } + + default: + + if (iter == end) + break; + + if (!socket_.is_open()) + { + ec = boost::asio::error::operation_aborted; + break; + } + + if (!ec) + break; + + ++iter; + ++index_; + } + + handler_(static_cast<const boost::system::error_code&>(ec), + static_cast<const typename Protocol::endpoint&>( + ec || iter == end ? typename Protocol::endpoint() : *iter)); + } + } + + //private: + basic_socket<Protocol BOOST_ASIO_SVC_TARG>& socket_; + EndpointSequence endpoints_; + std::size_t index_; + int start_; + RangeConnectHandler handler_; + }; + + template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition, + typename RangeConnectHandler> + inline void* asio_handler_allocate(std::size_t size, + range_connect_op<Protocol BOOST_ASIO_SVC_TARG, EndpointSequence, + ConnectCondition, RangeConnectHandler>* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition, + typename RangeConnectHandler> + inline void asio_handler_deallocate(void* pointer, std::size_t size, + range_connect_op<Protocol BOOST_ASIO_SVC_TARG, EndpointSequence, + ConnectCondition, RangeConnectHandler>* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition, + typename RangeConnectHandler> + inline bool asio_handler_is_continuation( + range_connect_op<Protocol BOOST_ASIO_SVC_TARG, EndpointSequence, + ConnectCondition, RangeConnectHandler>* this_handler) + { + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template <typename Function, typename Protocol + BOOST_ASIO_SVC_TPARAM, typename EndpointSequence, + typename ConnectCondition, typename RangeConnectHandler> + inline void asio_handler_invoke(Function& function, + range_connect_op<Protocol BOOST_ASIO_SVC_TARG, EndpointSequence, + ConnectCondition, RangeConnectHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Function, typename Protocol + BOOST_ASIO_SVC_TPARAM, typename EndpointSequence, + typename ConnectCondition, typename RangeConnectHandler> + inline void asio_handler_invoke(const Function& function, + range_connect_op<Protocol BOOST_ASIO_SVC_TARG, EndpointSequence, + ConnectCondition, RangeConnectHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> + class iterator_connect_op : base_from_connect_condition<ConnectCondition> { public: - connect_op(basic_socket<Protocol, SocketService>& sock, + iterator_connect_op(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& sock, const Iterator& begin, const Iterator& end, const ConnectCondition& connect_condition, - ComposedConnectHandler& handler) + IteratorConnectHandler& handler) : base_from_connect_condition<ConnectCondition>(connect_condition), socket_(sock), iter_(begin), end_(end), start_(0), - handler_(BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(handler)) + handler_(BOOST_ASIO_MOVE_CAST(IteratorConnectHandler)(handler)) { } #if defined(BOOST_ASIO_HAS_MOVE) - connect_op(const connect_op& other) + iterator_connect_op(const iterator_connect_op& other) : base_from_connect_condition<ConnectCondition>(other), socket_(other.socket_), iter_(other.iter_), @@ -203,13 +484,13 @@ namespace detail { } - connect_op(connect_op&& other) + iterator_connect_op(iterator_connect_op&& other) : base_from_connect_condition<ConnectCondition>(other), socket_(other.socket_), iter_(other.iter_), end_(other.end_), start_(other.start_), - handler_(BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(other.handler_)) + handler_(BOOST_ASIO_MOVE_CAST(IteratorConnectHandler)(other.handler_)) { } #endif // defined(BOOST_ASIO_HAS_MOVE) @@ -227,14 +508,16 @@ namespace detail { socket_.close(ec); socket_.async_connect(*iter_, - BOOST_ASIO_MOVE_CAST(connect_op)(*this)); + BOOST_ASIO_MOVE_CAST(iterator_connect_op)(*this)); return; } if (start) { ec = boost::asio::error::not_found; - socket_.get_io_service().post(detail::bind_handler(*this, ec)); + boost::asio::post(socket_.get_executor(), + detail::bind_handler( + BOOST_ASIO_MOVE_CAST(iterator_connect_op)(*this), ec)); return; } @@ -261,164 +544,311 @@ namespace detail } //private: - basic_socket<Protocol, SocketService>& socket_; + basic_socket<Protocol BOOST_ASIO_SVC_TARG>& socket_; Iterator iter_; Iterator end_; int start_; - ComposedConnectHandler handler_; + IteratorConnectHandler handler_; }; - template <typename Protocol, typename SocketService, typename Iterator, - typename ConnectCondition, typename ComposedConnectHandler> + template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> inline void* asio_handler_allocate(std::size_t size, - connect_op<Protocol, SocketService, Iterator, - ConnectCondition, ComposedConnectHandler>* this_handler) + iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, + ConnectCondition, IteratorConnectHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename Protocol, typename SocketService, typename Iterator, - typename ConnectCondition, typename ComposedConnectHandler> + template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - connect_op<Protocol, SocketService, Iterator, - ConnectCondition, ComposedConnectHandler>* this_handler) + iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, + ConnectCondition, IteratorConnectHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename Protocol, typename SocketService, typename Iterator, - typename ConnectCondition, typename ComposedConnectHandler> + template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> inline bool asio_handler_is_continuation( - connect_op<Protocol, SocketService, Iterator, - ConnectCondition, ComposedConnectHandler>* this_handler) + iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, + ConnectCondition, IteratorConnectHandler>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename Protocol, - typename SocketService, typename Iterator, - typename ConnectCondition, typename ComposedConnectHandler> + template <typename Function, typename Protocol + BOOST_ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> inline void asio_handler_invoke(Function& function, - connect_op<Protocol, SocketService, Iterator, - ConnectCondition, ComposedConnectHandler>* this_handler) + iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, + ConnectCondition, IteratorConnectHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } - template <typename Function, typename Protocol, - typename SocketService, typename Iterator, - typename ConnectCondition, typename ComposedConnectHandler> + template <typename Function, typename Protocol + BOOST_ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> inline void asio_handler_invoke(const Function& function, - connect_op<Protocol, SocketService, Iterator, - ConnectCondition, ComposedConnectHandler>* this_handler) + iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, + ConnectCondition, IteratorConnectHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail -template <typename Protocol, typename SocketService, - typename Iterator, typename ComposedConnectHandler> -inline BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler, +#if !defined(GENERATING_DOCUMENTATION) + +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition, + typename RangeConnectHandler, typename Allocator> +struct associated_allocator< + detail::range_connect_op<Protocol BOOST_ASIO_SVC_TARG, + EndpointSequence, ConnectCondition, RangeConnectHandler>, + Allocator> +{ + typedef typename associated_allocator< + RangeConnectHandler, Allocator>::type type; + + static type get( + const detail::range_connect_op<Protocol BOOST_ASIO_SVC_TARG, + EndpointSequence, ConnectCondition, RangeConnectHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<RangeConnectHandler, + Allocator>::get(h.handler_, a); + } +}; + +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename EndpointSequence, typename ConnectCondition, + typename RangeConnectHandler, typename Executor> +struct associated_executor< + detail::range_connect_op<Protocol BOOST_ASIO_SVC_TARG, + EndpointSequence, ConnectCondition, RangeConnectHandler>, + Executor> +{ + typedef typename associated_executor< + RangeConnectHandler, Executor>::type type; + + static type get( + const detail::range_connect_op<Protocol BOOST_ASIO_SVC_TARG, + EndpointSequence, ConnectCondition, RangeConnectHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<RangeConnectHandler, + Executor>::get(h.handler_, ex); + } +}; + +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename Iterator, typename ConnectCondition, + typename IteratorConnectHandler, typename Allocator> +struct associated_allocator< + detail::iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, + ConnectCondition, IteratorConnectHandler>, + Allocator> +{ + typedef typename associated_allocator< + IteratorConnectHandler, Allocator>::type type; + + static type get( + const detail::iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, + Iterator, ConnectCondition, IteratorConnectHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<IteratorConnectHandler, + Allocator>::get(h.handler_, a); + } +}; + +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename Iterator, typename ConnectCondition, + typename IteratorConnectHandler, typename Executor> +struct associated_executor< + detail::iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, + ConnectCondition, IteratorConnectHandler>, + Executor> +{ + typedef typename associated_executor< + IteratorConnectHandler, Executor>::type type; + + static type get( + const detail::iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, + Iterator, ConnectCondition, IteratorConnectHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<IteratorConnectHandler, + Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename EndpointSequence, typename RangeConnectHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, + void (boost::system::error_code, typename Protocol::endpoint)) +async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, + BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, + typename enable_if<is_endpoint_sequence< + EndpointSequence>::value>::type*) +{ + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a RangeConnectHandler. + BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK( + RangeConnectHandler, handler, typename Protocol::endpoint) type_check; + + async_completion<RangeConnectHandler, + void (boost::system::error_code, typename Protocol::endpoint)> + init(handler); + + detail::range_connect_op<Protocol BOOST_ASIO_SVC_TARG, EndpointSequence, + detail::default_connect_condition, + BOOST_ASIO_HANDLER_TYPE(RangeConnectHandler, + void (boost::system::error_code, typename Protocol::endpoint))>(s, + endpoints, detail::default_connect_condition(), + init.completion_handler)(boost::system::error_code(), 1); + + return init.result.get(); +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename Iterator, typename IteratorConnectHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) -async_connect(basic_socket<Protocol, SocketService>& s, - Iterator begin, BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler) +async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + Iterator begin, BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, + typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) { // 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; + // not meet the documented type requirements for a IteratorConnectHandler. + BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( + IteratorConnectHandler, handler, Iterator) type_check; - detail::async_result_init<ComposedConnectHandler, - void (boost::system::error_code, Iterator)> init( - BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(handler)); + async_completion<IteratorConnectHandler, + void (boost::system::error_code, Iterator)> init(handler); - detail::connect_op<Protocol, SocketService, Iterator, + detail::iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, detail::default_connect_condition, BOOST_ASIO_HANDLER_TYPE( - ComposedConnectHandler, void (boost::system::error_code, Iterator))>(s, - begin, Iterator(), detail::default_connect_condition(), init.handler)( - boost::system::error_code(), 1); + IteratorConnectHandler, void (boost::system::error_code, Iterator))>(s, + begin, Iterator(), detail::default_connect_condition(), + init.completion_handler)(boost::system::error_code(), 1); return init.result.get(); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) -template <typename Protocol, typename SocketService, - typename Iterator, typename ComposedConnectHandler> -inline BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, + typename Iterator, typename IteratorConnectHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) -async_connect(basic_socket<Protocol, SocketService>& s, +async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, Iterator end, - BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler) + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) 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; + // not meet the documented type requirements for a IteratorConnectHandler. + BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( + IteratorConnectHandler, handler, Iterator) type_check; - detail::async_result_init<ComposedConnectHandler, - void (boost::system::error_code, Iterator)> init( - BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(handler)); + async_completion<IteratorConnectHandler, + void (boost::system::error_code, Iterator)> init(handler); - detail::connect_op<Protocol, SocketService, Iterator, + detail::iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, detail::default_connect_condition, BOOST_ASIO_HANDLER_TYPE( - ComposedConnectHandler, void (boost::system::error_code, Iterator))>(s, - begin, end, detail::default_connect_condition(), init.handler)( + IteratorConnectHandler, void (boost::system::error_code, Iterator))>(s, + begin, end, detail::default_connect_condition(), + init.completion_handler)(boost::system::error_code(), 1); + + return init.result.get(); +} + +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename EndpointSequence, + typename ConnectCondition, typename RangeConnectHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, + void (boost::system::error_code, typename Protocol::endpoint)) +async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, + typename enable_if<is_endpoint_sequence< + EndpointSequence>::value>::type*) +{ + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a RangeConnectHandler. + BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK( + RangeConnectHandler, handler, typename Protocol::endpoint) type_check; + + async_completion<RangeConnectHandler, + void (boost::system::error_code, typename Protocol::endpoint)> + init(handler); + + detail::range_connect_op<Protocol BOOST_ASIO_SVC_TARG, EndpointSequence, + ConnectCondition, BOOST_ASIO_HANDLER_TYPE(RangeConnectHandler, + void (boost::system::error_code, typename Protocol::endpoint))>(s, + endpoints, connect_condition, init.completion_handler)( boost::system::error_code(), 1); return init.result.get(); } -template <typename Protocol, typename SocketService, typename Iterator, - typename ConnectCondition, typename ComposedConnectHandler> -inline BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler, +#if !defined(BOOST_ASIO_NO_DEPRECATED) +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) -async_connect(basic_socket<Protocol, SocketService>& s, +async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, ConnectCondition connect_condition, - BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler) + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, + typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) { // 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; + // not meet the documented type requirements for a IteratorConnectHandler. + BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( + IteratorConnectHandler, handler, Iterator) type_check; - detail::async_result_init<ComposedConnectHandler, - void (boost::system::error_code, Iterator)> init( - BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(handler)); + async_completion<IteratorConnectHandler, + void (boost::system::error_code, Iterator)> init(handler); - detail::connect_op<Protocol, SocketService, Iterator, + detail::iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, ConnectCondition, BOOST_ASIO_HANDLER_TYPE( - ComposedConnectHandler, void (boost::system::error_code, Iterator))>(s, - begin, Iterator(), connect_condition, init.handler)( + IteratorConnectHandler, void (boost::system::error_code, Iterator))>(s, + begin, Iterator(), connect_condition, init.completion_handler)( boost::system::error_code(), 1); return init.result.get(); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) -template <typename Protocol, typename SocketService, typename Iterator, - typename ConnectCondition, typename ComposedConnectHandler> -inline BOOST_ASIO_INITFN_RESULT_TYPE(ComposedConnectHandler, +template <typename Protocol BOOST_ASIO_SVC_TPARAM, typename Iterator, + typename ConnectCondition, typename IteratorConnectHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) -async_connect(basic_socket<Protocol, SocketService>& s, +async_connect(basic_socket<Protocol BOOST_ASIO_SVC_TARG>& s, Iterator begin, Iterator end, ConnectCondition connect_condition, - BOOST_ASIO_MOVE_ARG(ComposedConnectHandler) handler) + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) 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; + // not meet the documented type requirements for a IteratorConnectHandler. + BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( + IteratorConnectHandler, handler, Iterator) type_check; - detail::async_result_init<ComposedConnectHandler, - void (boost::system::error_code, Iterator)> init( - BOOST_ASIO_MOVE_CAST(ComposedConnectHandler)(handler)); + async_completion<IteratorConnectHandler, + void (boost::system::error_code, Iterator)> init(handler); - detail::connect_op<Protocol, SocketService, Iterator, + detail::iterator_connect_op<Protocol BOOST_ASIO_SVC_TARG, Iterator, ConnectCondition, BOOST_ASIO_HANDLER_TYPE( - ComposedConnectHandler, void (boost::system::error_code, Iterator))>(s, - begin, end, connect_condition, init.handler)( + IteratorConnectHandler, void (boost::system::error_code, Iterator))>(s, + begin, end, connect_condition, init.completion_handler)( boost::system::error_code(), 1); return init.result.get(); diff --git a/boost/asio/impl/defer.hpp b/boost/asio/impl/defer.hpp new file mode 100644 index 0000000000..afc29f965b --- /dev/null +++ b/boost/asio/impl/defer.hpp @@ -0,0 +1,79 @@ +// +// impl/defer.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IMPL_DEFER_HPP +#define BOOST_ASIO_IMPL_DEFER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/associated_executor.hpp> +#include <boost/asio/detail/work_dispatcher.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( + BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef BOOST_ASIO_HANDLER_TYPE(CompletionToken, void()) handler; + + async_completion<CompletionToken, void()> init(token); + + typename associated_executor<handler>::type ex( + (get_associated_executor)(init.completion_handler)); + + typename associated_allocator<handler>::type alloc( + (get_associated_allocator)(init.completion_handler)); + + ex.defer(BOOST_ASIO_MOVE_CAST(handler)(init.completion_handler), alloc); + + return init.result.get(); +} + +template <typename Executor, typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( + const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_executor<Executor>::value>::type*) +{ + typedef BOOST_ASIO_HANDLER_TYPE(CompletionToken, void()) handler; + + async_completion<CompletionToken, void()> init(token); + + typename associated_allocator<handler>::type alloc( + (get_associated_allocator)(init.completion_handler)); + + ex.defer(detail::work_dispatcher<handler>(init.completion_handler), alloc); + + return init.result.get(); +} + +template <typename ExecutionContext, typename CompletionToken> +inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( + ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_convertible< + ExecutionContext&, execution_context&>::value>::type*) +{ + return (defer)(ctx.get_executor(), + BOOST_ASIO_MOVE_CAST(CompletionToken)(token)); +} + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_DEFER_HPP diff --git a/boost/asio/impl/dispatch.hpp b/boost/asio/impl/dispatch.hpp new file mode 100644 index 0000000000..5589b375e3 --- /dev/null +++ b/boost/asio/impl/dispatch.hpp @@ -0,0 +1,80 @@ +// +// impl/dispatch.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IMPL_DISPATCH_HPP +#define BOOST_ASIO_IMPL_DISPATCH_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/associated_executor.hpp> +#include <boost/asio/detail/work_dispatcher.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( + BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef BOOST_ASIO_HANDLER_TYPE(CompletionToken, void()) handler; + + async_completion<CompletionToken, void()> init(token); + + typename associated_executor<handler>::type ex( + (get_associated_executor)(init.completion_handler)); + + typename associated_allocator<handler>::type alloc( + (get_associated_allocator)(init.completion_handler)); + + ex.dispatch(BOOST_ASIO_MOVE_CAST(handler)(init.completion_handler), alloc); + + return init.result.get(); +} + +template <typename Executor, typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( + const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_executor<Executor>::value>::type*) +{ + typedef BOOST_ASIO_HANDLER_TYPE(CompletionToken, void()) handler; + + async_completion<CompletionToken, void()> init(token); + + typename associated_allocator<handler>::type alloc( + (get_associated_allocator)(init.completion_handler)); + + ex.dispatch(detail::work_dispatcher<handler>( + init.completion_handler), alloc); + + return init.result.get(); +} + +template <typename ExecutionContext, typename CompletionToken> +inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( + ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_convertible< + ExecutionContext&, execution_context&>::value>::type*) +{ + return (dispatch)(ctx.get_executor(), + BOOST_ASIO_MOVE_CAST(CompletionToken)(token)); +} + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_DISPATCH_HPP diff --git a/boost/asio/impl/execution_context.hpp b/boost/asio/impl/execution_context.hpp new file mode 100644 index 0000000000..86acfc2d6e --- /dev/null +++ b/boost/asio/impl/execution_context.hpp @@ -0,0 +1,109 @@ +// +// impl/execution_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IMPL_EXECUTION_CONTEXT_HPP +#define BOOST_ASIO_IMPL_EXECUTION_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/handler_type_requirements.hpp> +#include <boost/asio/detail/scoped_ptr.hpp> +#include <boost/asio/detail/service_registry.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +template <typename Service> +inline Service& use_service(execution_context& e) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast<execution_context::service*>(static_cast<Service*>(0)); + + return e.service_registry_->template use_service<Service>(); +} + +#if !defined(GENERATING_DOCUMENTATION) +# if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename Service, typename... Args> +Service& make_service(execution_context& e, BOOST_ASIO_MOVE_ARG(Args)... args) +{ + detail::scoped_ptr<Service> svc( + new Service(e, BOOST_ASIO_MOVE_CAST(Args)(args)...)); + e.service_registry_->template add_service<Service>(svc.get()); + Service& result = *svc; + svc.release(); + return result; +} + +# else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename Service> +Service& make_service(execution_context& e) +{ + detail::scoped_ptr<Service> svc(new Service(e)); + e.service_registry_->template add_service<Service>(svc.get()); + Service& result = *svc; + svc.release(); + return result; +} + +#define BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF(n) \ + template <typename Service, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + Service& make_service(execution_context& e, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + detail::scoped_ptr<Service> svc( \ + new Service(e, BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ + e.service_registry_->template add_service<Service>(svc.get()); \ + Service& result = *svc; \ + svc.release(); \ + return result; \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF) +#undef BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF + +# endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename Service> +inline void add_service(execution_context& e, Service* svc) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast<execution_context::service*>(static_cast<Service*>(0)); + + e.service_registry_->template add_service<Service>(svc); +} + +template <typename Service> +inline bool has_service(execution_context& e) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast<execution_context::service*>(static_cast<Service*>(0)); + + return e.service_registry_->template has_service<Service>(); +} + +inline execution_context& execution_context::service::context() +{ + return owner_; +} + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_EXECUTION_CONTEXT_HPP diff --git a/boost/asio/impl/execution_context.ipp b/boost/asio/impl/execution_context.ipp new file mode 100644 index 0000000000..01e92f6604 --- /dev/null +++ b/boost/asio/impl/execution_context.ipp @@ -0,0 +1,84 @@ +// +// impl/execution_context.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IMPL_EXECUTION_CONTEXT_IPP +#define BOOST_ASIO_IMPL_EXECUTION_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/execution_context.hpp> +#include <boost/asio/detail/service_registry.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +execution_context::execution_context() + : service_registry_(new boost::asio::detail::service_registry(*this)) +{ +} + +execution_context::~execution_context() +{ + shutdown(); + destroy(); + delete service_registry_; +} + +void execution_context::shutdown() +{ + service_registry_->shutdown_services(); +} + +void execution_context::destroy() +{ + service_registry_->destroy_services(); +} + +void execution_context::notify_fork( + boost::asio::execution_context::fork_event event) +{ + service_registry_->notify_fork(event); +} + +execution_context::service::service(execution_context& owner) + : owner_(owner), + next_(0) +{ +} + +execution_context::service::~service() +{ +} + +void execution_context::service::notify_fork(execution_context::fork_event) +{ +} + +service_already_exists::service_already_exists() + : std::logic_error("Service already exists.") +{ +} + +invalid_service_owner::invalid_service_owner() + : std::logic_error("Invalid service owner.") +{ +} + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_EXECUTION_CONTEXT_IPP diff --git a/boost/asio/impl/executor.hpp b/boost/asio/impl/executor.hpp new file mode 100644 index 0000000000..e97a7d57c9 --- /dev/null +++ b/boost/asio/impl/executor.hpp @@ -0,0 +1,388 @@ +// +// impl/executor.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IMPL_EXECUTOR_HPP +#define BOOST_ASIO_IMPL_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/atomic_count.hpp> +#include <boost/asio/detail/executor_op.hpp> +#include <boost/asio/detail/global.hpp> +#include <boost/asio/detail/memory.hpp> +#include <boost/asio/detail/recycling_allocator.hpp> +#include <boost/asio/executor.hpp> +#include <boost/asio/system_executor.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +#if !defined(GENERATING_DOCUMENTATION) + +#if defined(BOOST_ASIO_HAS_MOVE) + +// Lightweight, move-only function object wrapper. +class executor::function +{ +public: + template <typename F, typename Alloc> + explicit function(F f, const Alloc& a) + { + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<F, Alloc> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + op_ = new (p.v) op(BOOST_ASIO_MOVE_CAST(F)(f), a); + p.v = 0; + } + + function(function&& other) + : op_(other.op_) + { + other.op_ = 0; + } + + ~function() + { + if (op_) + op_->destroy(); + } + + void operator()() + { + if (op_) + { + detail::scheduler_operation* op = op_; + op_ = 0; + op->complete(this, boost::system::error_code(), 0); + } + } + +private: + detail::scheduler_operation* op_; +}; + +#else // defined(BOOST_ASIO_HAS_MOVE) + +// Not so lightweight, copyable function object wrapper. +class executor::function +{ +public: + template <typename F, typename Alloc> + explicit function(const F& f, const Alloc&) + : impl_(new impl<F>(f)) + { + } + + void operator()() + { + impl_->invoke_(impl_.get()); + } + +private: + // Base class for polymorphic function implementations. + struct impl_base + { + void (*invoke_)(impl_base*); + }; + + // Polymorphic function implementation. + template <typename F> + struct impl : impl_base + { + impl(const F& f) + : function_(f) + { + invoke_ = &function::invoke<F>; + } + + F function_; + }; + + // Helper to invoke a function. + template <typename F> + static void invoke(impl_base* i) + { + static_cast<impl<F>*>(i)->function_(); + } + + detail::shared_ptr<impl_base> impl_; +}; + +#endif // defined(BOOST_ASIO_HAS_MOVE) + +// Default polymorphic allocator implementation. +template <typename Executor, typename Allocator> +class executor::impl + : public executor::impl_base +{ +public: + typedef BOOST_ASIO_REBIND_ALLOC(Allocator, impl) allocator_type; + + static impl_base* create(const Executor& e, Allocator a = Allocator()) + { + raw_mem mem(a); + impl* p = new (mem.ptr_) impl(e, a); + mem.ptr_ = 0; + return p; + } + + impl(const Executor& e, const Allocator& a) BOOST_ASIO_NOEXCEPT + : impl_base(false), + ref_count_(1), + executor_(e), + allocator_(a) + { + } + + impl_base* clone() const BOOST_ASIO_NOEXCEPT + { + ++ref_count_; + return const_cast<impl_base*>(static_cast<const impl_base*>(this)); + } + + void destroy() BOOST_ASIO_NOEXCEPT + { + if (--ref_count_ == 0) + { + allocator_type alloc(allocator_); + impl* p = this; + p->~impl(); + alloc.deallocate(p, 1); + } + } + + void on_work_started() BOOST_ASIO_NOEXCEPT + { + executor_.on_work_started(); + } + + void on_work_finished() BOOST_ASIO_NOEXCEPT + { + executor_.on_work_finished(); + } + + execution_context& context() BOOST_ASIO_NOEXCEPT + { + return executor_.context(); + } + + void dispatch(BOOST_ASIO_MOVE_ARG(function) f) + { + executor_.dispatch(BOOST_ASIO_MOVE_CAST(function)(f), allocator_); + } + + void post(BOOST_ASIO_MOVE_ARG(function) f) + { + executor_.post(BOOST_ASIO_MOVE_CAST(function)(f), allocator_); + } + + void defer(BOOST_ASIO_MOVE_ARG(function) f) + { + executor_.defer(BOOST_ASIO_MOVE_CAST(function)(f), allocator_); + } + + type_id_result_type target_type() const BOOST_ASIO_NOEXCEPT + { + return type_id<Executor>(); + } + + void* target() BOOST_ASIO_NOEXCEPT + { + return &executor_; + } + + const void* target() const BOOST_ASIO_NOEXCEPT + { + return &executor_; + } + + bool equals(const impl_base* e) const BOOST_ASIO_NOEXCEPT + { + if (this == e) + return true; + if (target_type() != e->target_type()) + return false; + return executor_ == *static_cast<const Executor*>(e->target()); + } + +private: + mutable detail::atomic_count ref_count_; + Executor executor_; + Allocator allocator_; + + struct raw_mem + { + allocator_type allocator_; + impl* ptr_; + + explicit raw_mem(const Allocator& a) + : allocator_(a), + ptr_(allocator_.allocate(1)) + { + } + + ~raw_mem() + { + if (ptr_) + allocator_.deallocate(ptr_, 1); + } + + private: + // Disallow copying and assignment. + raw_mem(const raw_mem&); + raw_mem operator=(const raw_mem&); + }; +}; + +// Polymorphic allocator specialisation for system_executor. +template <typename Allocator> +class executor::impl<system_executor, Allocator> + : public executor::impl_base +{ +public: + static impl_base* create(const system_executor&, + const Allocator& = Allocator()) + { + return &detail::global<impl<system_executor, std::allocator<void> > >(); + } + + impl() + : impl_base(true) + { + } + + impl_base* clone() const BOOST_ASIO_NOEXCEPT + { + return const_cast<impl_base*>(static_cast<const impl_base*>(this)); + } + + void destroy() BOOST_ASIO_NOEXCEPT + { + } + + void on_work_started() BOOST_ASIO_NOEXCEPT + { + executor_.on_work_started(); + } + + void on_work_finished() BOOST_ASIO_NOEXCEPT + { + executor_.on_work_finished(); + } + + execution_context& context() BOOST_ASIO_NOEXCEPT + { + return executor_.context(); + } + + void dispatch(BOOST_ASIO_MOVE_ARG(function) f) + { + executor_.dispatch(BOOST_ASIO_MOVE_CAST(function)(f), allocator_); + } + + void post(BOOST_ASIO_MOVE_ARG(function) f) + { + executor_.post(BOOST_ASIO_MOVE_CAST(function)(f), allocator_); + } + + void defer(BOOST_ASIO_MOVE_ARG(function) f) + { + executor_.defer(BOOST_ASIO_MOVE_CAST(function)(f), allocator_); + } + + type_id_result_type target_type() const BOOST_ASIO_NOEXCEPT + { + return type_id<system_executor>(); + } + + void* target() BOOST_ASIO_NOEXCEPT + { + return &executor_; + } + + const void* target() const BOOST_ASIO_NOEXCEPT + { + return &executor_; + } + + bool equals(const impl_base* e) const BOOST_ASIO_NOEXCEPT + { + return this == e; + } + +private: + system_executor executor_; + Allocator allocator_; +}; + +template <typename Executor> +executor::executor(Executor e) + : impl_(impl<Executor, std::allocator<void> >::create(e)) +{ +} + +template <typename Executor, typename Allocator> +executor::executor(allocator_arg_t, const Allocator& a, Executor e) + : impl_(impl<Executor, Allocator>::create(e, a)) +{ +} + +template <typename Function, typename Allocator> +void executor::dispatch(BOOST_ASIO_MOVE_ARG(Function) f, + const Allocator& a) const +{ + impl_base* i = get_impl(); + if (i->fast_dispatch_) + system_executor().dispatch(BOOST_ASIO_MOVE_CAST(Function)(f), a); + else + i->dispatch(function(BOOST_ASIO_MOVE_CAST(Function)(f), a)); +} + +template <typename Function, typename Allocator> +void executor::post(BOOST_ASIO_MOVE_ARG(Function) f, + const Allocator& a) const +{ + get_impl()->post(function(BOOST_ASIO_MOVE_CAST(Function)(f), a)); +} + +template <typename Function, typename Allocator> +void executor::defer(BOOST_ASIO_MOVE_ARG(Function) f, + const Allocator& a) const +{ + get_impl()->defer(function(BOOST_ASIO_MOVE_CAST(Function)(f), a)); +} + +template <typename Executor> +Executor* executor::target() BOOST_ASIO_NOEXCEPT +{ + return impl_ && impl_->target_type() == type_id<Executor>() + ? static_cast<Executor*>(impl_->target()) : 0; +} + +template <typename Executor> +const Executor* executor::target() const BOOST_ASIO_NOEXCEPT +{ + return impl_ && impl_->target_type() == type_id<Executor>() + ? static_cast<Executor*>(impl_->target()) : 0; +} + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_EXECUTOR_HPP diff --git a/boost/asio/ssl/basic_context.hpp b/boost/asio/impl/executor.ipp index 734398bc29..dbedbc6cf0 100644 --- a/boost/asio/ssl/basic_context.hpp +++ b/boost/asio/impl/executor.ipp @@ -1,6 +1,6 @@ // -// ssl/basic_context.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// impl/executor.ipp +// ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,35 +8,33 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_SSL_BASIC_CONTEXT_HPP -#define BOOST_ASIO_SSL_BASIC_CONTEXT_HPP +#ifndef BOOST_ASIO_IMPL_EXECUTOR_IPP +#define BOOST_ASIO_IMPL_EXECUTOR_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> - -#if defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/ssl/old/basic_context.hpp> -#endif // defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <boost/asio/executor.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { -namespace ssl { - -#if defined(BOOST_ASIO_ENABLE_OLD_SSL) -using boost::asio::ssl::old::basic_context; +bad_executor::bad_executor() BOOST_ASIO_NOEXCEPT +{ +} -#endif // defined(BOOST_ASIO_ENABLE_OLD_SSL) +const char* bad_executor::what() const BOOST_ASIO_NOEXCEPT_OR_NOTHROW +{ + return "bad executor"; +} -} // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> -#endif // BOOST_ASIO_SSL_BASIC_CONTEXT_HPP +#endif // BOOST_ASIO_IMPL_EXECUTOR_IPP diff --git a/boost/asio/impl/handler_alloc_hook.ipp b/boost/asio/impl/handler_alloc_hook.ipp index ddc84c75cf..d3e82e8bc2 100644 --- a/boost/asio/impl/handler_alloc_hook.ipp +++ b/boost/asio/impl/handler_alloc_hook.ipp @@ -16,38 +16,20 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/detail/call_stack.hpp> +#include <boost/asio/detail/thread_context.hpp> +#include <boost/asio/detail/thread_info_base.hpp> #include <boost/asio/handler_alloc_hook.hpp> -#if !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) -# if defined(BOOST_ASIO_HAS_IOCP) -# include <boost/asio/detail/win_iocp_thread_info.hpp> -# else // defined(BOOST_ASIO_HAS_IOCP) -# include <boost/asio/detail/task_io_service_thread_info.hpp> -# endif // defined(BOOST_ASIO_HAS_IOCP) -#endif // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) - #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { -#if defined(BOOST_ASIO_HAS_IOCP) -namespace detail { class win_iocp_io_service; } -#endif // defined(BOOST_ASIO_HAS_IOCP) - void* asio_handler_allocate(std::size_t size, ...) { #if !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) -# if defined(BOOST_ASIO_HAS_IOCP) - typedef detail::win_iocp_io_service io_service_impl; - typedef detail::win_iocp_thread_info thread_info; -# else // defined(BOOST_ASIO_HAS_IOCP) - typedef detail::task_io_service io_service_impl; - typedef detail::task_io_service_thread_info thread_info; -# endif // defined(BOOST_ASIO_HAS_IOCP) - typedef detail::call_stack<io_service_impl, thread_info> call_stack; - return thread_info::allocate(call_stack::top(), size); + return detail::thread_info_base::allocate( + detail::thread_context::thread_call_stack::top(), size); #else // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) return ::operator new(size); #endif // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) @@ -56,15 +38,8 @@ void* asio_handler_allocate(std::size_t size, ...) void asio_handler_deallocate(void* pointer, std::size_t size, ...) { #if !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) -# if defined(BOOST_ASIO_HAS_IOCP) - typedef detail::win_iocp_io_service io_service_impl; - typedef detail::win_iocp_thread_info thread_info; -# else // defined(BOOST_ASIO_HAS_IOCP) - typedef detail::task_io_service io_service_impl; - typedef detail::task_io_service_thread_info thread_info; -# endif // defined(BOOST_ASIO_HAS_IOCP) - typedef detail::call_stack<io_service_impl, thread_info> call_stack; - thread_info::deallocate(call_stack::top(), pointer, size); + detail::thread_info_base::deallocate( + detail::thread_context::thread_call_stack::top(), pointer, size); #else // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) (void)size; ::operator delete(pointer); diff --git a/boost/asio/impl/io_context.hpp b/boost/asio/impl/io_context.hpp new file mode 100644 index 0000000000..93e719ed80 --- /dev/null +++ b/boost/asio/impl/io_context.hpp @@ -0,0 +1,345 @@ +// +// impl/io_context.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IMPL_IO_CONTEXT_HPP +#define BOOST_ASIO_IMPL_IO_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/completion_handler.hpp> +#include <boost/asio/detail/executor_op.hpp> +#include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/handler_type_requirements.hpp> +#include <boost/asio/detail/recycling_allocator.hpp> +#include <boost/asio/detail/service_registry.hpp> +#include <boost/asio/detail/throw_error.hpp> +#include <boost/asio/detail/type_traits.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +template <typename Service> +inline Service& use_service(io_context& ioc) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast<execution_context::service*>(static_cast<Service*>(0)); + (void)static_cast<const execution_context::id*>(&Service::id); + + return ioc.service_registry_->template use_service<Service>(ioc); +} + +template <> +inline detail::io_context_impl& use_service<detail::io_context_impl>( + io_context& ioc) +{ + return ioc.impl_; +} + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#if defined(BOOST_ASIO_HAS_IOCP) +# include <boost/asio/detail/win_iocp_io_context.hpp> +#else +# include <boost/asio/detail/scheduler.hpp> +#endif + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +inline io_context::executor_type +io_context::get_executor() BOOST_ASIO_NOEXCEPT +{ + return executor_type(*this); +} + +#if defined(BOOST_ASIO_HAS_CHRONO) + +template <typename Rep, typename Period> +std::size_t io_context::run_for( + const chrono::duration<Rep, Period>& rel_time) +{ + return this->run_until(chrono::steady_clock::now() + rel_time); +} + +template <typename Clock, typename Duration> +std::size_t io_context::run_until( + const chrono::time_point<Clock, Duration>& abs_time) +{ + std::size_t n = 0; + while (this->run_one_until(abs_time)) + if (n != (std::numeric_limits<std::size_t>::max)()) + ++n; + return n; +} + +template <typename Rep, typename Period> +std::size_t io_context::run_one_for( + const chrono::duration<Rep, Period>& rel_time) +{ + return this->run_one_until(chrono::steady_clock::now() + rel_time); +} + +template <typename Clock, typename Duration> +std::size_t io_context::run_one_until( + const chrono::time_point<Clock, Duration>& abs_time) +{ + typename Clock::time_point now = Clock::now(); + while (now < abs_time) + { + typename Clock::duration rel_time = abs_time - now; + if (rel_time > chrono::seconds(1)) + rel_time = chrono::seconds(1); + + boost::system::error_code ec; + std::size_t s = impl_.wait_one( + static_cast<long>(chrono::duration_cast< + chrono::microseconds>(rel_time).count()), ec); + boost::asio::detail::throw_error(ec); + + if (s || impl_.stopped()) + return s; + + now = Clock::now(); + } + + return 0; +} + +#endif // defined(BOOST_ASIO_HAS_CHRONO) + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +inline void io_context::reset() +{ + restart(); +} + +template <typename CompletionHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) +io_context::dispatch(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) +{ + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a CompletionHandler. + BOOST_ASIO_COMPLETION_HANDLER_CHECK(CompletionHandler, handler) type_check; + + async_completion<CompletionHandler, void ()> init(handler); + + if (impl_.can_dispatch()) + { + detail::fenced_block b(detail::fenced_block::full); + boost_asio_handler_invoke_helpers::invoke( + init.completion_handler, init.completion_handler); + } + else + { + // Allocate and construct an operation to wrap the handler. + typedef detail::completion_handler< + typename handler_type<CompletionHandler, void ()>::type> op; + typename op::ptr p = { detail::addressof(init.completion_handler), + op::ptr::allocate(init.completion_handler), 0 }; + p.p = new (p.v) op(init.completion_handler); + + BOOST_ASIO_HANDLER_CREATION((*this, *p.p, + "io_context", this, 0, "dispatch")); + + impl_.do_dispatch(p.p); + p.v = p.p = 0; + } + + return init.result.get(); +} + +template <typename CompletionHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) +io_context::post(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) +{ + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a CompletionHandler. + BOOST_ASIO_COMPLETION_HANDLER_CHECK(CompletionHandler, handler) type_check; + + async_completion<CompletionHandler, void ()> init(handler); + + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(init.completion_handler); + + // Allocate and construct an operation to wrap the handler. + typedef detail::completion_handler< + typename handler_type<CompletionHandler, void ()>::type> op; + typename op::ptr p = { detail::addressof(init.completion_handler), + op::ptr::allocate(init.completion_handler), 0 }; + p.p = new (p.v) op(init.completion_handler); + + BOOST_ASIO_HANDLER_CREATION((*this, *p.p, + "io_context", this, 0, "post")); + + impl_.post_immediate_completion(p.p, is_continuation); + p.v = p.p = 0; + + return init.result.get(); +} + +template <typename Handler> +#if defined(GENERATING_DOCUMENTATION) +unspecified +#else +inline detail::wrapped_handler<io_context&, Handler> +#endif +io_context::wrap(Handler handler) +{ + return detail::wrapped_handler<io_context&, Handler>(*this, handler); +} + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +inline io_context& +io_context::executor_type::context() const BOOST_ASIO_NOEXCEPT +{ + return io_context_; +} + +inline void +io_context::executor_type::on_work_started() const BOOST_ASIO_NOEXCEPT +{ + io_context_.impl_.work_started(); +} + +inline void +io_context::executor_type::on_work_finished() const BOOST_ASIO_NOEXCEPT +{ + io_context_.impl_.work_finished(); +} + +template <typename Function, typename Allocator> +void io_context::executor_type::dispatch( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay<Function>::type function_type; + + // Invoke immediately if we are already inside the thread pool. + if (io_context_.impl_.can_dispatch()) + { + // Make a local, non-const copy of the function. + function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); + + detail::fenced_block b(detail::fenced_block::full); + boost_asio_handler_invoke_helpers::invoke(tmp, tmp); + return; + } + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, Allocator, detail::operation> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); + + BOOST_ASIO_HANDLER_CREATION((this->context(), *p.p, + "io_context", &this->context(), 0, "post")); + + io_context_.impl_.post_immediate_completion(p.p, false); + p.v = p.p = 0; +} + +template <typename Function, typename Allocator> +void io_context::executor_type::post( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay<Function>::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, Allocator, detail::operation> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); + + BOOST_ASIO_HANDLER_CREATION((this->context(), *p.p, + "io_context", &this->context(), 0, "post")); + + io_context_.impl_.post_immediate_completion(p.p, false); + p.v = p.p = 0; +} + +template <typename Function, typename Allocator> +void io_context::executor_type::defer( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay<Function>::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, Allocator, detail::operation> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); + + BOOST_ASIO_HANDLER_CREATION((this->context(), *p.p, + "io_context", &this->context(), 0, "defer")); + + io_context_.impl_.post_immediate_completion(p.p, true); + p.v = p.p = 0; +} + +inline bool +io_context::executor_type::running_in_this_thread() const BOOST_ASIO_NOEXCEPT +{ + return io_context_.impl_.can_dispatch(); +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +inline io_context::work::work(boost::asio::io_context& io_context) + : io_context_impl_(io_context.impl_) +{ + io_context_impl_.work_started(); +} + +inline io_context::work::work(const work& other) + : io_context_impl_(other.io_context_impl_) +{ + io_context_impl_.work_started(); +} + +inline io_context::work::~work() +{ + io_context_impl_.work_finished(); +} + +inline boost::asio::io_context& io_context::work::get_io_context() +{ + return static_cast<boost::asio::io_context&>(io_context_impl_.context()); +} + +inline boost::asio::io_context& io_context::work::get_io_service() +{ + return static_cast<boost::asio::io_context&>(io_context_impl_.context()); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +inline boost::asio::io_context& io_context::service::get_io_context() +{ + return static_cast<boost::asio::io_context&>(context()); +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +inline boost::asio::io_context& io_context::service::get_io_service() +{ + return static_cast<boost::asio::io_context&>(context()); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_IO_CONTEXT_HPP diff --git a/boost/asio/impl/io_context.ipp b/boost/asio/impl/io_context.ipp new file mode 100644 index 0000000000..0dd24713c5 --- /dev/null +++ b/boost/asio/impl/io_context.ipp @@ -0,0 +1,176 @@ +// +// impl/io_context.ipp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IMPL_IO_CONTEXT_IPP +#define BOOST_ASIO_IMPL_IO_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/detail/concurrency_hint.hpp> +#include <boost/asio/detail/limits.hpp> +#include <boost/asio/detail/scoped_ptr.hpp> +#include <boost/asio/detail/service_registry.hpp> +#include <boost/asio/detail/throw_error.hpp> + +#if defined(BOOST_ASIO_HAS_IOCP) +# include <boost/asio/detail/win_iocp_io_context.hpp> +#else +# include <boost/asio/detail/scheduler.hpp> +#endif + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +io_context::io_context() + : impl_(add_impl(new impl_type(*this, BOOST_ASIO_CONCURRENCY_HINT_DEFAULT))) +{ +} + +io_context::io_context(int concurrency_hint) + : impl_(add_impl(new impl_type(*this, concurrency_hint == 1 + ? BOOST_ASIO_CONCURRENCY_HINT_1 : concurrency_hint))) +{ +} + +io_context::impl_type& io_context::add_impl(io_context::impl_type* impl) +{ + boost::asio::detail::scoped_ptr<impl_type> scoped_impl(impl); + boost::asio::add_service<impl_type>(*this, scoped_impl.get()); + return *scoped_impl.release(); +} + +io_context::~io_context() +{ +} + +io_context::count_type io_context::run() +{ + boost::system::error_code ec; + count_type s = impl_.run(ec); + boost::asio::detail::throw_error(ec); + return s; +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +io_context::count_type io_context::run(boost::system::error_code& ec) +{ + return impl_.run(ec); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +io_context::count_type io_context::run_one() +{ + boost::system::error_code ec; + count_type s = impl_.run_one(ec); + boost::asio::detail::throw_error(ec); + return s; +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +io_context::count_type io_context::run_one(boost::system::error_code& ec) +{ + return impl_.run_one(ec); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +io_context::count_type io_context::poll() +{ + boost::system::error_code ec; + count_type s = impl_.poll(ec); + boost::asio::detail::throw_error(ec); + return s; +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +io_context::count_type io_context::poll(boost::system::error_code& ec) +{ + return impl_.poll(ec); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +io_context::count_type io_context::poll_one() +{ + boost::system::error_code ec; + count_type s = impl_.poll_one(ec); + boost::asio::detail::throw_error(ec); + return s; +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +io_context::count_type io_context::poll_one(boost::system::error_code& ec) +{ + return impl_.poll_one(ec); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +void io_context::stop() +{ + impl_.stop(); +} + +bool io_context::stopped() const +{ + return impl_.stopped(); +} + +void io_context::restart() +{ + impl_.restart(); +} + +io_context::service::service(boost::asio::io_context& owner) + : execution_context::service(owner) +{ +} + +io_context::service::~service() +{ +} + +void io_context::service::shutdown() +{ +#if !defined(BOOST_ASIO_NO_DEPRECATED) + shutdown_service(); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +void io_context::service::shutdown_service() +{ +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +void io_context::service::notify_fork(io_context::fork_event ev) +{ +#if !defined(BOOST_ASIO_NO_DEPRECATED) + fork_service(ev); +#else // !defined(BOOST_ASIO_NO_DEPRECATED) + (void)ev; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +void io_context::service::fork_service(io_context::fork_event) +{ +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_IO_CONTEXT_IPP diff --git a/boost/asio/impl/io_service.hpp b/boost/asio/impl/io_service.hpp deleted file mode 100644 index beee3f3978..0000000000 --- a/boost/asio/impl/io_service.hpp +++ /dev/null @@ -1,156 +0,0 @@ -// -// impl/io_service.hpp -// ~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2017 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) -// - -#ifndef BOOST_ASIO_IMPL_IO_SERVICE_HPP -#define BOOST_ASIO_IMPL_IO_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include <boost/asio/detail/handler_type_requirements.hpp> -#include <boost/asio/detail/service_registry.hpp> - -#include <boost/asio/detail/push_options.hpp> - -namespace boost { -namespace asio { - -template <typename Service> -inline Service& use_service(io_service& ios) -{ - // Check that Service meets the necessary type requirements. - (void)static_cast<io_service::service*>(static_cast<Service*>(0)); - (void)static_cast<const io_service::id*>(&Service::id); - - return ios.service_registry_->template use_service<Service>(); -} - -template <> -inline detail::io_service_impl& use_service<detail::io_service_impl>( - io_service& ios) -{ - return ios.impl_; -} - -template <typename Service> -inline void add_service(io_service& ios, Service* svc) -{ - // Check that Service meets the necessary type requirements. - (void)static_cast<io_service::service*>(static_cast<Service*>(0)); - (void)static_cast<const io_service::id*>(&Service::id); - - ios.service_registry_->template add_service<Service>(svc); -} - -template <typename Service> -inline bool has_service(io_service& ios) -{ - // Check that Service meets the necessary type requirements. - (void)static_cast<io_service::service*>(static_cast<Service*>(0)); - (void)static_cast<const io_service::id*>(&Service::id); - - return ios.service_registry_->template has_service<Service>(); -} - -} // namespace asio -} // namespace boost - -#include <boost/asio/detail/pop_options.hpp> - -#if defined(BOOST_ASIO_HAS_IOCP) -# include <boost/asio/detail/win_iocp_io_service.hpp> -#else -# include <boost/asio/detail/task_io_service.hpp> -#endif - -#include <boost/asio/detail/push_options.hpp> - -namespace boost { -namespace asio { - -template <typename CompletionHandler> -inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) -io_service::dispatch(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) -{ - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a CompletionHandler. - BOOST_ASIO_COMPLETION_HANDLER_CHECK(CompletionHandler, handler) type_check; - - detail::async_result_init< - CompletionHandler, void ()> init( - BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); - - impl_.dispatch(init.handler); - - return init.result.get(); -} - -template <typename CompletionHandler> -inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) -io_service::post(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) -{ - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a CompletionHandler. - BOOST_ASIO_COMPLETION_HANDLER_CHECK(CompletionHandler, handler) type_check; - - detail::async_result_init< - CompletionHandler, void ()> init( - BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); - - impl_.post(init.handler); - - return init.result.get(); -} - -template <typename Handler> -#if defined(GENERATING_DOCUMENTATION) -unspecified -#else -inline detail::wrapped_handler<io_service&, Handler> -#endif -io_service::wrap(Handler handler) -{ - return detail::wrapped_handler<io_service&, Handler>(*this, handler); -} - -inline io_service::work::work(boost::asio::io_service& io_service) - : io_service_impl_(io_service.impl_) -{ - io_service_impl_.work_started(); -} - -inline io_service::work::work(const work& other) - : io_service_impl_(other.io_service_impl_) -{ - io_service_impl_.work_started(); -} - -inline io_service::work::~work() -{ - io_service_impl_.work_finished(); -} - -inline boost::asio::io_service& io_service::work::get_io_service() -{ - return io_service_impl_.get_io_service(); -} - -inline boost::asio::io_service& io_service::service::get_io_service() -{ - return owner_; -} - -} // namespace asio -} // namespace boost - -#include <boost/asio/detail/pop_options.hpp> - -#endif // BOOST_ASIO_IMPL_IO_SERVICE_HPP diff --git a/boost/asio/impl/io_service.ipp b/boost/asio/impl/io_service.ipp deleted file mode 100644 index 428db3f879..0000000000 --- a/boost/asio/impl/io_service.ipp +++ /dev/null @@ -1,157 +0,0 @@ -// -// impl/io_service.ipp -// ~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2017 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) -// - -#ifndef BOOST_ASIO_IMPL_IO_SERVICE_IPP -#define BOOST_ASIO_IMPL_IO_SERVICE_IPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include <boost/asio/detail/config.hpp> -#include <boost/asio/io_service.hpp> -#include <boost/asio/detail/limits.hpp> -#include <boost/asio/detail/scoped_ptr.hpp> -#include <boost/asio/detail/service_registry.hpp> -#include <boost/asio/detail/throw_error.hpp> - -#if defined(BOOST_ASIO_HAS_IOCP) -# include <boost/asio/detail/win_iocp_io_service.hpp> -#else -# include <boost/asio/detail/task_io_service.hpp> -#endif - -#include <boost/asio/detail/push_options.hpp> - -namespace boost { -namespace asio { - -io_service::io_service() - : service_registry_(new boost::asio::detail::service_registry( - *this, static_cast<impl_type*>(0), - (std::numeric_limits<std::size_t>::max)())), - impl_(service_registry_->first_service<impl_type>()) -{ -} - -io_service::io_service(std::size_t concurrency_hint) - : service_registry_(new boost::asio::detail::service_registry( - *this, static_cast<impl_type*>(0), concurrency_hint)), - impl_(service_registry_->first_service<impl_type>()) -{ -} - -io_service::~io_service() -{ - delete service_registry_; -} - -std::size_t io_service::run() -{ - boost::system::error_code ec; - std::size_t s = impl_.run(ec); - boost::asio::detail::throw_error(ec); - return s; -} - -std::size_t io_service::run(boost::system::error_code& ec) -{ - return impl_.run(ec); -} - -std::size_t io_service::run_one() -{ - boost::system::error_code ec; - std::size_t s = impl_.run_one(ec); - boost::asio::detail::throw_error(ec); - return s; -} - -std::size_t io_service::run_one(boost::system::error_code& ec) -{ - return impl_.run_one(ec); -} - -std::size_t io_service::poll() -{ - boost::system::error_code ec; - std::size_t s = impl_.poll(ec); - boost::asio::detail::throw_error(ec); - return s; -} - -std::size_t io_service::poll(boost::system::error_code& ec) -{ - return impl_.poll(ec); -} - -std::size_t io_service::poll_one() -{ - boost::system::error_code ec; - std::size_t s = impl_.poll_one(ec); - boost::asio::detail::throw_error(ec); - return s; -} - -std::size_t io_service::poll_one(boost::system::error_code& ec) -{ - return impl_.poll_one(ec); -} - -void io_service::stop() -{ - impl_.stop(); -} - -bool io_service::stopped() const -{ - return impl_.stopped(); -} - -void io_service::reset() -{ - impl_.reset(); -} - -void io_service::notify_fork(boost::asio::io_service::fork_event event) -{ - service_registry_->notify_fork(event); -} - -io_service::service::service(boost::asio::io_service& owner) - : owner_(owner), - next_(0) -{ -} - -io_service::service::~service() -{ -} - -void io_service::service::fork_service(boost::asio::io_service::fork_event) -{ -} - -service_already_exists::service_already_exists() - : std::logic_error("Service already exists.") -{ -} - -invalid_service_owner::invalid_service_owner() - : std::logic_error("Invalid service owner.") -{ -} - -} // namespace asio -} // namespace boost - -#include <boost/asio/detail/pop_options.hpp> - -#endif // BOOST_ASIO_IMPL_IO_SERVICE_IPP diff --git a/boost/asio/impl/post.hpp b/boost/asio/impl/post.hpp new file mode 100644 index 0000000000..520633d42b --- /dev/null +++ b/boost/asio/impl/post.hpp @@ -0,0 +1,79 @@ +// +// impl/post.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IMPL_POST_HPP +#define BOOST_ASIO_IMPL_POST_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/associated_executor.hpp> +#include <boost/asio/detail/work_dispatcher.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( + BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef BOOST_ASIO_HANDLER_TYPE(CompletionToken, void()) handler; + + async_completion<CompletionToken, void()> init(token); + + typename associated_executor<handler>::type ex( + (get_associated_executor)(init.completion_handler)); + + typename associated_allocator<handler>::type alloc( + (get_associated_allocator)(init.completion_handler)); + + ex.post(BOOST_ASIO_MOVE_CAST(handler)(init.completion_handler), alloc); + + return init.result.get(); +} + +template <typename Executor, typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( + const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_executor<Executor>::value>::type*) +{ + typedef BOOST_ASIO_HANDLER_TYPE(CompletionToken, void()) handler; + + async_completion<CompletionToken, void()> init(token); + + typename associated_allocator<handler>::type alloc( + (get_associated_allocator)(init.completion_handler)); + + ex.post(detail::work_dispatcher<handler>(init.completion_handler), alloc); + + return init.result.get(); +} + +template <typename ExecutionContext, typename CompletionToken> +inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( + ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_convertible< + ExecutionContext&, execution_context&>::value>::type*) +{ + return (post)(ctx.get_executor(), + BOOST_ASIO_MOVE_CAST(CompletionToken)(token)); +} + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_POST_HPP diff --git a/boost/asio/impl/read.hpp b/boost/asio/impl/read.hpp index 8648e47918..886565f2e8 100644 --- a/boost/asio/impl/read.hpp +++ b/boost/asio/impl/read.hpp @@ -16,6 +16,8 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <algorithm> +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/associated_executor.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/completion_condition.hpp> #include <boost/asio/detail/array_fwd.hpp> @@ -35,30 +37,46 @@ namespace boost { namespace asio { +namespace detail +{ + template <typename SyncReadStream, typename MutableBufferSequence, + typename MutableBufferIterator, typename CompletionCondition> + std::size_t read_buffer_sequence(SyncReadStream& s, + const MutableBufferSequence& buffers, const MutableBufferIterator&, + CompletionCondition completion_condition, boost::system::error_code& ec) + { + ec = boost::system::error_code(); + boost::asio::detail::consuming_buffers<mutable_buffer, + MutableBufferSequence, MutableBufferIterator> tmp(buffers); + while (!tmp.empty()) + { + if (std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, tmp.total_consumed()))) + tmp.consume(s.read_some(tmp.prepare(max_size), ec)); + else + break; + } + return tmp.total_consumed();; + } +} // namespace detail + template <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, - CompletionCondition completion_condition, boost::system::error_code& ec) + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type*) { - ec = boost::system::error_code(); - boost::asio::detail::consuming_buffers< - mutable_buffer, MutableBufferSequence> tmp(buffers); - std::size_t total_transferred = 0; - tmp.prepare(detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred))); - while (tmp.begin() != tmp.end()) - { - std::size_t bytes_transferred = s.read_some(tmp, ec); - tmp.consume(bytes_transferred); - total_transferred += bytes_transferred; - tmp.prepare(detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred))); - } - return total_transferred; + return detail::read_buffer_sequence(s, buffers, + boost::asio::buffer_sequence_begin(buffers), completion_condition, ec); } template <typename SyncReadStream, typename MutableBufferSequence> -inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers) +inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type*) { boost::system::error_code ec; std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec); @@ -68,7 +86,10 @@ inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers) template <typename SyncReadStream, typename MutableBufferSequence> inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, - boost::system::error_code& ec) + boost::system::error_code& ec, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type*) { return read(s, buffers, transfer_all(), ec); } @@ -76,7 +97,10 @@ inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, template <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition> inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, - CompletionCondition completion_condition) + CompletionCondition completion_condition, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type*) { boost::system::error_code ec; std::size_t bytes_transferred = read(s, buffers, completion_condition, ec); @@ -84,19 +108,25 @@ inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, return bytes_transferred; } -#if !defined(BOOST_ASIO_NO_IOSTREAM) - -template <typename SyncReadStream, typename Allocator, +template <typename SyncReadStream, typename DynamicBuffer, typename CompletionCondition> std::size_t read(SyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, - CompletionCondition completion_condition, boost::system::error_code& ec) + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type*) { + typename decay<DynamicBuffer>::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + ec = boost::system::error_code(); std::size_t total_transferred = 0; std::size_t max_size = detail::adapt_completion_condition_result( completion_condition(ec, total_transferred)); - std::size_t bytes_available = read_size_helper(b, max_size); + std::size_t bytes_available = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(max_size, b.max_size() - b.size())); while (bytes_available > 0) { std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec); @@ -104,27 +134,81 @@ std::size_t read(SyncReadStream& s, total_transferred += bytes_transferred; max_size = detail::adapt_completion_condition_result( completion_condition(ec, total_transferred)); - bytes_available = read_size_helper(b, max_size); + bytes_available = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(max_size, b.max_size() - b.size())); } return total_transferred; } -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename DynamicBuffer> inline std::size_t read(SyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b) + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type*) { boost::system::error_code ec; - std::size_t bytes_transferred = read(s, b, transfer_all(), ec); + std::size_t bytes_transferred = read(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), transfer_all(), ec); boost::asio::detail::throw_error(ec, "read"); return bytes_transferred; } +template <typename SyncReadStream, typename DynamicBuffer> +inline std::size_t read(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type*) +{ + return read(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + transfer_all(), ec); +} + +template <typename SyncReadStream, typename DynamicBuffer, + typename CompletionCondition> +inline std::size_t read(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + completion_condition, ec); + boost::asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +template <typename SyncReadStream, typename Allocator, + typename CompletionCondition> +inline std::size_t read(SyncReadStream& s, + boost::asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, boost::system::error_code& ec) +{ + return read(s, basic_streambuf_ref<Allocator>(b), completion_condition, ec); +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read(SyncReadStream& s, + boost::asio::basic_streambuf<Allocator>& b) +{ + return read(s, basic_streambuf_ref<Allocator>(b)); +} + template <typename SyncReadStream, typename Allocator> inline std::size_t read(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, boost::system::error_code& ec) { - return read(s, b, transfer_all(), ec); + return read(s, basic_streambuf_ref<Allocator>(b), ec); } template <typename SyncReadStream, typename Allocator, @@ -133,18 +217,17 @@ inline std::size_t read(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition) { - boost::system::error_code ec; - std::size_t bytes_transferred = read(s, b, completion_condition, ec); - boost::asio::detail::throw_error(ec, "read"); - return bytes_transferred; + return read(s, basic_streambuf_ref<Allocator>(b), completion_condition); } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) namespace detail { template <typename AsyncReadStream, typename MutableBufferSequence, - typename CompletionCondition, typename ReadHandler> + typename MutableBufferIterator, typename CompletionCondition, + typename ReadHandler> class read_op : detail::base_from_completion_cond<CompletionCondition> { @@ -156,7 +239,6 @@ namespace detail stream_(stream), buffers_(buffers), start_(0), - total_transferred_(0), handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) { } @@ -167,7 +249,6 @@ namespace detail stream_(other.stream_), buffers_(other.buffers_), start_(other.start_), - total_transferred_(other.total_transferred_), handler_(other.handler_) { } @@ -177,7 +258,6 @@ namespace detail stream_(other.stream_), buffers_(other.buffers_), start_(other.start_), - total_transferred_(other.total_transferred_), handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) { } @@ -186,285 +266,39 @@ namespace detail void operator()(const boost::system::error_code& ec, std::size_t bytes_transferred, int start = 0) { + std::size_t max_size; switch (start_ = start) { case 1: - buffers_.prepare(this->check_for_completion(ec, total_transferred_)); - for (;;) + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + do { - stream_.async_read_some(buffers_, + stream_.async_read_some(buffers_.prepare(max_size), BOOST_ASIO_MOVE_CAST(read_op)(*this)); return; default: - total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - buffers_.prepare(this->check_for_completion(ec, total_transferred_)); - if ((!ec && bytes_transferred == 0) - || buffers_.begin() == buffers_.end()) - break; - } - - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); - } - } - - //private: - AsyncReadStream& stream_; - boost::asio::detail::consuming_buffers< - mutable_buffer, MutableBufferSequence> buffers_; - int start_; - std::size_t total_transferred_; - ReadHandler handler_; - }; - - template <typename AsyncReadStream, - typename CompletionCondition, typename ReadHandler> - class read_op<AsyncReadStream, boost::asio::mutable_buffers_1, - CompletionCondition, ReadHandler> - : detail::base_from_completion_cond<CompletionCondition> - { - public: - read_op(AsyncReadStream& stream, - const boost::asio::mutable_buffers_1& buffers, - CompletionCondition completion_condition, ReadHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), - stream_(stream), - buffer_(buffers), - start_(0), - total_transferred_(0), - handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) - { - } - -#if defined(BOOST_ASIO_HAS_MOVE) - read_op(const read_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - stream_(other.stream_), - buffer_(other.buffer_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(other.handler_) - { - } - - read_op(read_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - stream_(other.stream_), - buffer_(other.buffer_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) - { - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred, int start = 0) - { - std::size_t n = 0; - switch (start_ = start) - { - case 1: - n = this->check_for_completion(ec, total_transferred_); - for (;;) - { - stream_.async_read_some( - boost::asio::buffer(buffer_ + total_transferred_, n), - BOOST_ASIO_MOVE_CAST(read_op)(*this)); - return; default: - total_transferred_ += bytes_transferred; - if ((!ec && bytes_transferred == 0) - || (n = this->check_for_completion(ec, total_transferred_)) == 0 - || total_transferred_ == boost::asio::buffer_size(buffer_)) - break; - } - - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); - } - } - - //private: - AsyncReadStream& stream_; - boost::asio::mutable_buffer buffer_; - int start_; - std::size_t total_transferred_; - ReadHandler handler_; - }; - - template <typename AsyncReadStream, typename Elem, - typename CompletionCondition, typename ReadHandler> - class read_op<AsyncReadStream, boost::array<Elem, 2>, - CompletionCondition, ReadHandler> - : detail::base_from_completion_cond<CompletionCondition> - { - public: - read_op(AsyncReadStream& stream, const boost::array<Elem, 2>& buffers, - CompletionCondition completion_condition, ReadHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), - stream_(stream), - buffers_(buffers), - start_(0), - total_transferred_(0), - handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) - { - } - -#if defined(BOOST_ASIO_HAS_MOVE) - read_op(const read_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - stream_(other.stream_), - buffers_(other.buffers_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(other.handler_) - { - } - - read_op(read_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - stream_(other.stream_), - buffers_(other.buffers_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) - { - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred, int start = 0) - { - typename boost::asio::detail::dependent_type<Elem, - boost::array<boost::asio::mutable_buffer, 2> >::type bufs = {{ - boost::asio::mutable_buffer(buffers_[0]), - boost::asio::mutable_buffer(buffers_[1]) }}; - std::size_t buffer_size0 = boost::asio::buffer_size(bufs[0]); - std::size_t buffer_size1 = boost::asio::buffer_size(bufs[1]); - std::size_t n = 0; - switch (start_ = start) - { - case 1: - n = this->check_for_completion(ec, total_transferred_); - for (;;) - { - bufs[0] = boost::asio::buffer(bufs[0] + total_transferred_, n); - bufs[1] = boost::asio::buffer( - bufs[1] + (total_transferred_ < buffer_size0 - ? 0 : total_transferred_ - buffer_size0), - n - boost::asio::buffer_size(bufs[0])); - stream_.async_read_some(bufs, BOOST_ASIO_MOVE_CAST(read_op)(*this)); - return; default: - total_transferred_ += bytes_transferred; - if ((!ec && bytes_transferred == 0) - || (n = this->check_for_completion(ec, total_transferred_)) == 0 - || total_transferred_ == buffer_size0 + buffer_size1) - break; - } - - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); - } - } - - //private: - AsyncReadStream& stream_; - boost::array<Elem, 2> buffers_; - int start_; - std::size_t total_transferred_; - ReadHandler handler_; - }; - -#if defined(BOOST_ASIO_HAS_STD_ARRAY) - - template <typename AsyncReadStream, typename Elem, - typename CompletionCondition, typename ReadHandler> - class read_op<AsyncReadStream, std::array<Elem, 2>, - CompletionCondition, ReadHandler> - : detail::base_from_completion_cond<CompletionCondition> - { - public: - read_op(AsyncReadStream& stream, const std::array<Elem, 2>& buffers, - CompletionCondition completion_condition, ReadHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), - stream_(stream), - buffers_(buffers), - start_(0), - total_transferred_(0), - handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) - { - } - -#if defined(BOOST_ASIO_HAS_MOVE) - read_op(const read_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - stream_(other.stream_), - buffers_(other.buffers_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(other.handler_) - { - } - - read_op(read_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - stream_(other.stream_), - buffers_(other.buffers_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) - { - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred, int start = 0) - { - typename boost::asio::detail::dependent_type<Elem, - std::array<boost::asio::mutable_buffer, 2> >::type bufs = {{ - boost::asio::mutable_buffer(buffers_[0]), - boost::asio::mutable_buffer(buffers_[1]) }}; - std::size_t buffer_size0 = boost::asio::buffer_size(bufs[0]); - std::size_t buffer_size1 = boost::asio::buffer_size(bufs[1]); - std::size_t n = 0; - switch (start_ = start) - { - case 1: - n = this->check_for_completion(ec, total_transferred_); - for (;;) - { - bufs[0] = boost::asio::buffer(bufs[0] + total_transferred_, n); - bufs[1] = boost::asio::buffer( - bufs[1] + (total_transferred_ < buffer_size0 - ? 0 : total_transferred_ - buffer_size0), - n - boost::asio::buffer_size(bufs[0])); - stream_.async_read_some(bufs, BOOST_ASIO_MOVE_CAST(read_op)(*this)); - return; default: - total_transferred_ += bytes_transferred; - if ((!ec && bytes_transferred == 0) - || (n = this->check_for_completion(ec, total_transferred_)) == 0 - || total_transferred_ == buffer_size0 + buffer_size1) + if ((!ec && bytes_transferred == 0) || buffers_.empty()) break; - } + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + } while (max_size > 0); - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + handler_(ec, buffers_.total_consumed()); } } //private: AsyncReadStream& stream_; - std::array<Elem, 2> buffers_; + boost::asio::detail::consuming_buffers<mutable_buffer, + MutableBufferSequence, MutableBufferIterator> buffers_; int start_; - std::size_t total_transferred_; ReadHandler handler_; }; -#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) - template <typename AsyncReadStream, typename MutableBufferSequence, - typename CompletionCondition, typename ReadHandler> + typename MutableBufferIterator, typename CompletionCondition, + typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, - read_op<AsyncReadStream, MutableBufferSequence, + read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( @@ -472,9 +306,10 @@ namespace detail } template <typename AsyncReadStream, typename MutableBufferSequence, - typename CompletionCondition, typename ReadHandler> + typename MutableBufferIterator, typename CompletionCondition, + typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_op<AsyncReadStream, MutableBufferSequence, + read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( @@ -482,9 +317,10 @@ namespace detail } template <typename AsyncReadStream, typename MutableBufferSequence, - typename CompletionCondition, typename ReadHandler> + typename MutableBufferIterator, typename CompletionCondition, + typename ReadHandler> inline bool asio_handler_is_continuation( - read_op<AsyncReadStream, MutableBufferSequence, + read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true @@ -493,10 +329,10 @@ namespace detail } template <typename Function, typename AsyncReadStream, - typename MutableBufferSequence, typename CompletionCondition, - typename ReadHandler> + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler> inline void asio_handler_invoke(Function& function, - read_op<AsyncReadStream, MutableBufferSequence, + read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -504,38 +340,93 @@ namespace detail } template <typename Function, typename AsyncReadStream, - typename MutableBufferSequence, typename CompletionCondition, - typename ReadHandler> + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler> inline void asio_handler_invoke(const Function& function, - read_op<AsyncReadStream, MutableBufferSequence, + read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } + + template <typename AsyncReadStream, typename MutableBufferSequence, + typename MutableBufferIterator, typename CompletionCondition, + typename ReadHandler> + inline void start_read_buffer_sequence_op(AsyncReadStream& stream, + const MutableBufferSequence& buffers, const MutableBufferIterator&, + CompletionCondition completion_condition, ReadHandler& handler) + { + detail::read_op<AsyncReadStream, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>( + stream, buffers, completion_condition, handler)( + boost::system::error_code(), 0, 1); + } } // namespace detail +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename MutableBufferSequence, + typename MutableBufferIterator, typename CompletionCondition, + typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_op<AsyncReadStream, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::read_op<AsyncReadStream, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename MutableBufferSequence, + typename MutableBufferIterator, typename CompletionCondition, + typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_op<AsyncReadStream, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::read_op<AsyncReadStream, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + template <typename AsyncReadStream, typename MutableBufferSequence, typename CompletionCondition, typename ReadHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type*) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); - detail::read_op<AsyncReadStream, MutableBufferSequence, - CompletionCondition, BOOST_ASIO_HANDLER_TYPE( - ReadHandler, void (boost::system::error_code, std::size_t))>( - s, buffers, completion_condition, init.handler)( - boost::system::error_code(), 0, 1); + detail::start_read_buffer_sequence_op(s, buffers, + boost::asio::buffer_sequence_begin(buffers), completion_condition, + init.completion_handler); return init.result.get(); } @@ -545,42 +436,41 @@ template <typename AsyncReadStream, typename MutableBufferSequence, inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type*) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); - detail::read_op<AsyncReadStream, MutableBufferSequence, - detail::transfer_all_t, BOOST_ASIO_HANDLER_TYPE( - ReadHandler, void (boost::system::error_code, std::size_t))>( - s, buffers, transfer_all(), init.handler)( - boost::system::error_code(), 0, 1); + detail::start_read_buffer_sequence_op(s, buffers, + boost::asio::buffer_sequence_begin(buffers), transfer_all(), + init.completion_handler); return init.result.get(); } -#if !defined(BOOST_ASIO_NO_IOSTREAM) - namespace detail { - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBuffer, typename CompletionCondition, typename ReadHandler> - class read_streambuf_op + class read_dynbuf_op : detail::base_from_completion_cond<CompletionCondition> { public: - read_streambuf_op(AsyncReadStream& stream, - basic_streambuf<Allocator>& streambuf, + template <typename BufferSequence> + read_dynbuf_op(AsyncReadStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, CompletionCondition completion_condition, ReadHandler& handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), - streambuf_(streambuf), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), start_(0), total_transferred_(0), handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) @@ -588,20 +478,20 @@ namespace detail } #if defined(BOOST_ASIO_HAS_MOVE) - read_streambuf_op(const read_streambuf_op& other) + read_dynbuf_op(const read_dynbuf_op& other) : detail::base_from_completion_cond<CompletionCondition>(other), stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(other.buffers_), start_(other.start_), total_transferred_(other.total_transferred_), handler_(other.handler_) { } - read_streambuf_op(read_streambuf_op&& other) + read_dynbuf_op(read_dynbuf_op&& other) : detail::base_from_completion_cond<CompletionCondition>(other), stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), start_(other.start_), total_transferred_(other.total_transferred_), handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) @@ -617,16 +507,24 @@ namespace detail { case 1: max_size = this->check_for_completion(ec, total_transferred_); - bytes_available = read_size_helper(streambuf_, max_size); + bytes_available = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(max_size, + buffers_.max_size() - buffers_.size())); for (;;) { - stream_.async_read_some(streambuf_.prepare(bytes_available), - BOOST_ASIO_MOVE_CAST(read_streambuf_op)(*this)); + stream_.async_read_some(buffers_.prepare(bytes_available), + BOOST_ASIO_MOVE_CAST(read_dynbuf_op)(*this)); return; default: total_transferred_ += bytes_transferred; - streambuf_.commit(bytes_transferred); + buffers_.commit(bytes_transferred); max_size = this->check_for_completion(ec, total_transferred_); - bytes_available = read_size_helper(streambuf_, max_size); + bytes_available = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(max_size, + buffers_.max_size() - buffers_.size())); if ((!ec && bytes_transferred == 0) || bytes_available == 0) break; } @@ -637,36 +535,36 @@ namespace detail //private: AsyncReadStream& stream_; - boost::asio::basic_streambuf<Allocator>& streambuf_; + DynamicBuffer buffers_; int start_; std::size_t total_transferred_; ReadHandler handler_; }; - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBuffer, typename CompletionCondition, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, - read_streambuf_op<AsyncReadStream, Allocator, + read_dynbuf_op<AsyncReadStream, DynamicBuffer, CompletionCondition, ReadHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBuffer, typename CompletionCondition, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_streambuf_op<AsyncReadStream, Allocator, + read_dynbuf_op<AsyncReadStream, DynamicBuffer, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBuffer, typename CompletionCondition, typename ReadHandler> inline bool asio_handler_is_continuation( - read_streambuf_op<AsyncReadStream, Allocator, + read_dynbuf_op<AsyncReadStream, DynamicBuffer, CompletionCondition, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true @@ -675,9 +573,10 @@ namespace detail } template <typename Function, typename AsyncReadStream, - typename Allocator, typename CompletionCondition, typename ReadHandler> + typename DynamicBuffer, typename CompletionCondition, + typename ReadHandler> inline void asio_handler_invoke(Function& function, - read_streambuf_op<AsyncReadStream, Allocator, + read_dynbuf_op<AsyncReadStream, DynamicBuffer, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -685,9 +584,10 @@ namespace detail } template <typename Function, typename AsyncReadStream, - typename Allocator, typename CompletionCondition, typename ReadHandler> + typename DynamicBuffer, typename CompletionCondition, + typename ReadHandler> inline void asio_handler_invoke(const Function& function, - read_streambuf_op<AsyncReadStream, Allocator, + read_dynbuf_op<AsyncReadStream, DynamicBuffer, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -695,57 +595,119 @@ namespace detail } } // namespace detail -template <typename AsyncReadStream, typename Allocator, +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer, + typename CompletionCondition, typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_dynbuf_op<AsyncReadStream, + DynamicBuffer, CompletionCondition, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::read_dynbuf_op<AsyncReadStream, + DynamicBuffer, CompletionCondition, ReadHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename DynamicBuffer, + typename CompletionCondition, typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_dynbuf_op<AsyncReadStream, + DynamicBuffer, CompletionCondition, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::read_dynbuf_op<AsyncReadStream, + DynamicBuffer, CompletionCondition, ReadHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type*) +{ + return async_read(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + transfer_all(), BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +template <typename AsyncReadStream, typename DynamicBuffer, typename CompletionCondition, typename ReadHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, CompletionCondition completion_condition, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type*) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); - detail::read_streambuf_op<AsyncReadStream, Allocator, - CompletionCondition, BOOST_ASIO_HANDLER_TYPE( - ReadHandler, void (boost::system::error_code, std::size_t))>( - s, b, completion_condition, init.handler)( - boost::system::error_code(), 0, 1); + detail::read_dynbuf_op<AsyncReadStream, + typename decay<DynamicBuffer>::type, + CompletionCondition, BOOST_ASIO_HANDLER_TYPE( + ReadHandler, void (boost::system::error_code, std::size_t))>( + s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + completion_condition, init.completion_handler)( + boost::system::error_code(), 0, 1); return init.result.get(); } +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + template <typename AsyncReadStream, typename Allocator, typename ReadHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) -async_read(AsyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, +async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( + return async_read(s, basic_streambuf_ref<Allocator>(b), BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +} - detail::read_streambuf_op<AsyncReadStream, Allocator, - detail::transfer_all_t, BOOST_ASIO_HANDLER_TYPE( - ReadHandler, void (boost::system::error_code, std::size_t))>( - s, b, transfer_all(), init.handler)( - boost::system::error_code(), 0, 1); - - return init.result.get(); +template <typename AsyncReadStream, typename Allocator, + typename CompletionCondition, typename ReadHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read(s, basic_streambuf_ref<Allocator>(b), + completion_condition, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) } // namespace asio } // namespace boost diff --git a/boost/asio/impl/read_at.hpp b/boost/asio/impl/read_at.hpp index 0ec8a94e44..457bc056f4 100644 --- a/boost/asio/impl/read_at.hpp +++ b/boost/asio/impl/read_at.hpp @@ -16,6 +16,8 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <algorithm> +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/associated_executor.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/completion_condition.hpp> #include <boost/asio/detail/array_fwd.hpp> @@ -35,28 +37,41 @@ namespace boost { namespace asio { +namespace detail +{ + template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence, + typename MutableBufferIterator, typename CompletionCondition> + std::size_t read_at_buffer_sequence(SyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + const MutableBufferIterator&, CompletionCondition completion_condition, + boost::system::error_code& ec) + { + ec = boost::system::error_code(); + boost::asio::detail::consuming_buffers<mutable_buffer, + MutableBufferSequence, MutableBufferIterator> tmp(buffers); + while (!tmp.empty()) + { + if (std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, tmp.total_consumed()))) + { + tmp.consume(d.read_some_at(offset + tmp.total_consumed(), + tmp.prepare(max_size), ec)); + } + else + break; + } + return tmp.total_consumed();; + } +} // namespace detail + template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence, typename CompletionCondition> std::size_t read_at(SyncRandomAccessReadDevice& d, uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition, boost::system::error_code& ec) { - ec = boost::system::error_code(); - boost::asio::detail::consuming_buffers< - mutable_buffer, MutableBufferSequence> tmp(buffers); - std::size_t total_transferred = 0; - tmp.prepare(detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred))); - while (tmp.begin() != tmp.end()) - { - std::size_t bytes_transferred = d.read_some_at( - offset + total_transferred, tmp, ec); - tmp.consume(bytes_transferred); - total_transferred += bytes_transferred; - tmp.prepare(detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred))); - } - return total_transferred; + return detail::read_at_buffer_sequence(d, offset, buffers, + boost::asio::buffer_sequence_begin(buffers), completion_condition, ec); } template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence> @@ -91,6 +106,7 @@ inline std::size_t read_at(SyncRandomAccessReadDevice& d, return bytes_transferred; } +#if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) template <typename SyncRandomAccessReadDevice, typename Allocator, @@ -150,12 +166,13 @@ inline std::size_t read_at(SyncRandomAccessReadDevice& d, } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) namespace detail { template <typename AsyncRandomAccessReadDevice, - typename MutableBufferSequence, typename CompletionCondition, - typename ReadHandler> + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler> class read_at_op : detail::base_from_completion_cond<CompletionCondition> { @@ -169,7 +186,6 @@ namespace detail offset_(offset), buffers_(buffers), start_(0), - total_transferred_(0), handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) { } @@ -181,7 +197,6 @@ namespace detail offset_(other.offset_), buffers_(other.buffers_), start_(other.start_), - total_transferred_(other.total_transferred_), handler_(other.handler_) { } @@ -192,7 +207,6 @@ namespace detail offset_(other.offset_), buffers_(other.buffers_), start_(other.start_), - total_transferred_(other.total_transferred_), handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) { } @@ -201,326 +215,64 @@ namespace detail void operator()(const boost::system::error_code& ec, std::size_t bytes_transferred, int start = 0) { + std::size_t max_size; switch (start_ = start) { case 1: - buffers_.prepare(this->check_for_completion(ec, total_transferred_)); - for (;;) + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + do { - device_.async_read_some_at(offset_ + total_transferred_, - buffers_, BOOST_ASIO_MOVE_CAST(read_at_op)(*this)); + device_.async_read_some_at( + offset_ + buffers_.total_consumed(), buffers_.prepare(max_size), + BOOST_ASIO_MOVE_CAST(read_at_op)(*this)); return; default: - total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - buffers_.prepare(this->check_for_completion(ec, total_transferred_)); - if ((!ec && bytes_transferred == 0) - || buffers_.begin() == buffers_.end()) + if ((!ec && bytes_transferred == 0) || buffers_.empty()) break; - } + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + } while (max_size > 0); - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + handler_(ec, buffers_.total_consumed()); } } //private: AsyncRandomAccessReadDevice& device_; uint64_t offset_; - boost::asio::detail::consuming_buffers< - mutable_buffer, MutableBufferSequence> buffers_; + boost::asio::detail::consuming_buffers<mutable_buffer, + MutableBufferSequence, MutableBufferIterator> buffers_; int start_; - std::size_t total_transferred_; ReadHandler handler_; }; template <typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> - class read_at_op<AsyncRandomAccessReadDevice, - boost::asio::mutable_buffers_1, CompletionCondition, ReadHandler> - : detail::base_from_completion_cond<CompletionCondition> - { - public: - read_at_op(AsyncRandomAccessReadDevice& device, - uint64_t offset, const boost::asio::mutable_buffers_1& buffers, - CompletionCondition completion_condition, ReadHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), - device_(device), - offset_(offset), - buffer_(buffers), - start_(0), - total_transferred_(0), - handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) - { - } - -#if defined(BOOST_ASIO_HAS_MOVE) - read_at_op(const read_at_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - device_(other.device_), - offset_(other.offset_), - buffer_(other.buffer_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(other.handler_) - { - } - - read_at_op(read_at_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - device_(other.device_), - offset_(other.offset_), - buffer_(other.buffer_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) - { - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred, int start = 0) - { - std::size_t n = 0; - switch (start_ = start) - { - case 1: - n = this->check_for_completion(ec, total_transferred_); - for (;;) - { - device_.async_read_some_at(offset_ + total_transferred_, - boost::asio::buffer(buffer_ + total_transferred_, n), - BOOST_ASIO_MOVE_CAST(read_at_op)(*this)); - return; default: - total_transferred_ += bytes_transferred; - if ((!ec && bytes_transferred == 0) - || (n = this->check_for_completion(ec, total_transferred_)) == 0 - || total_transferred_ == boost::asio::buffer_size(buffer_)) - break; - } - - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); - } - } - - //private: - AsyncRandomAccessReadDevice& device_; - uint64_t offset_; - boost::asio::mutable_buffer buffer_; - int start_; - std::size_t total_transferred_; - ReadHandler handler_; - }; - - template <typename AsyncRandomAccessReadDevice, typename Elem, - typename CompletionCondition, typename ReadHandler> - class read_at_op<AsyncRandomAccessReadDevice, boost::array<Elem, 2>, - CompletionCondition, ReadHandler> - : detail::base_from_completion_cond<CompletionCondition> - { - public: - read_at_op(AsyncRandomAccessReadDevice& device, - uint64_t offset, const boost::array<Elem, 2>& buffers, - CompletionCondition completion_condition, ReadHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), - device_(device), - offset_(offset), - buffers_(buffers), - start_(0), - total_transferred_(0), - handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) - { - } - -#if defined(BOOST_ASIO_HAS_MOVE) - read_at_op(const read_at_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - device_(other.device_), - offset_(other.offset_), - buffers_(other.buffers_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(other.handler_) - { - } - - read_at_op(read_at_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - device_(other.device_), - offset_(other.offset_), - buffers_(other.buffers_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) - { - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred, int start = 0) - { - typename boost::asio::detail::dependent_type<Elem, - boost::array<boost::asio::mutable_buffer, 2> >::type bufs = {{ - boost::asio::mutable_buffer(buffers_[0]), - boost::asio::mutable_buffer(buffers_[1]) }}; - std::size_t buffer_size0 = boost::asio::buffer_size(bufs[0]); - std::size_t buffer_size1 = boost::asio::buffer_size(bufs[1]); - std::size_t n = 0; - switch (start_ = start) - { - case 1: - n = this->check_for_completion(ec, total_transferred_); - for (;;) - { - bufs[0] = boost::asio::buffer(bufs[0] + total_transferred_, n); - bufs[1] = boost::asio::buffer( - bufs[1] + (total_transferred_ < buffer_size0 - ? 0 : total_transferred_ - buffer_size0), - n - boost::asio::buffer_size(bufs[0])); - device_.async_read_some_at(offset_ + total_transferred_, - bufs, BOOST_ASIO_MOVE_CAST(read_at_op)(*this)); - return; default: - total_transferred_ += bytes_transferred; - if ((!ec && bytes_transferred == 0) - || (n = this->check_for_completion(ec, total_transferred_)) == 0 - || total_transferred_ == buffer_size0 + buffer_size1) - break; - } - - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); - } - } - - //private: - AsyncRandomAccessReadDevice& device_; - uint64_t offset_; - boost::array<Elem, 2> buffers_; - int start_; - std::size_t total_transferred_; - ReadHandler handler_; - }; - -#if defined(BOOST_ASIO_HAS_STD_ARRAY) - - template <typename AsyncRandomAccessReadDevice, typename Elem, - typename CompletionCondition, typename ReadHandler> - class read_at_op<AsyncRandomAccessReadDevice, std::array<Elem, 2>, - CompletionCondition, ReadHandler> - : detail::base_from_completion_cond<CompletionCondition> - { - public: - read_at_op(AsyncRandomAccessReadDevice& device, - uint64_t offset, const std::array<Elem, 2>& buffers, - CompletionCondition completion_condition, ReadHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), - device_(device), - offset_(offset), - buffers_(buffers), - start_(0), - total_transferred_(0), - handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) - { - } - -#if defined(BOOST_ASIO_HAS_MOVE) - read_at_op(const read_at_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - device_(other.device_), - offset_(other.offset_), - buffers_(other.buffers_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(other.handler_) - { - } - - read_at_op(read_at_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - device_(other.device_), - offset_(other.offset_), - buffers_(other.buffers_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) - { - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred, int start = 0) - { - typename boost::asio::detail::dependent_type<Elem, - std::array<boost::asio::mutable_buffer, 2> >::type bufs = {{ - boost::asio::mutable_buffer(buffers_[0]), - boost::asio::mutable_buffer(buffers_[1]) }}; - std::size_t buffer_size0 = boost::asio::buffer_size(bufs[0]); - std::size_t buffer_size1 = boost::asio::buffer_size(bufs[1]); - std::size_t n = 0; - switch (start_ = start) - { - case 1: - n = this->check_for_completion(ec, total_transferred_); - for (;;) - { - bufs[0] = boost::asio::buffer(bufs[0] + total_transferred_, n); - bufs[1] = boost::asio::buffer( - bufs[1] + (total_transferred_ < buffer_size0 - ? 0 : total_transferred_ - buffer_size0), - n - boost::asio::buffer_size(bufs[0])); - device_.async_read_some_at(offset_ + total_transferred_, - bufs, BOOST_ASIO_MOVE_CAST(read_at_op)(*this)); - return; default: - total_transferred_ += bytes_transferred; - if ((!ec && bytes_transferred == 0) - || (n = this->check_for_completion(ec, total_transferred_)) == 0 - || total_transferred_ == buffer_size0 + buffer_size1) - break; - } - - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); - } - } - - //private: - AsyncRandomAccessReadDevice& device_; - uint64_t offset_; - std::array<Elem, 2> buffers_; - int start_; - std::size_t total_transferred_; - ReadHandler handler_; - }; - -#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) - - template <typename AsyncRandomAccessReadDevice, - typename MutableBufferSequence, typename CompletionCondition, - typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, - CompletionCondition, ReadHandler>* this_handler) + MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template <typename AsyncRandomAccessReadDevice, - typename MutableBufferSequence, typename CompletionCondition, - typename ReadHandler> + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, - CompletionCondition, ReadHandler>* this_handler) + MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template <typename AsyncRandomAccessReadDevice, - typename MutableBufferSequence, typename CompletionCondition, - typename ReadHandler> + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler> inline bool asio_handler_is_continuation( read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, - CompletionCondition, ReadHandler>* this_handler) + MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( @@ -528,42 +280,86 @@ namespace detail } template <typename Function, typename AsyncRandomAccessReadDevice, - typename MutableBufferSequence, typename CompletionCondition, - typename ReadHandler> + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler> inline void asio_handler_invoke(Function& function, read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, - CompletionCondition, ReadHandler>* this_handler) + MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } template <typename Function, typename AsyncRandomAccessReadDevice, - typename MutableBufferSequence, typename CompletionCondition, - typename ReadHandler> + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler> inline void asio_handler_invoke(const Function& function, read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, - CompletionCondition, ReadHandler>* this_handler) + MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } template <typename AsyncRandomAccessReadDevice, - typename MutableBufferSequence, typename CompletionCondition, - typename ReadHandler> - inline read_at_op<AsyncRandomAccessReadDevice, - MutableBufferSequence, CompletionCondition, ReadHandler> - make_read_at_op(AsyncRandomAccessReadDevice& d, + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler> + inline void start_read_at_buffer_sequence_op(AsyncRandomAccessReadDevice& d, uint64_t offset, const MutableBufferSequence& buffers, - CompletionCondition completion_condition, ReadHandler handler) + const MutableBufferIterator&, CompletionCondition completion_condition, + ReadHandler& handler) { - return read_at_op<AsyncRandomAccessReadDevice, - MutableBufferSequence, CompletionCondition, ReadHandler>( - d, offset, buffers, completion_condition, handler); + detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>( + d, offset, buffers, completion_condition, handler)( + boost::system::error_code(), 0, 1); } } // namespace detail +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::read_at_op<AsyncRandomAccessReadDevice, + MutableBufferSequence, MutableBufferIterator, + CompletionCondition, ReadHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncRandomAccessReadDevice, + typename MutableBufferSequence, typename MutableBufferIterator, + typename CompletionCondition, typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, + MutableBufferIterator, CompletionCondition, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::read_at_op<AsyncRandomAccessReadDevice, + MutableBufferSequence, MutableBufferIterator, + CompletionCondition, ReadHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, typename CompletionCondition, typename ReadHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, @@ -577,15 +373,12 @@ async_read_at(AsyncRandomAccessReadDevice& d, // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); - detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, - CompletionCondition, BOOST_ASIO_HANDLER_TYPE(ReadHandler, - void (boost::system::error_code, std::size_t))>( - d, offset, buffers, completion_condition, init.handler)( - boost::system::error_code(), 0, 1); + detail::start_read_at_buffer_sequence_op(d, offset, buffers, + boost::asio::buffer_sequence_begin(buffers), completion_condition, + init.completion_handler); return init.result.get(); } @@ -602,19 +395,17 @@ async_read_at(AsyncRandomAccessReadDevice& d, // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); - detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, - detail::transfer_all_t, BOOST_ASIO_HANDLER_TYPE(ReadHandler, - void (boost::system::error_code, std::size_t))>( - d, offset, buffers, transfer_all(), init.handler)( - boost::system::error_code(), 0, 1); + detail::start_read_at_buffer_sequence_op(d, offset, buffers, + boost::asio::buffer_sequence_begin(buffers), transfer_all(), + init.completion_handler); return init.result.get(); } +#if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) namespace detail @@ -751,6 +542,46 @@ namespace detail } } // namespace detail +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncRandomAccessReadDevice, typename Allocator, + typename CompletionCondition, typename ReadHandler, typename Allocator1> +struct associated_allocator< + detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, + Allocator, CompletionCondition, ReadHandler>, + Allocator1> +{ + typedef typename associated_allocator<ReadHandler, Allocator1>::type type; + + static type get( + const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, + Allocator, CompletionCondition, ReadHandler>& h, + const Allocator1& a = Allocator1()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator1>::get(h.handler_, a); + } +}; + +template <typename AsyncRandomAccessReadDevice, typename Executor, + typename CompletionCondition, typename ReadHandler, typename Executor1> +struct associated_executor< + detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, + Executor, CompletionCondition, ReadHandler>, + Executor1> +{ + typedef typename associated_executor<ReadHandler, Executor1>::type type; + + static type get( + const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, + Executor, CompletionCondition, ReadHandler>& h, + const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor1>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + template <typename AsyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition, typename ReadHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, @@ -764,14 +595,13 @@ async_read_at(AsyncRandomAccessReadDevice& d, // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, CompletionCondition, BOOST_ASIO_HANDLER_TYPE(ReadHandler, void (boost::system::error_code, std::size_t))>( - d, offset, b, completion_condition, init.handler)( + d, offset, b, completion_condition, init.completion_handler)( boost::system::error_code(), 0, 1); return init.result.get(); @@ -789,20 +619,20 @@ async_read_at(AsyncRandomAccessReadDevice& d, // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, detail::transfer_all_t, BOOST_ASIO_HANDLER_TYPE(ReadHandler, void (boost::system::error_code, std::size_t))>( - d, offset, b, transfer_all(), init.handler)( + d, offset, b, transfer_all(), init.completion_handler)( boost::system::error_code(), 0, 1); return init.result.get(); } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) } // namespace asio } // namespace boost diff --git a/boost/asio/impl/read_until.hpp b/boost/asio/impl/read_until.hpp index 737dedcdf2..c8a409f46b 100644 --- a/boost/asio/impl/read_until.hpp +++ b/boost/asio/impl/read_until.hpp @@ -19,6 +19,8 @@ #include <string> #include <vector> #include <utility> +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/associated_executor.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/buffers_iterator.hpp> #include <boost/asio/detail/bind_handler.hpp> @@ -34,32 +36,35 @@ namespace boost { namespace asio { -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename DynamicBuffer> inline std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, char delim) + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, char delim) { boost::system::error_code ec; - std::size_t bytes_transferred = read_until(s, b, delim, ec); + std::size_t bytes_transferred = read_until(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), delim, ec); boost::asio::detail::throw_error(ec, "read_until"); return bytes_transferred; } -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename DynamicBuffer> std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, char delim, - boost::system::error_code& ec) + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + char delim, boost::system::error_code& ec) { + typename decay<DynamicBuffer>::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. - typedef typename boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator<const_buffers_type> iterator; - const_buffers_type buffers = b.data(); - iterator begin = iterator::begin(buffers); + typedef typename DynamicBuffer::const_buffers_type buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = b.data(); + iterator begin = iterator::begin(data_buffers); iterator start_pos = begin + search_position; - iterator end = iterator::end(buffers); + iterator end = iterator::end(data_buffers); // Look for a match. iterator iter = std::find(start_pos, end, delim); @@ -83,19 +88,23 @@ std::size_t read_until(SyncReadStream& s, } // Need more data. - std::size_t bytes_to_read = read_size_helper(b, 65536); + std::size_t bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(65536, b.max_size() - b.size())); b.commit(s.read_some(b.prepare(bytes_to_read), ec)); if (ec) return 0; } } -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename DynamicBuffer> inline std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, const std::string& delim) + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim) { boost::system::error_code ec; - std::size_t bytes_transferred = read_until(s, b, delim, ec); + std::size_t bytes_transferred = read_until(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), delim, ec); boost::asio::detail::throw_error(ec, "read_until"); return bytes_transferred; } @@ -135,22 +144,24 @@ namespace detail } } // namespace detail -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename DynamicBuffer> std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, const std::string& delim, - boost::system::error_code& ec) + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec) { + typename decay<DynamicBuffer>::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. - typedef typename boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator<const_buffers_type> iterator; - const_buffers_type buffers = b.data(); - iterator begin = iterator::begin(buffers); + typedef typename DynamicBuffer::const_buffers_type buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = b.data(); + iterator begin = iterator::begin(data_buffers); iterator start_pos = begin + search_position; - iterator end = iterator::end(buffers); + iterator end = iterator::end(data_buffers); // Look for a match. std::pair<iterator, bool> result = detail::partial_search( @@ -183,41 +194,48 @@ std::size_t read_until(SyncReadStream& s, } // Need more data. - std::size_t bytes_to_read = read_size_helper(b, 65536); + std::size_t bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(65536, b.max_size() - b.size())); b.commit(s.read_some(b.prepare(bytes_to_read), ec)); if (ec) return 0; } } +#if !defined(BOOST_ASIO_NO_EXTENSIONS) #if defined(BOOST_ASIO_HAS_BOOST_REGEX) -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename DynamicBuffer> inline std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr) + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + const boost::regex& expr) { boost::system::error_code ec; - std::size_t bytes_transferred = read_until(s, b, expr, ec); + std::size_t bytes_transferred = read_until(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), expr, ec); boost::asio::detail::throw_error(ec, "read_until"); return bytes_transferred; } -template <typename SyncReadStream, typename Allocator> +template <typename SyncReadStream, typename DynamicBuffer> std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr, - boost::system::error_code& ec) + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + const boost::regex& expr, boost::system::error_code& ec) { + typename decay<DynamicBuffer>::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. - typedef typename boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator<const_buffers_type> iterator; - const_buffers_type buffers = b.data(); - iterator begin = iterator::begin(buffers); + typedef typename DynamicBuffer::const_buffers_type buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = b.data(); + iterator begin = iterator::begin(data_buffers); iterator start_pos = begin + search_position; - iterator end = iterator::end(buffers); + iterator end = iterator::end(data_buffers); // Look for a match. boost::match_results<iterator, @@ -261,23 +279,41 @@ std::size_t read_until(SyncReadStream& s, #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) -template <typename SyncReadStream, typename Allocator, typename MatchCondition> +template <typename SyncReadStream, + typename DynamicBuffer, typename MatchCondition> +inline std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + MatchCondition match_condition, + typename enable_if<is_match_condition<MatchCondition>::value>::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + match_condition, ec); + boost::asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template <typename SyncReadStream, + typename DynamicBuffer, typename MatchCondition> std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, MatchCondition match_condition, boost::system::error_code& ec, typename enable_if<is_match_condition<MatchCondition>::value>::type*) { + typename decay<DynamicBuffer>::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. - typedef typename boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator<const_buffers_type> iterator; - const_buffers_type buffers = b.data(); - iterator begin = iterator::begin(buffers); + typedef typename DynamicBuffer::const_buffers_type buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = b.data(); + iterator begin = iterator::begin(data_buffers); iterator start_pos = begin + search_position; - iterator end = iterator::end(buffers); + iterator end = iterator::end(data_buffers); // Look for a match. std::pair<iterator, bool> result = match_condition(start_pos, end); @@ -306,35 +342,100 @@ std::size_t read_until(SyncReadStream& s, } // Need more data. - std::size_t bytes_to_read = read_size_helper(b, 65536); + std::size_t bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, b.capacity() - b.size()), + std::min<std::size_t>(65536, b.max_size() - b.size())); b.commit(s.read_some(b.prepare(bytes_to_read), ec)); if (ec) return 0; } } +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf<Allocator>& b, char delim) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), delim); +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf<Allocator>& b, char delim, + boost::system::error_code& ec) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec); +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf<Allocator>& b, + BOOST_ASIO_STRING_VIEW_PARAM delim) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), delim); +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf<Allocator>& b, + BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec); +} + +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), expr); +} + +template <typename SyncReadStream, typename Allocator> +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr, + boost::system::error_code& ec) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), expr, ec); +} + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + template <typename SyncReadStream, typename Allocator, typename MatchCondition> inline std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, MatchCondition match_condition, typename enable_if<is_match_condition<MatchCondition>::value>::type*) { - boost::system::error_code ec; - std::size_t bytes_transferred = read_until(s, b, match_condition, ec); - boost::asio::detail::throw_error(ec, "read_until"); - return bytes_transferred; + return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition); +} + +template <typename SyncReadStream, typename Allocator, typename MatchCondition> +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf<Allocator>& b, + MatchCondition match_condition, boost::system::error_code& ec, + typename enable_if<is_match_condition<MatchCondition>::value>::type*) +{ + return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition, ec); } +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + namespace detail { - template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> class read_until_delim_op { public: + template <typename BufferSequence> read_until_delim_op(AsyncReadStream& stream, - boost::asio::basic_streambuf<Allocator>& streambuf, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, char delim, ReadHandler& handler) : stream_(stream), - streambuf_(streambuf), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), delim_(delim), start_(0), search_position_(0), @@ -345,7 +446,7 @@ namespace detail #if defined(BOOST_ASIO_HAS_MOVE) read_until_delim_op(const read_until_delim_op& other) : stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(other.buffers_), delim_(other.delim_), start_(other.start_), search_position_(other.search_position_), @@ -355,7 +456,7 @@ namespace detail read_until_delim_op(read_until_delim_op&& other) : stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), delim_(other.delim_), start_(other.start_), search_position_(other.search_position_), @@ -376,13 +477,13 @@ namespace detail { { // Determine the range of the data to be searched. - typedef typename boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator<const_buffers_type> iterator; - const_buffers_type buffers = streambuf_.data(); - iterator begin = iterator::begin(buffers); + typedef typename DynamicBuffer::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = buffers_.data(); + iterator begin = iterator::begin(data_buffers); iterator start_pos = begin + search_position_; - iterator end = iterator::end(buffers); + iterator end = iterator::end(data_buffers); // Look for a match. iterator iter = std::find(start_pos, end, delim_); @@ -394,7 +495,7 @@ namespace detail } // No match yet. Check if buffer is full. - else if (streambuf_.size() == streambuf_.max_size()) + else if (buffers_.size() == buffers_.max_size()) { search_position_ = not_found; bytes_to_read = 0; @@ -405,7 +506,11 @@ namespace detail { // Next search can start with the new data. search_position_ = end - begin; - bytes_to_read = read_size_helper(streambuf_, 65536); + bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(65536, + buffers_.max_size() - buffers_.size())); } } @@ -414,10 +519,10 @@ namespace detail break; // Start a new asynchronous read operation to obtain more data. - stream_.async_read_some(streambuf_.prepare(bytes_to_read), + stream_.async_read_some(buffers_.prepare(bytes_to_read), BOOST_ASIO_MOVE_CAST(read_until_delim_op)(*this)); return; default: - streambuf_.commit(bytes_transferred); + buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) break; } @@ -436,97 +541,143 @@ namespace detail //private: AsyncReadStream& stream_; - boost::asio::basic_streambuf<Allocator>& streambuf_; + DynamicBuffer buffers_; char delim_; int start_; std::size_t search_position_; ReadHandler handler_; }; - template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, read_until_delim_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBuffer, ReadHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, read_until_delim_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBuffer, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> inline bool asio_handler_is_continuation( read_until_delim_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBuffer, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename AsyncReadStream, typename Allocator, - typename ReadHandler> + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> inline void asio_handler_invoke(Function& function, read_until_delim_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBuffer, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } - template <typename Function, typename AsyncReadStream, typename Allocator, - typename ReadHandler> + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> inline void asio_handler_invoke(const Function& function, read_until_delim_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBuffer, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail -template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer, + typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_until_delim_op<AsyncReadStream, + DynamicBuffer, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::read_until_delim_op<AsyncReadStream, + DynamicBuffer, ReadHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename DynamicBuffer, + typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_until_delim_op<AsyncReadStream, + DynamicBuffer, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::read_until_delim_op<AsyncReadStream, + DynamicBuffer, ReadHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, char delim, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); detail::read_until_delim_op<AsyncReadStream, - Allocator, BOOST_ASIO_HANDLER_TYPE(ReadHandler, - void (boost::system::error_code, std::size_t))>( - s, b, delim, init.handler)( - boost::system::error_code(), 0, 1); + typename decay<DynamicBuffer>::type, + BOOST_ASIO_HANDLER_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t))>( + s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + delim, init.completion_handler)(boost::system::error_code(), 0, 1); return init.result.get(); } namespace detail { - template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> class read_until_delim_string_op { public: + template <typename BufferSequence> read_until_delim_string_op(AsyncReadStream& stream, - boost::asio::basic_streambuf<Allocator>& streambuf, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, const std::string& delim, ReadHandler& handler) : stream_(stream), - streambuf_(streambuf), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), delim_(delim), start_(0), search_position_(0), @@ -537,7 +688,7 @@ namespace detail #if defined(BOOST_ASIO_HAS_MOVE) read_until_delim_string_op(const read_until_delim_string_op& other) : stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(other.buffers_), delim_(other.delim_), start_(other.start_), search_position_(other.search_position_), @@ -547,7 +698,7 @@ namespace detail read_until_delim_string_op(read_until_delim_string_op&& other) : stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), delim_(BOOST_ASIO_MOVE_CAST(std::string)(other.delim_)), start_(other.start_), search_position_(other.search_position_), @@ -568,13 +719,13 @@ namespace detail { { // Determine the range of the data to be searched. - typedef typename boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator<const_buffers_type> iterator; - const_buffers_type buffers = streambuf_.data(); - iterator begin = iterator::begin(buffers); + typedef typename DynamicBuffer::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = buffers_.data(); + iterator begin = iterator::begin(data_buffers); iterator start_pos = begin + search_position_; - iterator end = iterator::end(buffers); + iterator end = iterator::end(data_buffers); // Look for a match. std::pair<iterator, bool> result = detail::partial_search( @@ -587,7 +738,7 @@ namespace detail } // No match yet. Check if buffer is full. - else if (streambuf_.size() == streambuf_.max_size()) + else if (buffers_.size() == buffers_.max_size()) { search_position_ = not_found; bytes_to_read = 0; @@ -608,7 +759,11 @@ namespace detail search_position_ = end - begin; } - bytes_to_read = read_size_helper(streambuf_, 65536); + bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(65536, + buffers_.max_size() - buffers_.size())); } } @@ -617,10 +772,10 @@ namespace detail break; // Start a new asynchronous read operation to obtain more data. - stream_.async_read_some(streambuf_.prepare(bytes_to_read), + stream_.async_read_some(buffers_.prepare(bytes_to_read), BOOST_ASIO_MOVE_CAST(read_until_delim_string_op)(*this)); return; default: - streambuf_.commit(bytes_transferred); + buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) break; } @@ -639,35 +794,38 @@ namespace detail //private: AsyncReadStream& stream_; - boost::asio::basic_streambuf<Allocator>& streambuf_; + DynamicBuffer buffers_; std::string delim_; int start_; std::size_t search_position_; ReadHandler handler_; }; - template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, read_until_delim_string_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBuffer, ReadHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, read_until_delim_string_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBuffer, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, typename ReadHandler> + template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> inline bool asio_handler_is_continuation( read_until_delim_string_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBuffer, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( @@ -675,64 +833,109 @@ namespace detail } template <typename Function, typename AsyncReadStream, - typename Allocator, typename ReadHandler> + typename DynamicBuffer, typename ReadHandler> inline void asio_handler_invoke(Function& function, read_until_delim_string_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBuffer, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } template <typename Function, typename AsyncReadStream, - typename Allocator, typename ReadHandler> + typename DynamicBuffer, typename ReadHandler> inline void asio_handler_invoke(const Function& function, read_until_delim_string_op<AsyncReadStream, - Allocator, ReadHandler>* this_handler) + DynamicBuffer, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail -template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer, + typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_until_delim_string_op<AsyncReadStream, + DynamicBuffer, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::read_until_delim_string_op<AsyncReadStream, + DynamicBuffer, ReadHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename DynamicBuffer, + typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_until_delim_string_op<AsyncReadStream, + DynamicBuffer, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::read_until_delim_string_op<AsyncReadStream, + DynamicBuffer, ReadHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, const std::string& delim, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); detail::read_until_delim_string_op<AsyncReadStream, - Allocator, BOOST_ASIO_HANDLER_TYPE(ReadHandler, - void (boost::system::error_code, std::size_t))>( - s, b, delim, init.handler)( - boost::system::error_code(), 0, 1); + typename decay<DynamicBuffer>::type, + BOOST_ASIO_HANDLER_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t))>( + s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + static_cast<std::string>(delim), + init.completion_handler)(boost::system::error_code(), 0, 1); return init.result.get(); } +#if !defined(BOOST_ASIO_NO_EXTENSIONS) #if defined(BOOST_ASIO_HAS_BOOST_REGEX) namespace detail { - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBuffer, typename RegEx, typename ReadHandler> class read_until_expr_op { public: + template <typename BufferSequence> read_until_expr_op(AsyncReadStream& stream, - boost::asio::basic_streambuf<Allocator>& streambuf, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, const boost::regex& expr, ReadHandler& handler) : stream_(stream), - streambuf_(streambuf), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), expr_(expr), start_(0), search_position_(0), @@ -743,7 +946,7 @@ namespace detail #if defined(BOOST_ASIO_HAS_MOVE) read_until_expr_op(const read_until_expr_op& other) : stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(other.buffers_), expr_(other.expr_), start_(other.start_), search_position_(other.search_position_), @@ -753,7 +956,7 @@ namespace detail read_until_expr_op(read_until_expr_op&& other) : stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), expr_(other.expr_), start_(other.start_), search_position_(other.search_position_), @@ -774,13 +977,13 @@ namespace detail { { // Determine the range of the data to be searched. - typedef typename boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator<const_buffers_type> iterator; - const_buffers_type buffers = streambuf_.data(); - iterator begin = iterator::begin(buffers); + typedef typename DynamicBuffer::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = buffers_.data(); + iterator begin = iterator::begin(data_buffers); iterator start_pos = begin + search_position_; - iterator end = iterator::end(buffers); + iterator end = iterator::end(data_buffers); // Look for a match. boost::match_results<iterator, @@ -796,7 +999,7 @@ namespace detail } // No match yet. Check if buffer is full. - else if (streambuf_.size() == streambuf_.max_size()) + else if (buffers_.size() == buffers_.max_size()) { search_position_ = not_found; bytes_to_read = 0; @@ -817,7 +1020,11 @@ namespace detail search_position_ = end - begin; } - bytes_to_read = read_size_helper(streambuf_, 65536); + bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(65536, + buffers_.max_size() - buffers_.size())); } } @@ -826,10 +1033,10 @@ namespace detail break; // Start a new asynchronous read operation to obtain more data. - stream_.async_read_some(streambuf_.prepare(bytes_to_read), + stream_.async_read_some(buffers_.prepare(bytes_to_read), BOOST_ASIO_MOVE_CAST(read_until_expr_op)(*this)); return; default: - streambuf_.commit(bytes_transferred); + buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) break; } @@ -848,85 +1055,127 @@ namespace detail //private: AsyncReadStream& stream_; - boost::asio::basic_streambuf<Allocator>& streambuf_; + DynamicBuffer buffers_; RegEx expr_; int start_; std::size_t search_position_; ReadHandler handler_; }; - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBuffer, typename RegEx, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, read_until_expr_op<AsyncReadStream, - Allocator, RegEx, ReadHandler>* this_handler) + DynamicBuffer, RegEx, ReadHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBuffer, typename RegEx, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, read_until_expr_op<AsyncReadStream, - Allocator, RegEx, ReadHandler>* this_handler) + DynamicBuffer, RegEx, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBuffer, typename RegEx, typename ReadHandler> inline bool asio_handler_is_continuation( read_until_expr_op<AsyncReadStream, - Allocator, RegEx, ReadHandler>* this_handler) + DynamicBuffer, RegEx, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename AsyncReadStream, typename Allocator, - typename RegEx, typename ReadHandler> + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer, typename RegEx, typename ReadHandler> inline void asio_handler_invoke(Function& function, read_until_expr_op<AsyncReadStream, - Allocator, RegEx, ReadHandler>* this_handler) + DynamicBuffer, RegEx, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } - template <typename Function, typename AsyncReadStream, typename Allocator, - typename RegEx, typename ReadHandler> + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer, typename RegEx, typename ReadHandler> inline void asio_handler_invoke(const Function& function, read_until_expr_op<AsyncReadStream, - Allocator, RegEx, ReadHandler>* this_handler) + DynamicBuffer, RegEx, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail -template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer, + typename RegEx, typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_until_expr_op<AsyncReadStream, + DynamicBuffer, RegEx, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::read_until_expr_op<AsyncReadStream, + DynamicBuffer, RegEx, ReadHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename DynamicBuffer, + typename RegEx, typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_until_expr_op<AsyncReadStream, + DynamicBuffer, RegEx, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::read_until_expr_op<AsyncReadStream, + DynamicBuffer, RegEx, ReadHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + const boost::regex& expr, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); - detail::read_until_expr_op<AsyncReadStream, Allocator, - boost::regex, BOOST_ASIO_HANDLER_TYPE(ReadHandler, - void (boost::system::error_code, std::size_t))>( - s, b, expr, init.handler)( - boost::system::error_code(), 0, 1); + detail::read_until_expr_op<AsyncReadStream, + typename decay<DynamicBuffer>::type, + boost::regex, BOOST_ASIO_HANDLER_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t))>( + s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + expr, init.completion_handler)(boost::system::error_code(), 0, 1); return init.result.get(); } @@ -935,16 +1184,17 @@ async_read_until(AsyncReadStream& s, namespace detail { - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBuffer, typename MatchCondition, typename ReadHandler> class read_until_match_op { public: + template <typename BufferSequence> read_until_match_op(AsyncReadStream& stream, - boost::asio::basic_streambuf<Allocator>& streambuf, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, MatchCondition match_condition, ReadHandler& handler) : stream_(stream), - streambuf_(streambuf), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), match_condition_(match_condition), start_(0), search_position_(0), @@ -955,7 +1205,7 @@ namespace detail #if defined(BOOST_ASIO_HAS_MOVE) read_until_match_op(const read_until_match_op& other) : stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(other.buffers_), match_condition_(other.match_condition_), start_(other.start_), search_position_(other.search_position_), @@ -965,7 +1215,7 @@ namespace detail read_until_match_op(read_until_match_op&& other) : stream_(other.stream_), - streambuf_(other.streambuf_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), match_condition_(other.match_condition_), start_(other.start_), search_position_(other.search_position_), @@ -986,13 +1236,13 @@ namespace detail { { // Determine the range of the data to be searched. - typedef typename boost::asio::basic_streambuf< - Allocator>::const_buffers_type const_buffers_type; - typedef boost::asio::buffers_iterator<const_buffers_type> iterator; - const_buffers_type buffers = streambuf_.data(); - iterator begin = iterator::begin(buffers); + typedef typename DynamicBuffer::const_buffers_type + buffers_type; + typedef buffers_iterator<buffers_type> iterator; + buffers_type data_buffers = buffers_.data(); + iterator begin = iterator::begin(data_buffers); iterator start_pos = begin + search_position_; - iterator end = iterator::end(buffers); + iterator end = iterator::end(data_buffers); // Look for a match. std::pair<iterator, bool> result = match_condition_(start_pos, end); @@ -1004,7 +1254,7 @@ namespace detail } // No match yet. Check if buffer is full. - else if (streambuf_.size() == streambuf_.max_size()) + else if (buffers_.size() == buffers_.max_size()) { search_position_ = not_found; bytes_to_read = 0; @@ -1025,7 +1275,11 @@ namespace detail search_position_ = end - begin; } - bytes_to_read = read_size_helper(streambuf_, 65536); + bytes_to_read = std::min<std::size_t>( + std::max<std::size_t>(512, + buffers_.capacity() - buffers_.size()), + std::min<std::size_t>(65536, + buffers_.max_size() - buffers_.size())); } } @@ -1034,10 +1288,10 @@ namespace detail break; // Start a new asynchronous read operation to obtain more data. - stream_.async_read_some(streambuf_.prepare(bytes_to_read), + stream_.async_read_some(buffers_.prepare(bytes_to_read), BOOST_ASIO_MOVE_CAST(read_until_match_op)(*this)); return; default: - streambuf_.commit(bytes_transferred); + buffers_.commit(bytes_transferred); if (ec || bytes_transferred == 0) break; } @@ -1056,71 +1310,113 @@ namespace detail //private: AsyncReadStream& stream_; - boost::asio::basic_streambuf<Allocator>& streambuf_; + DynamicBuffer buffers_; MatchCondition match_condition_; int start_; std::size_t search_position_; ReadHandler handler_; }; - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBuffer, typename MatchCondition, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, - read_until_match_op<AsyncReadStream, - Allocator, MatchCondition, ReadHandler>* this_handler) + read_until_match_op<AsyncReadStream, DynamicBuffer, + MatchCondition, ReadHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBuffer, typename MatchCondition, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_match_op<AsyncReadStream, - Allocator, MatchCondition, ReadHandler>* this_handler) + read_until_match_op<AsyncReadStream, DynamicBuffer, + MatchCondition, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename AsyncReadStream, typename Allocator, + template <typename AsyncReadStream, typename DynamicBuffer, typename MatchCondition, typename ReadHandler> inline bool asio_handler_is_continuation( - read_until_match_op<AsyncReadStream, - Allocator, MatchCondition, ReadHandler>* this_handler) + read_until_match_op<AsyncReadStream, DynamicBuffer, + MatchCondition, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename AsyncReadStream, typename Allocator, - typename MatchCondition, typename ReadHandler> + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer, typename MatchCondition, + typename ReadHandler> inline void asio_handler_invoke(Function& function, - read_until_match_op<AsyncReadStream, - Allocator, MatchCondition, ReadHandler>* this_handler) + read_until_match_op<AsyncReadStream, DynamicBuffer, + MatchCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } - template <typename Function, typename AsyncReadStream, typename Allocator, - typename MatchCondition, typename ReadHandler> + template <typename Function, typename AsyncReadStream, + typename DynamicBuffer, typename MatchCondition, + typename ReadHandler> inline void asio_handler_invoke(const Function& function, - read_until_match_op<AsyncReadStream, - Allocator, MatchCondition, ReadHandler>* this_handler) + read_until_match_op<AsyncReadStream, DynamicBuffer, + MatchCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail -template <typename AsyncReadStream, typename Allocator, +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer, + typename MatchCondition, typename ReadHandler, typename Allocator> +struct associated_allocator< + detail::read_until_match_op<AsyncReadStream, + DynamicBuffer, MatchCondition, ReadHandler>, + Allocator> +{ + typedef typename associated_allocator<ReadHandler, Allocator>::type type; + + static type get( + const detail::read_until_match_op<AsyncReadStream, + DynamicBuffer, MatchCondition, ReadHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncReadStream, typename DynamicBuffer, + typename MatchCondition, typename ReadHandler, typename Executor> +struct associated_executor< + detail::read_until_match_op<AsyncReadStream, + DynamicBuffer, MatchCondition, ReadHandler>, + Executor> +{ + typedef typename associated_executor<ReadHandler, Executor>::type type; + + static type get( + const detail::read_until_match_op<AsyncReadStream, + DynamicBuffer, MatchCondition, ReadHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncReadStream, typename DynamicBuffer, typename MatchCondition, typename ReadHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, typename enable_if<is_match_condition<MatchCondition>::value>::type*) { @@ -1128,19 +1424,76 @@ async_read_until(AsyncReadStream& s, // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); - detail::read_until_match_op<AsyncReadStream, Allocator, - MatchCondition, BOOST_ASIO_HANDLER_TYPE(ReadHandler, - void (boost::system::error_code, std::size_t))>( - s, b, match_condition, init.handler)( - boost::system::error_code(), 0, 1); + detail::read_until_match_op<AsyncReadStream, + typename decay<DynamicBuffer>::type, + MatchCondition, BOOST_ASIO_HANDLER_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t))>( + s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + match_condition, init.completion_handler)( + boost::system::error_code(), 0, 1); return init.result.get(); } +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf<Allocator>& b, + char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read_until(s, basic_streambuf_ref<Allocator>(b), + delim, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf<Allocator>& b, + BOOST_ASIO_STRING_VIEW_PARAM delim, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read_until(s, basic_streambuf_ref<Allocator>(b), + delim, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) + +template <typename AsyncReadStream, typename Allocator, typename ReadHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read_until(s, basic_streambuf_ref<Allocator>(b), + expr, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + +template <typename AsyncReadStream, typename Allocator, + typename MatchCondition, typename ReadHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf<Allocator>& b, + MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if<is_match_condition<MatchCondition>::value>::type*) +{ + return async_read_until(s, basic_streambuf_ref<Allocator>(b), + match_condition, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + } // namespace asio } // namespace boost diff --git a/boost/asio/impl/serial_port_base.ipp b/boost/asio/impl/serial_port_base.ipp index fcb6ce3df4..25a8a60ba0 100644 --- a/boost/asio/impl/serial_port_base.ipp +++ b/boost/asio/impl/serial_port_base.ipp @@ -38,7 +38,7 @@ namespace boost { namespace asio { -boost::system::error_code serial_port_base::baud_rate::store( +BOOST_ASIO_SYNC_OP_VOID serial_port_base::baud_rate::store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) @@ -112,9 +112,9 @@ boost::system::error_code serial_port_base::baud_rate::store( # endif default: ec = boost::asio::error::invalid_argument; - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } -# if defined(_BSD_SOURCE) +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) ::cfsetspeed(&storage, baud); # else ::cfsetispeed(&storage, baud); @@ -122,10 +122,10 @@ boost::system::error_code serial_port_base::baud_rate::store( # endif #endif ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } -boost::system::error_code serial_port_base::baud_rate::load( +BOOST_ASIO_SYNC_OP_VOID serial_port_base::baud_rate::load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) @@ -200,11 +200,11 @@ boost::system::error_code serial_port_base::baud_rate::load( default: value_ = 0; ec = boost::asio::error::invalid_argument; - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } #endif ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } serial_port_base::flow_control::flow_control( @@ -218,7 +218,7 @@ serial_port_base::flow_control::flow_control( } } -boost::system::error_code serial_port_base::flow_control::store( +BOOST_ASIO_SYNC_OP_VOID serial_port_base::flow_control::store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) @@ -250,7 +250,7 @@ boost::system::error_code serial_port_base::flow_control::store( { case none: storage.c_iflag &= ~(IXOFF | IXON); -# if defined(_BSD_SOURCE) +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) storage.c_cflag &= ~CRTSCTS; # elif defined(__QNXNTO__) storage.c_cflag &= ~(IHFLOW | OHFLOW); @@ -258,14 +258,14 @@ boost::system::error_code serial_port_base::flow_control::store( break; case software: storage.c_iflag |= IXOFF | IXON; -# if defined(_BSD_SOURCE) +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) storage.c_cflag &= ~CRTSCTS; # elif defined(__QNXNTO__) storage.c_cflag &= ~(IHFLOW | OHFLOW); # endif break; case hardware: -# if defined(_BSD_SOURCE) +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) storage.c_iflag &= ~(IXOFF | IXON); storage.c_cflag |= CRTSCTS; break; @@ -275,17 +275,17 @@ boost::system::error_code serial_port_base::flow_control::store( break; # else ec = boost::asio::error::operation_not_supported; - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); # endif default: break; } #endif ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } -boost::system::error_code serial_port_base::flow_control::load( +BOOST_ASIO_SYNC_OP_VOID serial_port_base::flow_control::load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) @@ -306,7 +306,7 @@ boost::system::error_code serial_port_base::flow_control::load( { value_ = software; } -# if defined(_BSD_SOURCE) +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) else if (storage.c_cflag & CRTSCTS) { value_ = hardware; @@ -323,7 +323,7 @@ boost::system::error_code serial_port_base::flow_control::load( } #endif ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } serial_port_base::parity::parity(serial_port_base::parity::type t) @@ -336,7 +336,7 @@ serial_port_base::parity::parity(serial_port_base::parity::type t) } } -boost::system::error_code serial_port_base::parity::store( +BOOST_ASIO_SYNC_OP_VOID serial_port_base::parity::store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) @@ -380,10 +380,10 @@ boost::system::error_code serial_port_base::parity::store( } #endif ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } -boost::system::error_code serial_port_base::parity::load( +BOOST_ASIO_SYNC_OP_VOID serial_port_base::parity::load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) @@ -417,7 +417,7 @@ boost::system::error_code serial_port_base::parity::load( } #endif ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } serial_port_base::stop_bits::stop_bits( @@ -431,7 +431,7 @@ serial_port_base::stop_bits::stop_bits( } } -boost::system::error_code serial_port_base::stop_bits::store( +BOOST_ASIO_SYNC_OP_VOID serial_port_base::stop_bits::store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) @@ -460,14 +460,14 @@ boost::system::error_code serial_port_base::stop_bits::store( break; default: ec = boost::asio::error::operation_not_supported; - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } #endif ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } -boost::system::error_code serial_port_base::stop_bits::load( +BOOST_ASIO_SYNC_OP_VOID serial_port_base::stop_bits::load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) @@ -491,7 +491,7 @@ boost::system::error_code serial_port_base::stop_bits::load( value_ = (storage.c_cflag & CSTOPB) ? two : one; #endif ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } serial_port_base::character_size::character_size(unsigned int t) @@ -504,7 +504,7 @@ serial_port_base::character_size::character_size(unsigned int t) } } -boost::system::error_code serial_port_base::character_size::store( +BOOST_ASIO_SYNC_OP_VOID serial_port_base::character_size::store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) @@ -521,10 +521,10 @@ boost::system::error_code serial_port_base::character_size::store( } #endif ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } -boost::system::error_code serial_port_base::character_size::load( +BOOST_ASIO_SYNC_OP_VOID serial_port_base::character_size::load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) @@ -541,7 +541,7 @@ boost::system::error_code serial_port_base::character_size::load( } #endif ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } // namespace asio diff --git a/boost/asio/impl/spawn.hpp b/boost/asio/impl/spawn.hpp index a42fc6fbad..ec1ff45d19 100644 --- a/boost/asio/impl/spawn.hpp +++ b/boost/asio/impl/spawn.hpp @@ -16,14 +16,18 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/associated_executor.hpp> #include <boost/asio/async_result.hpp> +#include <boost/asio/bind_executor.hpp> #include <boost/asio/detail/atomic_count.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/noncopyable.hpp> -#include <boost/asio/detail/shared_ptr.hpp> -#include <boost/asio/handler_type.hpp> +#include <boost/asio/detail/type_traits.hpp> +#include <boost/system/system_error.hpp> #include <boost/asio/detail/push_options.hpp> @@ -64,7 +68,7 @@ namespace detail { //private: shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_; typename basic_yield_context<Handler>::caller_type& ca_; - Handler& handler_; + Handler handler_; atomic_count* ready_; boost::system::error_code* ec_; T* value_; @@ -100,7 +104,7 @@ namespace detail { //private: shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_; typename basic_yield_context<Handler>::caller_type& ca_; - Handler& handler_; + Handler handler_; atomic_count* ready_; boost::system::error_code* ec_; }; @@ -143,11 +147,140 @@ namespace detail { function, this_handler->handler_); } + template <typename Handler, typename T> + class coro_async_result + { + public: + typedef coro_handler<Handler, T> completion_handler_type; + typedef T return_type; + + explicit coro_async_result(completion_handler_type& h) + : handler_(h), + ca_(h.ca_), + ready_(2) + { + h.ready_ = &ready_; + out_ec_ = h.ec_; + if (!out_ec_) h.ec_ = &ec_; + h.value_ = &value_; + } + + return_type get() + { + // Must not hold shared_ptr to coro while suspended. + handler_.coro_.reset(); + + if (--ready_ != 0) + ca_(); + if (!out_ec_ && ec_) throw boost::system::system_error(ec_); + return BOOST_ASIO_MOVE_CAST(return_type)(value_); + } + + private: + completion_handler_type& handler_; + typename basic_yield_context<Handler>::caller_type& ca_; + atomic_count ready_; + boost::system::error_code* out_ec_; + boost::system::error_code ec_; + return_type value_; + }; + + template <typename Handler> + class coro_async_result<Handler, void> + { + public: + typedef coro_handler<Handler, void> completion_handler_type; + typedef void return_type; + + explicit coro_async_result(completion_handler_type& h) + : handler_(h), + ca_(h.ca_), + ready_(2) + { + h.ready_ = &ready_; + out_ec_ = h.ec_; + if (!out_ec_) h.ec_ = &ec_; + } + + void get() + { + // Must not hold shared_ptr to coro while suspended. + handler_.coro_.reset(); + + if (--ready_ != 0) + ca_(); + if (!out_ec_ && ec_) throw boost::system::system_error(ec_); + } + + private: + completion_handler_type& handler_; + typename basic_yield_context<Handler>::caller_type& ca_; + atomic_count ready_; + boost::system::error_code* out_ec_; + boost::system::error_code ec_; + }; + } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename Handler, typename ReturnType> +class async_result<basic_yield_context<Handler>, ReturnType()> + : public detail::coro_async_result<Handler, void> +{ +public: + explicit async_result( + typename detail::coro_async_result<Handler, + void>::completion_handler_type& h) + : detail::coro_async_result<Handler, void>(h) + { + } +}; + +template <typename Handler, typename ReturnType, typename Arg1> +class async_result<basic_yield_context<Handler>, ReturnType(Arg1)> + : public detail::coro_async_result<Handler, typename decay<Arg1>::type> +{ +public: + explicit async_result( + typename detail::coro_async_result<Handler, + typename decay<Arg1>::type>::completion_handler_type& h) + : detail::coro_async_result<Handler, Arg1>(h) + { + } +}; + +template <typename Handler, typename ReturnType> +class async_result<basic_yield_context<Handler>, + ReturnType(boost::system::error_code)> + : public detail::coro_async_result<Handler, void> +{ +public: + explicit async_result( + typename detail::coro_async_result<Handler, + void>::completion_handler_type& h) + : detail::coro_async_result<Handler, void>(h) + { + } +}; + +template <typename Handler, typename ReturnType, typename Arg2> +class async_result<basic_yield_context<Handler>, + ReturnType(boost::system::error_code, Arg2)> + : public detail::coro_async_result<Handler, typename decay<Arg2>::type> +{ +public: + explicit async_result( + typename detail::coro_async_result<Handler, + typename decay<Arg2>::type>::completion_handler_type& h) + : detail::coro_async_result<Handler, Arg2>(h) + { + } +}; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +template <typename Handler, typename ReturnType> struct handler_type<basic_yield_context<Handler>, ReturnType()> { typedef detail::coro_handler<Handler, void> type; @@ -156,7 +289,7 @@ struct handler_type<basic_yield_context<Handler>, ReturnType()> template <typename Handler, typename ReturnType, typename Arg1> struct handler_type<basic_yield_context<Handler>, ReturnType(Arg1)> { - typedef detail::coro_handler<Handler, Arg1> type; + typedef detail::coro_handler<Handler, typename decay<Arg1>::type> type; }; template <typename Handler, typename ReturnType> @@ -170,74 +303,48 @@ template <typename Handler, typename ReturnType, typename Arg2> struct handler_type<basic_yield_context<Handler>, ReturnType(boost::system::error_code, Arg2)> { - typedef detail::coro_handler<Handler, Arg2> type; + typedef detail::coro_handler<Handler, typename decay<Arg2>::type> type; }; template <typename Handler, typename T> class async_result<detail::coro_handler<Handler, T> > + : public detail::coro_async_result<Handler, T> { public: - typedef T type; - - explicit async_result(detail::coro_handler<Handler, T>& h) - : handler_(h), - ca_(h.ca_), - ready_(2) - { - h.ready_ = &ready_; - out_ec_ = h.ec_; - if (!out_ec_) h.ec_ = &ec_; - h.value_ = &value_; - } + typedef typename detail::coro_async_result<Handler, T>::return_type type; - type get() + explicit async_result( + typename detail::coro_async_result<Handler, + void>::completion_handler_type& h) + : detail::coro_async_result<Handler, T>(h) { - handler_.coro_.reset(); // Must not hold shared_ptr to coro while suspended. - if (--ready_ != 0) - ca_(); - if (!out_ec_ && ec_) throw boost::system::system_error(ec_); - return BOOST_ASIO_MOVE_CAST(type)(value_); } - -private: - detail::coro_handler<Handler, T>& handler_; - typename basic_yield_context<Handler>::caller_type& ca_; - detail::atomic_count ready_; - boost::system::error_code* out_ec_; - boost::system::error_code ec_; - type value_; }; -template <typename Handler> -class async_result<detail::coro_handler<Handler, void> > +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +template <typename Handler, typename T, typename Allocator> +struct associated_allocator<detail::coro_handler<Handler, T>, Allocator> { -public: - typedef void type; + typedef typename associated_allocator<Handler, Allocator>::type type; - explicit async_result(detail::coro_handler<Handler, void>& h) - : handler_(h), - ca_(h.ca_), - ready_(2) + static type get(const detail::coro_handler<Handler, T>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { - h.ready_ = &ready_; - out_ec_ = h.ec_; - if (!out_ec_) h.ec_ = &ec_; + return associated_allocator<Handler, Allocator>::get(h.handler_, a); } +}; + +template <typename Handler, typename T, typename Executor> +struct associated_executor<detail::coro_handler<Handler, T>, Executor> +{ + typedef typename associated_executor<Handler, Executor>::type type; - void get() + static type get(const detail::coro_handler<Handler, T>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { - handler_.coro_.reset(); // Must not hold shared_ptr to coro while suspended. - if (--ready_ != 0) - ca_(); - if (!out_ec_ && ec_) throw boost::system::system_error(ec_); + return associated_executor<Handler, Executor>::get(h.handler_, ex); } - -private: - detail::coro_handler<Handler, void>& handler_; - typename basic_yield_context<Handler>::caller_type& ca_; - detail::atomic_count ready_; - boost::system::error_code* out_ec_; - boost::system::error_code ec_; }; namespace detail { @@ -270,6 +377,7 @@ namespace detail { #endif // !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2) const basic_yield_context<Handler> yield( data->coro_, ca, data->handler_); + (data->function_)(yield); if (data->call_handler_) (data->handler_)(); @@ -294,22 +402,61 @@ namespace detail { boost::coroutines::attributes attributes_; }; + template <typename Function, typename Handler, typename Function1> + inline void asio_handler_invoke(Function& function, + spawn_helper<Handler, Function1>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->data_->handler_); + } + + template <typename Function, typename Handler, typename Function1> + inline void asio_handler_invoke(const Function& function, + spawn_helper<Handler, Function1>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->data_->handler_); + } + inline void default_spawn_handler() {} } // namespace detail +template <typename Function> +inline void spawn(BOOST_ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes) +{ + typedef typename decay<Function>::type function_type; + + typename associated_executor<function_type>::type ex( + (get_associated_executor)(function)); + + boost::asio::spawn(ex, BOOST_ASIO_MOVE_CAST(Function)(function), attributes); +} + template <typename Handler, typename Function> void spawn(BOOST_ASIO_MOVE_ARG(Handler) handler, BOOST_ASIO_MOVE_ARG(Function) function, - const boost::coroutines::attributes& attributes) + const boost::coroutines::attributes& attributes, + typename enable_if<!is_executor<typename decay<Handler>::type>::value && + !is_convertible<Handler&, execution_context&>::value>::type*) { - detail::spawn_helper<Handler, Function> helper; + typedef typename decay<Handler>::type handler_type; + + typename associated_executor<handler_type>::type ex( + (get_associated_executor)(handler)); + + typename associated_allocator<handler_type>::type a( + (get_associated_allocator)(handler)); + + detail::spawn_helper<handler_type, Function> helper; helper.data_.reset( - new detail::spawn_data<Handler, Function>( + new detail::spawn_data<handler_type, Function>( BOOST_ASIO_MOVE_CAST(Handler)(handler), true, BOOST_ASIO_MOVE_CAST(Function)(function))); helper.attributes_ = attributes; - boost_asio_handler_invoke_helpers::invoke(helper, helper.data_->handler_); + + ex.dispatch(helper, a); } template <typename Handler, typename Function> @@ -318,30 +465,61 @@ void spawn(basic_yield_context<Handler> ctx, const boost::coroutines::attributes& attributes) { Handler handler(ctx.handler_); // Explicit copy that might be moved from. + + typename associated_executor<Handler>::type ex( + (get_associated_executor)(handler)); + + typename associated_allocator<Handler>::type a( + (get_associated_allocator)(handler)); + detail::spawn_helper<Handler, Function> helper; helper.data_.reset( new detail::spawn_data<Handler, Function>( BOOST_ASIO_MOVE_CAST(Handler)(handler), false, BOOST_ASIO_MOVE_CAST(Function)(function))); helper.attributes_ = attributes; - boost_asio_handler_invoke_helpers::invoke(helper, helper.data_->handler_); + + ex.dispatch(helper, a); } -template <typename Function> -void spawn(boost::asio::io_service::strand strand, +template <typename Function, typename Executor> +inline void spawn(const Executor& ex, + BOOST_ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes, + typename enable_if<is_executor<Executor>::value>::type*) +{ + boost::asio::spawn(boost::asio::strand<Executor>(ex), + BOOST_ASIO_MOVE_CAST(Function)(function), attributes); +} + +template <typename Function, typename Executor> +inline void spawn(const strand<Executor>& ex, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes) { - boost::asio::spawn(strand.wrap(&detail::default_spawn_handler), + boost::asio::spawn(boost::asio::bind_executor( + ex, &detail::default_spawn_handler), BOOST_ASIO_MOVE_CAST(Function)(function), attributes); } template <typename Function> -void spawn(boost::asio::io_service& io_service, +inline void spawn(const boost::asio::io_context::strand& s, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes) { - boost::asio::spawn(boost::asio::io_service::strand(io_service), + boost::asio::spawn(boost::asio::bind_executor( + s, &detail::default_spawn_handler), + BOOST_ASIO_MOVE_CAST(Function)(function), attributes); +} + +template <typename Function, typename ExecutionContext> +inline void spawn(ExecutionContext& ctx, + BOOST_ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes, + typename enable_if<is_convertible< + ExecutionContext&, execution_context&>::value>::type*) +{ + boost::asio::spawn(ctx.get_executor(), BOOST_ASIO_MOVE_CAST(Function)(function), attributes); } diff --git a/boost/asio/impl/src.hpp b/boost/asio/impl/src.hpp index 7b9a03eda9..ad75cb744d 100644 --- a/boost/asio/impl/src.hpp +++ b/boost/asio/impl/src.hpp @@ -20,9 +20,13 @@ #endif #include <boost/asio/impl/error.ipp> +#include <boost/asio/impl/execution_context.ipp> +#include <boost/asio/impl/executor.ipp> #include <boost/asio/impl/handler_alloc_hook.ipp> -#include <boost/asio/impl/io_service.ipp> +#include <boost/asio/impl/io_context.ipp> #include <boost/asio/impl/serial_port_base.ipp> +#include <boost/asio/impl/system_context.ipp> +#include <boost/asio/impl/thread_pool.ipp> #include <boost/asio/detail/impl/buffer_sequence_adapter.ipp> #include <boost/asio/detail/impl/descriptor_ops.ipp> #include <boost/asio/detail/impl/dev_poll_reactor.ipp> @@ -30,6 +34,7 @@ #include <boost/asio/detail/impl/eventfd_select_interrupter.ipp> #include <boost/asio/detail/impl/handler_tracking.ipp> #include <boost/asio/detail/impl/kqueue_reactor.ipp> +#include <boost/asio/detail/impl/null_event.ipp> #include <boost/asio/detail/impl/pipe_select_interrupter.ipp> #include <boost/asio/detail/impl/posix_event.ipp> #include <boost/asio/detail/impl/posix_mutex.ipp> @@ -39,18 +44,19 @@ #include <boost/asio/detail/impl/reactive_serial_port_service.ipp> #include <boost/asio/detail/impl/reactive_socket_service_base.ipp> #include <boost/asio/detail/impl/resolver_service_base.ipp> +#include <boost/asio/detail/impl/scheduler.ipp> #include <boost/asio/detail/impl/select_reactor.ipp> #include <boost/asio/detail/impl/service_registry.ipp> #include <boost/asio/detail/impl/signal_set_service.ipp> #include <boost/asio/detail/impl/socket_ops.ipp> #include <boost/asio/detail/impl/socket_select_interrupter.ipp> +#include <boost/asio/detail/impl/strand_executor_service.ipp> #include <boost/asio/detail/impl/strand_service.ipp> -#include <boost/asio/detail/impl/task_io_service.ipp> #include <boost/asio/detail/impl/throw_error.ipp> #include <boost/asio/detail/impl/timer_queue_ptime.ipp> #include <boost/asio/detail/impl/timer_queue_set.ipp> #include <boost/asio/detail/impl/win_iocp_handle_service.ipp> -#include <boost/asio/detail/impl/win_iocp_io_service.ipp> +#include <boost/asio/detail/impl/win_iocp_io_context.ipp> #include <boost/asio/detail/impl/win_iocp_serial_port_service.ipp> #include <boost/asio/detail/impl/win_iocp_socket_service_base.ipp> #include <boost/asio/detail/impl/win_event.ipp> @@ -67,6 +73,8 @@ #include <boost/asio/ip/impl/address_v4.ipp> #include <boost/asio/ip/impl/address_v6.ipp> #include <boost/asio/ip/impl/host_name.ipp> +#include <boost/asio/ip/impl/network_v4.ipp> +#include <boost/asio/ip/impl/network_v6.ipp> #include <boost/asio/ip/detail/impl/endpoint.ipp> #include <boost/asio/local/detail/impl/endpoint.ipp> diff --git a/boost/asio/ssl/context_service.hpp b/boost/asio/impl/system_context.hpp index b0a31f3750..88d42e51f9 100644 --- a/boost/asio/ssl/context_service.hpp +++ b/boost/asio/impl/system_context.hpp @@ -1,5 +1,5 @@ // -// ssl/context_service.hpp +// impl/system_context.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -8,35 +8,29 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_SSL_CONTEXT_SERVICE_HPP -#define BOOST_ASIO_SSL_CONTEXT_SERVICE_HPP +#ifndef BOOST_ASIO_IMPL_SYSTEM_CONTEXT_HPP +#define BOOST_ASIO_IMPL_SYSTEM_CONTEXT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include <boost/asio/detail/config.hpp> - -#if defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/ssl/old/context_service.hpp> -#endif // defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <boost/asio/system_executor.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { -namespace ssl { -#if defined(BOOST_ASIO_ENABLE_OLD_SSL) +inline system_context::executor_type +system_context::get_executor() BOOST_ASIO_NOEXCEPT +{ + return system_executor(); +} -using boost::asio::ssl::old::context_service; - -#endif // defined(BOOST_ASIO_ENABLE_OLD_SSL) - -} // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> -#endif // BOOST_ASIO_SSL_CONTEXT_SERVICE_HPP +#endif // BOOST_ASIO_IMPL_SYSTEM_CONTEXT_HPP diff --git a/boost/asio/impl/system_context.ipp b/boost/asio/impl/system_context.ipp new file mode 100644 index 0000000000..86bb44548f --- /dev/null +++ b/boost/asio/impl/system_context.ipp @@ -0,0 +1,75 @@ +// +// impl/system_context.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IMPL_SYSTEM_CONTEXT_IPP +#define BOOST_ASIO_IMPL_SYSTEM_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/system_context.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +struct system_context::thread_function +{ + detail::scheduler* scheduler_; + + void operator()() + { + boost::system::error_code ec; + scheduler_->run(ec); + } +}; + +system_context::system_context() + : scheduler_(use_service<detail::scheduler>(*this)) +{ + scheduler_.work_started(); + + thread_function f = { &scheduler_ }; + std::size_t num_threads = detail::thread::hardware_concurrency() * 2; + threads_.create_threads(f, num_threads ? num_threads : 2); +} + +system_context::~system_context() +{ + scheduler_.work_finished(); + scheduler_.stop(); + threads_.join(); +} + +void system_context::stop() +{ + scheduler_.stop(); +} + +bool system_context::stopped() const BOOST_ASIO_NOEXCEPT +{ + return scheduler_.stopped(); +} + +void system_context::join() +{ + scheduler_.work_finished(); + threads_.join(); +} + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_SYSTEM_CONTEXT_IPP diff --git a/boost/asio/impl/system_executor.hpp b/boost/asio/impl/system_executor.hpp new file mode 100644 index 0000000000..c8a0cf4027 --- /dev/null +++ b/boost/asio/impl/system_executor.hpp @@ -0,0 +1,87 @@ +// +// impl/system_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IMPL_SYSTEM_EXECUTOR_HPP +#define BOOST_ASIO_IMPL_SYSTEM_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/executor_op.hpp> +#include <boost/asio/detail/global.hpp> +#include <boost/asio/detail/recycling_allocator.hpp> +#include <boost/asio/detail/type_traits.hpp> +#include <boost/asio/system_context.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +inline system_context& system_executor::context() const BOOST_ASIO_NOEXCEPT +{ + return detail::global<system_context>(); +} + +template <typename Function, typename Allocator> +void system_executor::dispatch( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator&) const +{ + typename decay<Function>::type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); + boost_asio_handler_invoke_helpers::invoke(tmp, tmp); +} + +template <typename Function, typename Allocator> +void system_executor::post( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay<Function>::type function_type; + + system_context& ctx = detail::global<system_context>(); + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); + + BOOST_ASIO_HANDLER_CREATION((ctx, *p.p, + "system_executor", &this->context(), 0, "post")); + + ctx.scheduler_.post_immediate_completion(p.p, false); + p.v = p.p = 0; +} + +template <typename Function, typename Allocator> +void system_executor::defer( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay<Function>::type function_type; + + system_context& ctx = detail::global<system_context>(); + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); + + BOOST_ASIO_HANDLER_CREATION((ctx, *p.p, + "system_executor", &this->context(), 0, "defer")); + + ctx.scheduler_.post_immediate_completion(p.p, true); + p.v = p.p = 0; +} + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_SYSTEM_EXECUTOR_HPP diff --git a/boost/asio/impl/thread_pool.hpp b/boost/asio/impl/thread_pool.hpp new file mode 100644 index 0000000000..53a4900d34 --- /dev/null +++ b/boost/asio/impl/thread_pool.hpp @@ -0,0 +1,129 @@ +// +// impl/thread_pool.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IMPL_THREAD_POOL_HPP +#define BOOST_ASIO_IMPL_THREAD_POOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/executor_op.hpp> +#include <boost/asio/detail/fenced_block.hpp> +#include <boost/asio/detail/recycling_allocator.hpp> +#include <boost/asio/detail/type_traits.hpp> +#include <boost/asio/execution_context.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +inline thread_pool::executor_type +thread_pool::get_executor() BOOST_ASIO_NOEXCEPT +{ + return executor_type(*this); +} + +inline thread_pool& +thread_pool::executor_type::context() const BOOST_ASIO_NOEXCEPT +{ + return pool_; +} + +inline void +thread_pool::executor_type::on_work_started() const BOOST_ASIO_NOEXCEPT +{ + pool_.scheduler_.work_started(); +} + +inline void thread_pool::executor_type::on_work_finished() +const BOOST_ASIO_NOEXCEPT +{ + pool_.scheduler_.work_finished(); +} + +template <typename Function, typename Allocator> +void thread_pool::executor_type::dispatch( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay<Function>::type function_type; + + // Invoke immediately if we are already inside the thread pool. + if (pool_.scheduler_.can_dispatch()) + { + // Make a local, non-const copy of the function. + function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); + + detail::fenced_block b(detail::fenced_block::full); + boost_asio_handler_invoke_helpers::invoke(tmp, tmp); + return; + } + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); + + BOOST_ASIO_HANDLER_CREATION((pool_, *p.p, + "thread_pool", &this->context(), 0, "dispatch")); + + pool_.scheduler_.post_immediate_completion(p.p, false); + p.v = p.p = 0; +} + +template <typename Function, typename Allocator> +void thread_pool::executor_type::post( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay<Function>::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); + + BOOST_ASIO_HANDLER_CREATION((pool_, *p.p, + "thread_pool", &this->context(), 0, "post")); + + pool_.scheduler_.post_immediate_completion(p.p, false); + p.v = p.p = 0; +} + +template <typename Function, typename Allocator> +void thread_pool::executor_type::defer( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay<Function>::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); + + BOOST_ASIO_HANDLER_CREATION((pool_, *p.p, + "thread_pool", &this->context(), 0, "defer")); + + pool_.scheduler_.post_immediate_completion(p.p, true); + p.v = p.p = 0; +} + +inline bool +thread_pool::executor_type::running_in_this_thread() const BOOST_ASIO_NOEXCEPT +{ + return pool_.scheduler_.can_dispatch(); +} + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_THREAD_POOL_HPP diff --git a/boost/asio/impl/thread_pool.ipp b/boost/asio/impl/thread_pool.ipp new file mode 100644 index 0000000000..43ae029359 --- /dev/null +++ b/boost/asio/impl/thread_pool.ipp @@ -0,0 +1,78 @@ +// +// impl/thread_pool.ipp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IMPL_THREAD_POOL_IPP +#define BOOST_ASIO_IMPL_THREAD_POOL_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/thread_pool.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +struct thread_pool::thread_function +{ + detail::scheduler* scheduler_; + + void operator()() + { + boost::system::error_code ec; + scheduler_->run(ec); + } +}; + +thread_pool::thread_pool() + : scheduler_(use_service<detail::scheduler>(*this)) +{ + scheduler_.work_started(); + + thread_function f = { &scheduler_ }; + std::size_t num_threads = detail::thread::hardware_concurrency() * 2; + threads_.create_threads(f, num_threads ? num_threads : 2); +} + +thread_pool::thread_pool(std::size_t num_threads) + : scheduler_(use_service<detail::scheduler>(*this)) +{ + scheduler_.work_started(); + + thread_function f = { &scheduler_ }; + threads_.create_threads(f, num_threads); +} + +thread_pool::~thread_pool() +{ + stop(); + join(); +} + +void thread_pool::stop() +{ + scheduler_.stop(); +} + +void thread_pool::join() +{ + scheduler_.work_finished(); + threads_.join(); +} + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IMPL_THREAD_POOL_IPP diff --git a/boost/asio/impl/use_future.hpp b/boost/asio/impl/use_future.hpp index c74050ea63..e02dfeebd2 100644 --- a/boost/asio/impl/use_future.hpp +++ b/boost/asio/impl/use_future.hpp @@ -17,11 +17,13 @@ #include <boost/asio/detail/config.hpp> #include <future> +#include <tuple> #include <boost/asio/async_result.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/system/error_code.hpp> -#include <boost/asio/handler_type.hpp> +#include <boost/asio/packaged_task.hpp> #include <boost/system/system_error.hpp> -#include <boost/asio/detail/memory.hpp> +#include <boost/asio/system_executor.hpp> #include <boost/asio/detail/push_options.hpp> @@ -29,146 +31,905 @@ namespace boost { namespace asio { namespace detail { - // Completion handler to adapt a promise as a completion handler. - template <typename T> - class promise_handler - { - public: - // Construct from use_future special value. - template <typename Alloc> - promise_handler(use_future_t<Alloc> uf) - : promise_(std::allocate_shared<std::promise<T> >( - BOOST_ASIO_REBIND_ALLOC(Alloc, char)(uf.get_allocator()), - std::allocator_arg, - BOOST_ASIO_REBIND_ALLOC(Alloc, char)(uf.get_allocator()))) +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename T, typename F, typename... Args> +inline void promise_invoke_and_set(std::promise<T>& p, + F& f, BOOST_ASIO_MOVE_ARG(Args)... args) +{ +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + try +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + { + p.set_value(f(BOOST_ASIO_MOVE_CAST(Args)(args)...)); + } +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + catch (...) + { + p.set_exception(std::current_exception()); + } +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) +} + +template <typename F, typename... Args> +inline void promise_invoke_and_set(std::promise<void>& p, + F& f, BOOST_ASIO_MOVE_ARG(Args)... args) +{ +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + try +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + { + f(BOOST_ASIO_MOVE_CAST(Args)(args)...); + p.set_value(); + } +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + catch (...) + { + p.set_exception(std::current_exception()); + } +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) +} + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename T, typename F> +inline void promise_invoke_and_set(std::promise<T>& p, F& f) +{ +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + try +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + { + p.set_value(f()); + } +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + catch (...) + { + p.set_exception(std::current_exception()); + } +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) +} + +template <typename F, typename Args> +inline void promise_invoke_and_set(std::promise<void>& p, F& f) +{ +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + try +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + { + f(); + p.set_value(); +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + } + catch (...) + { + p.set_exception(std::current_exception()); + } +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) +} + +#if defined(BOOST_ASIO_NO_EXCEPTIONS) + +#define BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF(n) \ + template <typename T, typename F, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + inline void promise_invoke_and_set(std::promise<T>& p, \ + F& f, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + p.set_value(f(BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ + } \ + \ + template <typename F, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + inline void promise_invoke_and_set(std::promise<void>& p, \ + F& f, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + f(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + p.set_value(); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF) +#undef BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF + +#else // defined(BOOST_ASIO_NO_EXCEPTIONS) + +#define BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF(n) \ + template <typename T, typename F, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + inline void promise_invoke_and_set(std::promise<T>& p, \ + F& f, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + try \ + { \ + p.set_value(f(BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ + } \ + catch (...) \ + { \ + p.set_exception(std::current_exception()); \ + } \ + } \ + \ + template <typename F, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + inline void promise_invoke_and_set(std::promise<void>& p, \ + F& f, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + try \ + { \ + f(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + p.set_value(); \ + } \ + catch (...) \ + { \ + p.set_exception(std::current_exception()); \ + } \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF) +#undef BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF + +#endif // defined(BOOST_ASIO_NO_EXCEPTIONS) + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +// A function object adapter to invoke a nullary function object and capture +// any exception thrown into a promise. +template <typename T, typename F> +class promise_invoker +{ +public: + promise_invoker(const shared_ptr<std::promise<T> >& p, + BOOST_ASIO_MOVE_ARG(F) f) + : p_(p), f_(BOOST_ASIO_MOVE_CAST(F)(f)) + { + } + + void operator()() + { +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + try +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) { + f_(); } - - void operator()(T t) +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + catch (...) { - promise_->set_value(t); + p_->set_exception(std::current_exception()); } +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + } + +private: + shared_ptr<std::promise<T> > p_; + typename decay<F>::type f_; +}; + +// An executor that adapts the system_executor to capture any exeption thrown +// by a submitted function object and save it into a promise. +template <typename T> +class promise_executor +{ +public: + explicit promise_executor(const shared_ptr<std::promise<T> >& p) + : p_(p) + { + } + + execution_context& context() const BOOST_ASIO_NOEXCEPT + { + return system_executor().context(); + } + + void on_work_started() const BOOST_ASIO_NOEXCEPT {} + void on_work_finished() const BOOST_ASIO_NOEXCEPT {} + + template <typename F, typename A> + void dispatch(BOOST_ASIO_MOVE_ARG(F) f, const A&) const + { + promise_invoker<T, F>(p_, BOOST_ASIO_MOVE_CAST(F)(f))(); + } + + template <typename F, typename A> + void post(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const + { + system_executor().post( + promise_invoker<T, F>(p_, BOOST_ASIO_MOVE_CAST(F)(f)), a); + } + + template <typename F, typename A> + void defer(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const + { + system_executor().defer( + promise_invoker<T, F>(p_, BOOST_ASIO_MOVE_CAST(F)(f)), a); + } + + friend bool operator==(const promise_executor& a, + const promise_executor& b) BOOST_ASIO_NOEXCEPT + { + return a.p_ == b.p_; + } + + friend bool operator!=(const promise_executor& a, + const promise_executor& b) BOOST_ASIO_NOEXCEPT + { + return a.p_ != b.p_; + } + +private: + shared_ptr<std::promise<T> > p_; +}; + +// The base class for all completion handlers that create promises. +template <typename T> +class promise_creator +{ +public: + typedef promise_executor<T> executor_type; + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return executor_type(p_); + } + + typedef std::future<T> future_type; + + future_type get_future() + { + return p_->get_future(); + } + +protected: + template <typename Allocator> + void create_promise(const Allocator& a) + { + BOOST_ASIO_REBIND_ALLOC(Allocator, char) b(a); + p_ = std::allocate_shared<std::promise<T>>(b, std::allocator_arg, b); + } - void operator()(const boost::system::error_code& ec, T t) + shared_ptr<std::promise<T> > p_; +}; + +// For completion signature void(). +class promise_handler_0 + : public promise_creator<void> +{ +public: + void operator()() + { + this->p_->set_value(); + } +}; + +// For completion signature void(error_code). +class promise_handler_ec_0 + : public promise_creator<void> +{ +public: + void operator()(const boost::system::error_code& ec) + { + if (ec) { - if (ec) - promise_->set_exception( - std::make_exception_ptr( - boost::system::system_error(ec))); - else - promise_->set_value(t); + this->p_->set_exception( + std::make_exception_ptr( + boost::system::system_error(ec))); } - - //private: - std::shared_ptr<std::promise<T> > promise_; - }; - - // Completion handler to adapt a void promise as a completion handler. - template <> - class promise_handler<void> - { - public: - // Construct from use_future special value. Used during rebinding. - template <typename Alloc> - promise_handler(use_future_t<Alloc> uf) - : promise_(std::allocate_shared<std::promise<void> >( - BOOST_ASIO_REBIND_ALLOC(Alloc, char)(uf.get_allocator()), - std::allocator_arg, - BOOST_ASIO_REBIND_ALLOC(Alloc, char)(uf.get_allocator()))) + else { + this->p_->set_value(); } + } +}; - void operator()() +// For completion signature void(exception_ptr). +class promise_handler_ex_0 + : public promise_creator<void> +{ +public: + void operator()(const std::exception_ptr& ex) + { + if (ex) { - promise_->set_value(); + this->p_->set_exception(ex); } + else + { + this->p_->set_value(); + } + } +}; + +// For completion signature void(T). +template <typename T> +class promise_handler_1 + : public promise_creator<T> +{ +public: + template <typename Arg> + void operator()(BOOST_ASIO_MOVE_ARG(Arg) arg) + { + this->p_->set_value(BOOST_ASIO_MOVE_CAST(Arg)(arg)); + } +}; - void operator()(const boost::system::error_code& ec) +// For completion signature void(error_code, T). +template <typename T> +class promise_handler_ec_1 + : public promise_creator<T> +{ +public: + template <typename Arg> + void operator()(const boost::system::error_code& ec, + BOOST_ASIO_MOVE_ARG(Arg) arg) + { + if (ec) { - if (ec) - promise_->set_exception( - std::make_exception_ptr( - boost::system::system_error(ec))); - else - promise_->set_value(); + this->p_->set_exception( + std::make_exception_ptr( + boost::system::system_error(ec))); } + else + this->p_->set_value(BOOST_ASIO_MOVE_CAST(Arg)(arg)); + } +}; - //private: - std::shared_ptr<std::promise<void> > promise_; - }; +// For completion signature void(exception_ptr, T). +template <typename T> +class promise_handler_ex_1 + : public promise_creator<T> +{ +public: + template <typename Arg> + void operator()(const std::exception_ptr& ex, + BOOST_ASIO_MOVE_ARG(Arg) arg) + { + if (ex) + this->p_->set_exception(ex); + else + this->p_->set_value(BOOST_ASIO_MOVE_CAST(Arg)(arg)); + } +}; - // Ensure any exceptions thrown from the handler are propagated back to the - // caller via the future. - template <typename Function, typename T> - void asio_handler_invoke(Function f, promise_handler<T>* h) +// For completion signature void(T1, ..., Tn); +template <typename T> +class promise_handler_n + : public promise_creator<T> +{ +public: +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename... Args> + void operator()(BOOST_ASIO_MOVE_ARG(Args)... args) { - std::shared_ptr<std::promise<T> > p(h->promise_); - try + this->p_->set_value( + std::forward_as_tuple( + BOOST_ASIO_MOVE_CAST(Args)(args)...)); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#define BOOST_ASIO_PRIVATE_CALL_OP_DEF(n) \ + template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + void operator()(BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + {\ + this->p_->set_value( \ + std::forward_as_tuple( \ + BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CALL_OP_DEF) +#undef BOOST_ASIO_PRIVATE_CALL_OP_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +}; + +// For completion signature void(error_code, T1, ..., Tn); +template <typename T> +class promise_handler_ec_n + : public promise_creator<T> +{ +public: +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename... Args> + void operator()(const boost::system::error_code& ec, + BOOST_ASIO_MOVE_ARG(Args)... args) + { + if (ec) { - f(); + this->p_->set_exception( + std::make_exception_ptr( + boost::system::system_error(ec))); } - catch (...) + else { - p->set_exception(std::current_exception()); + this->p_->set_value( + std::forward_as_tuple( + BOOST_ASIO_MOVE_CAST(Args)(args)...)); } } -} // namespace detail +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) -#if !defined(GENERATING_DOCUMENTATION) +#define BOOST_ASIO_PRIVATE_CALL_OP_DEF(n) \ + template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + void operator()(const boost::system::error_code& ec, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + {\ + if (ec) \ + { \ + this->p_->set_exception( \ + std::make_exception_ptr( \ + boost::system::system_error(ec))); \ + } \ + else \ + { \ + this->p_->set_value( \ + std::forward_as_tuple( \ + BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ + } \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CALL_OP_DEF) +#undef BOOST_ASIO_PRIVATE_CALL_OP_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +}; -// Handler traits specialisation for promise_handler. +// For completion signature void(exception_ptr, T1, ..., Tn); template <typename T> -class async_result<detail::promise_handler<T> > +class promise_handler_ex_n + : public promise_creator<T> +{ +public: +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename... Args> + void operator()(const std::exception_ptr& ex, + BOOST_ASIO_MOVE_ARG(Args)... args) + { + if (ex) + this->p_->set_exception(ex); + else + { + this->p_->set_value( + std::forward_as_tuple( + BOOST_ASIO_MOVE_CAST(Args)(args)...)); + } + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#define BOOST_ASIO_PRIVATE_CALL_OP_DEF(n) \ + template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + void operator()(const std::exception_ptr& ex, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + {\ + if (ex) \ + this->p_->set_exception(ex); \ + else \ + { \ + this->p_->set_value( \ + std::forward_as_tuple( \ + BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ + } \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CALL_OP_DEF) +#undef BOOST_ASIO_PRIVATE_CALL_OP_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +}; + +// Helper template to choose the appropriate concrete promise handler +// implementation based on the supplied completion signature. +template <typename> class promise_handler_selector; + +template <> +class promise_handler_selector<void()> + : public promise_handler_0 {}; + +template <> +class promise_handler_selector<void(boost::system::error_code)> + : public promise_handler_ec_0 {}; + +template <> +class promise_handler_selector<void(std::exception_ptr)> + : public promise_handler_ex_0 {}; + +template <typename Arg> +class promise_handler_selector<void(Arg)> + : public promise_handler_1<Arg> {}; + +template <typename Arg> +class promise_handler_selector<void(boost::system::error_code, Arg)> + : public promise_handler_ec_1<Arg> {}; + +template <typename Arg> +class promise_handler_selector<void(std::exception_ptr, Arg)> + : public promise_handler_ex_1<Arg> {}; + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename... Arg> +class promise_handler_selector<void(Arg...)> + : public promise_handler_n<std::tuple<Arg...> > {}; + +template <typename... Arg> +class promise_handler_selector<void(boost::system::error_code, Arg...)> + : public promise_handler_ec_n<std::tuple<Arg...> > {}; + +template <typename... Arg> +class promise_handler_selector<void(std::exception_ptr, Arg...)> + : public promise_handler_ex_n<std::tuple<Arg...> > {}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#define BOOST_ASIO_PRIVATE_PROMISE_SELECTOR_DEF(n) \ + template <typename Arg, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + class promise_handler_selector< \ + void(Arg, BOOST_ASIO_VARIADIC_TARGS(n))> \ + : public promise_handler_n< \ + std::tuple<Arg, BOOST_ASIO_VARIADIC_TARGS(n)> > {}; \ + \ + template <typename Arg, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + class promise_handler_selector< \ + void(boost::system::error_code, Arg, BOOST_ASIO_VARIADIC_TARGS(n))> \ + : public promise_handler_ec_n< \ + std::tuple<Arg, BOOST_ASIO_VARIADIC_TARGS(n)> > {}; \ + \ + template <typename Arg, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + class promise_handler_selector< \ + void(std::exception_ptr, Arg, BOOST_ASIO_VARIADIC_TARGS(n))> \ + : public promise_handler_ex_n< \ + std::tuple<Arg, BOOST_ASIO_VARIADIC_TARGS(n)> > {}; \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_PROMISE_SELECTOR_DEF) +#undef BOOST_ASIO_PRIVATE_PROMISE_SELECTOR_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +// Completion handlers produced from the use_future completion token, when not +// using use_future::operator(). +template <typename Signature, typename Allocator> +class promise_handler + : public promise_handler_selector<Signature> { public: - // The initiating function will return a future. - typedef std::future<T> type; + typedef Allocator allocator_type; + typedef void result_type; - // Constructor creates a new promise for the async operation, and obtains the - // corresponding future. - explicit async_result(detail::promise_handler<T>& h) + promise_handler(use_future_t<Allocator> u) + : allocator_(u.get_allocator()) { - value_ = h.promise_->get_future(); + this->create_promise(allocator_); } - // Obtain the future to be returned from the initiating function. - type get() { return std::move(value_); } + allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT + { + return allocator_; + } private: - type value_; + Allocator allocator_; }; -// Handler type specialisation for use_future. -template <typename Allocator, typename ReturnType> -struct handler_type<use_future_t<Allocator>, ReturnType()> +template <typename Function, typename Signature, typename Allocator> +inline void asio_handler_invoke(Function& f, + promise_handler<Signature, Allocator>* h) { - typedef detail::promise_handler<void> type; + typename promise_handler<Signature, Allocator>::executor_type + ex(h->get_executor()); + ex.dispatch(BOOST_ASIO_MOVE_CAST(Function)(f), std::allocator<void>()); +} + +template <typename Function, typename Signature, typename Allocator> +inline void asio_handler_invoke(const Function& f, + promise_handler<Signature, Allocator>* h) +{ + typename promise_handler<Signature, Allocator>::executor_type + ex(h->get_executor()); + ex.dispatch(f, std::allocator<void>()); +} + +// Helper base class for async_result specialisation. +template <typename Signature, typename Allocator> +class promise_async_result +{ +public: + typedef promise_handler<Signature, Allocator> completion_handler_type; + typedef typename completion_handler_type::future_type return_type; + + explicit promise_async_result(completion_handler_type& h) + : future_(h.get_future()) + { + } + + return_type get() + { + return BOOST_ASIO_MOVE_CAST(return_type)(future_); + } + +private: + return_type future_; }; -// Handler type specialisation for use_future. -template <typename Allocator, typename ReturnType, typename Arg1> -struct handler_type<use_future_t<Allocator>, ReturnType(Arg1)> +// Return value from use_future::operator(). +template <typename Function, typename Allocator> +class packaged_token { - typedef detail::promise_handler<Arg1> type; +public: + packaged_token(Function f, const Allocator& a) + : function_(BOOST_ASIO_MOVE_CAST(Function)(f)), + allocator_(a) + { + } + +//private: + Function function_; + Allocator allocator_; }; -// Handler type specialisation for use_future. -template <typename Allocator, typename ReturnType> -struct handler_type<use_future_t<Allocator>, - ReturnType(boost::system::error_code)> +// Completion handlers produced from the use_future completion token, when +// using use_future::operator(). +template <typename Function, typename Allocator, typename Result> +class packaged_handler + : public promise_creator<Result> { - typedef detail::promise_handler<void> type; +public: + typedef Allocator allocator_type; + typedef void result_type; + + packaged_handler(packaged_token<Function, Allocator> t) + : function_(BOOST_ASIO_MOVE_CAST(Function)(t.function_)), + allocator_(t.allocator_) + { + this->create_promise(allocator_); + } + + allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT + { + return allocator_; + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template <typename... Args> + void operator()(BOOST_ASIO_MOVE_ARG(Args)... args) + { + (promise_invoke_and_set)(*this->p_, + function_, BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + void operator()() + { + (promise_invoke_and_set)(*this->p_, function_); + } + +#define BOOST_ASIO_PRIVATE_CALL_OP_DEF(n) \ + template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + void operator()(BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + {\ + (promise_invoke_and_set)(*this->p_, \ + function_, BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CALL_OP_DEF) +#undef BOOST_ASIO_PRIVATE_CALL_OP_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +private: + Function function_; + Allocator allocator_; +}; + +template <typename Function, + typename Function1, typename Allocator, typename Result> +inline void asio_handler_invoke(Function& f, + packaged_handler<Function1, Allocator, Result>* h) +{ + typename packaged_handler<Function1, Allocator, Result>::executor_type + ex(h->get_executor()); + ex.dispatch(BOOST_ASIO_MOVE_CAST(Function)(f), std::allocator<void>()); +} + +template <typename Function, + typename Function1, typename Allocator, typename Result> +inline void asio_handler_invoke(const Function& f, + packaged_handler<Function1, Allocator, Result>* h) +{ + typename packaged_handler<Function1, Allocator, Result>::executor_type + ex(h->get_executor()); + ex.dispatch(f, std::allocator<void>()); +} + +// Helper base class for async_result specialisation. +template <typename Function, typename Allocator, typename Result> +class packaged_async_result +{ +public: + typedef packaged_handler<Function, Allocator, Result> completion_handler_type; + typedef typename completion_handler_type::future_type return_type; + + explicit packaged_async_result(completion_handler_type& h) + : future_(h.get_future()) + { + } + + return_type get() + { + return BOOST_ASIO_MOVE_CAST(return_type)(future_); + } + +private: + return_type future_; +}; + +} // namespace detail + +template <typename Allocator> template <typename Function> +inline detail::packaged_token<typename decay<Function>::type, Allocator> +use_future_t<Allocator>::operator()(BOOST_ASIO_MOVE_ARG(Function) f) const +{ + return detail::packaged_token<typename decay<Function>::type, Allocator>( + BOOST_ASIO_MOVE_CAST(Function)(f), allocator_); +} + +#if !defined(GENERATING_DOCUMENTATION) + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename Allocator, typename Result, typename... Args> +class async_result<use_future_t<Allocator>, Result(Args...)> + : public detail::promise_async_result< + void(typename decay<Args>::type...), Allocator> +{ +public: + explicit async_result( + typename detail::promise_async_result<void(typename decay<Args>::type...), + Allocator>::completion_handler_type& h) + : detail::promise_async_result< + void(typename decay<Args>::type...), Allocator>(h) + { + } +}; + +template <typename Function, typename Allocator, + typename Result, typename... Args> +class async_result<detail::packaged_token<Function, Allocator>, Result(Args...)> + : public detail::packaged_async_result<Function, Allocator, + typename result_of<Function(Args...)>::type> +{ +public: + explicit async_result( + typename detail::packaged_async_result<Function, Allocator, + typename result_of<Function(Args...)>::type>::completion_handler_type& h) + : detail::packaged_async_result<Function, Allocator, + typename result_of<Function(Args...)>::type>(h) + { + } +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename Allocator, typename Result> +class async_result<use_future_t<Allocator>, Result()> + : public detail::promise_async_result<void(), Allocator> +{ +public: + explicit async_result( + typename detail::promise_async_result< + void(), Allocator>::completion_handler_type& h) + : detail::promise_async_result<void(), Allocator>(h) + { + } +}; + +template <typename Function, typename Allocator, typename Result> +class async_result<detail::packaged_token<Function, Allocator>, Result()> + : public detail::packaged_async_result<Function, Allocator, + typename result_of<Function()>::type> +{ +public: + explicit async_result( + typename detail::packaged_async_result<Function, Allocator, + typename result_of<Function()>::type>::completion_handler_type& h) + : detail::packaged_async_result<Function, Allocator, + typename result_of<Function()>::type>(h) + { + } }; -// Handler type specialisation for use_future. -template <typename Allocator, typename ReturnType, typename Arg2> -struct handler_type<use_future_t<Allocator>, - ReturnType(boost::system::error_code, Arg2)> +#define BOOST_ASIO_PRIVATE_ASYNC_RESULT_DEF(n) \ + template <typename Allocator, \ + typename Result, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + class async_result<use_future_t<Allocator>, \ + Result(BOOST_ASIO_VARIADIC_TARGS(n))> \ + : public detail::promise_async_result< \ + void(BOOST_ASIO_VARIADIC_DECAY(n)), Allocator> \ + { \ + public: \ + explicit async_result( \ + typename detail::promise_async_result< \ + void(BOOST_ASIO_VARIADIC_DECAY(n)), \ + Allocator>::completion_handler_type& h) \ + : detail::promise_async_result< \ + void(BOOST_ASIO_VARIADIC_DECAY(n)), Allocator>(h) \ + { \ + } \ + }; \ + \ + template <typename Function, typename Allocator, \ + typename Result, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ + class async_result<detail::packaged_token<Function, Allocator>, \ + Result(BOOST_ASIO_VARIADIC_TARGS(n))> \ + : public detail::packaged_async_result<Function, Allocator, \ + typename result_of<Function(BOOST_ASIO_VARIADIC_TARGS(n))>::type> \ + { \ + public: \ + explicit async_result( \ + typename detail::packaged_async_result<Function, Allocator, \ + typename result_of<Function(BOOST_ASIO_VARIADIC_TARGS(n))>::type \ + >::completion_handler_type& h) \ + : detail::packaged_async_result<Function, Allocator, \ + typename result_of<Function(BOOST_ASIO_VARIADIC_TARGS(n))>::type>(h) \ + { \ + } \ + }; \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ASYNC_RESULT_DEF) +#undef BOOST_ASIO_PRIVATE_ASYNC_RESULT_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +template <typename Allocator, typename Signature> +struct handler_type<use_future_t<Allocator>, Signature> { - typedef detail::promise_handler<Arg2> type; + typedef typename async_result<use_future_t<Allocator>, + Signature>::completion_handler_type type; }; +template <typename Signature, typename Allocator> +class async_result<detail::promise_handler<Signature, Allocator> > + : public detail::promise_async_result<Signature, Allocator> +{ +public: + typedef typename detail::promise_async_result< + Signature, Allocator>::return_type type; + + explicit async_result( + typename detail::promise_async_result< + Signature, Allocator>::completion_handler_type& h) + : detail::promise_async_result<Signature, Allocator>(h) + { + } +}; + +template <typename Function, typename Allocator, typename Signature> +struct handler_type<detail::packaged_token<Function, Allocator>, Signature> +{ + typedef typename async_result<detail::packaged_token<Function, Allocator>, + Signature>::completion_handler_type type; +}; + +template <typename Function, typename Allocator, typename Result> +class async_result<detail::packaged_handler<Function, Allocator, Result> > + : public detail::packaged_async_result<Function, Allocator, Result> +{ +public: + typedef typename detail::packaged_async_result< + Function, Allocator, Result>::return_type type; + + explicit async_result( + typename detail::packaged_async_result< + Function, Allocator, Result>::completion_handler_type& h) + : detail::packaged_async_result<Function, Allocator, Result>(h) + { + } +}; + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio diff --git a/boost/asio/impl/write.hpp b/boost/asio/impl/write.hpp index 84313fed09..8048380f9f 100644 --- a/boost/asio/impl/write.hpp +++ b/boost/asio/impl/write.hpp @@ -15,6 +15,8 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/associated_executor.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/completion_condition.hpp> #include <boost/asio/detail/array_fwd.hpp> @@ -33,30 +35,46 @@ namespace boost { namespace asio { -template <typename SyncWriteStream, typename ConstBufferSequence, - typename CompletionCondition> -std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, - CompletionCondition completion_condition, boost::system::error_code& ec) +namespace detail { - ec = boost::system::error_code(); - boost::asio::detail::consuming_buffers< - const_buffer, ConstBufferSequence> tmp(buffers); - std::size_t total_transferred = 0; - tmp.prepare(detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred))); - while (tmp.begin() != tmp.end()) + template <typename SyncWriteStream, typename ConstBufferSequence, + typename ConstBufferIterator, typename CompletionCondition> + std::size_t write_buffer_sequence(SyncWriteStream& s, + const ConstBufferSequence& buffers, const ConstBufferIterator&, + CompletionCondition completion_condition, boost::system::error_code& ec) { - std::size_t bytes_transferred = s.write_some(tmp, ec); - tmp.consume(bytes_transferred); - total_transferred += bytes_transferred; - tmp.prepare(detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred))); + ec = boost::system::error_code(); + boost::asio::detail::consuming_buffers<const_buffer, + ConstBufferSequence, ConstBufferIterator> tmp(buffers); + while (!tmp.empty()) + { + if (std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, tmp.total_consumed()))) + tmp.consume(s.write_some(tmp.prepare(max_size), ec)); + else + break; + } + return tmp.total_consumed();; } - return total_transferred; +} // namespace detail + +template <typename SyncWriteStream, typename ConstBufferSequence, + typename CompletionCondition> +inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type*) +{ + return detail::write_buffer_sequence(s, buffers, + boost::asio::buffer_sequence_begin(buffers), completion_condition, ec); } template <typename SyncWriteStream, typename ConstBufferSequence> -inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers) +inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type*) { boost::system::error_code ec; std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec); @@ -66,7 +84,10 @@ inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers) template <typename SyncWriteStream, typename ConstBufferSequence> inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, - boost::system::error_code& ec) + boost::system::error_code& ec, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type*) { return write(s, buffers, transfer_all(), ec); } @@ -74,7 +95,10 @@ inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, template <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition> inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, - CompletionCondition completion_condition) + CompletionCondition completion_condition, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type*) { boost::system::error_code ec; std::size_t bytes_transferred = write(s, buffers, completion_condition, ec); @@ -82,35 +106,92 @@ inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, return bytes_transferred; } -#if !defined(BOOST_ASIO_NO_IOSTREAM) - -template <typename SyncWriteStream, typename Allocator, +template <typename SyncWriteStream, typename DynamicBuffer, typename CompletionCondition> std::size_t write(SyncWriteStream& s, - boost::asio::basic_streambuf<Allocator>& b, - CompletionCondition completion_condition, boost::system::error_code& ec) + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type*) { + typename decay<DynamicBuffer>::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers)); + std::size_t bytes_transferred = write(s, b.data(), completion_condition, ec); b.consume(bytes_transferred); return bytes_transferred; } -template <typename SyncWriteStream, typename Allocator> +template <typename SyncWriteStream, typename DynamicBuffer> inline std::size_t write(SyncWriteStream& s, - boost::asio::basic_streambuf<Allocator>& b) + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type*) { boost::system::error_code ec; - std::size_t bytes_transferred = write(s, b, transfer_all(), ec); + std::size_t bytes_transferred = write(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + transfer_all(), ec); boost::asio::detail::throw_error(ec, "write"); return bytes_transferred; } +template <typename SyncWriteStream, typename DynamicBuffer> +inline std::size_t write(SyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type*) +{ + return write(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + transfer_all(), ec); +} + +template <typename SyncWriteStream, typename DynamicBuffer, + typename CompletionCondition> +inline std::size_t write(SyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = write(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + completion_condition, ec); + boost::asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +template <typename SyncWriteStream, typename Allocator, + typename CompletionCondition> +inline std::size_t write(SyncWriteStream& s, + boost::asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, boost::system::error_code& ec) +{ + return write(s, basic_streambuf_ref<Allocator>(b), completion_condition, ec); +} + +template <typename SyncWriteStream, typename Allocator> +inline std::size_t write(SyncWriteStream& s, + boost::asio::basic_streambuf<Allocator>& b) +{ + return write(s, basic_streambuf_ref<Allocator>(b)); +} + template <typename SyncWriteStream, typename Allocator> inline std::size_t write(SyncWriteStream& s, boost::asio::basic_streambuf<Allocator>& b, boost::system::error_code& ec) { - return write(s, b, transfer_all(), ec); + return write(s, basic_streambuf_ref<Allocator>(b), ec); } template <typename SyncWriteStream, typename Allocator, @@ -119,18 +200,17 @@ inline std::size_t write(SyncWriteStream& s, boost::asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition) { - boost::system::error_code ec; - std::size_t bytes_transferred = write(s, b, completion_condition, ec); - boost::asio::detail::throw_error(ec, "write"); - return bytes_transferred; + return write(s, basic_streambuf_ref<Allocator>(b), completion_condition); } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) namespace detail { template <typename AsyncWriteStream, typename ConstBufferSequence, - typename CompletionCondition, typename WriteHandler> + typename ConstBufferIterator, typename CompletionCondition, + typename WriteHandler> class write_op : detail::base_from_completion_cond<CompletionCondition> { @@ -142,7 +222,6 @@ namespace detail stream_(stream), buffers_(buffers), start_(0), - total_transferred_(0), handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) { } @@ -153,7 +232,6 @@ namespace detail stream_(other.stream_), buffers_(other.buffers_), start_(other.start_), - total_transferred_(other.total_transferred_), handler_(other.handler_) { } @@ -163,7 +241,6 @@ namespace detail stream_(other.stream_), buffers_(other.buffers_), start_(other.start_), - total_transferred_(other.total_transferred_), handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) { } @@ -172,362 +249,39 @@ namespace detail void operator()(const boost::system::error_code& ec, std::size_t bytes_transferred, int start = 0) { + std::size_t max_size; switch (start_ = start) { case 1: - buffers_.prepare(this->check_for_completion(ec, total_transferred_)); - for (;;) + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + do { - stream_.async_write_some(buffers_, + stream_.async_write_some(buffers_.prepare(max_size), BOOST_ASIO_MOVE_CAST(write_op)(*this)); return; default: - total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - buffers_.prepare(this->check_for_completion(ec, total_transferred_)); - if ((!ec && bytes_transferred == 0) - || buffers_.begin() == buffers_.end()) - break; - } - - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); - } - } - - //private: - AsyncWriteStream& stream_; - boost::asio::detail::consuming_buffers< - const_buffer, ConstBufferSequence> buffers_; - int start_; - std::size_t total_transferred_; - WriteHandler handler_; - }; - - template <typename AsyncWriteStream, - typename CompletionCondition, typename WriteHandler> - class write_op<AsyncWriteStream, boost::asio::mutable_buffers_1, - CompletionCondition, WriteHandler> - : detail::base_from_completion_cond<CompletionCondition> - { - public: - write_op(AsyncWriteStream& stream, - const boost::asio::mutable_buffers_1& buffers, - CompletionCondition completion_condition, - WriteHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), - stream_(stream), - buffer_(buffers), - start_(0), - total_transferred_(0), - handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) - { - } - -#if defined(BOOST_ASIO_HAS_MOVE) - write_op(const write_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - stream_(other.stream_), - buffer_(other.buffer_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(other.handler_) - { - } - - write_op(write_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - stream_(other.stream_), - buffer_(other.buffer_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) - { - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred, int start = 0) - { - std::size_t n = 0; - switch (start_ = start) - { - case 1: - n = this->check_for_completion(ec, total_transferred_); - for (;;) - { - stream_.async_write_some( - boost::asio::buffer(buffer_ + total_transferred_, n), - BOOST_ASIO_MOVE_CAST(write_op)(*this)); - return; default: - total_transferred_ += bytes_transferred; - if ((!ec && bytes_transferred == 0) - || (n = this->check_for_completion(ec, total_transferred_)) == 0 - || total_transferred_ == boost::asio::buffer_size(buffer_)) - break; - } - - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); - } - } - - //private: - AsyncWriteStream& stream_; - boost::asio::mutable_buffer buffer_; - int start_; - std::size_t total_transferred_; - WriteHandler handler_; - }; - - template <typename AsyncWriteStream, - typename CompletionCondition, typename WriteHandler> - class write_op<AsyncWriteStream, boost::asio::const_buffers_1, - CompletionCondition, WriteHandler> - : detail::base_from_completion_cond<CompletionCondition> - { - public: - write_op(AsyncWriteStream& stream, - const boost::asio::const_buffers_1& buffers, - CompletionCondition completion_condition, - WriteHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), - stream_(stream), - buffer_(buffers), - start_(0), - total_transferred_(0), - handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) - { - } - -#if defined(BOOST_ASIO_HAS_MOVE) - write_op(const write_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - stream_(other.stream_), - buffer_(other.buffer_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(other.handler_) - { - } - - write_op(write_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - stream_(other.stream_), - buffer_(other.buffer_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) - { - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred, int start = 0) - { - std::size_t n = 0; - switch (start_ = start) - { - case 1: - n = this->check_for_completion(ec, total_transferred_); - for (;;) - { - stream_.async_write_some( - boost::asio::buffer(buffer_ + total_transferred_, n), - BOOST_ASIO_MOVE_CAST(write_op)(*this)); - return; default: - total_transferred_ += bytes_transferred; - if ((!ec && bytes_transferred == 0) - || (n = this->check_for_completion(ec, total_transferred_)) == 0 - || total_transferred_ == boost::asio::buffer_size(buffer_)) - break; - } - - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); - } - } - - //private: - AsyncWriteStream& stream_; - boost::asio::const_buffer buffer_; - int start_; - std::size_t total_transferred_; - WriteHandler handler_; - }; - - template <typename AsyncWriteStream, typename Elem, - typename CompletionCondition, typename WriteHandler> - class write_op<AsyncWriteStream, boost::array<Elem, 2>, - CompletionCondition, WriteHandler> - : detail::base_from_completion_cond<CompletionCondition> - { - public: - write_op(AsyncWriteStream& stream, const boost::array<Elem, 2>& buffers, - CompletionCondition completion_condition, WriteHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), - stream_(stream), - buffers_(buffers), - start_(0), - total_transferred_(0), - handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) - { - } - -#if defined(BOOST_ASIO_HAS_MOVE) - write_op(const write_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - stream_(other.stream_), - buffers_(other.buffers_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(other.handler_) - { - } - - write_op(write_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - stream_(other.stream_), - buffers_(other.buffers_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) - { - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred, int start = 0) - { - typename boost::asio::detail::dependent_type<Elem, - boost::array<boost::asio::const_buffer, 2> >::type bufs = {{ - boost::asio::const_buffer(buffers_[0]), - boost::asio::const_buffer(buffers_[1]) }}; - std::size_t buffer_size0 = boost::asio::buffer_size(bufs[0]); - std::size_t buffer_size1 = boost::asio::buffer_size(bufs[1]); - std::size_t n = 0; - switch (start_ = start) - { - case 1: - n = this->check_for_completion(ec, total_transferred_); - for (;;) - { - bufs[0] = boost::asio::buffer(bufs[0] + total_transferred_, n); - bufs[1] = boost::asio::buffer( - bufs[1] + (total_transferred_ < buffer_size0 - ? 0 : total_transferred_ - buffer_size0), - n - boost::asio::buffer_size(bufs[0])); - stream_.async_write_some(bufs, BOOST_ASIO_MOVE_CAST(write_op)(*this)); - return; default: - total_transferred_ += bytes_transferred; - if ((!ec && bytes_transferred == 0) - || (n = this->check_for_completion(ec, total_transferred_)) == 0 - || total_transferred_ == buffer_size0 + buffer_size1) + if ((!ec && bytes_transferred == 0) || buffers_.empty()) break; - } + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + } while (max_size > 0); - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + handler_(ec, buffers_.total_consumed()); } } //private: AsyncWriteStream& stream_; - boost::array<Elem, 2> buffers_; + boost::asio::detail::consuming_buffers<const_buffer, + ConstBufferSequence, ConstBufferIterator> buffers_; int start_; - std::size_t total_transferred_; WriteHandler handler_; }; -#if defined(BOOST_ASIO_HAS_STD_ARRAY) - - template <typename AsyncWriteStream, typename Elem, - typename CompletionCondition, typename WriteHandler> - class write_op<AsyncWriteStream, std::array<Elem, 2>, - CompletionCondition, WriteHandler> - : detail::base_from_completion_cond<CompletionCondition> - { - public: - write_op(AsyncWriteStream& stream, const std::array<Elem, 2>& buffers, - CompletionCondition completion_condition, WriteHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), - stream_(stream), - buffers_(buffers), - start_(0), - total_transferred_(0), - handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) - { - } - -#if defined(BOOST_ASIO_HAS_MOVE) - write_op(const write_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - stream_(other.stream_), - buffers_(other.buffers_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(other.handler_) - { - } - - write_op(write_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - stream_(other.stream_), - buffers_(other.buffers_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) - { - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred, int start = 0) - { - typename boost::asio::detail::dependent_type<Elem, - std::array<boost::asio::const_buffer, 2> >::type bufs = {{ - boost::asio::const_buffer(buffers_[0]), - boost::asio::const_buffer(buffers_[1]) }}; - std::size_t buffer_size0 = boost::asio::buffer_size(bufs[0]); - std::size_t buffer_size1 = boost::asio::buffer_size(bufs[1]); - std::size_t n = 0; - switch (start_ = start) - { - case 1: - n = this->check_for_completion(ec, total_transferred_); - for (;;) - { - bufs[0] = boost::asio::buffer(bufs[0] + total_transferred_, n); - bufs[1] = boost::asio::buffer( - bufs[1] + (total_transferred_ < buffer_size0 - ? 0 : total_transferred_ - buffer_size0), - n - boost::asio::buffer_size(bufs[0])); - stream_.async_write_some(bufs, BOOST_ASIO_MOVE_CAST(write_op)(*this)); - return; default: - total_transferred_ += bytes_transferred; - if ((!ec && bytes_transferred == 0) - || (n = this->check_for_completion(ec, total_transferred_)) == 0 - || total_transferred_ == buffer_size0 + buffer_size1) - break; - } - - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); - } - } - - //private: - AsyncWriteStream& stream_; - std::array<Elem, 2> buffers_; - int start_; - std::size_t total_transferred_; - WriteHandler handler_; - }; - -#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) - template <typename AsyncWriteStream, typename ConstBufferSequence, - typename CompletionCondition, typename WriteHandler> + typename ConstBufferIterator, typename CompletionCondition, + typename WriteHandler> inline void* asio_handler_allocate(std::size_t size, - write_op<AsyncWriteStream, ConstBufferSequence, + write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( @@ -535,9 +289,10 @@ namespace detail } template <typename AsyncWriteStream, typename ConstBufferSequence, - typename CompletionCondition, typename WriteHandler> + typename ConstBufferIterator, typename CompletionCondition, + typename WriteHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - write_op<AsyncWriteStream, ConstBufferSequence, + write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( @@ -545,9 +300,10 @@ namespace detail } template <typename AsyncWriteStream, typename ConstBufferSequence, - typename CompletionCondition, typename WriteHandler> + typename ConstBufferIterator, typename CompletionCondition, + typename WriteHandler> inline bool asio_handler_is_continuation( - write_op<AsyncWriteStream, ConstBufferSequence, + write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { return this_handler->start_ == 0 ? true @@ -556,10 +312,10 @@ namespace detail } template <typename Function, typename AsyncWriteStream, - typename ConstBufferSequence, typename CompletionCondition, - typename WriteHandler> + typename ConstBufferSequence, typename ConstBufferIterator, + typename CompletionCondition, typename WriteHandler> inline void asio_handler_invoke(Function& function, - write_op<AsyncWriteStream, ConstBufferSequence, + write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -567,38 +323,94 @@ namespace detail } template <typename Function, typename AsyncWriteStream, - typename ConstBufferSequence, typename CompletionCondition, - typename WriteHandler> + typename ConstBufferSequence, typename ConstBufferIterator, + typename CompletionCondition, typename WriteHandler> inline void asio_handler_invoke(const Function& function, - write_op<AsyncWriteStream, ConstBufferSequence, + write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } + + template <typename AsyncWriteStream, typename ConstBufferSequence, + typename ConstBufferIterator, typename CompletionCondition, + typename WriteHandler> + inline void start_write_buffer_sequence_op(AsyncWriteStream& stream, + const ConstBufferSequence& buffers, const ConstBufferIterator&, + CompletionCondition completion_condition, WriteHandler& handler) + { + detail::write_op<AsyncWriteStream, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>( + stream, buffers, completion_condition, handler)( + boost::system::error_code(), 0, 1); + } + } // namespace detail +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncWriteStream, typename ConstBufferSequence, + typename ConstBufferIterator, typename CompletionCondition, + typename WriteHandler, typename Allocator> +struct associated_allocator< + detail::write_op<AsyncWriteStream, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>, + Allocator> +{ + typedef typename associated_allocator<WriteHandler, Allocator>::type type; + + static type get( + const detail::write_op<AsyncWriteStream, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncWriteStream, typename ConstBufferSequence, + typename ConstBufferIterator, typename CompletionCondition, + typename WriteHandler, typename Executor> +struct associated_executor< + detail::write_op<AsyncWriteStream, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>, + Executor> +{ + typedef typename associated_executor<WriteHandler, Executor>::type type; + + static type get( + const detail::write_op<AsyncWriteStream, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + template <typename AsyncWriteStream, typename ConstBufferSequence, typename CompletionCondition, typename WriteHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type*) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); - detail::write_op<AsyncWriteStream, ConstBufferSequence, - CompletionCondition, BOOST_ASIO_HANDLER_TYPE( - WriteHandler, void (boost::system::error_code, std::size_t))>( - s, buffers, completion_condition, init.handler)( - boost::system::error_code(), 0, 1); + detail::start_write_buffer_sequence_op(s, buffers, + boost::asio::buffer_sequence_begin(buffers), completion_condition, + init.completion_handler); return init.result.get(); } @@ -608,132 +420,227 @@ template <typename AsyncWriteStream, typename ConstBufferSequence, inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type*) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); - detail::write_op<AsyncWriteStream, ConstBufferSequence, - detail::transfer_all_t, BOOST_ASIO_HANDLER_TYPE( - WriteHandler, void (boost::system::error_code, std::size_t))>( - s, buffers, transfer_all(), init.handler)( - boost::system::error_code(), 0, 1); + detail::start_write_buffer_sequence_op(s, buffers, + boost::asio::buffer_sequence_begin(buffers), transfer_all(), + init.completion_handler); return init.result.get(); } -#if !defined(BOOST_ASIO_NO_IOSTREAM) - namespace detail { - template <typename Allocator, typename WriteHandler> - class write_streambuf_handler + template <typename AsyncWriteStream, typename DynamicBuffer, + typename CompletionCondition, typename WriteHandler> + class write_dynbuf_op { public: - write_streambuf_handler(boost::asio::basic_streambuf<Allocator>& streambuf, - WriteHandler& handler) - : streambuf_(streambuf), + template <typename BufferSequence> + write_dynbuf_op(AsyncWriteStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + CompletionCondition completion_condition, WriteHandler& handler) + : stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + completion_condition_( + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)), handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) { } #if defined(BOOST_ASIO_HAS_MOVE) - write_streambuf_handler(const write_streambuf_handler& other) - : streambuf_(other.streambuf_), + write_dynbuf_op(const write_dynbuf_op& other) + : stream_(other.stream_), + buffers_(other.buffers_), + completion_condition_(other.completion_condition_), handler_(other.handler_) { } - write_streambuf_handler(write_streambuf_handler&& other) - : streambuf_(other.streambuf_), + write_dynbuf_op(write_dynbuf_op&& other) + : stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer)(other.buffers_)), + completion_condition_( + BOOST_ASIO_MOVE_CAST(CompletionCondition)( + other.completion_condition_)), handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) { } #endif // defined(BOOST_ASIO_HAS_MOVE) void operator()(const boost::system::error_code& ec, - const std::size_t bytes_transferred) + std::size_t bytes_transferred, int start = 0) { - streambuf_.consume(bytes_transferred); - handler_(ec, bytes_transferred); + switch (start) + { + case 1: + async_write(stream_, buffers_.data(), completion_condition_, + BOOST_ASIO_MOVE_CAST(write_dynbuf_op)(*this)); + return; default: + buffers_.consume(bytes_transferred); + handler_(ec, static_cast<const std::size_t&>(bytes_transferred)); + } } //private: - boost::asio::basic_streambuf<Allocator>& streambuf_; + AsyncWriteStream& stream_; + DynamicBuffer buffers_; + CompletionCondition completion_condition_; WriteHandler handler_; }; - template <typename Allocator, typename WriteHandler> + template <typename AsyncWriteStream, typename DynamicBuffer, + typename CompletionCondition, typename WriteHandler> inline void* asio_handler_allocate(std::size_t size, - write_streambuf_handler<Allocator, WriteHandler>* this_handler) + write_dynbuf_op<AsyncWriteStream, DynamicBuffer, + CompletionCondition, WriteHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename Allocator, typename WriteHandler> + template <typename AsyncWriteStream, typename DynamicBuffer, + typename CompletionCondition, typename WriteHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - write_streambuf_handler<Allocator, WriteHandler>* this_handler) + write_dynbuf_op<AsyncWriteStream, DynamicBuffer, + CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename Allocator, typename WriteHandler> + template <typename AsyncWriteStream, typename DynamicBuffer, + typename CompletionCondition, typename WriteHandler> inline bool asio_handler_is_continuation( - write_streambuf_handler<Allocator, WriteHandler>* this_handler) + write_dynbuf_op<AsyncWriteStream, DynamicBuffer, + CompletionCondition, WriteHandler>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } - template <typename Function, typename Allocator, typename WriteHandler> + template <typename Function, typename AsyncWriteStream, + typename DynamicBuffer, typename CompletionCondition, + typename WriteHandler> inline void asio_handler_invoke(Function& function, - write_streambuf_handler<Allocator, WriteHandler>* this_handler) + write_dynbuf_op<AsyncWriteStream, DynamicBuffer, + CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } - template <typename Function, typename Allocator, typename WriteHandler> + template <typename Function, typename AsyncWriteStream, + typename DynamicBuffer, typename CompletionCondition, + typename WriteHandler> inline void asio_handler_invoke(const Function& function, - write_streambuf_handler<Allocator, WriteHandler>* this_handler) + write_dynbuf_op<AsyncWriteStream, DynamicBuffer, + CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail -template <typename AsyncWriteStream, typename Allocator, +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncWriteStream, typename DynamicBuffer, + typename CompletionCondition, typename WriteHandler, typename Allocator> +struct associated_allocator< + detail::write_dynbuf_op<AsyncWriteStream, + DynamicBuffer, CompletionCondition, WriteHandler>, + Allocator> +{ + typedef typename associated_allocator<WriteHandler, Allocator>::type type; + + static type get( + const detail::write_dynbuf_op<AsyncWriteStream, + DynamicBuffer, CompletionCondition, WriteHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncWriteStream, typename DynamicBuffer, + typename CompletionCondition, typename WriteHandler, typename Executor> +struct associated_executor< + detail::write_dynbuf_op<AsyncWriteStream, + DynamicBuffer, CompletionCondition, WriteHandler>, + Executor> +{ + typedef typename associated_executor<WriteHandler, Executor>::type type; + + static type get( + const detail::write_dynbuf_op<AsyncWriteStream, + DynamicBuffer, CompletionCondition, WriteHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncWriteStream, + typename DynamicBuffer, typename WriteHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type*) +{ + return async_write(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + transfer_all(), BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +} + +template <typename AsyncWriteStream, typename DynamicBuffer, typename CompletionCondition, typename WriteHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, - boost::asio::basic_streambuf<Allocator>& b, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, CompletionCondition completion_condition, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type*) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); - async_write(s, b.data(), completion_condition, - detail::write_streambuf_handler<Allocator, BOOST_ASIO_HANDLER_TYPE( - WriteHandler, void (boost::system::error_code, std::size_t))>( - b, init.handler)); + detail::write_dynbuf_op<AsyncWriteStream, + typename decay<DynamicBuffer>::type, + CompletionCondition, BOOST_ASIO_HANDLER_TYPE( + WriteHandler, void (boost::system::error_code, std::size_t))>( + s, BOOST_ASIO_MOVE_CAST(DynamicBuffer)(buffers), + completion_condition, init.completion_handler)( + boost::system::error_code(), 0, 1); return init.result.get(); } +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + template <typename AsyncWriteStream, typename Allocator, typename WriteHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) @@ -741,23 +648,25 @@ async_write(AsyncWriteStream& s, boost::asio::basic_streambuf<Allocator>& b, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( + return async_write(s, basic_streambuf_ref<Allocator>(b), BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +} - async_write(s, b.data(), transfer_all(), - detail::write_streambuf_handler<Allocator, BOOST_ASIO_HANDLER_TYPE( - WriteHandler, void (boost::system::error_code, std::size_t))>( - b, init.handler)); - - return init.result.get(); +template <typename AsyncWriteStream, typename Allocator, + typename CompletionCondition, typename WriteHandler> +inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + boost::asio::basic_streambuf<Allocator>& b, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) +{ + return async_write(s, basic_streambuf_ref<Allocator>(b), + completion_condition, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) } // namespace asio } // namespace boost diff --git a/boost/asio/impl/write_at.hpp b/boost/asio/impl/write_at.hpp index 20e95d9338..b1cf426c5e 100644 --- a/boost/asio/impl/write_at.hpp +++ b/boost/asio/impl/write_at.hpp @@ -15,6 +15,8 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/associated_executor.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/completion_condition.hpp> #include <boost/asio/detail/array_fwd.hpp> @@ -33,28 +35,41 @@ namespace boost { namespace asio { +namespace detail +{ + template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence, + typename ConstBufferIterator, typename CompletionCondition> + std::size_t write_at_buffer_sequence(SyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + const ConstBufferIterator&, CompletionCondition completion_condition, + boost::system::error_code& ec) + { + ec = boost::system::error_code(); + boost::asio::detail::consuming_buffers<const_buffer, + ConstBufferSequence, ConstBufferIterator> tmp(buffers); + while (!tmp.empty()) + { + if (std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, tmp.total_consumed()))) + { + tmp.consume(d.write_some_at(offset + tmp.total_consumed(), + tmp.prepare(max_size), ec)); + } + else + break; + } + return tmp.total_consumed();; + } +} // namespace detail + template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence, typename CompletionCondition> std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition, boost::system::error_code& ec) { - ec = boost::system::error_code(); - boost::asio::detail::consuming_buffers< - const_buffer, ConstBufferSequence> tmp(buffers); - std::size_t total_transferred = 0; - tmp.prepare(detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred))); - while (tmp.begin() != tmp.end()) - { - std::size_t bytes_transferred = d.write_some_at( - offset + total_transferred, tmp, ec); - tmp.consume(bytes_transferred); - total_transferred += bytes_transferred; - tmp.prepare(detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred))); - } - return total_transferred; + return detail::write_at_buffer_sequence(d, offset, buffers, + boost::asio::buffer_sequence_begin(buffers), completion_condition, ec); } template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence> @@ -89,6 +104,7 @@ inline std::size_t write_at(SyncRandomAccessWriteDevice& d, return bytes_transferred; } +#if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) template <typename SyncRandomAccessWriteDevice, typename Allocator, @@ -135,10 +151,12 @@ inline std::size_t write_at(SyncRandomAccessWriteDevice& d, } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) namespace detail { - template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, + template <typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> class write_at_op : detail::base_from_completion_cond<CompletionCondition> @@ -153,7 +171,6 @@ namespace detail offset_(offset), buffers_(buffers), start_(0), - total_transferred_(0), handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) { } @@ -165,7 +182,6 @@ namespace detail offset_(other.offset_), buffers_(other.buffers_), start_(other.start_), - total_transferred_(other.total_transferred_), handler_(other.handler_) { } @@ -176,7 +192,6 @@ namespace detail offset_(other.offset_), buffers_(other.buffers_), start_(other.start_), - total_transferred_(other.total_transferred_), handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) { } @@ -185,405 +200,64 @@ namespace detail void operator()(const boost::system::error_code& ec, std::size_t bytes_transferred, int start = 0) { + std::size_t max_size; switch (start_ = start) { case 1: - buffers_.prepare(this->check_for_completion(ec, total_transferred_)); - for (;;) + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + do { device_.async_write_some_at( - offset_ + total_transferred_, buffers_, + offset_ + buffers_.total_consumed(), buffers_.prepare(max_size), BOOST_ASIO_MOVE_CAST(write_at_op)(*this)); return; default: - total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - buffers_.prepare(this->check_for_completion(ec, total_transferred_)); - if ((!ec && bytes_transferred == 0) - || buffers_.begin() == buffers_.end()) + if ((!ec && bytes_transferred == 0) || buffers_.empty()) break; - } + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + } while (max_size > 0); - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); + handler_(ec, buffers_.total_consumed()); } } //private: AsyncRandomAccessWriteDevice& device_; uint64_t offset_; - boost::asio::detail::consuming_buffers< - const_buffer, ConstBufferSequence> buffers_; + boost::asio::detail::consuming_buffers<const_buffer, + ConstBufferSequence, ConstBufferIterator> buffers_; int start_; - std::size_t total_transferred_; WriteHandler handler_; }; template <typename AsyncRandomAccessWriteDevice, - typename CompletionCondition, typename WriteHandler> - class write_at_op<AsyncRandomAccessWriteDevice, - boost::asio::mutable_buffers_1, CompletionCondition, WriteHandler> - : detail::base_from_completion_cond<CompletionCondition> - { - public: - write_at_op(AsyncRandomAccessWriteDevice& device, - uint64_t offset, const boost::asio::mutable_buffers_1& buffers, - CompletionCondition completion_condition, - WriteHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), - device_(device), - offset_(offset), - buffer_(buffers), - start_(0), - total_transferred_(0), - handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) - { - } - -#if defined(BOOST_ASIO_HAS_MOVE) - write_at_op(const write_at_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - device_(other.device_), - offset_(other.offset_), - buffer_(other.buffer_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(other.handler_) - { - } - - write_at_op(write_at_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - device_(other.device_), - offset_(other.offset_), - buffer_(other.buffer_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) - { - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred, int start = 0) - { - std::size_t n = 0; - switch (start_ = start) - { - case 1: - n = this->check_for_completion(ec, total_transferred_); - for (;;) - { - device_.async_write_some_at(offset_ + total_transferred_, - boost::asio::buffer(buffer_ + total_transferred_, n), - BOOST_ASIO_MOVE_CAST(write_at_op)(*this)); - return; default: - total_transferred_ += bytes_transferred; - if ((!ec && bytes_transferred == 0) - || (n = this->check_for_completion(ec, total_transferred_)) == 0 - || total_transferred_ == boost::asio::buffer_size(buffer_)) - break; - } - - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); - } - } - - //private: - AsyncRandomAccessWriteDevice& device_; - uint64_t offset_; - boost::asio::mutable_buffer buffer_; - int start_; - std::size_t total_transferred_; - WriteHandler handler_; - }; - - template <typename AsyncRandomAccessWriteDevice, - typename CompletionCondition, typename WriteHandler> - class write_at_op<AsyncRandomAccessWriteDevice, boost::asio::const_buffers_1, - CompletionCondition, WriteHandler> - : detail::base_from_completion_cond<CompletionCondition> - { - public: - write_at_op(AsyncRandomAccessWriteDevice& device, - uint64_t offset, const boost::asio::const_buffers_1& buffers, - CompletionCondition completion_condition, - WriteHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), - device_(device), - offset_(offset), - buffer_(buffers), - start_(0), - total_transferred_(0), - handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) - { - } - -#if defined(BOOST_ASIO_HAS_MOVE) - write_at_op(const write_at_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - device_(other.device_), - offset_(other.offset_), - buffer_(other.buffer_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(other.handler_) - { - } - - write_at_op(write_at_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - device_(other.device_), - offset_(other.offset_), - buffer_(other.buffer_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) - { - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred, int start = 0) - { - std::size_t n = 0; - switch (start_ = start) - { - case 1: - n = this->check_for_completion(ec, total_transferred_); - for (;;) - { - device_.async_write_some_at(offset_ + total_transferred_, - boost::asio::buffer(buffer_ + total_transferred_, n), - BOOST_ASIO_MOVE_CAST(write_at_op)(*this)); - return; default: - total_transferred_ += bytes_transferred; - if ((!ec && bytes_transferred == 0) - || (n = this->check_for_completion(ec, total_transferred_)) == 0 - || total_transferred_ == boost::asio::buffer_size(buffer_)) - break; - } - - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); - } - } - - //private: - AsyncRandomAccessWriteDevice& device_; - uint64_t offset_; - boost::asio::const_buffer buffer_; - int start_; - std::size_t total_transferred_; - WriteHandler handler_; - }; - - template <typename AsyncRandomAccessWriteDevice, typename Elem, - typename CompletionCondition, typename WriteHandler> - class write_at_op<AsyncRandomAccessWriteDevice, boost::array<Elem, 2>, - CompletionCondition, WriteHandler> - : detail::base_from_completion_cond<CompletionCondition> - { - public: - write_at_op(AsyncRandomAccessWriteDevice& device, - uint64_t offset, const boost::array<Elem, 2>& buffers, - CompletionCondition completion_condition, WriteHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), - device_(device), - offset_(offset), - buffers_(buffers), - start_(0), - total_transferred_(0), - handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) - { - } - -#if defined(BOOST_ASIO_HAS_MOVE) - write_at_op(const write_at_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - device_(other.device_), - offset_(other.offset_), - buffers_(other.buffers_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(other.handler_) - { - } - - write_at_op(write_at_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - device_(other.device_), - offset_(other.offset_), - buffers_(other.buffers_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) - { - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred, int start = 0) - { - typename boost::asio::detail::dependent_type<Elem, - boost::array<boost::asio::const_buffer, 2> >::type bufs = {{ - boost::asio::const_buffer(buffers_[0]), - boost::asio::const_buffer(buffers_[1]) }}; - std::size_t buffer_size0 = boost::asio::buffer_size(bufs[0]); - std::size_t buffer_size1 = boost::asio::buffer_size(bufs[1]); - std::size_t n = 0; - switch (start_ = start) - { - case 1: - n = this->check_for_completion(ec, total_transferred_); - for (;;) - { - bufs[0] = boost::asio::buffer(bufs[0] + total_transferred_, n); - bufs[1] = boost::asio::buffer( - bufs[1] + (total_transferred_ < buffer_size0 - ? 0 : total_transferred_ - buffer_size0), - n - boost::asio::buffer_size(bufs[0])); - device_.async_write_some_at(offset_ + total_transferred_, - bufs, BOOST_ASIO_MOVE_CAST(write_at_op)(*this)); - return; default: - total_transferred_ += bytes_transferred; - if ((!ec && bytes_transferred == 0) - || (n = this->check_for_completion(ec, total_transferred_)) == 0 - || total_transferred_ == buffer_size0 + buffer_size1) - break; - } - - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); - } - } - - //private: - AsyncRandomAccessWriteDevice& device_; - uint64_t offset_; - boost::array<Elem, 2> buffers_; - int start_; - std::size_t total_transferred_; - WriteHandler handler_; - }; - -#if defined(BOOST_ASIO_HAS_STD_ARRAY) - - template <typename AsyncRandomAccessWriteDevice, typename Elem, - typename CompletionCondition, typename WriteHandler> - class write_at_op<AsyncRandomAccessWriteDevice, std::array<Elem, 2>, - CompletionCondition, WriteHandler> - : detail::base_from_completion_cond<CompletionCondition> - { - public: - write_at_op(AsyncRandomAccessWriteDevice& device, - uint64_t offset, const std::array<Elem, 2>& buffers, - CompletionCondition completion_condition, WriteHandler& handler) - : detail::base_from_completion_cond< - CompletionCondition>(completion_condition), - device_(device), - offset_(offset), - buffers_(buffers), - start_(0), - total_transferred_(0), - handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) - { - } - -#if defined(BOOST_ASIO_HAS_MOVE) - write_at_op(const write_at_op& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - device_(other.device_), - offset_(other.offset_), - buffers_(other.buffers_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(other.handler_) - { - } - - write_at_op(write_at_op&& other) - : detail::base_from_completion_cond<CompletionCondition>(other), - device_(other.device_), - offset_(other.offset_), - buffers_(other.buffers_), - start_(other.start_), - total_transferred_(other.total_transferred_), - handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) - { - } -#endif // defined(BOOST_ASIO_HAS_MOVE) - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred, int start = 0) - { - typename boost::asio::detail::dependent_type<Elem, - std::array<boost::asio::const_buffer, 2> >::type bufs = {{ - boost::asio::const_buffer(buffers_[0]), - boost::asio::const_buffer(buffers_[1]) }}; - std::size_t buffer_size0 = boost::asio::buffer_size(bufs[0]); - std::size_t buffer_size1 = boost::asio::buffer_size(bufs[1]); - std::size_t n = 0; - switch (start_ = start) - { - case 1: - n = this->check_for_completion(ec, total_transferred_); - for (;;) - { - bufs[0] = boost::asio::buffer(bufs[0] + total_transferred_, n); - bufs[1] = boost::asio::buffer( - bufs[1] + (total_transferred_ < buffer_size0 - ? 0 : total_transferred_ - buffer_size0), - n - boost::asio::buffer_size(bufs[0])); - device_.async_write_some_at(offset_ + total_transferred_, - bufs, BOOST_ASIO_MOVE_CAST(write_at_op)(*this)); - return; default: - total_transferred_ += bytes_transferred; - if ((!ec && bytes_transferred == 0) - || (n = this->check_for_completion(ec, total_transferred_)) == 0 - || total_transferred_ == buffer_size0 + buffer_size1) - break; - } - - handler_(ec, static_cast<const std::size_t&>(total_transferred_)); - } - } - - //private: - AsyncRandomAccessWriteDevice& device_; - uint64_t offset_; - std::array<Elem, 2> buffers_; - int start_; - std::size_t total_transferred_; - WriteHandler handler_; - }; - -#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) - - template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, + typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> inline void* asio_handler_allocate(std::size_t size, write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, - CompletionCondition, WriteHandler>* this_handler) + ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } - template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, + template <typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, - CompletionCondition, WriteHandler>* this_handler) + ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } - template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, + template <typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> inline bool asio_handler_is_continuation( write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, - CompletionCondition, WriteHandler>* this_handler) + ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( @@ -591,41 +265,86 @@ namespace detail } template <typename Function, typename AsyncRandomAccessWriteDevice, - typename ConstBufferSequence, typename CompletionCondition, - typename WriteHandler> + typename ConstBufferSequence, typename ConstBufferIterator, + typename CompletionCondition, typename WriteHandler> inline void asio_handler_invoke(Function& function, write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, - CompletionCondition, WriteHandler>* this_handler) + ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } template <typename Function, typename AsyncRandomAccessWriteDevice, - typename ConstBufferSequence, typename CompletionCondition, - typename WriteHandler> + typename ConstBufferSequence, typename ConstBufferIterator, + typename CompletionCondition, typename WriteHandler> inline void asio_handler_invoke(const Function& function, write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, - CompletionCondition, WriteHandler>* this_handler) + ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } - template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, + template <typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> - inline write_at_op<AsyncRandomAccessWriteDevice, - ConstBufferSequence, CompletionCondition, WriteHandler> - make_write_at_op(AsyncRandomAccessWriteDevice& d, + inline void start_write_at_buffer_sequence_op(AsyncRandomAccessWriteDevice& d, uint64_t offset, const ConstBufferSequence& buffers, - CompletionCondition completion_condition, WriteHandler handler) + const ConstBufferIterator&, CompletionCondition completion_condition, + WriteHandler& handler) { - return write_at_op<AsyncRandomAccessWriteDevice, - ConstBufferSequence, CompletionCondition, WriteHandler>( - d, offset, buffers, completion_condition, handler); + detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>( + d, offset, buffers, completion_condition, handler)( + boost::system::error_code(), 0, 1); } } // namespace detail +#if !defined(GENERATING_DOCUMENTATION) + +template <typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename ConstBufferIterator, + typename CompletionCondition, typename WriteHandler, typename Allocator> +struct associated_allocator< + detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>, + Allocator> +{ + typedef typename associated_allocator<WriteHandler, Allocator>::type type; + + static type get( + const detail::write_at_op<AsyncRandomAccessWriteDevice, + ConstBufferSequence, ConstBufferIterator, + CompletionCondition, WriteHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); + } +}; + +template <typename AsyncRandomAccessWriteDevice, + typename ConstBufferSequence, typename ConstBufferIterator, + typename CompletionCondition, typename WriteHandler, typename Executor> +struct associated_executor< + detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, + ConstBufferIterator, CompletionCondition, WriteHandler>, + Executor> +{ + typedef typename associated_executor<WriteHandler, Executor>::type type; + + static type get( + const detail::write_at_op<AsyncRandomAccessWriteDevice, + ConstBufferSequence, ConstBufferIterator, + CompletionCondition, WriteHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, typename CompletionCondition, typename WriteHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, @@ -639,15 +358,12 @@ async_write_at(AsyncRandomAccessWriteDevice& d, // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); - detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, - CompletionCondition, BOOST_ASIO_HANDLER_TYPE( - WriteHandler, void (boost::system::error_code, std::size_t))>( - d, offset, buffers, completion_condition, init.handler)( - boost::system::error_code(), 0, 1); + detail::start_write_at_buffer_sequence_op(d, offset, buffers, + boost::asio::buffer_sequence_begin(buffers), completion_condition, + init.completion_handler); return init.result.get(); } @@ -664,19 +380,17 @@ async_write_at(AsyncRandomAccessWriteDevice& d, // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); - detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, - detail::transfer_all_t, BOOST_ASIO_HANDLER_TYPE( - WriteHandler, void (boost::system::error_code, std::size_t))>( - d, offset, buffers, transfer_all(), init.handler)( - boost::system::error_code(), 0, 1); + detail::start_write_at_buffer_sequence_op(d, offset, buffers, + boost::asio::buffer_sequence_begin(buffers), transfer_all(), + init.completion_handler); return init.result.get(); } +#if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) namespace detail @@ -768,6 +482,40 @@ namespace detail } } // namespace detail +#if !defined(GENERATING_DOCUMENTATION) + +template <typename Allocator, typename WriteHandler, typename Allocator1> +struct associated_allocator< + detail::write_at_streambuf_op<Allocator, WriteHandler>, + Allocator1> +{ + typedef typename associated_allocator<WriteHandler, Allocator1>::type type; + + static type get( + const detail::write_at_streambuf_op<Allocator, WriteHandler>& h, + const Allocator1& a = Allocator1()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<WriteHandler, Allocator1>::get(h.handler_, a); + } +}; + +template <typename Executor, typename WriteHandler, typename Executor1> +struct associated_executor< + detail::write_at_streambuf_op<Executor, WriteHandler>, + Executor1> +{ + typedef typename associated_executor<WriteHandler, Executor1>::type type; + + static type get( + const detail::write_at_streambuf_op<Executor, WriteHandler>& h, + const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<WriteHandler, Executor1>::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + template <typename AsyncRandomAccessWriteDevice, typename Allocator, typename CompletionCondition, typename WriteHandler> inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, @@ -781,14 +529,13 @@ async_write_at(AsyncRandomAccessWriteDevice& d, // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); async_write_at(d, offset, b.data(), completion_condition, detail::write_at_streambuf_op<Allocator, BOOST_ASIO_HANDLER_TYPE( WriteHandler, void (boost::system::error_code, std::size_t))>( - b, init.handler)); + b, init.completion_handler)); return init.result.get(); } @@ -805,19 +552,19 @@ async_write_at(AsyncRandomAccessWriteDevice& d, // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); async_write_at(d, offset, b.data(), transfer_all(), detail::write_at_streambuf_op<Allocator, BOOST_ASIO_HANDLER_TYPE( WriteHandler, void (boost::system::error_code, std::size_t))>( - b, init.handler)); + b, init.completion_handler)); return init.result.get(); } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) } // namespace asio } // namespace boost diff --git a/boost/asio/io_context.hpp b/boost/asio/io_context.hpp new file mode 100644 index 0000000000..2eb3c4624f --- /dev/null +++ b/boost/asio/io_context.hpp @@ -0,0 +1,878 @@ +// +// io_context.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IO_CONTEXT_HPP +#define BOOST_ASIO_IO_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <cstddef> +#include <stdexcept> +#include <typeinfo> +#include <boost/asio/async_result.hpp> +#include <boost/asio/detail/noncopyable.hpp> +#include <boost/asio/detail/wrapped_handler.hpp> +#include <boost/system/error_code.hpp> +#include <boost/asio/execution_context.hpp> + +#if defined(BOOST_ASIO_HAS_CHRONO) +# include <boost/asio/detail/chrono.hpp> +#endif // defined(BOOST_ASIO_HAS_CHRONO) + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# include <boost/asio/detail/winsock_init.hpp> +#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ + || defined(__osf__) +# include <boost/asio/detail/signal_init.hpp> +#endif + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +namespace detail { +#if defined(BOOST_ASIO_HAS_IOCP) + typedef class win_iocp_io_context io_context_impl; + class win_iocp_overlapped_ptr; +#else + typedef class scheduler io_context_impl; +#endif +} // namespace detail + +/// Provides core I/O functionality. +/** + * The io_context class provides the core I/O functionality for users of the + * asynchronous I/O objects, including: + * + * @li boost::asio::ip::tcp::socket + * @li boost::asio::ip::tcp::acceptor + * @li boost::asio::ip::udp::socket + * @li boost::asio::deadline_timer. + * + * The io_context class also includes facilities intended for developers of + * custom asynchronous services. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe, with the specific exceptions of the restart() + * and notify_fork() functions. Calling restart() while there are unfinished + * run(), run_one(), run_for(), run_until(), poll() or poll_one() calls results + * in undefined behaviour. The notify_fork() function should not be called + * while any io_context function, or any function on an I/O object that is + * associated with the io_context, is being called in another thread. + * + * @par Concepts: + * Dispatcher. + * + * @par Synchronous and asynchronous operations + * + * Synchronous operations on I/O objects implicitly run the io_context object + * for an individual operation. The io_context functions run(), run_one(), + * run_for(), run_until(), poll() or poll_one() must be called for the + * io_context to perform asynchronous operations on behalf of a C++ program. + * Notification that an asynchronous operation has completed is delivered by + * invocation of the associated handler. Handlers are invoked only by a thread + * that is currently calling any overload of run(), run_one(), run_for(), + * run_until(), poll() or poll_one() for the io_context. + * + * @par Effect of exceptions thrown from handlers + * + * If an exception is thrown from a handler, the exception is allowed to + * propagate through the throwing thread's invocation of run(), run_one(), + * run_for(), run_until(), poll() or poll_one(). No other threads that are + * calling any of these functions are affected. It is then the responsibility + * of the application to catch the exception. + * + * After the exception has been caught, the run(), run_one(), run_for(), + * run_until(), poll() or poll_one() call may be restarted @em without the need + * for an intervening call to restart(). This allows the thread to rejoin the + * io_context object's thread pool without impacting any other threads in the + * pool. + * + * For example: + * + * @code + * boost::asio::io_context io_context; + * ... + * for (;;) + * { + * try + * { + * io_context.run(); + * break; // run() exited normally + * } + * catch (my_exception& e) + * { + * // Deal with exception as appropriate. + * } + * } + * @endcode + * + * @par Submitting arbitrary tasks to the io_context + * + * To submit functions to the io_context, use the @ref boost::asio::dispatch, + * @ref boost::asio::post or @ref boost::asio::defer free functions. + * + * For example: + * + * @code void my_task() + * { + * ... + * } + * + * ... + * + * boost::asio::io_context io_context; + * + * // Submit a function to the io_context. + * boost::asio::post(io_context, my_task); + * + * // Submit a lambda object to the io_context. + * boost::asio::post(io_context, + * []() + * { + * ... + * }); + * + * // Run the io_context until it runs out of work. + * io_context.run(); @endcode + * + * @par Stopping the io_context from running out of work + * + * Some applications may need to prevent an io_context object's run() call from + * returning when there is no more work to do. For example, the io_context may + * be being run in a background thread that is launched prior to the + * application's asynchronous operations. The run() call may be kept running by + * creating an object of type + * boost::asio::executor_work_guard<io_context::executor_type>: + * + * @code boost::asio::io_context io_context; + * boost::asio::executor_work_guard<boost::asio::io_context::executor_type> + * = boost::asio::make_work_guard(io_context); + * ... @endcode + * + * To effect a shutdown, the application will then need to call the io_context + * object's stop() member function. This will cause the io_context run() call + * to return as soon as possible, abandoning unfinished operations and without + * permitting ready handlers to be dispatched. + * + * Alternatively, if the application requires that all operations and handlers + * be allowed to finish normally, the work object may be explicitly reset. + * + * @code boost::asio::io_context io_context; + * boost::asio::executor_work_guard<boost::asio::io_context::executor_type> + * = boost::asio::make_work_guard(io_context); + * ... + * work.reset(); // Allow run() to exit. @endcode + */ +class io_context + : public execution_context +{ +private: + typedef detail::io_context_impl impl_type; +#if defined(BOOST_ASIO_HAS_IOCP) + friend class detail::win_iocp_overlapped_ptr; +#endif + +public: + class executor_type; + friend class executor_type; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + class work; + friend class work; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + class service; + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) + class strand; +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + + /// The type used to count the number of handlers executed by the context. + typedef std::size_t count_type; + + /// Constructor. + BOOST_ASIO_DECL io_context(); + + /// Constructor. + /** + * Construct with a hint about the required level of concurrency. + * + * @param concurrency_hint A suggestion to the implementation on how many + * threads it should allow to run simultaneously. + */ + BOOST_ASIO_DECL explicit io_context(int concurrency_hint); + + /// Destructor. + /** + * On destruction, the io_context performs the following sequence of + * operations: + * + * @li For each service object @c svc in the io_context set, in reverse order + * of the beginning of service object lifetime, performs + * @c svc->shutdown(). + * + * @li Uninvoked handler objects that were scheduled for deferred invocation + * on the io_context, or any associated strand, are destroyed. + * + * @li For each service object @c svc in the io_context set, in reverse order + * of the beginning of service object lifetime, performs + * <tt>delete static_cast<io_context::service*>(svc)</tt>. + * + * @note The destruction sequence described above permits programs to + * simplify their resource management by using @c shared_ptr<>. Where an + * object's lifetime is tied to the lifetime of a connection (or some other + * sequence of asynchronous operations), a @c shared_ptr to the object would + * be bound into the handlers for all asynchronous operations associated with + * it. This works as follows: + * + * @li When a single connection ends, all associated asynchronous operations + * complete. The corresponding handler objects are destroyed, and all + * @c shared_ptr references to the objects are destroyed. + * + * @li To shut down the whole program, the io_context function stop() is + * called to terminate any run() calls as soon as possible. The io_context + * destructor defined above destroys all handlers, causing all @c shared_ptr + * references to all connection objects to be destroyed. + */ + BOOST_ASIO_DECL ~io_context(); + + /// Obtains the executor associated with the io_context. + executor_type get_executor() BOOST_ASIO_NOEXCEPT; + + /// Run the io_context object's event processing loop. + /** + * The run() function blocks until all work has finished and there are no + * more handlers to be dispatched, or until the io_context has been stopped. + * + * Multiple threads may call the run() function to set up a pool of threads + * from which the io_context may execute handlers. All threads that are + * waiting in the pool are equivalent and the io_context may choose any one + * of them to invoke a handler. + * + * A normal exit from the run() function implies that the io_context object + * is stopped (the stopped() function returns @c true). Subsequent calls to + * run(), run_one(), poll() or poll_one() will return immediately unless there + * is a prior call to restart(). + * + * @return The number of handlers that were executed. + * + * @note Calling the run() function from a thread that is currently calling + * one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on + * the same io_context object may introduce the potential for deadlock. It is + * the caller's reponsibility to avoid this. + * + * The poll() function may also be used to dispatch ready handlers, but + * without blocking. + */ + BOOST_ASIO_DECL count_type run(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overload.) Run the io_context object's + /// event processing loop. + /** + * The run() function blocks until all work has finished and there are no + * more handlers to be dispatched, or until the io_context has been stopped. + * + * Multiple threads may call the run() function to set up a pool of threads + * from which the io_context may execute handlers. All threads that are + * waiting in the pool are equivalent and the io_context may choose any one + * of them to invoke a handler. + * + * A normal exit from the run() function implies that the io_context object + * is stopped (the stopped() function returns @c true). Subsequent calls to + * run(), run_one(), poll() or poll_one() will return immediately unless there + * is a prior call to restart(). + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of handlers that were executed. + * + * @note Calling the run() function from a thread that is currently calling + * one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on + * the same io_context object may introduce the potential for deadlock. It is + * the caller's reponsibility to avoid this. + * + * The poll() function may also be used to dispatch ready handlers, but + * without blocking. + */ + BOOST_ASIO_DECL count_type run(boost::system::error_code& ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +#if defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) + /// Run the io_context object's event processing loop for a specified + /// duration. + /** + * The run_for() function blocks until all work has finished and there are no + * more handlers to be dispatched, until the io_context has been stopped, or + * until the specified duration has elapsed. + * + * @param rel_time The duration for which the call may block. + * + * @return The number of handlers that were executed. + */ + template <typename Rep, typename Period> + std::size_t run_for(const chrono::duration<Rep, Period>& rel_time); + + /// Run the io_context object's event processing loop until a specified time. + /** + * The run_until() function blocks until all work has finished and there are + * no more handlers to be dispatched, until the io_context has been stopped, + * or until the specified time has been reached. + * + * @param abs_time The time point until which the call may block. + * + * @return The number of handlers that were executed. + */ + template <typename Clock, typename Duration> + std::size_t run_until(const chrono::time_point<Clock, Duration>& abs_time); +#endif // defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) + + /// Run the io_context object's event processing loop to execute at most one + /// handler. + /** + * The run_one() function blocks until one handler has been dispatched, or + * until the io_context has been stopped. + * + * @return The number of handlers that were executed. A zero return value + * implies that the io_context object is stopped (the stopped() function + * returns @c true). Subsequent calls to run(), run_one(), poll() or + * poll_one() will return immediately unless there is a prior call to + * restart(). + * + * @note Calling the run_one() function from a thread that is currently + * calling one of run(), run_one(), run_for(), run_until(), poll() or + * poll_one() on the same io_context object may introduce the potential for + * deadlock. It is the caller's reponsibility to avoid this. + */ + BOOST_ASIO_DECL count_type run_one(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overlaod.) Run the io_context object's + /// event processing loop to execute at most one handler. + /** + * The run_one() function blocks until one handler has been dispatched, or + * until the io_context has been stopped. + * + * @return The number of handlers that were executed. A zero return value + * implies that the io_context object is stopped (the stopped() function + * returns @c true). Subsequent calls to run(), run_one(), poll() or + * poll_one() will return immediately unless there is a prior call to + * restart(). + * + * @return The number of handlers that were executed. + * + * @note Calling the run_one() function from a thread that is currently + * calling one of run(), run_one(), run_for(), run_until(), poll() or + * poll_one() on the same io_context object may introduce the potential for + * deadlock. It is the caller's reponsibility to avoid this. + */ + BOOST_ASIO_DECL count_type run_one(boost::system::error_code& ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +#if defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) + /// Run the io_context object's event processing loop for a specified duration + /// to execute at most one handler. + /** + * The run_one_for() function blocks until one handler has been dispatched, + * until the io_context has been stopped, or until the specified duration has + * elapsed. + * + * @param rel_time The duration for which the call may block. + * + * @return The number of handlers that were executed. + */ + template <typename Rep, typename Period> + std::size_t run_one_for(const chrono::duration<Rep, Period>& rel_time); + + /// Run the io_context object's event processing loop until a specified time + /// to execute at most one handler. + /** + * The run_one_until() function blocks until one handler has been dispatched, + * until the io_context has been stopped, or until the specified time has + * been reached. + * + * @param abs_time The time point until which the call may block. + * + * @return The number of handlers that were executed. + */ + template <typename Clock, typename Duration> + std::size_t run_one_until( + const chrono::time_point<Clock, Duration>& abs_time); +#endif // defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) + + /// Run the io_context object's event processing loop to execute ready + /// handlers. + /** + * The poll() function runs handlers that are ready to run, without blocking, + * until the io_context has been stopped or there are no more ready handlers. + * + * @return The number of handlers that were executed. + */ + BOOST_ASIO_DECL count_type poll(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overload.) Run the io_context object's + /// event processing loop to execute ready handlers. + /** + * The poll() function runs handlers that are ready to run, without blocking, + * until the io_context has been stopped or there are no more ready handlers. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of handlers that were executed. + */ + BOOST_ASIO_DECL count_type poll(boost::system::error_code& ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Run the io_context object's event processing loop to execute one ready + /// handler. + /** + * The poll_one() function runs at most one handler that is ready to run, + * without blocking. + * + * @return The number of handlers that were executed. + */ + BOOST_ASIO_DECL count_type poll_one(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overload.) Run the io_context object's + /// event processing loop to execute one ready handler. + /** + * The poll_one() function runs at most one handler that is ready to run, + * without blocking. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of handlers that were executed. + */ + BOOST_ASIO_DECL count_type poll_one(boost::system::error_code& ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Stop the io_context object's event processing loop. + /** + * This function does not block, but instead simply signals the io_context to + * stop. All invocations of its run() or run_one() member functions should + * return as soon as possible. Subsequent calls to run(), run_one(), poll() + * or poll_one() will return immediately until restart() is called. + */ + BOOST_ASIO_DECL void stop(); + + /// Determine whether the io_context object has been stopped. + /** + * This function is used to determine whether an io_context object has been + * stopped, either through an explicit call to stop(), or due to running out + * of work. When an io_context object is stopped, calls to run(), run_one(), + * poll() or poll_one() will return immediately without invoking any + * handlers. + * + * @return @c true if the io_context object is stopped, otherwise @c false. + */ + BOOST_ASIO_DECL bool stopped() const; + + /// Restart the io_context in preparation for a subsequent run() invocation. + /** + * This function must be called prior to any second or later set of + * invocations of the run(), run_one(), poll() or poll_one() functions when a + * previous invocation of these functions returned due to the io_context + * being stopped or running out of work. After a call to restart(), the + * io_context object's stopped() function will return @c false. + * + * This function must not be called while there are any unfinished calls to + * the run(), run_one(), poll() or poll_one() functions. + */ + BOOST_ASIO_DECL void restart(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use restart().) Reset the io_context in preparation for a + /// subsequent run() invocation. + /** + * This function must be called prior to any second or later set of + * invocations of the run(), run_one(), poll() or poll_one() functions when a + * previous invocation of these functions returned due to the io_context + * being stopped or running out of work. After a call to restart(), the + * io_context object's stopped() function will return @c false. + * + * This function must not be called while there are any unfinished calls to + * the run(), run_one(), poll() or poll_one() functions. + */ + void reset(); + + /// (Deprecated: Use boost::asio::dispatch().) Request the io_context to + /// invoke the given handler. + /** + * This function is used to ask the io_context to execute the given handler. + * + * The io_context guarantees that the handler will only be called in a thread + * in which the run(), run_one(), poll() or poll_one() member functions is + * currently being invoked. The handler may be executed inside this function + * if the guarantee can be met. + * + * @param handler The handler to be called. The io_context will make + * a copy of the handler object as required. The function signature of the + * handler must be: @code void handler(); @endcode + * + * @note This function throws an exception only if: + * + * @li the handler's @c asio_handler_allocate function; or + * + * @li the handler's copy constructor + * + * throws an exception. + */ + template <typename CompletionHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) + dispatch(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler); + + /// (Deprecated: Use boost::asio::post().) Request the io_context to invoke + /// the given handler and return immediately. + /** + * This function is used to ask the io_context to execute the given handler, + * but without allowing the io_context to call the handler from inside this + * function. + * + * The io_context guarantees that the handler will only be called in a thread + * in which the run(), run_one(), poll() or poll_one() member functions is + * currently being invoked. + * + * @param handler The handler to be called. The io_context will make + * a copy of the handler object as required. The function signature of the + * handler must be: @code void handler(); @endcode + * + * @note This function throws an exception only if: + * + * @li the handler's @c asio_handler_allocate function; or + * + * @li the handler's copy constructor + * + * throws an exception. + */ + template <typename CompletionHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) + post(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler); + + /// (Deprecated: Use boost::asio::bind_executor().) Create a new handler that + /// automatically dispatches the wrapped handler on the io_context. + /** + * This function is used to create a new handler function object that, when + * invoked, will automatically pass the wrapped handler to the io_context + * object's dispatch function. + * + * @param handler The handler to be wrapped. The io_context will make a copy + * of the handler object as required. The function signature of the handler + * must be: @code void handler(A1 a1, ... An an); @endcode + * + * @return A function object that, when invoked, passes the wrapped handler to + * the io_context object's dispatch function. Given a function object with the + * signature: + * @code R f(A1 a1, ... An an); @endcode + * If this function object is passed to the wrap function like so: + * @code io_context.wrap(f); @endcode + * then the return value is a function object with the signature + * @code void g(A1 a1, ... An an); @endcode + * that, when invoked, executes code equivalent to: + * @code io_context.dispatch(boost::bind(f, a1, ... an)); @endcode + */ + template <typename Handler> +#if defined(GENERATING_DOCUMENTATION) + unspecified +#else + detail::wrapped_handler<io_context&, Handler> +#endif + wrap(Handler handler); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +private: + // Helper function to add the implementation. + BOOST_ASIO_DECL impl_type& add_impl(impl_type* impl); + + // Backwards compatible overload for use with services derived from + // io_context::service. + template <typename Service> + friend Service& use_service(io_context& ioc); + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + detail::winsock_init<> init_; +#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ + || defined(__osf__) + detail::signal_init<> init_; +#endif + + // The implementation. + impl_type& impl_; +}; + +/// Executor used to submit functions to an io_context. +class io_context::executor_type +{ +public: + /// Obtain the underlying execution context. + io_context& context() const BOOST_ASIO_NOEXCEPT; + + /// Inform the io_context that it has some outstanding work to do. + /** + * This function is used to inform the io_context that some work has begun. + * This ensures that the io_context's run() and run_one() functions do not + * exit while the work is underway. + */ + void on_work_started() const BOOST_ASIO_NOEXCEPT; + + /// Inform the io_context that some work is no longer outstanding. + /** + * This function is used to inform the io_context that some work has + * finished. Once the count of unfinished work reaches zero, the io_context + * is stopped and the run() and run_one() functions may exit. + */ + void on_work_finished() const BOOST_ASIO_NOEXCEPT; + + /// Request the io_context to invoke the given function object. + /** + * This function is used to ask the io_context to execute the given function + * object. If the current thread is running the io_context, @c dispatch() + * executes the function before returning. Otherwise, the function will be + * scheduled to run on the io_context. + * + * @param f The function object to be called. The executor will make a copy + * of the handler object as required. The function signature of the function + * object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Request the io_context to invoke the given function object. + /** + * This function is used to ask the io_context to execute the given function + * object. The function object will never be executed inside @c post(). + * Instead, it will be scheduled to run on the io_context. + * + * @param f The function object to be called. The executor will make a copy + * of the handler object as required. The function signature of the function + * object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Request the io_context to invoke the given function object. + /** + * This function is used to ask the io_context to execute the given function + * object. The function object will never be executed inside @c defer(). + * Instead, it will be scheduled to run on the io_context. + * + * If the current thread belongs to the io_context, @c defer() will delay + * scheduling the function object until the current thread returns control to + * the pool. + * + * @param f The function object to be called. The executor will make a copy + * of the handler object as required. The function signature of the function + * object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Determine whether the io_context is running in the current thread. + /** + * @return @c true if the current thread is running the io_context. Otherwise + * returns @c false. + */ + bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT; + + /// Compare two executors for equality. + /** + * Two executors are equal if they refer to the same underlying io_context. + */ + friend bool operator==(const executor_type& a, + const executor_type& b) BOOST_ASIO_NOEXCEPT + { + return &a.io_context_ == &b.io_context_; + } + + /// Compare two executors for inequality. + /** + * Two executors are equal if they refer to the same underlying io_context. + */ + friend bool operator!=(const executor_type& a, + const executor_type& b) BOOST_ASIO_NOEXCEPT + { + return &a.io_context_ != &b.io_context_; + } + +private: + friend class io_context; + + // Constructor. + explicit executor_type(io_context& i) : io_context_(i) {} + + // The underlying io_context. + io_context& io_context_; +}; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +/// (Deprecated: Use executor_work_guard.) Class to inform the io_context when +/// it has work to do. +/** + * The work class is used to inform the io_context when work starts and + * finishes. This ensures that the io_context object's run() function will not + * exit while work is underway, and that it does exit when there is no + * unfinished work remaining. + * + * The work class is copy-constructible so that it may be used as a data member + * in a handler class. It is not assignable. + */ +class io_context::work +{ +public: + /// Constructor notifies the io_context that work is starting. + /** + * The constructor is used to inform the io_context that some work has begun. + * This ensures that the io_context object's run() function will not exit + * while the work is underway. + */ + explicit work(boost::asio::io_context& io_context); + + /// Copy constructor notifies the io_context that work is starting. + /** + * The constructor is used to inform the io_context that some work has begun. + * This ensures that the io_context object's run() function will not exit + * while the work is underway. + */ + work(const work& other); + + /// Destructor notifies the io_context that the work is complete. + /** + * The destructor is used to inform the io_context that some work has + * finished. Once the count of unfinished work reaches zero, the io_context + * object's run() function is permitted to exit. + */ + ~work(); + + /// Get the io_context associated with the work. + boost::asio::io_context& get_io_context(); + + /// (Deprecated: Use get_io_context().) Get the io_context associated with the + /// work. + boost::asio::io_context& get_io_service(); + +private: + // Prevent assignment. + void operator=(const work& other); + + // The io_context implementation. + detail::io_context_impl& io_context_impl_; +}; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +/// Base class for all io_context services. +class io_context::service + : public execution_context::service +{ +public: + /// Get the io_context object that owns the service. + boost::asio::io_context& get_io_context(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// Get the io_context object that owns the service. + boost::asio::io_context& get_io_service(); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +private: + /// Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL virtual void shutdown(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use shutdown().) Destroy all user-defined handler objects + /// owned by the service. + BOOST_ASIO_DECL virtual void shutdown_service(); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Handle notification of a fork-related event to perform any necessary + /// housekeeping. + /** + * This function is not a pure virtual so that services only have to + * implement it if necessary. The default implementation does nothing. + */ + BOOST_ASIO_DECL virtual void notify_fork( + execution_context::fork_event event); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use notify_fork().) Handle notification of a fork-related + /// event to perform any necessary housekeeping. + /** + * This function is not a pure virtual so that services only have to + * implement it if necessary. The default implementation does nothing. + */ + BOOST_ASIO_DECL virtual void fork_service( + execution_context::fork_event event); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +protected: + /// Constructor. + /** + * @param owner The io_context object that owns the service. + */ + BOOST_ASIO_DECL service(boost::asio::io_context& owner); + + /// Destructor. + BOOST_ASIO_DECL virtual ~service(); +}; + +namespace detail { + +// Special service base class to keep classes header-file only. +template <typename Type> +class service_base + : public boost::asio::io_context::service +{ +public: + static boost::asio::detail::service_id<Type> id; + + // Constructor. + service_base(boost::asio::io_context& io_context) + : boost::asio::io_context::service(io_context) + { + } +}; + +template <typename Type> +boost::asio::detail::service_id<Type> service_base<Type>::id; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#include <boost/asio/impl/io_context.hpp> +#if defined(BOOST_ASIO_HEADER_ONLY) +# include <boost/asio/impl/io_context.ipp> +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +// If both io_context.hpp and strand.hpp have been included, automatically +// include the header file needed for the io_context::strand class. +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +# if defined(BOOST_ASIO_STRAND_HPP) +# include <boost/asio/io_context_strand.hpp> +# endif // defined(BOOST_ASIO_STRAND_HPP) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +#endif // BOOST_ASIO_IO_CONTEXT_HPP diff --git a/boost/asio/io_context_strand.hpp b/boost/asio/io_context_strand.hpp new file mode 100644 index 0000000000..2190a7b7db --- /dev/null +++ b/boost/asio/io_context_strand.hpp @@ -0,0 +1,384 @@ +// +// io_context_strand.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IO_CONTEXT_STRAND_HPP +#define BOOST_ASIO_IO_CONTEXT_STRAND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) + +#include <boost/asio/async_result.hpp> +#include <boost/asio/detail/handler_type_requirements.hpp> +#include <boost/asio/detail/strand_service.hpp> +#include <boost/asio/detail/wrapped_handler.hpp> +#include <boost/asio/io_context.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +/// Provides serialised handler execution. +/** + * The io_context::strand class provides the ability to post and dispatch + * handlers with the guarantee that none of those handlers will execute + * concurrently. + * + * @par Order of handler invocation + * Given: + * + * @li a strand object @c s + * + * @li an object @c a meeting completion handler requirements + * + * @li an object @c a1 which is an arbitrary copy of @c a made by the + * implementation + * + * @li an object @c b meeting completion handler requirements + * + * @li an object @c b1 which is an arbitrary copy of @c b made by the + * implementation + * + * if any of the following conditions are true: + * + * @li @c s.post(a) happens-before @c s.post(b) + * + * @li @c s.post(a) happens-before @c s.dispatch(b), where the latter is + * performed outside the strand + * + * @li @c s.dispatch(a) happens-before @c s.post(b), where the former is + * performed outside the strand + * + * @li @c s.dispatch(a) happens-before @c s.dispatch(b), where both are + * performed outside the strand + * + * then @c asio_handler_invoke(a1, &a1) happens-before + * @c asio_handler_invoke(b1, &b1). + * + * Note that in the following case: + * @code async_op_1(..., s.wrap(a)); + * async_op_2(..., s.wrap(b)); @endcode + * the completion of the first async operation will perform @c s.dispatch(a), + * and the second will perform @c s.dispatch(b), but the order in which those + * are performed is unspecified. That is, you cannot state whether one + * happens-before the other. Therefore none of the above conditions are met and + * no ordering guarantee is made. + * + * @note The implementation makes no guarantee that handlers posted or + * dispatched through different @c strand objects will be invoked concurrently. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe. + * + * @par Concepts: + * Dispatcher. + */ +class io_context::strand +{ +public: + /// Constructor. + /** + * Constructs the strand. + * + * @param io_context The io_context object that the strand will use to + * dispatch handlers that are ready to be run. + */ + explicit strand(boost::asio::io_context& io_context) + : service_(boost::asio::use_service< + boost::asio::detail::strand_service>(io_context)) + { + service_.construct(impl_); + } + + /// Destructor. + /** + * Destroys a strand. + * + * Handlers posted through the strand that have not yet been invoked will + * still be dispatched in a way that meets the guarantee of non-concurrency. + */ + ~strand() + { + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use context().) Get the io_context associated with the + /// strand. + /** + * This function may be used to obtain the io_context object that the strand + * uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the strand will use to + * dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_context() + { + return service_.get_io_context(); + } + + /// (Deprecated: Use context().) Get the io_context associated with the + /// strand. + /** + * This function may be used to obtain the io_context object that the strand + * uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the strand will use to + * dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_service() + { + return service_.get_io_context(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Obtain the underlying execution context. + boost::asio::io_context& context() const BOOST_ASIO_NOEXCEPT + { + return service_.get_io_context(); + } + + /// Inform the strand that it has some outstanding work to do. + /** + * The strand delegates this call to its underlying io_context. + */ + void on_work_started() const BOOST_ASIO_NOEXCEPT + { + context().get_executor().on_work_started(); + } + + /// Inform the strand that some work is no longer outstanding. + /** + * The strand delegates this call to its underlying io_context. + */ + void on_work_finished() const BOOST_ASIO_NOEXCEPT + { + context().get_executor().on_work_finished(); + } + + /// Request the strand to invoke the given function object. + /** + * This function is used to ask the strand to execute the given function + * object on its underlying io_context. The function object will be executed + * inside this function if the strand is not otherwise busy and if the + * underlying io_context's executor's @c dispatch() function is also able to + * execute the function before returning. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const + { + typename decay<Function>::type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); + service_.dispatch(impl_, tmp); + (void)a; + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use boost::asio::dispatch().) Request the strand to invoke + /// the given handler. + /** + * This function is used to ask the strand to execute the given handler. + * + * The strand object guarantees that handlers posted or dispatched through + * the strand will not be executed concurrently. The handler may be executed + * inside this function if the guarantee can be met. If this function is + * called from within a handler that was posted or dispatched through the same + * strand, then the new handler will be executed immediately. + * + * The strand's guarantee is in addition to the guarantee provided by the + * underlying io_context. The io_context guarantees that the handler will only + * be called in a thread in which the io_context's run member function is + * currently being invoked. + * + * @param handler The handler to be called. The strand will make a copy of the + * handler object as required. The function signature of the handler must be: + * @code void handler(); @endcode + */ + template <typename CompletionHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) + dispatch(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a CompletionHandler. + BOOST_ASIO_COMPLETION_HANDLER_CHECK(CompletionHandler, handler) type_check; + + async_completion<CompletionHandler, void ()> init(handler); + + service_.dispatch(impl_, init.completion_handler); + + return init.result.get(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Request the strand to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object will never be executed inside this function. + * Instead, it will be scheduled to run by the underlying io_context. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const + { + typename decay<Function>::type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); + service_.post(impl_, tmp); + (void)a; + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use boost::asio::post().) Request the strand to invoke the + /// given handler and return immediately. + /** + * This function is used to ask the strand to execute the given handler, but + * without allowing the strand to call the handler from inside this function. + * + * The strand object guarantees that handlers posted or dispatched through + * the strand will not be executed concurrently. The strand's guarantee is in + * addition to the guarantee provided by the underlying io_context. The + * io_context guarantees that the handler will only be called in a thread in + * which the io_context's run member function is currently being invoked. + * + * @param handler The handler to be called. The strand will make a copy of the + * handler object as required. The function signature of the handler must be: + * @code void handler(); @endcode + */ + template <typename CompletionHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) + post(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a CompletionHandler. + BOOST_ASIO_COMPLETION_HANDLER_CHECK(CompletionHandler, handler) type_check; + + async_completion<CompletionHandler, void ()> init(handler); + + service_.post(impl_, init.completion_handler); + + return init.result.get(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Request the strand to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object will never be executed inside this function. + * Instead, it will be scheduled to run by the underlying io_context. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const + { + typename decay<Function>::type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); + service_.post(impl_, tmp); + (void)a; + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use boost::asio::bind_executor().) Create a new handler that + /// automatically dispatches the wrapped handler on the strand. + /** + * This function is used to create a new handler function object that, when + * invoked, will automatically pass the wrapped handler to the strand's + * dispatch function. + * + * @param handler The handler to be wrapped. The strand will make a copy of + * the handler object as required. The function signature of the handler must + * be: @code void handler(A1 a1, ... An an); @endcode + * + * @return A function object that, when invoked, passes the wrapped handler to + * the strand's dispatch function. Given a function object with the signature: + * @code R f(A1 a1, ... An an); @endcode + * If this function object is passed to the wrap function like so: + * @code strand.wrap(f); @endcode + * then the return value is a function object with the signature + * @code void g(A1 a1, ... An an); @endcode + * that, when invoked, executes code equivalent to: + * @code strand.dispatch(boost::bind(f, a1, ... an)); @endcode + */ + template <typename Handler> +#if defined(GENERATING_DOCUMENTATION) + unspecified +#else + detail::wrapped_handler<strand, Handler, detail::is_continuation_if_running> +#endif + wrap(Handler handler) + { + return detail::wrapped_handler<io_context::strand, Handler, + detail::is_continuation_if_running>(*this, handler); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Determine whether the strand is running in the current thread. + /** + * @return @c true if the current thread is executing a handler that was + * submitted to the strand using post(), dispatch() or wrap(). Otherwise + * returns @c false. + */ + bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT + { + return service_.running_in_this_thread(impl_); + } + + /// Compare two strands for equality. + /** + * Two strands are equal if they refer to the same ordered, non-concurrent + * state. + */ + friend bool operator==(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT + { + return a.impl_ == b.impl_; + } + + /// Compare two strands for inequality. + /** + * Two strands are equal if they refer to the same ordered, non-concurrent + * state. + */ + friend bool operator!=(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT + { + return a.impl_ != b.impl_; + } + +private: + boost::asio::detail::strand_service& service_; + mutable boost::asio::detail::strand_service::implementation_type impl_; +}; + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +#endif // BOOST_ASIO_IO_CONTEXT_STRAND_HPP diff --git a/boost/asio/io_service.hpp b/boost/asio/io_service.hpp index f2b4667311..b04424dd69 100644 --- a/boost/asio/io_service.hpp +++ b/boost/asio/io_service.hpp @@ -15,758 +15,21 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include <boost/asio/detail/config.hpp> -#include <cstddef> -#include <stdexcept> -#include <typeinfo> -#include <boost/asio/async_result.hpp> -#include <boost/asio/detail/noncopyable.hpp> -#include <boost/asio/detail/wrapped_handler.hpp> -#include <boost/system/error_code.hpp> - -#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) -# include <boost/asio/detail/winsock_init.hpp> -#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ - || defined(__osf__) -# include <boost/asio/detail/signal_init.hpp> -#endif +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { -class io_service; -template <typename Service> Service& use_service(io_service& ios); -template <typename Service> void add_service(io_service& ios, Service* svc); -template <typename Service> bool has_service(io_service& ios); - -namespace detail { -#if defined(BOOST_ASIO_HAS_IOCP) - typedef class win_iocp_io_service io_service_impl; - class win_iocp_overlapped_ptr; -#else - typedef class task_io_service io_service_impl; -#endif - class service_registry; -} // namespace detail - -/// Provides core I/O functionality. -/** - * The io_service class provides the core I/O functionality for users of the - * asynchronous I/O objects, including: - * - * @li boost::asio::ip::tcp::socket - * @li boost::asio::ip::tcp::acceptor - * @li boost::asio::ip::udp::socket - * @li boost::asio::deadline_timer. - * - * The io_service class also includes facilities intended for developers of - * custom asynchronous services. - * - * @par Thread Safety - * @e Distinct @e objects: Safe.@n - * @e Shared @e objects: Safe, with the specific exceptions of the reset() and - * notify_fork() functions. Calling reset() while there are unfinished run(), - * run_one(), poll() or poll_one() calls results in undefined behaviour. The - * notify_fork() function should not be called while any io_service function, - * or any function on an I/O object that is associated with the io_service, is - * being called in another thread. - * - * @par Concepts: - * Dispatcher. - * - * @par Synchronous and asynchronous operations - * - * Synchronous operations on I/O objects implicitly run the io_service object - * for an individual operation. The io_service functions run(), run_one(), - * poll() or poll_one() must be called for the io_service to perform - * asynchronous operations on behalf of a C++ program. Notification that an - * asynchronous operation has completed is delivered by invocation of the - * associated handler. Handlers are invoked only by a thread that is currently - * calling any overload of run(), run_one(), poll() or poll_one() for the - * io_service. - * - * @par Effect of exceptions thrown from handlers - * - * If an exception is thrown from a handler, the exception is allowed to - * propagate through the throwing thread's invocation of run(), run_one(), - * poll() or poll_one(). No other threads that are calling any of these - * functions are affected. It is then the responsibility of the application to - * catch the exception. - * - * After the exception has been caught, the run(), run_one(), poll() or - * poll_one() call may be restarted @em without the need for an intervening - * call to reset(). This allows the thread to rejoin the io_service object's - * thread pool without impacting any other threads in the pool. - * - * For example: - * - * @code - * boost::asio::io_service io_service; - * ... - * for (;;) - * { - * try - * { - * io_service.run(); - * break; // run() exited normally - * } - * catch (my_exception& e) - * { - * // Deal with exception as appropriate. - * } - * } - * @endcode - * - * @par Stopping the io_service from running out of work - * - * Some applications may need to prevent an io_service object's run() call from - * returning when there is no more work to do. For example, the io_service may - * be being run in a background thread that is launched prior to the - * application's asynchronous operations. The run() call may be kept running by - * creating an object of type boost::asio::io_service::work: - * - * @code boost::asio::io_service io_service; - * boost::asio::io_service::work work(io_service); - * ... @endcode - * - * To effect a shutdown, the application will then need to call the io_service - * object's stop() member function. This will cause the io_service run() call - * to return as soon as possible, abandoning unfinished operations and without - * permitting ready handlers to be dispatched. - * - * Alternatively, if the application requires that all operations and handlers - * be allowed to finish normally, the work object may be explicitly destroyed. - * - * @code boost::asio::io_service io_service; - * auto_ptr<boost::asio::io_service::work> work( - * new boost::asio::io_service::work(io_service)); - * ... - * work.reset(); // Allow run() to exit. @endcode - * - * @par The io_service class and I/O services - * - * Class io_service implements an extensible, type-safe, polymorphic set of I/O - * services, indexed by service type. An object of class io_service must be - * initialised before I/O objects such as sockets, resolvers and timers can be - * used. These I/O objects are distinguished by having constructors that accept - * an @c io_service& parameter. - * - * I/O services exist to manage the logical interface to the operating system on - * behalf of the I/O objects. In particular, there are resources that are shared - * across a class of I/O objects. For example, timers may be implemented in - * terms of a single timer queue. The I/O services manage these shared - * resources. - * - * Access to the services of an io_service is via three function templates, - * use_service(), add_service() and has_service(). - * - * In a call to @c use_service<Service>(), the type argument chooses a service, - * making available all members of the named type. If @c Service is not present - * in an io_service, an object of type @c Service is created and added to the - * io_service. A C++ program can check if an io_service implements a - * particular service with the function template @c has_service<Service>(). - * - * Service objects may be explicitly added to an io_service using the function - * template @c add_service<Service>(). If the @c Service is already present, the - * service_already_exists exception is thrown. If the owner of the service is - * not the same object as the io_service parameter, the invalid_service_owner - * exception is thrown. - * - * Once a service reference is obtained from an io_service object by calling - * use_service(), that reference remains usable as long as the owning io_service - * object exists. - * - * All I/O service implementations have io_service::service as a public base - * class. Custom I/O services may be implemented by deriving from this class and - * then added to an io_service using the facilities described above. - */ -class io_service - : private noncopyable -{ -private: - typedef detail::io_service_impl impl_type; -#if defined(BOOST_ASIO_HAS_IOCP) - friend class detail::win_iocp_overlapped_ptr; -#endif - -public: - class work; - friend class work; - - class id; - - class service; - - class strand; - - /// Constructor. - BOOST_ASIO_DECL io_service(); - - /// Constructor. - /** - * Construct with a hint about the required level of concurrency. - * - * @param concurrency_hint A suggestion to the implementation on how many - * threads it should allow to run simultaneously. - */ - BOOST_ASIO_DECL explicit io_service(std::size_t concurrency_hint); - - /// Destructor. - /** - * On destruction, the io_service performs the following sequence of - * operations: - * - * @li For each service object @c svc in the io_service set, in reverse order - * of the beginning of service object lifetime, performs - * @c svc->shutdown_service(). - * - * @li Uninvoked handler objects that were scheduled for deferred invocation - * on the io_service, or any associated strand, are destroyed. - * - * @li For each service object @c svc in the io_service set, in reverse order - * of the beginning of service object lifetime, performs - * <tt>delete static_cast<io_service::service*>(svc)</tt>. - * - * @note The destruction sequence described above permits programs to - * simplify their resource management by using @c shared_ptr<>. Where an - * object's lifetime is tied to the lifetime of a connection (or some other - * sequence of asynchronous operations), a @c shared_ptr to the object would - * be bound into the handlers for all asynchronous operations associated with - * it. This works as follows: - * - * @li When a single connection ends, all associated asynchronous operations - * complete. The corresponding handler objects are destroyed, and all - * @c shared_ptr references to the objects are destroyed. - * - * @li To shut down the whole program, the io_service function stop() is - * called to terminate any run() calls as soon as possible. The io_service - * destructor defined above destroys all handlers, causing all @c shared_ptr - * references to all connection objects to be destroyed. - */ - BOOST_ASIO_DECL ~io_service(); - - /// Run the io_service object's event processing loop. - /** - * The run() function blocks until all work has finished and there are no - * more handlers to be dispatched, or until the io_service has been stopped. - * - * Multiple threads may call the run() function to set up a pool of threads - * from which the io_service may execute handlers. All threads that are - * waiting in the pool are equivalent and the io_service may choose any one - * of them to invoke a handler. - * - * A normal exit from the run() function implies that the io_service object - * is stopped (the stopped() function returns @c true). Subsequent calls to - * run(), run_one(), poll() or poll_one() will return immediately unless there - * is a prior call to reset(). - * - * @return The number of handlers that were executed. - * - * @throws boost::system::system_error Thrown on failure. - * - * @note The run() function must not be called from a thread that is currently - * calling one of run(), run_one(), poll() or poll_one() on the same - * io_service object. - * - * The poll() function may also be used to dispatch ready handlers, but - * without blocking. - */ - BOOST_ASIO_DECL std::size_t run(); - - /// Run the io_service object's event processing loop. - /** - * The run() function blocks until all work has finished and there are no - * more handlers to be dispatched, or until the io_service has been stopped. - * - * Multiple threads may call the run() function to set up a pool of threads - * from which the io_service may execute handlers. All threads that are - * waiting in the pool are equivalent and the io_service may choose any one - * of them to invoke a handler. - * - * A normal exit from the run() function implies that the io_service object - * is stopped (the stopped() function returns @c true). Subsequent calls to - * run(), run_one(), poll() or poll_one() will return immediately unless there - * is a prior call to reset(). - * - * @param ec Set to indicate what error occurred, if any. - * - * @return The number of handlers that were executed. - * - * @note The run() function must not be called from a thread that is currently - * calling one of run(), run_one(), poll() or poll_one() on the same - * io_service object. - * - * The poll() function may also be used to dispatch ready handlers, but - * without blocking. - */ - BOOST_ASIO_DECL std::size_t run(boost::system::error_code& ec); - - /// Run the io_service object's event processing loop to execute at most one - /// handler. - /** - * The run_one() function blocks until one handler has been dispatched, or - * until the io_service has been stopped. - * - * @return The number of handlers that were executed. A zero return value - * implies that the io_service object is stopped (the stopped() function - * returns @c true). Subsequent calls to run(), run_one(), poll() or - * poll_one() will return immediately unless there is a prior call to - * reset(). - * - * @throws boost::system::system_error Thrown on failure. - */ - BOOST_ASIO_DECL std::size_t run_one(); - - /// Run the io_service object's event processing loop to execute at most one - /// handler. - /** - * The run_one() function blocks until one handler has been dispatched, or - * until the io_service has been stopped. - * - * @return The number of handlers that were executed. A zero return value - * implies that the io_service object is stopped (the stopped() function - * returns @c true). Subsequent calls to run(), run_one(), poll() or - * poll_one() will return immediately unless there is a prior call to - * reset(). - * - * @return The number of handlers that were executed. - */ - BOOST_ASIO_DECL std::size_t run_one(boost::system::error_code& ec); - - /// Run the io_service object's event processing loop to execute ready - /// handlers. - /** - * The poll() function runs handlers that are ready to run, without blocking, - * until the io_service has been stopped or there are no more ready handlers. - * - * @return The number of handlers that were executed. - * - * @throws boost::system::system_error Thrown on failure. - */ - BOOST_ASIO_DECL std::size_t poll(); - - /// Run the io_service object's event processing loop to execute ready - /// handlers. - /** - * The poll() function runs handlers that are ready to run, without blocking, - * until the io_service has been stopped or there are no more ready handlers. - * - * @param ec Set to indicate what error occurred, if any. - * - * @return The number of handlers that were executed. - */ - BOOST_ASIO_DECL std::size_t poll(boost::system::error_code& ec); - - /// Run the io_service object's event processing loop to execute one ready - /// handler. - /** - * The poll_one() function runs at most one handler that is ready to run, - * without blocking. - * - * @return The number of handlers that were executed. - * - * @throws boost::system::system_error Thrown on failure. - */ - BOOST_ASIO_DECL std::size_t poll_one(); - - /// Run the io_service object's event processing loop to execute one ready - /// handler. - /** - * The poll_one() function runs at most one handler that is ready to run, - * without blocking. - * - * @param ec Set to indicate what error occurred, if any. - * - * @return The number of handlers that were executed. - */ - BOOST_ASIO_DECL std::size_t poll_one(boost::system::error_code& ec); - - /// Stop the io_service object's event processing loop. - /** - * This function does not block, but instead simply signals the io_service to - * stop. All invocations of its run() or run_one() member functions should - * return as soon as possible. Subsequent calls to run(), run_one(), poll() - * or poll_one() will return immediately until reset() is called. - */ - BOOST_ASIO_DECL void stop(); - - /// Determine whether the io_service object has been stopped. - /** - * This function is used to determine whether an io_service object has been - * stopped, either through an explicit call to stop(), or due to running out - * of work. When an io_service object is stopped, calls to run(), run_one(), - * poll() or poll_one() will return immediately without invoking any - * handlers. - * - * @return @c true if the io_service object is stopped, otherwise @c false. - */ - BOOST_ASIO_DECL bool stopped() const; - - /// Reset the io_service in preparation for a subsequent run() invocation. - /** - * This function must be called prior to any second or later set of - * invocations of the run(), run_one(), poll() or poll_one() functions when a - * previous invocation of these functions returned due to the io_service - * being stopped or running out of work. After a call to reset(), the - * io_service object's stopped() function will return @c false. - * - * This function must not be called while there are any unfinished calls to - * the run(), run_one(), poll() or poll_one() functions. - */ - BOOST_ASIO_DECL void reset(); - - /// Request the io_service to invoke the given handler. - /** - * This function is used to ask the io_service to execute the given handler. - * - * The io_service guarantees that the handler will only be called in a thread - * in which the run(), run_one(), poll() or poll_one() member functions is - * currently being invoked. The handler may be executed inside this function - * if the guarantee can be met. - * - * @param handler The handler to be called. The io_service will make - * a copy of the handler object as required. The function signature of the - * handler must be: @code void handler(); @endcode - * - * @note This function throws an exception only if: - * - * @li the handler's @c asio_handler_allocate function; or - * - * @li the handler's copy constructor - * - * throws an exception. - */ - template <typename CompletionHandler> - BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) - dispatch(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler); - - /// Request the io_service to invoke the given handler and return immediately. - /** - * This function is used to ask the io_service to execute the given handler, - * but without allowing the io_service to call the handler from inside this - * function. - * - * The io_service guarantees that the handler will only be called in a thread - * in which the run(), run_one(), poll() or poll_one() member functions is - * currently being invoked. - * - * @param handler The handler to be called. The io_service will make - * a copy of the handler object as required. The function signature of the - * handler must be: @code void handler(); @endcode - * - * @note This function throws an exception only if: - * - * @li the handler's @c asio_handler_allocate function; or - * - * @li the handler's copy constructor - * - * throws an exception. - */ - template <typename CompletionHandler> - BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) - post(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler); - - /// Create a new handler that automatically dispatches the wrapped handler - /// on the io_service. - /** - * This function is used to create a new handler function object that, when - * invoked, will automatically pass the wrapped handler to the io_service - * object's dispatch function. - * - * @param handler The handler to be wrapped. The io_service will make a copy - * of the handler object as required. The function signature of the handler - * must be: @code void handler(A1 a1, ... An an); @endcode - * - * @return A function object that, when invoked, passes the wrapped handler to - * the io_service object's dispatch function. Given a function object with the - * signature: - * @code R f(A1 a1, ... An an); @endcode - * If this function object is passed to the wrap function like so: - * @code io_service.wrap(f); @endcode - * then the return value is a function object with the signature - * @code void g(A1 a1, ... An an); @endcode - * that, when invoked, executes code equivalent to: - * @code io_service.dispatch(boost::bind(f, a1, ... an)); @endcode - */ - template <typename Handler> -#if defined(GENERATING_DOCUMENTATION) - unspecified -#else - detail::wrapped_handler<io_service&, Handler> -#endif - wrap(Handler handler); - - /// Fork-related event notifications. - enum fork_event - { - /// Notify the io_service that the process is about to fork. - fork_prepare, - - /// Notify the io_service that the process has forked and is the parent. - fork_parent, - - /// Notify the io_service that the process has forked and is the child. - fork_child - }; - - /// Notify the io_service of a fork-related event. - /** - * This function is used to inform the io_service that the process is about - * to fork, or has just forked. This allows the io_service, and the services - * it contains, to perform any necessary housekeeping to ensure correct - * operation following a fork. - * - * This function must not be called while any other io_service function, or - * any function on an I/O object associated with the io_service, is being - * called in another thread. It is, however, safe to call this function from - * within a completion handler, provided no other thread is accessing the - * io_service. - * - * @param event A fork-related event. - * - * @throws boost::system::system_error Thrown on failure. If the notification - * fails the io_service object should no longer be used and should be - * destroyed. - * - * @par Example - * The following code illustrates how to incorporate the notify_fork() - * function: - * @code my_io_service.notify_fork(boost::asio::io_service::fork_prepare); - * if (fork() == 0) - * { - * // This is the child process. - * my_io_service.notify_fork(boost::asio::io_service::fork_child); - * } - * else - * { - * // This is the parent process. - * my_io_service.notify_fork(boost::asio::io_service::fork_parent); - * } @endcode - * - * @note For each service object @c svc in the io_service set, performs - * <tt>svc->fork_service();</tt>. When processing the fork_prepare event, - * services are visited in reverse order of the beginning of service object - * lifetime. Otherwise, services are visited in order of the beginning of - * service object lifetime. - */ - BOOST_ASIO_DECL void notify_fork(boost::asio::io_service::fork_event event); +#if !defined(BOOST_ASIO_NO_DEPRECATED) +/// Typedef for backwards compatibility. +typedef io_context io_service; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) - /// Obtain the service object corresponding to the given type. - /** - * This function is used to locate a service object that corresponds to - * the given service type. If there is no existing implementation of the - * service, then the io_service will create a new instance of the service. - * - * @param ios The io_service object that owns the service. - * - * @return The service interface implementing the specified service type. - * Ownership of the service interface is not transferred to the caller. - */ - template <typename Service> - friend Service& use_service(io_service& ios); - - /// Add a service object to the io_service. - /** - * This function is used to add a service to the io_service. - * - * @param ios The io_service object that owns the service. - * - * @param svc The service object. On success, ownership of the service object - * is transferred to the io_service. When the io_service object is destroyed, - * it will destroy the service object by performing: - * @code delete static_cast<io_service::service*>(svc) @endcode - * - * @throws boost::asio::service_already_exists Thrown if a service of the - * given type is already present in the io_service. - * - * @throws boost::asio::invalid_service_owner Thrown if the service's owning - * io_service is not the io_service object specified by the ios parameter. - */ - template <typename Service> - friend void add_service(io_service& ios, Service* svc); - - /// Determine if an io_service contains a specified service type. - /** - * This function is used to determine whether the io_service contains a - * service object corresponding to the given service type. - * - * @param ios The io_service object that owns the service. - * - * @return A boolean indicating whether the io_service contains the service. - */ - template <typename Service> - friend bool has_service(io_service& ios); - -private: -#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - detail::winsock_init<> init_; -#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ - || defined(__osf__) - detail::signal_init<> init_; -#endif - - // The service registry. - boost::asio::detail::service_registry* service_registry_; - - // The implementation. - impl_type& impl_; -}; - -/// Class to inform the io_service when it has work to do. -/** - * The work class is used to inform the io_service when work starts and - * finishes. This ensures that the io_service object's run() function will not - * exit while work is underway, and that it does exit when there is no - * unfinished work remaining. - * - * The work class is copy-constructible so that it may be used as a data member - * in a handler class. It is not assignable. - */ -class io_service::work -{ -public: - /// Constructor notifies the io_service that work is starting. - /** - * The constructor is used to inform the io_service that some work has begun. - * This ensures that the io_service object's run() function will not exit - * while the work is underway. - */ - explicit work(boost::asio::io_service& io_service); - - /// Copy constructor notifies the io_service that work is starting. - /** - * The constructor is used to inform the io_service that some work has begun. - * This ensures that the io_service object's run() function will not exit - * while the work is underway. - */ - work(const work& other); - - /// Destructor notifies the io_service that the work is complete. - /** - * The destructor is used to inform the io_service that some work has - * finished. Once the count of unfinished work reaches zero, the io_service - * object's run() function is permitted to exit. - */ - ~work(); - - /// Get the io_service associated with the work. - boost::asio::io_service& get_io_service(); - -private: - // Prevent assignment. - void operator=(const work& other); - - // The io_service implementation. - detail::io_service_impl& io_service_impl_; -}; - -/// Class used to uniquely identify a service. -class io_service::id - : private noncopyable -{ -public: - /// Constructor. - id() {} -}; - -/// Base class for all io_service services. -class io_service::service - : private noncopyable -{ -public: - /// Get the io_service object that owns the service. - boost::asio::io_service& get_io_service(); - -protected: - /// Constructor. - /** - * @param owner The io_service object that owns the service. - */ - BOOST_ASIO_DECL service(boost::asio::io_service& owner); - - /// Destructor. - BOOST_ASIO_DECL virtual ~service(); - -private: - /// Destroy all user-defined handler objects owned by the service. - virtual void shutdown_service() = 0; - - /// Handle notification of a fork-related event to perform any necessary - /// housekeeping. - /** - * This function is not a pure virtual so that services only have to - * implement it if necessary. The default implementation does nothing. - */ - BOOST_ASIO_DECL virtual void fork_service( - boost::asio::io_service::fork_event event); - - friend class boost::asio::detail::service_registry; - struct key - { - key() : type_info_(0), id_(0) {} - const std::type_info* type_info_; - const boost::asio::io_service::id* id_; - } key_; - - boost::asio::io_service& owner_; - service* next_; -}; - -/// Exception thrown when trying to add a duplicate service to an io_service. -class service_already_exists - : public std::logic_error -{ -public: - BOOST_ASIO_DECL service_already_exists(); -}; - -/// Exception thrown when trying to add a service object to an io_service where -/// the service has a different owner. -class invalid_service_owner - : public std::logic_error -{ -public: - BOOST_ASIO_DECL invalid_service_owner(); -}; - -namespace detail { - -// Special derived service id type to keep classes header-file only. -template <typename Type> -class service_id - : public boost::asio::io_service::id -{ -}; - -// Special service base class to keep classes header-file only. -template <typename Type> -class service_base - : public boost::asio::io_service::service -{ -public: - static boost::asio::detail::service_id<Type> id; - - // Constructor. - service_base(boost::asio::io_service& io_service) - : boost::asio::io_service::service(io_service) - { - } -}; - -template <typename Type> -boost::asio::detail::service_id<Type> service_base<Type>::id; - -} // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> -#include <boost/asio/impl/io_service.hpp> -#if defined(BOOST_ASIO_HEADER_ONLY) -# include <boost/asio/impl/io_service.ipp> -#endif // defined(BOOST_ASIO_HEADER_ONLY) - #endif // BOOST_ASIO_IO_SERVICE_HPP diff --git a/boost/asio/io_service_strand.hpp b/boost/asio/io_service_strand.hpp new file mode 100644 index 0000000000..af7224a5a1 --- /dev/null +++ b/boost/asio/io_service_strand.hpp @@ -0,0 +1,20 @@ +// +// io_service_strand.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IO_SERVICE_STRAND_HPP +#define BOOST_ASIO_IO_SERVICE_STRAND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/io_context_strand.hpp> + +#endif // BOOST_ASIO_IO_SERVICE_STRAND_HPP diff --git a/boost/asio/ip/address.hpp b/boost/asio/ip/address.hpp index 6e1b19e650..6d654b61b7 100644 --- a/boost/asio/ip/address.hpp +++ b/boost/asio/ip/address.hpp @@ -17,9 +17,13 @@ #include <boost/asio/detail/config.hpp> #include <string> +#include <boost/asio/detail/throw_exception.hpp> +#include <boost/asio/detail/string_view.hpp> +#include <boost/asio/detail/type_traits.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/ip/address_v4.hpp> #include <boost/asio/ip/address_v6.hpp> +#include <boost/asio/ip/bad_address_cast.hpp> #if !defined(BOOST_ASIO_NO_IOSTREAM) # include <iosfwd> @@ -94,29 +98,34 @@ public: /// Get the address as an IP version 6 address. BOOST_ASIO_DECL boost::asio::ip::address_v6 to_v6() const; - /// Get the address as a string in dotted decimal format. + /// Get the address as a string. BOOST_ASIO_DECL std::string to_string() const; - /// Get the address as a string in dotted decimal format. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use other overload.) Get the address as a string. BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; - /// Create an address from an IPv4 address string in dotted decimal form, - /// or from an IPv6 address in hexadecimal notation. - BOOST_ASIO_DECL static address from_string(const char* str); - - /// Create an address from an IPv4 address string in dotted decimal form, - /// or from an IPv6 address in hexadecimal notation. - BOOST_ASIO_DECL static address from_string( - const char* str, boost::system::error_code& ec); - - /// Create an address from an IPv4 address string in dotted decimal form, - /// or from an IPv6 address in hexadecimal notation. - BOOST_ASIO_DECL static address from_string(const std::string& str); - - /// Create an address from an IPv4 address string in dotted decimal form, - /// or from an IPv6 address in hexadecimal notation. - BOOST_ASIO_DECL static address from_string( + /// (Deprecated: Use make_address().) Create an address from an IPv4 address + /// string in dotted decimal form, or from an IPv6 address in hexadecimal + /// notation. + static address from_string(const char* str); + + /// (Deprecated: Use make_address().) Create an address from an IPv4 address + /// string in dotted decimal form, or from an IPv6 address in hexadecimal + /// notation. + static address from_string(const char* str, boost::system::error_code& ec); + + /// (Deprecated: Use make_address().) Create an address from an IPv4 address + /// string in dotted decimal form, or from an IPv6 address in hexadecimal + /// notation. + static address from_string(const std::string& str); + + /// (Deprecated: Use make_address().) Create an address from an IPv4 address + /// string in dotted decimal form, or from an IPv6 address in hexadecimal + /// notation. + static address from_string( const std::string& str, boost::system::error_code& ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Determine whether the address is a loopback address. BOOST_ASIO_DECL bool is_loopback() const; @@ -168,6 +177,57 @@ private: boost::asio::ip::address_v6 ipv6_address_; }; +/// Create an address from an IPv4 address string in dotted decimal form, +/// or from an IPv6 address in hexadecimal notation. +/** + * @relates address + */ +BOOST_ASIO_DECL address make_address(const char* str); + +/// Create an address from an IPv4 address string in dotted decimal form, +/// or from an IPv6 address in hexadecimal notation. +/** + * @relates address + */ +BOOST_ASIO_DECL address make_address( + const char* str, boost::system::error_code& ec); + +/// Create an address from an IPv4 address string in dotted decimal form, +/// or from an IPv6 address in hexadecimal notation. +/** + * @relates address + */ +BOOST_ASIO_DECL address make_address(const std::string& str); + +/// Create an address from an IPv4 address string in dotted decimal form, +/// or from an IPv6 address in hexadecimal notation. +/** + * @relates address + */ +BOOST_ASIO_DECL address make_address( + const std::string& str, boost::system::error_code& ec); + +#if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) \ + || defined(GENERATING_DOCUMENTATION) + +/// Create an address from an IPv4 address string in dotted decimal form, +/// or from an IPv6 address in hexadecimal notation. +/** + * @relates address + */ +BOOST_ASIO_DECL address make_address(string_view str); + +/// Create an address from an IPv4 address string in dotted decimal form, +/// or from an IPv6 address in hexadecimal notation. +/** + * @relates address + */ +BOOST_ASIO_DECL address make_address( + string_view str, boost::system::error_code& ec); + +#endif // defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + // || defined(GENERATING_DOCUMENTATION) + #if !defined(BOOST_ASIO_NO_IOSTREAM) /// Output an address as a string. diff --git a/boost/asio/ip/address_v4.hpp b/boost/asio/ip/address_v4.hpp index 3db4d4c825..399c051910 100644 --- a/boost/asio/ip/address_v4.hpp +++ b/boost/asio/ip/address_v4.hpp @@ -18,7 +18,9 @@ #include <boost/asio/detail/config.hpp> #include <string> #include <boost/asio/detail/array.hpp> +#include <boost/asio/detail/cstdint.hpp> #include <boost/asio/detail/socket_types.hpp> +#include <boost/asio/detail/string_view.hpp> #include <boost/asio/detail/winsock_init.hpp> #include <boost/system/error_code.hpp> @@ -44,6 +46,9 @@ namespace ip { class address_v4 { public: + /// The type used to represent an address as an unsigned integer. + typedef uint_least32_t uint_type; + /// The type used to represent an address as an array of bytes. /** * @note This type is defined in terms of the C++0x template @c std::array @@ -64,8 +69,8 @@ public: /// Construct an address from raw bytes. BOOST_ASIO_DECL explicit address_v4(const bytes_type& bytes); - /// Construct an address from a unsigned long in host byte order. - BOOST_ASIO_DECL explicit address_v4(unsigned long addr); + /// Construct an address from an unsigned integer in host byte order. + BOOST_ASIO_DECL explicit address_v4(uint_type addr); /// Copy constructor. address_v4(const address_v4& other) @@ -100,28 +105,40 @@ public: /// Get the address in bytes, in network byte order. BOOST_ASIO_DECL bytes_type to_bytes() const; + /// Get the address as an unsigned integer in host byte order + BOOST_ASIO_DECL uint_type to_uint() const; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) /// Get the address as an unsigned long in host byte order BOOST_ASIO_DECL unsigned long to_ulong() const; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Get the address as a string in dotted decimal format. BOOST_ASIO_DECL std::string to_string() const; - /// Get the address as a string in dotted decimal format. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use other overload.) Get the address as a string in dotted + /// decimal format. BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; - /// Create an address from an IP address string in dotted decimal form. - BOOST_ASIO_DECL static address_v4 from_string(const char* str); + /// (Deprecated: Use make_address_v4().) Create an address from an IP address + /// string in dotted decimal form. + static address_v4 from_string(const char* str); - /// Create an address from an IP address string in dotted decimal form. - BOOST_ASIO_DECL static address_v4 from_string( + /// (Deprecated: Use make_address_v4().) Create an address from an IP address + /// string in dotted decimal form. + static address_v4 from_string( const char* str, boost::system::error_code& ec); - /// Create an address from an IP address string in dotted decimal form. - BOOST_ASIO_DECL static address_v4 from_string(const std::string& str); + /// (Deprecated: Use make_address_v4().) Create an address from an IP address + /// string in dotted decimal form. + static address_v4 from_string(const std::string& str); - /// Create an address from an IP address string in dotted decimal form. - BOOST_ASIO_DECL static address_v4 from_string( + /// (Deprecated: Use make_address_v4().) Create an address from an IP address + /// string in dotted decimal form. + static address_v4 from_string( const std::string& str, boost::system::error_code& ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Determine whether the address is a loopback address. BOOST_ASIO_DECL bool is_loopback() const; @@ -129,14 +146,19 @@ public: /// Determine whether the address is unspecified. BOOST_ASIO_DECL bool is_unspecified() const; - /// Determine whether the address is a class A address. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use network_v4 class.) Determine whether the address is a + /// class A address. BOOST_ASIO_DECL bool is_class_a() const; - /// Determine whether the address is a class B address. + /// (Deprecated: Use network_v4 class.) Determine whether the address is a + /// class B address. BOOST_ASIO_DECL bool is_class_b() const; - /// Determine whether the address is a class C address. + /// (Deprecated: Use network_v4 class.) Determine whether the address is a + /// class C address. BOOST_ASIO_DECL bool is_class_c() const; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Determine whether the address is a multicast address. BOOST_ASIO_DECL bool is_multicast() const; @@ -156,25 +178,25 @@ public: /// Compare addresses for ordering. friend bool operator<(const address_v4& a1, const address_v4& a2) { - return a1.to_ulong() < a2.to_ulong(); + return a1.to_uint() < a2.to_uint(); } /// Compare addresses for ordering. friend bool operator>(const address_v4& a1, const address_v4& a2) { - return a1.to_ulong() > a2.to_ulong(); + return a1.to_uint() > a2.to_uint(); } /// Compare addresses for ordering. friend bool operator<=(const address_v4& a1, const address_v4& a2) { - return a1.to_ulong() <= a2.to_ulong(); + return a1.to_uint() <= a2.to_uint(); } /// Compare addresses for ordering. friend bool operator>=(const address_v4& a1, const address_v4& a2) { - return a1.to_ulong() >= a2.to_ulong(); + return a1.to_uint() >= a2.to_uint(); } /// Obtain an address object that represents any address. @@ -195,20 +217,86 @@ public: return address_v4(0xFFFFFFFF); } - /// Obtain an address object that represents the broadcast address that - /// corresponds to the specified address and netmask. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use network_v4 class.) Obtain an address object that + /// represents the broadcast address that corresponds to the specified + /// address and netmask. BOOST_ASIO_DECL static address_v4 broadcast( const address_v4& addr, const address_v4& mask); - /// Obtain the netmask that corresponds to the address, based on its address - /// class. + /// (Deprecated: Use network_v4 class.) Obtain the netmask that corresponds + /// to the address, based on its address class. BOOST_ASIO_DECL static address_v4 netmask(const address_v4& addr); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) private: // The underlying IPv4 address. boost::asio::detail::in4_addr_type addr_; }; +/// Create an IPv4 address from raw bytes in network order. +/** + * @relates address_v4 + */ +inline address_v4 make_address_v4(const address_v4::bytes_type& bytes) +{ + return address_v4(bytes); +} + +/// Create an IPv4 address from an unsigned integer in host byte order. +/** + * @relates address_v4 + */ +inline address_v4 make_address_v4(address_v4::uint_type addr) +{ + return address_v4(addr); +} + +/// Create an IPv4 address from an IP address string in dotted decimal form. +/** + * @relates address_v4 + */ +BOOST_ASIO_DECL address_v4 make_address_v4(const char* str); + +/// Create an IPv4 address from an IP address string in dotted decimal form. +/** + * @relates address_v4 + */ +BOOST_ASIO_DECL address_v4 make_address_v4( + const char* str, boost::system::error_code& ec); + +/// Create an IPv4 address from an IP address string in dotted decimal form. +/** + * @relates address_v4 + */ +BOOST_ASIO_DECL address_v4 make_address_v4(const std::string& str); + +/// Create an IPv4 address from an IP address string in dotted decimal form. +/** + * @relates address_v4 + */ +BOOST_ASIO_DECL address_v4 make_address_v4( + const std::string& str, boost::system::error_code& ec); + +#if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) \ + || defined(GENERATING_DOCUMENTATION) + +/// Create an IPv4 address from an IP address string in dotted decimal form. +/** + * @relates address_v4 + */ +BOOST_ASIO_DECL address_v4 make_address_v4(string_view str); + +/// Create an IPv4 address from an IP address string in dotted decimal form. +/** + * @relates address_v4 + */ +BOOST_ASIO_DECL address_v4 make_address_v4( + string_view str, boost::system::error_code& ec); + +#endif // defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + // || defined(GENERATING_DOCUMENTATION) + #if !defined(BOOST_ASIO_NO_IOSTREAM) /// Output an address as a string. diff --git a/boost/asio/ip/address_v4_iterator.hpp b/boost/asio/ip/address_v4_iterator.hpp new file mode 100644 index 0000000000..a2ccfc3748 --- /dev/null +++ b/boost/asio/ip/address_v4_iterator.hpp @@ -0,0 +1,164 @@ +// +// ip/address_v4_iterator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IP_ADDRESS_V4_ITERATOR_HPP +#define BOOST_ASIO_IP_ADDRESS_V4_ITERATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/ip/address_v4.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace ip { + +template <typename> class basic_address_iterator; + +/// An input iterator that can be used for traversing IPv4 addresses. +/** + * In addition to satisfying the input iterator requirements, this iterator + * also supports decrement. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template <> class basic_address_iterator<address_v4> +{ +public: + /// The type of the elements pointed to by the iterator. + typedef address_v4 value_type; + + /// Distance between two iterators. + typedef std::ptrdiff_t difference_type; + + /// The type of a pointer to an element pointed to by the iterator. + typedef const address_v4* pointer; + + /// The type of a reference to an element pointed to by the iterator. + typedef const address_v4& reference; + + /// Denotes that the iterator satisfies the input iterator requirements. + typedef std::input_iterator_tag iterator_category; + + /// Construct an iterator that points to the specified address. + basic_address_iterator(const address_v4& addr) BOOST_ASIO_NOEXCEPT + : address_(addr) + { + } + + /// Copy constructor. + basic_address_iterator( + const basic_address_iterator& other) BOOST_ASIO_NOEXCEPT + : address_(other.address_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + basic_address_iterator(basic_address_iterator&& other) BOOST_ASIO_NOEXCEPT + : address_(BOOST_ASIO_MOVE_CAST(address_v4)(other.address_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assignment operator. + basic_address_iterator& operator=( + const basic_address_iterator& other) BOOST_ASIO_NOEXCEPT + { + address_ = other.address_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move assignment operator. + basic_address_iterator& operator=( + basic_address_iterator&& other) BOOST_ASIO_NOEXCEPT + { + address_ = BOOST_ASIO_MOVE_CAST(address_v4)(other.address_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Dereference the iterator. + const address_v4& operator*() const BOOST_ASIO_NOEXCEPT + { + return address_; + } + + /// Dereference the iterator. + const address_v4* operator->() const BOOST_ASIO_NOEXCEPT + { + return &address_; + } + + /// Pre-increment operator. + basic_address_iterator& operator++() BOOST_ASIO_NOEXCEPT + { + address_ = address_v4((address_.to_uint() + 1) & 0xFFFFFFFF); + return *this; + } + + /// Post-increment operator. + basic_address_iterator operator++(int) BOOST_ASIO_NOEXCEPT + { + basic_address_iterator tmp(*this); + ++*this; + return tmp; + } + + /// Pre-decrement operator. + basic_address_iterator& operator--() BOOST_ASIO_NOEXCEPT + { + address_ = address_v4((address_.to_uint() - 1) & 0xFFFFFFFF); + return *this; + } + + /// Post-decrement operator. + basic_address_iterator operator--(int) + { + basic_address_iterator tmp(*this); + --*this; + return tmp; + } + + /// Compare two addresses for equality. + friend bool operator==(const basic_address_iterator& a, + const basic_address_iterator& b) + { + return a.address_ == b.address_; + } + + /// Compare two addresses for inequality. + friend bool operator!=(const basic_address_iterator& a, + const basic_address_iterator& b) + { + return a.address_ != b.address_; + } + +private: + address_v4 address_; +}; + +/// An input iterator that can be used for traversing IPv4 addresses. +typedef basic_address_iterator<address_v4> address_v4_iterator; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IP_ADDRESS_V4_ITERATOR_HPP diff --git a/boost/asio/ip/address_v4_range.hpp b/boost/asio/ip/address_v4_range.hpp new file mode 100644 index 0000000000..1e2afeaf5a --- /dev/null +++ b/boost/asio/ip/address_v4_range.hpp @@ -0,0 +1,136 @@ +// +// ip/address_v4_range.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IP_ADDRESS_V4_RANGE_HPP +#define BOOST_ASIO_IP_ADDRESS_V4_RANGE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/ip/address_v4_iterator.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace ip { + +template <typename> class basic_address_range; + +/// Represents a range of IPv4 addresses. +/** + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template <> class basic_address_range<address_v4> +{ +public: + /// The type of an iterator that points into the range. + typedef basic_address_iterator<address_v4> iterator; + + /// Construct an empty range. + basic_address_range() BOOST_ASIO_NOEXCEPT + : begin_(address_v4()), + end_(address_v4()) + { + } + + /// Construct an range that represents the given range of addresses. + explicit basic_address_range(const iterator& first, + const iterator& last) BOOST_ASIO_NOEXCEPT + : begin_(first), + end_(last) + { + } + + /// Copy constructor. + basic_address_range(const basic_address_range& other) BOOST_ASIO_NOEXCEPT + : begin_(other.begin_), + end_(other.end_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + basic_address_range(basic_address_range&& other) BOOST_ASIO_NOEXCEPT + : begin_(BOOST_ASIO_MOVE_CAST(iterator)(other.begin_)), + end_(BOOST_ASIO_MOVE_CAST(iterator)(other.end_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assignment operator. + basic_address_range& operator=( + const basic_address_range& other) BOOST_ASIO_NOEXCEPT + { + begin_ = other.begin_; + end_ = other.end_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move assignment operator. + basic_address_range& operator=( + basic_address_range&& other) BOOST_ASIO_NOEXCEPT + { + begin_ = BOOST_ASIO_MOVE_CAST(iterator)(other.begin_); + end_ = BOOST_ASIO_MOVE_CAST(iterator)(other.end_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Obtain an iterator that points to the start of the range. + iterator begin() const BOOST_ASIO_NOEXCEPT + { + return begin_; + } + + /// Obtain an iterator that points to the end of the range. + iterator end() const BOOST_ASIO_NOEXCEPT + { + return end_; + } + + /// Determine whether the range is empty. + bool empty() const BOOST_ASIO_NOEXCEPT + { + return size() == 0; + } + + /// Return the size of the range. + std::size_t size() const BOOST_ASIO_NOEXCEPT + { + return end_->to_uint() - begin_->to_uint(); + } + + /// Find an address in the range. + iterator find(const address_v4& addr) const BOOST_ASIO_NOEXCEPT + { + return addr >= *begin_ && addr < *end_ ? iterator(addr) : end_; + } + +private: + iterator begin_; + iterator end_; +}; + +/// Represents a range of IPv4 addresses. +typedef basic_address_range<address_v4> address_v4_range; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IP_ADDRESS_V4_RANGE_HPP diff --git a/boost/asio/ip/address_v6.hpp b/boost/asio/ip/address_v6.hpp index 10e9bc1594..496a1df323 100644 --- a/boost/asio/ip/address_v6.hpp +++ b/boost/asio/ip/address_v6.hpp @@ -19,6 +19,7 @@ #include <string> #include <boost/asio/detail/array.hpp> #include <boost/asio/detail/socket_types.hpp> +#include <boost/asio/detail/string_view.hpp> #include <boost/asio/detail/winsock_init.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/ip/address_v4.hpp> @@ -33,6 +34,8 @@ namespace boost { namespace asio { namespace ip { +template <typename> class basic_address_iterator; + /// Implements IP version 6 style addresses. /** * The boost::asio::ip::address_v6 class provides the ability to use and @@ -103,25 +106,32 @@ public: /// Get the address as a string. BOOST_ASIO_DECL std::string to_string() const; - /// Get the address as a string. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use other overload.) Get the address as a string. BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; - /// Create an address from an IP address string. - BOOST_ASIO_DECL static address_v6 from_string(const char* str); + /// (Deprecated: Use make_address_v6().) Create an IPv6 address from an IP + /// address string. + static address_v6 from_string(const char* str); - /// Create an address from an IP address string. - BOOST_ASIO_DECL static address_v6 from_string( + /// (Deprecated: Use make_address_v6().) Create an IPv6 address from an IP + /// address string. + static address_v6 from_string( const char* str, boost::system::error_code& ec); - /// Create an address from an IP address string. - BOOST_ASIO_DECL static address_v6 from_string(const std::string& str); + /// (Deprecated: Use make_address_v6().) Create an IPv6 address from an IP + /// address string. + static address_v6 from_string(const std::string& str); - /// Create an address from an IP address string. - BOOST_ASIO_DECL static address_v6 from_string( + /// (Deprecated: Use make_address_v6().) Create an IPv6 address from an IP + /// address string. + static address_v6 from_string( const std::string& str, boost::system::error_code& ec); - /// Converts an IPv4-mapped or IPv4-compatible address to an IPv4 address. + /// (Deprecated: Use make_address_v4().) Converts an IPv4-mapped or + /// IPv4-compatible address to an IPv4 address. BOOST_ASIO_DECL address_v4 to_v4() const; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Determine whether the address is a loopback address. BOOST_ASIO_DECL bool is_loopback() const; @@ -138,8 +148,11 @@ public: /// Determine whether the address is a mapped IPv4 address. BOOST_ASIO_DECL bool is_v4_mapped() const; - /// Determine whether the address is an IPv4-compatible address. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: No replacement.) Determine whether the address is an + /// IPv4-compatible address. BOOST_ASIO_DECL bool is_v4_compatible() const; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Determine whether the address is a multicast address. BOOST_ASIO_DECL bool is_multicast() const; @@ -200,13 +213,17 @@ public: /// Obtain an address object that represents the loopback address. BOOST_ASIO_DECL static address_v6 loopback(); - /// Create an IPv4-mapped IPv6 address. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use make_address_v6().) Create an IPv4-mapped IPv6 address. BOOST_ASIO_DECL static address_v6 v4_mapped(const address_v4& addr); - /// Create an IPv4-compatible IPv6 address. + /// (Deprecated: No replacement.) Create an IPv4-compatible IPv6 address. BOOST_ASIO_DECL static address_v6 v4_compatible(const address_v4& addr); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) private: + friend class basic_address_iterator<address_v6>; + // The underlying IPv6 address. boost::asio::detail::in6_addr_type addr_; @@ -214,6 +231,79 @@ private: unsigned long scope_id_; }; +/// Create an IPv6 address from raw bytes and scope ID. +/** + * @relates address_v6 + */ +inline address_v6 make_address_v6(const address_v6::bytes_type& bytes, + unsigned long scope_id = 0) +{ + return address_v6(bytes, scope_id); +} + +/// Create an IPv6 address from an IP address string. +/** + * @relates address_v6 + */ +BOOST_ASIO_DECL address_v6 make_address_v6(const char* str); + +/// Create an IPv6 address from an IP address string. +/** + * @relates address_v6 + */ +BOOST_ASIO_DECL address_v6 make_address_v6( + const char* str, boost::system::error_code& ec); + +/// Createan IPv6 address from an IP address string. +/** + * @relates address_v6 + */ +BOOST_ASIO_DECL address_v6 make_address_v6(const std::string& str); + +/// Create an IPv6 address from an IP address string. +/** + * @relates address_v6 + */ +BOOST_ASIO_DECL address_v6 make_address_v6( + const std::string& str, boost::system::error_code& ec); + +#if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) \ + || defined(GENERATING_DOCUMENTATION) + +/// Create an IPv6 address from an IP address string. +/** + * @relates address_v6 + */ +BOOST_ASIO_DECL address_v6 make_address_v6(string_view str); + +/// Create an IPv6 address from an IP address string. +/** + * @relates address_v6 + */ +BOOST_ASIO_DECL address_v6 make_address_v6( + string_view str, boost::system::error_code& ec); + +#endif // defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + // || defined(GENERATING_DOCUMENTATION) + +/// Tag type used for distinguishing overloads that deal in IPv4-mapped IPv6 +/// addresses. +enum v4_mapped_t { v4_mapped }; + +/// Create an IPv4 address from a IPv4-mapped IPv6 address. +/** + * @relates address_v4 + */ +BOOST_ASIO_DECL address_v4 make_address_v4( + v4_mapped_t, const address_v6& v6_addr); + +/// Create an IPv4-mapped IPv6 address from an IPv4 address. +/** + * @relates address_v6 + */ +BOOST_ASIO_DECL address_v6 make_address_v6( + v4_mapped_t, const address_v4& v4_addr); + #if !defined(BOOST_ASIO_NO_IOSTREAM) /// Output an address as a string. diff --git a/boost/asio/ip/address_v6_iterator.hpp b/boost/asio/ip/address_v6_iterator.hpp new file mode 100644 index 0000000000..4518996b3c --- /dev/null +++ b/boost/asio/ip/address_v6_iterator.hpp @@ -0,0 +1,185 @@ +// +// ip/address_v6_iterator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Oliver Kowalke (oliver dot kowalke at gmail 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) +// + +#ifndef BOOST_ASIO_IP_ADDRESS_V6_ITERATOR_HPP +#define BOOST_ASIO_IP_ADDRESS_V6_ITERATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/ip/address_v6.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace ip { + +template <typename> class basic_address_iterator; + +/// An input iterator that can be used for traversing IPv6 addresses. +/** + * In addition to satisfying the input iterator requirements, this iterator + * also supports decrement. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template <> class basic_address_iterator<address_v6> +{ +public: + /// The type of the elements pointed to by the iterator. + typedef address_v6 value_type; + + /// Distance between two iterators. + typedef std::ptrdiff_t difference_type; + + /// The type of a pointer to an element pointed to by the iterator. + typedef const address_v6* pointer; + + /// The type of a reference to an element pointed to by the iterator. + typedef const address_v6& reference; + + /// Denotes that the iterator satisfies the input iterator requirements. + typedef std::input_iterator_tag iterator_category; + + /// Construct an iterator that points to the specified address. + basic_address_iterator(const address_v6& addr) BOOST_ASIO_NOEXCEPT + : address_(addr) + { + } + + /// Copy constructor. + basic_address_iterator( + const basic_address_iterator& other) BOOST_ASIO_NOEXCEPT + : address_(other.address_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + basic_address_iterator(basic_address_iterator&& other) BOOST_ASIO_NOEXCEPT + : address_(BOOST_ASIO_MOVE_CAST(address_v6)(other.address_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assignment operator. + basic_address_iterator& operator=( + const basic_address_iterator& other) BOOST_ASIO_NOEXCEPT + { + address_ = other.address_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move assignment operator. + basic_address_iterator& operator=( + basic_address_iterator&& other) BOOST_ASIO_NOEXCEPT + { + address_ = BOOST_ASIO_MOVE_CAST(address_v6)(other.address_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Dereference the iterator. + const address_v6& operator*() const BOOST_ASIO_NOEXCEPT + { + return address_; + } + + /// Dereference the iterator. + const address_v6* operator->() const BOOST_ASIO_NOEXCEPT + { + return &address_; + } + + /// Pre-increment operator. + basic_address_iterator& operator++() BOOST_ASIO_NOEXCEPT + { + for (int i = 15; i >= 0; --i) + { + if (address_.addr_.s6_addr[i] < 0xFF) + { + ++address_.addr_.s6_addr[i]; + break; + } + + address_.addr_.s6_addr[i] = 0; + } + + return *this; + } + + /// Post-increment operator. + basic_address_iterator operator++(int) BOOST_ASIO_NOEXCEPT + { + basic_address_iterator tmp(*this); + ++*this; + return tmp; + } + + /// Pre-decrement operator. + basic_address_iterator& operator--() BOOST_ASIO_NOEXCEPT + { + for (int i = 15; i >= 0; --i) + { + if (address_.addr_.s6_addr[i] > 0) + { + --address_.addr_.s6_addr[i]; + break; + } + + address_.addr_.s6_addr[i] = 0xFF; + } + + return *this; + } + + /// Post-decrement operator. + basic_address_iterator operator--(int) + { + basic_address_iterator tmp(*this); + --*this; + return tmp; + } + + /// Compare two addresses for equality. + friend bool operator==(const basic_address_iterator& a, + const basic_address_iterator& b) + { + return a.address_ == b.address_; + } + + /// Compare two addresses for inequality. + friend bool operator!=(const basic_address_iterator& a, + const basic_address_iterator& b) + { + return a.address_ != b.address_; + } + +private: + address_v6 address_; +}; + +/// An input iterator that can be used for traversing IPv6 addresses. +typedef basic_address_iterator<address_v6> address_v6_iterator; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IP_ADDRESS_V6_ITERATOR_HPP diff --git a/boost/asio/ip/address_v6_range.hpp b/boost/asio/ip/address_v6_range.hpp new file mode 100644 index 0000000000..68b987d7c9 --- /dev/null +++ b/boost/asio/ip/address_v6_range.hpp @@ -0,0 +1,131 @@ +// +// ip/address_v6_range.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Oliver Kowalke (oliver dot kowalke at gmail 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) +// + +#ifndef BOOST_ASIO_IP_ADDRESS_V6_RANGE_HPP +#define BOOST_ASIO_IP_ADDRESS_V6_RANGE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/ip/address_v6_iterator.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace ip { + +template <typename> class basic_address_range; + +/// Represents a range of IPv6 addresses. +/** + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template <> class basic_address_range<address_v6> +{ +public: + /// The type of an iterator that points into the range. + typedef basic_address_iterator<address_v6> iterator; + + /// Construct an empty range. + basic_address_range() BOOST_ASIO_NOEXCEPT + : begin_(address_v6()), + end_(address_v6()) + { + } + + /// Construct an range that represents the given range of addresses. + explicit basic_address_range(const iterator& first, + const iterator& last) BOOST_ASIO_NOEXCEPT + : begin_(first), + end_(last) + { + } + + /// Copy constructor. + basic_address_range(const basic_address_range& other) BOOST_ASIO_NOEXCEPT + : begin_(other.begin_), + end_(other.end_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + basic_address_range(basic_address_range&& other) BOOST_ASIO_NOEXCEPT + : begin_(BOOST_ASIO_MOVE_CAST(iterator)(other.begin_)), + end_(BOOST_ASIO_MOVE_CAST(iterator)(other.end_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assignment operator. + basic_address_range& operator=( + const basic_address_range& other) BOOST_ASIO_NOEXCEPT + { + begin_ = other.begin_; + end_ = other.end_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move assignment operator. + basic_address_range& operator=( + basic_address_range&& other) BOOST_ASIO_NOEXCEPT + { + begin_ = BOOST_ASIO_MOVE_CAST(iterator)(other.begin_); + end_ = BOOST_ASIO_MOVE_CAST(iterator)(other.end_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Obtain an iterator that points to the start of the range. + iterator begin() const BOOST_ASIO_NOEXCEPT + { + return begin_; + } + + /// Obtain an iterator that points to the end of the range. + iterator end() const BOOST_ASIO_NOEXCEPT + { + return end_; + } + + /// Determine whether the range is empty. + bool empty() const BOOST_ASIO_NOEXCEPT + { + return begin_ == end_; + } + + /// Find an address in the range. + iterator find(const address_v6& addr) const BOOST_ASIO_NOEXCEPT + { + return addr >= *begin_ && addr < *end_ ? iterator(addr) : end_; + } + +private: + iterator begin_; + iterator end_; +}; + +/// Represents a range of IPv6 addresses. +typedef basic_address_range<address_v6> address_v6_range; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IP_ADDRESS_V6_RANGE_HPP diff --git a/boost/asio/ip/bad_address_cast.hpp b/boost/asio/ip/bad_address_cast.hpp new file mode 100644 index 0000000000..9c82fdfeb3 --- /dev/null +++ b/boost/asio/ip/bad_address_cast.hpp @@ -0,0 +1,50 @@ +// +// ip/bad_address_cast.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IP_BAD_ADDRESS_CAST_HPP +#define BOOST_ASIO_IP_BAD_ADDRESS_CAST_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <typeinfo> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace ip { + +/// Thrown to indicate a failed address conversion. +class bad_address_cast : public std::bad_cast +{ +public: + /// Default constructor. + bad_address_cast() {} + + /// Destructor. + virtual ~bad_address_cast() BOOST_ASIO_NOEXCEPT_OR_NOTHROW {} + + /// Get the message associated with the exception. + virtual const char* what() const BOOST_ASIO_NOEXCEPT_OR_NOTHROW + { + return "bad address cast"; + } +}; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IP_ADDRESS_HPP diff --git a/boost/asio/ip/basic_endpoint.hpp b/boost/asio/ip/basic_endpoint.hpp index 235b178589..7a9f72ba36 100644 --- a/boost/asio/ip/basic_endpoint.hpp +++ b/boost/asio/ip/basic_endpoint.hpp @@ -98,13 +98,13 @@ public: { } -#if defined(BOOST_ASIO_HAS_MOVE) +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move constructor. basic_endpoint(basic_endpoint&& other) : impl_(other.impl_) { } -#endif // defined(BOOST_ASIO_HAS_MOVE) +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Assign from another endpoint. basic_endpoint& operator=(const basic_endpoint& other) @@ -113,14 +113,14 @@ public: return *this; } -#if defined(BOOST_ASIO_HAS_MOVE) +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-assign from another endpoint. basic_endpoint& operator=(basic_endpoint&& other) { impl_ = other.impl_; return *this; } -#endif // defined(BOOST_ASIO_HAS_MOVE) +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// The protocol associated with the endpoint. protocol_type protocol() const diff --git a/boost/asio/ip/basic_resolver.hpp b/boost/asio/ip/basic_resolver.hpp index c5941de4f1..714e950832 100644 --- a/boost/asio/ip/basic_resolver.hpp +++ b/boost/asio/ip/basic_resolver.hpp @@ -16,13 +16,36 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> +#include <string> +#include <boost/asio/async_result.hpp> #include <boost/asio/basic_io_object.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> +#include <boost/asio/detail/string_view.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/ip/basic_resolver_iterator.hpp> #include <boost/asio/ip/basic_resolver_query.hpp> -#include <boost/asio/ip/resolver_service.hpp> +#include <boost/asio/ip/basic_resolver_results.hpp> +#include <boost/asio/ip/resolver_base.hpp> + +#if defined(BOOST_ASIO_HAS_MOVE) +# include <utility> +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/ip/resolver_service.hpp> +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include <boost/asio/detail/winrt_resolver_service.hpp> +# define BOOST_ASIO_SVC_T \ + boost::asio::detail::winrt_resolver_service<InternetProtocol> +# else +# include <boost/asio/detail/resolver_service.hpp> +# define BOOST_ASIO_SVC_T \ + boost::asio::detail::resolver_service<InternetProtocol> +# endif +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) #include <boost/asio/detail/push_options.hpp> @@ -39,35 +62,130 @@ namespace ip { * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template <typename InternetProtocol, - typename ResolverService = resolver_service<InternetProtocol> > +template <typename InternetProtocol + BOOST_ASIO_SVC_TPARAM_DEF1(= resolver_service<InternetProtocol>)> class basic_resolver - : public basic_io_object<ResolverService> + : BOOST_ASIO_SVC_ACCESS basic_io_object<BOOST_ASIO_SVC_T>, + public resolver_base { public: + /// The type of the executor associated with the object. + typedef io_context::executor_type executor_type; + /// The protocol type. typedef InternetProtocol protocol_type; /// The endpoint type. typedef typename InternetProtocol::endpoint endpoint_type; - /// The query type. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated.) The query type. typedef basic_resolver_query<InternetProtocol> query; - /// The iterator type. + /// (Deprecated.) The iterator type. typedef basic_resolver_iterator<InternetProtocol> iterator; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// The results type. + typedef basic_resolver_results<InternetProtocol> results_type; /// Constructor. /** * This constructor creates a basic_resolver. * - * @param io_service The io_service object that the resolver will use to - * dispatch handlers for any asynchronous operations performed on the timer. + * @param io_context The io_context object that the resolver will use to + * dispatch handlers for any asynchronous operations performed on the + * resolver. + */ + explicit basic_resolver(boost::asio::io_context& io_context) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_resolver from another. + /** + * This constructor moves a resolver from one object to another. + * + * @param other The other basic_resolver object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_resolver(io_context&) constructor. + */ + basic_resolver(basic_resolver&& other) + : basic_io_object<BOOST_ASIO_SVC_T>(std::move(other)) + { + } + + /// Move-assign a basic_resolver from another. + /** + * This assignment operator moves a resolver from one object to another. + * Cancels any outstanding asynchronous operations associated with the target + * object. + * + * @param other The other basic_resolver object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_resolver(io_context&) constructor. + */ + basic_resolver& operator=(basic_resolver&& other) + { + basic_io_object<BOOST_ASIO_SVC_T>::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the resolver. + /** + * This function destroys the resolver, cancelling any outstanding + * asynchronous wait operations associated with the resolver as if by calling + * @c cancel. + */ + ~basic_resolver() + { + } + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + // These functions are provided by basic_io_object<>. +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. */ - explicit basic_resolver(boost::asio::io_service& io_service) - : basic_io_object<ResolverService>(io_service) + boost::asio::io_context& get_io_context() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_service() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_service(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT { + return basic_io_object<BOOST_ASIO_SVC_T>::get_executor(); } +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) /// Cancel any asynchronous operations that are waiting on the resolver. /** @@ -77,56 +195,414 @@ public: */ void cancel() { - return this->service.cancel(this->implementation); + return this->get_service().cancel(this->get_implementation()); } - /// Perform forward resolution of a query to a list of entries. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated.) Perform forward resolution of a query to a list of entries. /** * This function is used to resolve a query into a list of endpoint entries. * * @param q A query object that determines what endpoints will be returned. * - * @returns A forward-only iterator that can be used to traverse the list - * of endpoint entries. + * @returns A range object representing the list of endpoint entries. A + * successful call to this function is guaranteed to return a non-empty + * range. + * + * @throws boost::system::system_error Thrown on failure. + */ + results_type resolve(const query& q) + { + boost::system::error_code ec; + results_type r = this->get_service().resolve( + this->get_implementation(), q, ec); + boost::asio::detail::throw_error(ec, "resolve"); + return r; + } + + /// (Deprecated.) Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve a query into a list of endpoint entries. + * + * @param q A query object that determines what endpoints will be returned. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns A range object representing the list of endpoint entries. An + * empty range is returned if an error occurs. A successful call to this + * function is guaranteed to return a non-empty range. + */ + results_type resolve(const query& q, boost::system::error_code& ec) + { + return this->get_service().resolve(this->get_implementation(), q, ec); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @returns A range object representing the list of endpoint entries. A + * successful call to this function is guaranteed to return a non-empty + * range. * * @throws boost::system::system_error Thrown on failure. * - * @note A default constructed iterator represents the end of the list. + * @note On POSIX systems, host names may be locally defined in the file + * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). * - * A successful call to this function is guaranteed to return at least one - * entry. + * On POSIX systems, service names are typically defined in the file + * <tt>/etc/services</tt>. On Windows, service names may be found in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems + * may use additional locations when resolving service names. */ - iterator resolve(const query& q) + results_type resolve(BOOST_ASIO_STRING_VIEW_PARAM host, + BOOST_ASIO_STRING_VIEW_PARAM service) + { + return resolve(host, service, resolver_base::flags()); + } + + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns A range object representing the list of endpoint entries. An + * empty range is returned if an error occurs. A successful call to this + * function is guaranteed to return a non-empty range. + * + * @note On POSIX systems, host names may be locally defined in the file + * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * <tt>/etc/services</tt>. On Windows, service names may be found in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems + * may use additional locations when resolving service names. + */ + results_type resolve(BOOST_ASIO_STRING_VIEW_PARAM host, + BOOST_ASIO_STRING_VIEW_PARAM service, boost::system::error_code& ec) + { + return resolve(host, service, resolver_base::flags(), ec); + } + + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for communication with + * remote hosts. + * + * @returns A range object representing the list of endpoint entries. A + * successful call to this function is guaranteed to return a non-empty + * range. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note On POSIX systems, host names may be locally defined in the file + * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * <tt>/etc/services</tt>. On Windows, service names may be found in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems + * may use additional locations when resolving service names. + */ + results_type resolve(BOOST_ASIO_STRING_VIEW_PARAM host, + BOOST_ASIO_STRING_VIEW_PARAM service, resolver_base::flags resolve_flags) { boost::system::error_code ec; - iterator i = this->service.resolve(this->implementation, q, ec); + basic_resolver_query<protocol_type> q(static_cast<std::string>(host), + static_cast<std::string>(service), resolve_flags); + results_type r = this->get_service().resolve( + this->get_implementation(), q, ec); boost::asio::detail::throw_error(ec, "resolve"); - return i; + return r; } /// Perform forward resolution of a query to a list of entries. /** - * This function is used to resolve a query into a list of endpoint entries. + * This function is used to resolve host and service names into a list of + * endpoint entries. * - * @param q A query object that determines what endpoints will be returned. + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for communication with + * remote hosts. * * @param ec Set to indicate what error occurred, if any. * - * @returns A forward-only iterator that can be used to traverse the list - * of endpoint entries. Returns a default constructed iterator if an error - * occurs. + * @returns A range object representing the list of endpoint entries. An + * empty range is returned if an error occurs. A successful call to this + * function is guaranteed to return a non-empty range. * - * @note A default constructed iterator represents the end of the list. + * @note On POSIX systems, host names may be locally defined in the file + * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). * - * A successful call to this function is guaranteed to return at least one - * entry. + * On POSIX systems, service names are typically defined in the file + * <tt>/etc/services</tt>. On Windows, service names may be found in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems + * may use additional locations when resolving service names. */ - iterator resolve(const query& q, boost::system::error_code& ec) + results_type resolve(BOOST_ASIO_STRING_VIEW_PARAM host, + BOOST_ASIO_STRING_VIEW_PARAM service, resolver_base::flags resolve_flags, + boost::system::error_code& ec) { - return this->service.resolve(this->implementation, q, ec); + basic_resolver_query<protocol_type> q(static_cast<std::string>(host), + static_cast<std::string>(service), resolve_flags); + return this->get_service().resolve(this->get_implementation(), q, ec); } - /// Asynchronously perform forward resolution of a query to a list of entries. + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @returns A range object representing the list of endpoint entries. A + * successful call to this function is guaranteed to return a non-empty + * range. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note On POSIX systems, host names may be locally defined in the file + * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * <tt>/etc/services</tt>. On Windows, service names may be found in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems + * may use additional locations when resolving service names. + */ + results_type resolve(const protocol_type& protocol, + BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service) + { + return resolve(protocol, host, service, resolver_base::flags()); + } + + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns A range object representing the list of endpoint entries. An + * empty range is returned if an error occurs. A successful call to this + * function is guaranteed to return a non-empty range. + * + * @note On POSIX systems, host names may be locally defined in the file + * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * <tt>/etc/services</tt>. On Windows, service names may be found in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems + * may use additional locations when resolving service names. + */ + results_type resolve(const protocol_type& protocol, + BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service, + boost::system::error_code& ec) + { + return resolve(protocol, host, service, resolver_base::flags(), ec); + } + + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for communication with + * remote hosts. + * + * @returns A range object representing the list of endpoint entries. A + * successful call to this function is guaranteed to return a non-empty + * range. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note On POSIX systems, host names may be locally defined in the file + * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * <tt>/etc/services</tt>. On Windows, service names may be found in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems + * may use additional locations when resolving service names. + */ + results_type resolve(const protocol_type& protocol, + BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service, + resolver_base::flags resolve_flags) + { + boost::system::error_code ec; + basic_resolver_query<protocol_type> q( + protocol, static_cast<std::string>(host), + static_cast<std::string>(service), resolve_flags); + results_type r = this->get_service().resolve( + this->get_implementation(), q, ec); + boost::asio::detail::throw_error(ec, "resolve"); + return r; + } + + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for communication with + * remote hosts. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns A range object representing the list of endpoint entries. An + * empty range is returned if an error occurs. A successful call to this + * function is guaranteed to return a non-empty range. + * + * @note On POSIX systems, host names may be locally defined in the file + * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * <tt>/etc/services</tt>. On Windows, service names may be found in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems + * may use additional locations when resolving service names. + */ + results_type resolve(const protocol_type& protocol, + BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service, + resolver_base::flags resolve_flags, boost::system::error_code& ec) + { + basic_resolver_query<protocol_type> q( + protocol, static_cast<std::string>(host), + static_cast<std::string>(service), resolve_flags); + return this->get_service().resolve(this->get_implementation(), q, ec); + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated.) Asynchronously perform forward resolution of a query to a + /// list of entries. /** * This function is used to asynchronously resolve a query into a list of * endpoint entries. @@ -138,35 +614,307 @@ public: * signature of the handler must be: * @code void handler( * const boost::system::error_code& error, // Result of operation. - * resolver::iterator iterator // Forward-only iterator that can - * // be used to traverse the list - * // of endpoint entries. + * resolver::results_type results // Resolved endpoints as a range. * ); @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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * - * @note A default constructed iterator represents the end of the list. - * - * A successful resolve operation is guaranteed to pass at least one entry to + * A successful resolve operation is guaranteed to pass a non-empty range to * the handler. */ template <typename ResolveHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, - void (boost::system::error_code, iterator)) + void (boost::system::error_code, results_type)) async_resolve(const query& q, BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a ResolveHandler. BOOST_ASIO_RESOLVE_HANDLER_CHECK( - ResolveHandler, handler, iterator) type_check; + ResolveHandler, handler, results_type) type_check; + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + return this->get_service().async_resolve(this->get_implementation(), q, + BOOST_ASIO_MOVE_CAST(ResolveHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + boost::asio::async_completion<ResolveHandler, + void (boost::system::error_code, results_type)> init(handler); + + this->get_service().async_resolve( + this->get_implementation(), q, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Asynchronously perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param handler The handler to be called when the resolve operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * resolver::results_type results // Resolved endpoints as a range. + * ); @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 + * boost::asio::io_context::post(). + * + * A successful resolve operation is guaranteed to pass a non-empty range to + * the handler. + * + * @note On POSIX systems, host names may be locally defined in the file + * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * <tt>/etc/services</tt>. On Windows, service names may be found in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems + * may use additional locations when resolving service names. + */ + template <typename ResolveHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, + void (boost::system::error_code, results_type)) + async_resolve(BOOST_ASIO_STRING_VIEW_PARAM host, + BOOST_ASIO_STRING_VIEW_PARAM service, + BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) + { + return async_resolve(host, service, resolver_base::flags(), + BOOST_ASIO_MOVE_CAST(ResolveHandler)(handler)); + } + + /// Asynchronously perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for communication with + * remote hosts. + * + * @param handler The handler to be called when the resolve operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * resolver::results_type results // Resolved endpoints as a range. + * ); @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 + * boost::asio::io_context::post(). + * + * A successful resolve operation is guaranteed to pass a non-empty range to + * the handler. + * + * @note On POSIX systems, host names may be locally defined in the file + * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * <tt>/etc/services</tt>. On Windows, service names may be found in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems + * may use additional locations when resolving service names. + */ + template <typename ResolveHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, + void (boost::system::error_code, results_type)) + async_resolve(BOOST_ASIO_STRING_VIEW_PARAM host, + BOOST_ASIO_STRING_VIEW_PARAM service, + resolver_base::flags resolve_flags, + BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ResolveHandler. + BOOST_ASIO_RESOLVE_HANDLER_CHECK( + ResolveHandler, handler, results_type) type_check; - return this->service.async_resolve(this->implementation, q, + basic_resolver_query<protocol_type> q(static_cast<std::string>(host), + static_cast<std::string>(service), resolve_flags); + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + return this->get_service().async_resolve(this->get_implementation(), q, + BOOST_ASIO_MOVE_CAST(ResolveHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + boost::asio::async_completion<ResolveHandler, + void (boost::system::error_code, results_type)> init(handler); + + this->get_service().async_resolve( + this->get_implementation(), q, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + } + + /// Asynchronously perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param handler The handler to be called when the resolve operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * resolver::results_type results // Resolved endpoints as a range. + * ); @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 + * boost::asio::io_context::post(). + * + * A successful resolve operation is guaranteed to pass a non-empty range to + * the handler. + * + * @note On POSIX systems, host names may be locally defined in the file + * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * <tt>/etc/services</tt>. On Windows, service names may be found in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems + * may use additional locations when resolving service names. + */ + template <typename ResolveHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, + void (boost::system::error_code, results_type)) + async_resolve(const protocol_type& protocol, + BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service, + BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) + { + return async_resolve(protocol, host, service, resolver_base::flags(), BOOST_ASIO_MOVE_CAST(ResolveHandler)(handler)); } + /// Asynchronously perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for communication with + * remote hosts. + * + * @param handler The handler to be called when the resolve operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * resolver::results_type results // Resolved endpoints as a range. + * ); @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 + * boost::asio::io_context::post(). + * + * A successful resolve operation is guaranteed to pass a non-empty range to + * the handler. + * + * @note On POSIX systems, host names may be locally defined in the file + * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * <tt>/etc/services</tt>. On Windows, service names may be found in the file + * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems + * may use additional locations when resolving service names. + */ + template <typename ResolveHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, + void (boost::system::error_code, results_type)) + async_resolve(const protocol_type& protocol, + BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service, + resolver_base::flags resolve_flags, + BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ResolveHandler. + BOOST_ASIO_RESOLVE_HANDLER_CHECK( + ResolveHandler, handler, results_type) type_check; + + basic_resolver_query<protocol_type> q( + protocol, static_cast<std::string>(host), + static_cast<std::string>(service), resolve_flags); + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + return this->get_service().async_resolve(this->get_implementation(), q, + BOOST_ASIO_MOVE_CAST(ResolveHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + boost::asio::async_completion<ResolveHandler, + void (boost::system::error_code, results_type)> init(handler); + + this->get_service().async_resolve( + this->get_implementation(), q, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + } + /// Perform reverse resolution of an endpoint to a list of entries. /** * This function is used to resolve an endpoint into a list of endpoint @@ -175,20 +923,17 @@ public: * @param e An endpoint object that determines what endpoints will be * returned. * - * @returns A forward-only iterator that can be used to traverse the list - * of endpoint entries. + * @returns A range object representing the list of endpoint entries. A + * successful call to this function is guaranteed to return a non-empty + * range. * * @throws boost::system::system_error Thrown on failure. - * - * @note A default constructed iterator represents the end of the list. - * - * A successful call to this function is guaranteed to return at least one - * entry. */ - iterator resolve(const endpoint_type& e) + results_type resolve(const endpoint_type& e) { boost::system::error_code ec; - iterator i = this->service.resolve(this->implementation, e, ec); + results_type i = this->get_service().resolve( + this->get_implementation(), e, ec); boost::asio::detail::throw_error(ec, "resolve"); return i; } @@ -203,18 +948,13 @@ public: * * @param ec Set to indicate what error occurred, if any. * - * @returns A forward-only iterator that can be used to traverse the list - * of endpoint entries. Returns a default constructed iterator if an error - * occurs. - * - * @note A default constructed iterator represents the end of the list. - * - * A successful call to this function is guaranteed to return at least one - * entry. + * @returns A range object representing the list of endpoint entries. An + * empty range is returned if an error occurs. A successful call to this + * function is guaranteed to return a non-empty range. */ - iterator resolve(const endpoint_type& e, boost::system::error_code& ec) + results_type resolve(const endpoint_type& e, boost::system::error_code& ec) { - return this->service.resolve(this->implementation, e, ec); + return this->get_service().resolve(this->get_implementation(), e, ec); } /// Asynchronously perform reverse resolution of an endpoint to a list of @@ -231,33 +971,39 @@ public: * signature of the handler must be: * @code void handler( * const boost::system::error_code& error, // Result of operation. - * resolver::iterator iterator // Forward-only iterator that can - * // be used to traverse the list - * // of endpoint entries. + * resolver::results_type results // Resolved endpoints as a range. * ); @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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * - * @note A default constructed iterator represents the end of the list. - * - * A successful resolve operation is guaranteed to pass at least one entry to + * A successful resolve operation is guaranteed to pass a non-empty range to * the handler. */ template <typename ResolveHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, - void (boost::system::error_code, iterator)) + void (boost::system::error_code, results_type)) async_resolve(const endpoint_type& e, BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) { // If you get an error on the following line it means that your handler does // not meet the documented type requirements for a ResolveHandler. BOOST_ASIO_RESOLVE_HANDLER_CHECK( - ResolveHandler, handler, iterator) type_check; + ResolveHandler, handler, results_type) type_check; - return this->service.async_resolve(this->implementation, e, +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + return this->get_service().async_resolve(this->get_implementation(), e, BOOST_ASIO_MOVE_CAST(ResolveHandler)(handler)); +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + boost::asio::async_completion<ResolveHandler, + void (boost::system::error_code, results_type)> init(handler); + + this->get_service().async_resolve( + this->get_implementation(), e, init.completion_handler); + + return init.result.get(); +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } }; @@ -267,4 +1013,8 @@ public: #include <boost/asio/detail/pop_options.hpp> +#if !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# undef BOOST_ASIO_SVC_T +#endif // !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_IP_BASIC_RESOLVER_HPP diff --git a/boost/asio/ip/basic_resolver_entry.hpp b/boost/asio/ip/basic_resolver_entry.hpp index 05c8547a0c..ec6c7bd6d5 100644 --- a/boost/asio/ip/basic_resolver_entry.hpp +++ b/boost/asio/ip/basic_resolver_entry.hpp @@ -17,6 +17,7 @@ #include <boost/asio/detail/config.hpp> #include <string> +#include <boost/asio/detail/string_view.hpp> #include <boost/asio/detail/push_options.hpp> @@ -50,10 +51,10 @@ public: /// Construct with specified endpoint, host name and service name. basic_resolver_entry(const endpoint_type& ep, - const std::string& host, const std::string& service) + BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service) : endpoint_(ep), - host_name_(host), - service_name_(service) + host_name_(static_cast<std::string>(host)), + service_name_(static_cast<std::string>(service)) { } @@ -75,12 +76,30 @@ public: return host_name_; } + /// Get the host name associated with the entry. + template <class Allocator> + std::basic_string<char, std::char_traits<char>, Allocator> host_name( + const Allocator& alloc = Allocator()) const + { + return std::basic_string<char, std::char_traits<char>, Allocator>( + host_name_.c_str(), alloc); + } + /// Get the service name associated with the entry. std::string service_name() const { return service_name_; } + /// Get the service name associated with the entry. + template <class Allocator> + std::basic_string<char, std::char_traits<char>, Allocator> service_name( + const Allocator& alloc = Allocator()) const + { + return std::basic_string<char, std::char_traits<char>, Allocator>( + service_name_.c_str(), alloc); + } + private: endpoint_type endpoint_; std::string host_name_; diff --git a/boost/asio/ip/basic_resolver_iterator.hpp b/boost/asio/ip/basic_resolver_iterator.hpp index b7deb77364..6571fdd982 100644 --- a/boost/asio/ip/basic_resolver_iterator.hpp +++ b/boost/asio/ip/basic_resolver_iterator.hpp @@ -21,7 +21,7 @@ #include <iterator> #include <string> #include <vector> -#include <boost/asio/detail/shared_ptr.hpp> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/ip/basic_resolver_entry.hpp> @@ -73,114 +73,45 @@ public: { } - /// Create an iterator from an addrinfo list returned by getaddrinfo. - static basic_resolver_iterator create( - boost::asio::detail::addrinfo_type* address_info, - const std::string& host_name, const std::string& service_name) + /// Copy constructor. + basic_resolver_iterator(const basic_resolver_iterator& other) + : values_(other.values_), + index_(other.index_) { - basic_resolver_iterator iter; - if (!address_info) - return iter; - - std::string actual_host_name = host_name; - if (address_info->ai_canonname) - actual_host_name = address_info->ai_canonname; - - iter.values_.reset(new values_type); - - while (address_info) - { - if (address_info->ai_family == BOOST_ASIO_OS_DEF(AF_INET) - || address_info->ai_family == BOOST_ASIO_OS_DEF(AF_INET6)) - { - using namespace std; // For memcpy. - typename InternetProtocol::endpoint endpoint; - endpoint.resize(static_cast<std::size_t>(address_info->ai_addrlen)); - memcpy(endpoint.data(), address_info->ai_addr, - address_info->ai_addrlen); - iter.values_->push_back( - basic_resolver_entry<InternetProtocol>(endpoint, - actual_host_name, service_name)); - } - address_info = address_info->ai_next; - } - - return iter; } - /// Create an iterator from an endpoint, host name and service name. - static basic_resolver_iterator create( - const typename InternetProtocol::endpoint& endpoint, - const std::string& host_name, const std::string& service_name) +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move constructor. + basic_resolver_iterator(basic_resolver_iterator&& other) + : values_(BOOST_ASIO_MOVE_CAST(values_ptr_type)(other.values_)), + index_(other.index_) { - basic_resolver_iterator iter; - iter.values_.reset(new values_type); - iter.values_->push_back( - basic_resolver_entry<InternetProtocol>( - endpoint, host_name, service_name)); - return iter; + other.index_ = 0; } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) - /// Create an iterator from a sequence of endpoints, host and service name. - template <typename EndpointIterator> - static basic_resolver_iterator create( - EndpointIterator begin, EndpointIterator end, - const std::string& host_name, const std::string& service_name) + /// Assignment operator. + basic_resolver_iterator& operator=(const basic_resolver_iterator& other) { - basic_resolver_iterator iter; - if (begin != end) - { - iter.values_.reset(new values_type); - for (EndpointIterator ep_iter = begin; ep_iter != end; ++ep_iter) - { - iter.values_->push_back( - basic_resolver_entry<InternetProtocol>( - *ep_iter, host_name, service_name)); - } - } - return iter; + values_ = other.values_; + index_ = other.index_; + return *this; } -#if defined(BOOST_ASIO_WINDOWS_RUNTIME) - /// Create an iterator from a Windows Runtime list of EndpointPair objects. - static basic_resolver_iterator create( - Windows::Foundation::Collections::IVectorView< - Windows::Networking::EndpointPair^>^ endpoints, - const boost::asio::detail::addrinfo_type& hints, - const std::string& host_name, const std::string& service_name) +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-assignment operator. + basic_resolver_iterator& operator=(basic_resolver_iterator&& other) { - basic_resolver_iterator iter; - if (endpoints->Size) + if (this != &other) { - iter.values_.reset(new values_type); - for (unsigned int i = 0; i < endpoints->Size; ++i) - { - auto pair = endpoints->GetAt(i); - - if (hints.ai_family == BOOST_ASIO_OS_DEF(AF_INET) - && pair->RemoteHostName->Type - != Windows::Networking::HostNameType::Ipv4) - continue; - - if (hints.ai_family == BOOST_ASIO_OS_DEF(AF_INET6) - && pair->RemoteHostName->Type - != Windows::Networking::HostNameType::Ipv6) - continue; - - iter.values_->push_back( - basic_resolver_entry<InternetProtocol>( - typename InternetProtocol::endpoint( - ip::address::from_string( - boost::asio::detail::winrt_utils::string( - pair->RemoteHostName->CanonicalName)), - boost::asio::detail::winrt_utils::integer( - pair->RemoteServiceName)), - host_name, service_name)); - } + values_ = BOOST_ASIO_MOVE_CAST(values_ptr_type)(other.values_); + index_ = other.index_; + other.index_ = 0; } - return iter; + + return *this; } -#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Dereference an iterator. const basic_resolver_entry<InternetProtocol>& operator*() const @@ -223,7 +154,7 @@ public: return !a.equal(b); } -private: +protected: void increment() { if (++index_ == values_->size()) @@ -249,7 +180,8 @@ private: } typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type; - boost::asio::detail::shared_ptr<values_type> values_; + typedef boost::asio::detail::shared_ptr<values_type> values_ptr_type; + values_ptr_type values_; std::size_t index_; }; diff --git a/boost/asio/ip/basic_resolver_results.hpp b/boost/asio/ip/basic_resolver_results.hpp new file mode 100644 index 0000000000..bd3248a1a9 --- /dev/null +++ b/boost/asio/ip/basic_resolver_results.hpp @@ -0,0 +1,313 @@ +// +// ip/basic_resolver_results.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IP_BASIC_RESOLVER_RESULTS_HPP +#define BOOST_ASIO_IP_BASIC_RESOLVER_RESULTS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <cstddef> +#include <cstring> +#include <boost/asio/detail/socket_ops.hpp> +#include <boost/asio/detail/socket_types.hpp> +#include <boost/asio/ip/basic_resolver_iterator.hpp> + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include <boost/asio/detail/winrt_utils.hpp> +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace ip { + +/// A range of entries produced by a resolver. +/** + * The boost::asio::ip::basic_resolver_results class template is used to define + * a range over the results returned by a resolver. + * + * The iterator's value_type, obtained when a results iterator is dereferenced, + * is: @code const basic_resolver_entry<InternetProtocol> @endcode + * + * @note For backward compatibility, basic_resolver_results is derived from + * basic_resolver_iterator. This derivation is deprecated. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template <typename InternetProtocol> +class basic_resolver_results +#if !defined(BOOST_ASIO_NO_DEPRECATED) + : public basic_resolver_iterator<InternetProtocol> +#else // !defined(BOOST_ASIO_NO_DEPRECATED) + : private basic_resolver_iterator<InternetProtocol> +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) +{ +public: + /// The protocol type associated with the results. + typedef InternetProtocol protocol_type; + + /// The endpoint type associated with the results. + typedef typename protocol_type::endpoint endpoint_type; + + /// The type of a value in the results range. + typedef basic_resolver_entry<endpoint_type> value_type; + + /// The type of a const reference to a value in the range. + typedef const value_type& const_reference; + + /// The type of a non-const reference to a value in the range. + typedef value_type& reference; + + /// The type of an iterator into the range. + typedef basic_resolver_iterator<protocol_type> const_iterator; + + /// The type of an iterator into the range. + typedef const_iterator iterator; + + /// Type used to represent the distance between two iterators in the range. + typedef std::ptrdiff_t difference_type; + + /// Type used to represent a count of the elements in the range. + typedef std::size_t size_type; + + /// Default constructor creates an empty range. + basic_resolver_results() + { + } + + /// Copy constructor. + basic_resolver_results(const basic_resolver_results& other) + : basic_resolver_iterator<InternetProtocol>(other) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move constructor. + basic_resolver_results(basic_resolver_results&& other) + : basic_resolver_iterator<InternetProtocol>( + BOOST_ASIO_MOVE_CAST(basic_resolver_results)(other)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Assignment operator. + basic_resolver_results& operator=(const basic_resolver_results& other) + { + basic_resolver_iterator<InternetProtocol>::operator=(other); + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-assignment operator. + basic_resolver_results& operator=(basic_resolver_results&& other) + { + basic_resolver_iterator<InternetProtocol>::operator=( + BOOST_ASIO_MOVE_CAST(basic_resolver_results)(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + +#if !defined(GENERATING_DOCUMENTATION) + // Create results from an addrinfo list returned by getaddrinfo. + static basic_resolver_results create( + boost::asio::detail::addrinfo_type* address_info, + const std::string& host_name, const std::string& service_name) + { + basic_resolver_results results; + if (!address_info) + return results; + + std::string actual_host_name = host_name; + if (address_info->ai_canonname) + actual_host_name = address_info->ai_canonname; + + results.values_.reset(new values_type); + + while (address_info) + { + if (address_info->ai_family == BOOST_ASIO_OS_DEF(AF_INET) + || address_info->ai_family == BOOST_ASIO_OS_DEF(AF_INET6)) + { + using namespace std; // For memcpy. + typename InternetProtocol::endpoint endpoint; + endpoint.resize(static_cast<std::size_t>(address_info->ai_addrlen)); + memcpy(endpoint.data(), address_info->ai_addr, + address_info->ai_addrlen); + results.values_->push_back( + basic_resolver_entry<InternetProtocol>(endpoint, + actual_host_name, service_name)); + } + address_info = address_info->ai_next; + } + + return results; + } + + // Create results from an endpoint, host name and service name. + static basic_resolver_results create(const endpoint_type& endpoint, + const std::string& host_name, const std::string& service_name) + { + basic_resolver_results results; + results.values_.reset(new values_type); + results.values_->push_back( + basic_resolver_entry<InternetProtocol>( + endpoint, host_name, service_name)); + return results; + } + + // Create results from a sequence of endpoints, host and service name. + template <typename EndpointIterator> + static basic_resolver_results create( + EndpointIterator begin, EndpointIterator end, + const std::string& host_name, const std::string& service_name) + { + basic_resolver_results results; + if (begin != end) + { + results.values_.reset(new values_type); + for (EndpointIterator ep_iter = begin; ep_iter != end; ++ep_iter) + { + results.values_->push_back( + basic_resolver_entry<InternetProtocol>( + *ep_iter, host_name, service_name)); + } + } + return results; + } + +# if defined(BOOST_ASIO_WINDOWS_RUNTIME) + // Create results from a Windows Runtime list of EndpointPair objects. + static basic_resolver_results create( + Windows::Foundation::Collections::IVectorView< + Windows::Networking::EndpointPair^>^ endpoints, + const boost::asio::detail::addrinfo_type& hints, + const std::string& host_name, const std::string& service_name) + { + basic_resolver_results results; + if (endpoints->Size) + { + results.values_.reset(new values_type); + for (unsigned int i = 0; i < endpoints->Size; ++i) + { + auto pair = endpoints->GetAt(i); + + if (hints.ai_family == BOOST_ASIO_OS_DEF(AF_INET) + && pair->RemoteHostName->Type + != Windows::Networking::HostNameType::Ipv4) + continue; + + if (hints.ai_family == BOOST_ASIO_OS_DEF(AF_INET6) + && pair->RemoteHostName->Type + != Windows::Networking::HostNameType::Ipv6) + continue; + + results.values_->push_back( + basic_resolver_entry<InternetProtocol>( + typename InternetProtocol::endpoint( + ip::make_address( + boost::asio::detail::winrt_utils::string( + pair->RemoteHostName->CanonicalName)), + boost::asio::detail::winrt_utils::integer( + pair->RemoteServiceName)), + host_name, service_name)); + } + } + return results; + } +# endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) +#endif // !defined(GENERATING_DOCUMENTATION) + + /// Get the number of entries in the results range. + size_type size() const BOOST_ASIO_NOEXCEPT + { + return this->values_->size(); + } + + /// Get the maximum number of entries permitted in a results range. + size_type max_size() const BOOST_ASIO_NOEXCEPT + { + return this->values_->max_size(); + } + + /// Determine whether the results range is empty. + bool empty() const BOOST_ASIO_NOEXCEPT + { + return this->values_->empty(); + } + + /// Obtain a begin iterator for the results range. + const_iterator begin() const + { + basic_resolver_results tmp(*this); + tmp.index_ = 0; + return tmp; + } + + /// Obtain an end iterator for the results range. + const_iterator end() const + { + return const_iterator(); + } + + /// Obtain a begin iterator for the results range. + const_iterator cbegin() const + { + return begin(); + } + + /// Obtain an end iterator for the results range. + const_iterator cend() const + { + return end(); + } + + /// Swap the results range with another. + void swap(basic_resolver_results& that) BOOST_ASIO_NOEXCEPT + { + if (this != &that) + { + this->values_.swap(that.values_); + std::size_t index = this->index_; + this->index_ = that.index_; + that.index_ = index; + } + } + + /// Test two iterators for equality. + friend bool operator==(const basic_resolver_results& a, + const basic_resolver_results& b) + { + return a.equal(b); + } + + /// Test two iterators for inequality. + friend bool operator!=(const basic_resolver_results& a, + const basic_resolver_results& b) + { + return !a.equal(b); + } + +private: + typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type; +}; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IP_BASIC_RESOLVER_RESULTS_HPP diff --git a/boost/asio/ip/detail/endpoint.hpp b/boost/asio/ip/detail/endpoint.hpp index 0a354e12a9..69a83a9e96 100644 --- a/boost/asio/ip/detail/endpoint.hpp +++ b/boost/asio/ip/detail/endpoint.hpp @@ -114,7 +114,7 @@ public: #if !defined(BOOST_ASIO_NO_IOSTREAM) // Convert to a string. - BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; + BOOST_ASIO_DECL std::string to_string() const; #endif // !defined(BOOST_ASIO_NO_IOSTREAM) private: diff --git a/boost/asio/ip/detail/impl/endpoint.ipp b/boost/asio/ip/detail/impl/endpoint.ipp index f1f9309af5..9908479327 100644 --- a/boost/asio/ip/detail/impl/endpoint.ipp +++ b/boost/asio/ip/detail/impl/endpoint.ipp @@ -81,8 +81,7 @@ endpoint::endpoint(const boost::asio::ip::address& addr, boost::asio::detail::socket_ops::host_to_network_short(port_num); data_.v4.sin_addr.s_addr = boost::asio::detail::socket_ops::host_to_network_long( - static_cast<boost::asio::detail::u_long_type>( - addr.to_v4().to_ulong())); + addr.to_v4().to_uint()); } else { @@ -178,18 +177,14 @@ bool operator<(const endpoint& e1, const endpoint& e2) } #if !defined(BOOST_ASIO_NO_IOSTREAM) -std::string endpoint::to_string(boost::system::error_code& ec) const +std::string endpoint::to_string() const { - std::string a = address().to_string(ec); - if (ec) - return std::string(); - std::ostringstream tmp_os; tmp_os.imbue(std::locale::classic()); if (is_v4()) - tmp_os << a; + tmp_os << address(); else - tmp_os << '[' << a << ']'; + tmp_os << '[' << address() << ']'; tmp_os << ':' << port(); return tmp_os.str(); diff --git a/boost/asio/ip/detail/socket_option.hpp b/boost/asio/ip/detail/socket_option.hpp index e8849fda92..e246ca0ef5 100644 --- a/boost/asio/ip/detail/socket_option.hpp +++ b/boost/asio/ip/detail/socket_option.hpp @@ -392,15 +392,15 @@ public: } // Construct with multicast address only. - explicit multicast_request(const boost::asio::ip::address& multicast_address) + explicit multicast_request(const address& multicast_address) : ipv4_value_(), // Zero-initialisation gives the "any" address. ipv6_value_() // Zero-initialisation gives the "any" address. { if (multicast_address.is_v6()) { using namespace std; // For memcpy. - boost::asio::ip::address_v6 ipv6_address = multicast_address.to_v6(); - boost::asio::ip::address_v6::bytes_type bytes = ipv6_address.to_bytes(); + address_v6 ipv6_address = multicast_address.to_v6(); + address_v6::bytes_type bytes = ipv6_address.to_bytes(); memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.data(), 16); ipv6_value_.ipv6mr_interface = ipv6_address.scope_id(); } @@ -408,37 +408,34 @@ public: { ipv4_value_.imr_multiaddr.s_addr = boost::asio::detail::socket_ops::host_to_network_long( - multicast_address.to_v4().to_ulong()); + multicast_address.to_v4().to_uint()); ipv4_value_.imr_interface.s_addr = boost::asio::detail::socket_ops::host_to_network_long( - boost::asio::ip::address_v4::any().to_ulong()); + address_v4::any().to_uint()); } } // Construct with multicast address and IPv4 address specifying an interface. - explicit multicast_request( - const boost::asio::ip::address_v4& multicast_address, - const boost::asio::ip::address_v4& network_interface - = boost::asio::ip::address_v4::any()) + explicit multicast_request(const address_v4& multicast_address, + const address_v4& network_interface = address_v4::any()) : ipv6_value_() // Zero-initialisation gives the "any" address. { ipv4_value_.imr_multiaddr.s_addr = boost::asio::detail::socket_ops::host_to_network_long( - multicast_address.to_ulong()); + multicast_address.to_uint()); ipv4_value_.imr_interface.s_addr = boost::asio::detail::socket_ops::host_to_network_long( - network_interface.to_ulong()); + network_interface.to_uint()); } // Construct with multicast address and IPv6 network interface index. explicit multicast_request( - const boost::asio::ip::address_v6& multicast_address, + const address_v6& multicast_address, unsigned long network_interface = 0) : ipv4_value_() // Zero-initialisation gives the "any" address. { using namespace std; // For memcpy. - boost::asio::ip::address_v6::bytes_type bytes = - multicast_address.to_bytes(); + address_v6::bytes_type bytes = multicast_address.to_bytes(); memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.data(), 16); if (network_interface) ipv6_value_.ipv6mr_interface = network_interface; @@ -497,16 +494,16 @@ public: { ipv4_value_.s_addr = boost::asio::detail::socket_ops::host_to_network_long( - boost::asio::ip::address_v4::any().to_ulong()); + address_v4::any().to_uint()); ipv6_value_ = 0; } // Construct with IPv4 interface. - explicit network_interface(const boost::asio::ip::address_v4& ipv4_interface) + explicit network_interface(const address_v4& ipv4_interface) { ipv4_value_.s_addr = boost::asio::detail::socket_ops::host_to_network_long( - ipv4_interface.to_ulong()); + ipv4_interface.to_uint()); ipv6_value_ = 0; } @@ -515,7 +512,7 @@ public: { ipv4_value_.s_addr = boost::asio::detail::socket_ops::host_to_network_long( - boost::asio::ip::address_v4::any().to_ulong()); + address_v4::any().to_uint()); ipv6_value_ = ipv6_interface; } diff --git a/boost/asio/ip/impl/address.hpp b/boost/asio/ip/impl/address.hpp index e595d7063b..552cb5fd6d 100644 --- a/boost/asio/ip/impl/address.hpp +++ b/boost/asio/ip/impl/address.hpp @@ -25,23 +25,37 @@ namespace boost { namespace asio { namespace ip { +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +inline address address::from_string(const char* str) +{ + return boost::asio::ip::make_address(str); +} + +inline address address::from_string( + const char* str, boost::system::error_code& ec) +{ + return boost::asio::ip::make_address(str, ec); +} + +inline address address::from_string(const std::string& str) +{ + return boost::asio::ip::make_address(str); +} + +inline address address::from_string( + const std::string& str, boost::system::error_code& ec) +{ + return boost::asio::ip::make_address(str, ec); +} + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + template <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const address& addr) { - boost::system::error_code ec; - std::string s = addr.to_string(ec); - if (ec) - { - if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit) - boost::asio::detail::throw_error(ec); - else - os.setstate(std::basic_ostream<Elem, Traits>::failbit); - } - else - for (std::string::iterator i = s.begin(); i != s.end(); ++i) - os << os.widen(*i); - return os; + return os << addr.to_string().c_str(); } } // namespace ip diff --git a/boost/asio/ip/impl/address.ipp b/boost/asio/ip/impl/address.ipp index 5eda3e9ecf..6c615592e5 100644 --- a/boost/asio/ip/impl/address.ipp +++ b/boost/asio/ip/impl/address.ipp @@ -21,6 +21,7 @@ #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/error.hpp> #include <boost/asio/ip/address.hpp> +#include <boost/asio/ip/bad_address_cast.hpp> #include <boost/system/system_error.hpp> #include <boost/asio/detail/push_options.hpp> @@ -100,11 +101,60 @@ address& address::operator=(const boost::asio::ip::address_v6& ipv6_address) return *this; } +address make_address(const char* str) +{ + boost::system::error_code ec; + address addr = make_address(str, ec); + boost::asio::detail::throw_error(ec); + return addr; +} + +address make_address(const char* str, boost::system::error_code& ec) +{ + boost::asio::ip::address_v6 ipv6_address = + boost::asio::ip::make_address_v6(str, ec); + if (!ec) + return address(ipv6_address); + + boost::asio::ip::address_v4 ipv4_address = + boost::asio::ip::make_address_v4(str, ec); + if (!ec) + return address(ipv4_address); + + return address(); +} + +address make_address(const std::string& str) +{ + return make_address(str.c_str()); +} + +address make_address(const std::string& str, + boost::system::error_code& ec) +{ + return make_address(str.c_str(), ec); +} + +#if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + +address make_address(string_view str) +{ + return make_address(static_cast<std::string>(str)); +} + +address make_address(string_view str, + boost::system::error_code& ec) +{ + return make_address(static_cast<std::string>(str), ec); +} + +#endif // defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + boost::asio::ip::address_v4 address::to_v4() const { if (type_ != ipv4) { - std::bad_cast ex; + bad_address_cast ex; boost::asio::detail::throw_exception(ex); } return ipv4_address_; @@ -114,7 +164,7 @@ boost::asio::ip::address_v6 address::to_v6() const { if (type_ != ipv6) { - std::bad_cast ex; + bad_address_cast ex; boost::asio::detail::throw_exception(ex); } return ipv6_address_; @@ -127,56 +177,14 @@ std::string address::to_string() const return ipv4_address_.to_string(); } +#if !defined(BOOST_ASIO_NO_DEPRECATED) std::string address::to_string(boost::system::error_code& ec) const { if (type_ == ipv6) return ipv6_address_.to_string(ec); return ipv4_address_.to_string(ec); } - -address address::from_string(const char* str) -{ - boost::system::error_code ec; - address addr = from_string(str, ec); - boost::asio::detail::throw_error(ec); - return addr; -} - -address address::from_string(const char* str, boost::system::error_code& ec) -{ - boost::asio::ip::address_v6 ipv6_address = - boost::asio::ip::address_v6::from_string(str, ec); - if (!ec) - { - address tmp; - tmp.type_ = ipv6; - tmp.ipv6_address_ = ipv6_address; - return tmp; - } - - boost::asio::ip::address_v4 ipv4_address = - boost::asio::ip::address_v4::from_string(str, ec); - if (!ec) - { - address tmp; - tmp.type_ = ipv4; - tmp.ipv4_address_ = ipv4_address; - return tmp; - } - - return address(); -} - -address address::from_string(const std::string& str) -{ - return from_string(str.c_str()); -} - -address address::from_string(const std::string& str, - boost::system::error_code& ec) -{ - return from_string(str.c_str(), ec); -} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) bool address::is_loopback() const { diff --git a/boost/asio/ip/impl/address_v4.hpp b/boost/asio/ip/impl/address_v4.hpp index 028b69b676..a273f5e73e 100644 --- a/boost/asio/ip/impl/address_v4.hpp +++ b/boost/asio/ip/impl/address_v4.hpp @@ -25,23 +25,37 @@ namespace boost { namespace asio { namespace ip { +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +inline address_v4 address_v4::from_string(const char* str) +{ + return boost::asio::ip::make_address_v4(str); +} + +inline address_v4 address_v4::from_string( + const char* str, boost::system::error_code& ec) +{ + return boost::asio::ip::make_address_v4(str, ec); +} + +inline address_v4 address_v4::from_string(const std::string& str) +{ + return boost::asio::ip::make_address_v4(str); +} + +inline address_v4 address_v4::from_string( + const std::string& str, boost::system::error_code& ec) +{ + return boost::asio::ip::make_address_v4(str, ec); +} + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + template <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const address_v4& addr) { - boost::system::error_code ec; - std::string s = addr.to_string(ec); - if (ec) - { - if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit) - boost::asio::detail::throw_error(ec); - else - os.setstate(std::basic_ostream<Elem, Traits>::failbit); - } - else - for (std::string::iterator i = s.begin(); i != s.end(); ++i) - os << os.widen(*i); - return os; + return os << addr.to_string().c_str(); } } // namespace ip diff --git a/boost/asio/ip/impl/address_v4.ipp b/boost/asio/ip/impl/address_v4.ipp index 440217bcb2..d6db61f80d 100644 --- a/boost/asio/ip/impl/address_v4.ipp +++ b/boost/asio/ip/impl/address_v4.ipp @@ -17,6 +17,7 @@ #include <boost/asio/detail/config.hpp> #include <climits> +#include <limits> #include <stdexcept> #include <boost/asio/error.hpp> #include <boost/asio/detail/socket_ops.hpp> @@ -45,15 +46,13 @@ address_v4::address_v4(const address_v4::bytes_type& bytes) memcpy(&addr_.s_addr, bytes.data(), 4); } -address_v4::address_v4(unsigned long addr) +address_v4::address_v4(address_v4::uint_type addr) { -#if ULONG_MAX > 0xFFFFFFFF - if (addr > 0xFFFFFFFF) + if ((std::numeric_limits<uint_type>::max)() > 0xFFFFFFFF) { - std::out_of_range ex("address_v4 from unsigned long"); + std::out_of_range ex("address_v4 from unsigned integer"); boost::asio::detail::throw_exception(ex); } -#endif // ULONG_MAX > 0xFFFFFFFF addr_.s_addr = boost::asio::detail::socket_ops::host_to_network_long( static_cast<boost::asio::detail::u_long_type>(addr)); @@ -71,19 +70,32 @@ address_v4::bytes_type address_v4::to_bytes() const return bytes; } +address_v4::uint_type address_v4::to_uint() const +{ + return boost::asio::detail::socket_ops::network_to_host_long(addr_.s_addr); +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) unsigned long address_v4::to_ulong() const { return boost::asio::detail::socket_ops::network_to_host_long(addr_.s_addr); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) std::string address_v4::to_string() const { boost::system::error_code ec; - std::string addr = to_string(ec); - boost::asio::detail::throw_error(ec); + char addr_str[boost::asio::detail::max_addr_v4_str_len]; + const char* addr = + boost::asio::detail::socket_ops::inet_ntop( + BOOST_ASIO_OS_DEF(AF_INET), &addr_, addr_str, + boost::asio::detail::max_addr_v4_str_len, 0, ec); + if (addr == 0) + boost::asio::detail::throw_error(ec); return addr; } +#if !defined(BOOST_ASIO_NO_DEPRECATED) std::string address_v4::to_string(boost::system::error_code& ec) const { char addr_str[boost::asio::detail::max_addr_v4_str_len]; @@ -95,69 +107,44 @@ std::string address_v4::to_string(boost::system::error_code& ec) const return std::string(); return addr; } - -address_v4 address_v4::from_string(const char* str) -{ - boost::system::error_code ec; - address_v4 addr = from_string(str, ec); - boost::asio::detail::throw_error(ec); - return addr; -} - -address_v4 address_v4::from_string( - const char* str, boost::system::error_code& ec) -{ - address_v4 tmp; - if (boost::asio::detail::socket_ops::inet_pton( - BOOST_ASIO_OS_DEF(AF_INET), str, &tmp.addr_, 0, ec) <= 0) - return address_v4(); - return tmp; -} - -address_v4 address_v4::from_string(const std::string& str) -{ - return from_string(str.c_str()); -} - -address_v4 address_v4::from_string( - const std::string& str, boost::system::error_code& ec) -{ - return from_string(str.c_str(), ec); -} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) bool address_v4::is_loopback() const { - return (to_ulong() & 0xFF000000) == 0x7F000000; + return (to_uint() & 0xFF000000) == 0x7F000000; } bool address_v4::is_unspecified() const { - return to_ulong() == 0; + return to_uint() == 0; } +#if !defined(BOOST_ASIO_NO_DEPRECATED) bool address_v4::is_class_a() const { - return (to_ulong() & 0x80000000) == 0; + return (to_uint() & 0x80000000) == 0; } bool address_v4::is_class_b() const { - return (to_ulong() & 0xC0000000) == 0x80000000; + return (to_uint() & 0xC0000000) == 0x80000000; } bool address_v4::is_class_c() const { - return (to_ulong() & 0xE0000000) == 0xC0000000; + return (to_uint() & 0xE0000000) == 0xC0000000; } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) bool address_v4::is_multicast() const { - return (to_ulong() & 0xF0000000) == 0xE0000000; + return (to_uint() & 0xF0000000) == 0xE0000000; } +#if !defined(BOOST_ASIO_NO_DEPRECATED) address_v4 address_v4::broadcast(const address_v4& addr, const address_v4& mask) { - return address_v4(addr.to_ulong() | (mask.to_ulong() ^ 0xFFFFFFFF)); + return address_v4(addr.to_uint() | (mask.to_uint() ^ 0xFFFFFFFF)); } address_v4 address_v4::netmask(const address_v4& addr) @@ -170,6 +157,51 @@ address_v4 address_v4::netmask(const address_v4& addr) return address_v4(0xFFFFFF00); return address_v4(0xFFFFFFFF); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +address_v4 make_address_v4(const char* str) +{ + boost::system::error_code ec; + address_v4 addr = make_address_v4(str, ec); + boost::asio::detail::throw_error(ec); + return addr; +} + +address_v4 make_address_v4( + const char* str, boost::system::error_code& ec) +{ + address_v4::bytes_type bytes; + if (boost::asio::detail::socket_ops::inet_pton( + BOOST_ASIO_OS_DEF(AF_INET), str, &bytes, 0, ec) <= 0) + return address_v4(); + return address_v4(bytes); +} + +address_v4 make_address_v4(const std::string& str) +{ + return make_address_v4(str.c_str()); +} + +address_v4 make_address_v4( + const std::string& str, boost::system::error_code& ec) +{ + return make_address_v4(str.c_str(), ec); +} + +#if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + +address_v4 make_address_v4(string_view str) +{ + return make_address_v4(static_cast<std::string>(str)); +} + +address_v4 make_address_v4(string_view str, + boost::system::error_code& ec) +{ + return make_address_v4(static_cast<std::string>(str), ec); +} + +#endif // defined(BOOST_ASIO_HAS_STD_STRING_VIEW) } // namespace ip } // namespace asio diff --git a/boost/asio/ip/impl/address_v6.hpp b/boost/asio/ip/impl/address_v6.hpp index 4b88129c50..e1d9932d30 100644 --- a/boost/asio/ip/impl/address_v6.hpp +++ b/boost/asio/ip/impl/address_v6.hpp @@ -25,23 +25,37 @@ namespace boost { namespace asio { namespace ip { +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +inline address_v6 address_v6::from_string(const char* str) +{ + return boost::asio::ip::make_address_v6(str); +} + +inline address_v6 address_v6::from_string( + const char* str, boost::system::error_code& ec) +{ + return boost::asio::ip::make_address_v6(str, ec); +} + +inline address_v6 address_v6::from_string(const std::string& str) +{ + return boost::asio::ip::make_address_v6(str); +} + +inline address_v6 address_v6::from_string( + const std::string& str, boost::system::error_code& ec) +{ + return boost::asio::ip::make_address_v6(str, ec); +} + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + template <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const address_v6& addr) { - boost::system::error_code ec; - std::string s = addr.to_string(ec); - if (ec) - { - if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit) - boost::asio::detail::throw_error(ec); - else - os.setstate(std::basic_ostream<Elem, Traits>::failbit); - } - else - for (std::string::iterator i = s.begin(); i != s.end(); ++i) - os << os.widen(*i); - return os; + return os << addr.to_string().c_str(); } } // namespace ip diff --git a/boost/asio/ip/impl/address_v6.ipp b/boost/asio/ip/impl/address_v6.ipp index 2d1a1974bf..1741bbcf79 100644 --- a/boost/asio/ip/impl/address_v6.ipp +++ b/boost/asio/ip/impl/address_v6.ipp @@ -24,6 +24,7 @@ #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/error.hpp> #include <boost/asio/ip/address_v6.hpp> +#include <boost/asio/ip/bad_address_cast.hpp> #include <boost/asio/detail/push_options.hpp> @@ -101,11 +102,17 @@ address_v6::bytes_type address_v6::to_bytes() const std::string address_v6::to_string() const { boost::system::error_code ec; - std::string addr = to_string(ec); - boost::asio::detail::throw_error(ec); + char addr_str[boost::asio::detail::max_addr_v6_str_len]; + const char* addr = + boost::asio::detail::socket_ops::inet_ntop( + BOOST_ASIO_OS_DEF(AF_INET6), &addr_, addr_str, + boost::asio::detail::max_addr_v6_str_len, scope_id_, ec); + if (addr == 0) + boost::asio::detail::throw_error(ec); return addr; } +#if !defined(BOOST_ASIO_NO_DEPRECATED) std::string address_v6::to_string(boost::system::error_code& ec) const { char addr_str[boost::asio::detail::max_addr_v6_str_len]; @@ -118,40 +125,11 @@ std::string address_v6::to_string(boost::system::error_code& ec) const return addr; } -address_v6 address_v6::from_string(const char* str) -{ - boost::system::error_code ec; - address_v6 addr = from_string(str, ec); - boost::asio::detail::throw_error(ec); - return addr; -} - -address_v6 address_v6::from_string( - const char* str, boost::system::error_code& ec) -{ - address_v6 tmp; - if (boost::asio::detail::socket_ops::inet_pton( - BOOST_ASIO_OS_DEF(AF_INET6), str, &tmp.addr_, &tmp.scope_id_, ec) <= 0) - return address_v6(); - return tmp; -} - -address_v6 address_v6::from_string(const std::string& str) -{ - return from_string(str.c_str()); -} - -address_v6 address_v6::from_string( - const std::string& str, boost::system::error_code& ec) -{ - return from_string(str.c_str(), ec); -} - address_v4 address_v6::to_v4() const { if (!is_v4_mapped() && !is_v4_compatible()) { - std::bad_cast ex; + bad_address_cast ex; boost::asio::detail::throw_exception(ex); } @@ -159,6 +137,7 @@ address_v4 address_v6::to_v4() const addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } }; return address_v4(v4_bytes); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) bool address_v6::is_loopback() const { @@ -204,6 +183,7 @@ bool address_v6::is_v4_mapped() const && (addr_.s6_addr[10] == 0xff) && (addr_.s6_addr[11] == 0xff)); } +#if !defined(BOOST_ASIO_NO_DEPRECATED) bool address_v6::is_v4_compatible() const { return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) @@ -217,6 +197,7 @@ bool address_v6::is_v4_compatible() const && (addr_.s6_addr[14] == 0) && ((addr_.s6_addr[15] == 0) || (addr_.s6_addr[15] == 1)))); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) bool address_v6::is_multicast() const { @@ -275,6 +256,7 @@ address_v6 address_v6::loopback() return tmp; } +#if !defined(BOOST_ASIO_NO_DEPRECATED) address_v6 address_v6::v4_mapped(const address_v4& addr) { address_v4::bytes_type v4_bytes = addr.to_bytes(); @@ -290,6 +272,76 @@ address_v6 address_v6::v4_compatible(const address_v4& addr) v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; return address_v6(v6_bytes); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +address_v6 make_address_v6(const char* str) +{ + boost::system::error_code ec; + address_v6 addr = make_address_v6(str, ec); + boost::asio::detail::throw_error(ec); + return addr; +} + +address_v6 make_address_v6( + const char* str, boost::system::error_code& ec) +{ + address_v6::bytes_type bytes; + unsigned long scope_id = 0; + if (boost::asio::detail::socket_ops::inet_pton( + BOOST_ASIO_OS_DEF(AF_INET6), str, &bytes[0], &scope_id, ec) <= 0) + return address_v6(); + return address_v6(bytes, scope_id); +} + +address_v6 make_address_v6(const std::string& str) +{ + return make_address_v6(str.c_str()); +} + +address_v6 make_address_v6( + const std::string& str, boost::system::error_code& ec) +{ + return make_address_v6(str.c_str(), ec); +} + +#if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + +address_v6 make_address_v6(string_view str) +{ + return make_address_v6(static_cast<std::string>(str)); +} + +address_v6 make_address_v6(string_view str, + boost::system::error_code& ec) +{ + return make_address_v6(static_cast<std::string>(str), ec); +} + +#endif // defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + +address_v4 make_address_v4( + v4_mapped_t, const address_v6& v6_addr) +{ + if (!v6_addr.is_v4_mapped()) + { + bad_address_cast ex; + boost::asio::detail::throw_exception(ex); + } + + address_v6::bytes_type v6_bytes = v6_addr.to_bytes(); + address_v4::bytes_type v4_bytes = { { v6_bytes[12], + v6_bytes[13], v6_bytes[14], v6_bytes[15] } }; + return address_v4(v4_bytes); +} + +address_v6 make_address_v6( + v4_mapped_t, const address_v4& v4_addr) +{ + address_v4::bytes_type v4_bytes = v4_addr.to_bytes(); + address_v6::bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0xFF, 0xFF, v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; + return address_v6(v6_bytes); +} } // namespace ip } // namespace asio diff --git a/boost/asio/ip/impl/basic_endpoint.hpp b/boost/asio/ip/impl/basic_endpoint.hpp index 4d9c4505c3..590e9748f3 100644 --- a/boost/asio/ip/impl/basic_endpoint.hpp +++ b/boost/asio/ip/impl/basic_endpoint.hpp @@ -31,19 +31,7 @@ std::basic_ostream<Elem, Traits>& operator<<( const basic_endpoint<InternetProtocol>& endpoint) { boost::asio::ip::detail::endpoint tmp_ep(endpoint.address(), endpoint.port()); - boost::system::error_code ec; - std::string s = tmp_ep.to_string(ec); - if (ec) - { - if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit) - boost::asio::detail::throw_error(ec); - else - os.setstate(std::basic_ostream<Elem, Traits>::failbit); - } - else - for (std::string::iterator i = s.begin(); i != s.end(); ++i) - os << os.widen(*i); - return os; + return os << tmp_ep.to_string().c_str(); } } // namespace ip diff --git a/boost/asio/ip/impl/network_v4.hpp b/boost/asio/ip/impl/network_v4.hpp new file mode 100644 index 0000000000..6d9ebaa184 --- /dev/null +++ b/boost/asio/ip/impl/network_v4.hpp @@ -0,0 +1,56 @@ +// +// ip/impl/network_v4.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail 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) +// + +#ifndef BOOST_ASIO_IP_IMPL_NETWORK_V4_HPP +#define BOOST_ASIO_IP_IMPL_NETWORK_V4_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +#include <boost/asio/detail/throw_error.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace ip { + +template <typename Elem, typename Traits> +std::basic_ostream<Elem, Traits>& operator<<( + std::basic_ostream<Elem, Traits>& os, const network_v4& addr) +{ + boost::system::error_code ec; + std::string s = addr.to_string(ec); + if (ec) + { + if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit) + boost::asio::detail::throw_error(ec); + else + os.setstate(std::basic_ostream<Elem, Traits>::failbit); + } + else + for (std::string::iterator i = s.begin(); i != s.end(); ++i) + os << os.widen(*i); + return os; +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#endif // BOOST_ASIO_IP_IMPL_NETWORK_V4_HPP diff --git a/boost/asio/ip/impl/network_v4.ipp b/boost/asio/ip/impl/network_v4.ipp new file mode 100644 index 0000000000..f59949d9f0 --- /dev/null +++ b/boost/asio/ip/impl/network_v4.ipp @@ -0,0 +1,217 @@ +// +// ip/impl/network_v4.ipp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail 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) +// + +#ifndef BOOST_ASIO_IP_IMPL_NETWORK_V4_IPP +#define BOOST_ASIO_IP_IMPL_NETWORK_V4_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <climits> +#include <cstdio> +#include <cstdlib> +#include <stdexcept> +#include <boost/asio/error.hpp> +#include <boost/asio/detail/throw_error.hpp> +#include <boost/asio/detail/throw_exception.hpp> +#include <boost/asio/ip/network_v4.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace ip { + +network_v4::network_v4(const address_v4& addr, unsigned short prefix_len) + : address_(addr), + prefix_length_(prefix_len) +{ + if (prefix_len > 32) + { + std::out_of_range ex("prefix length too large"); + boost::asio::detail::throw_exception(ex); + } +} + +network_v4::network_v4(const address_v4& addr, const address_v4& mask) + : address_(addr), + prefix_length_(0) +{ + address_v4::bytes_type mask_bytes = mask.to_bytes(); + bool finished = false; + for (std::size_t i = 0; i < mask_bytes.size(); ++i) + { + if (finished) + { + if (mask_bytes[i]) + { + std::invalid_argument ex("non-contiguous netmask"); + boost::asio::detail::throw_exception(ex); + } + continue; + } + else + { + switch (mask_bytes[i]) + { + case 255: + prefix_length_ += 8; + break; + case 254: // prefix_length_ += 7 + prefix_length_ += 1; + case 252: // prefix_length_ += 6 + prefix_length_ += 1; + case 248: // prefix_length_ += 5 + prefix_length_ += 1; + case 240: // prefix_length_ += 4 + prefix_length_ += 1; + case 224: // prefix_length_ += 3 + prefix_length_ += 1; + case 192: // prefix_length_ += 2 + prefix_length_ += 1; + case 128: // prefix_length_ += 1 + prefix_length_ += 1; + case 0: // nbits += 0 + finished = true; + break; + default: + std::out_of_range ex("non-contiguous netmask"); + boost::asio::detail::throw_exception(ex); + } + } + } +} + +address_v4 network_v4::netmask() const BOOST_ASIO_NOEXCEPT +{ + uint32_t nmbits = 0xffffffff; + if (prefix_length_ == 0) + nmbits = 0; + else + nmbits = nmbits << (32 - prefix_length_); + return address_v4(nmbits); +} + +address_v4_range network_v4::hosts() const BOOST_ASIO_NOEXCEPT +{ + return is_host() + ? address_v4_range(address_, address_v4(address_.to_uint() + 1)) + : address_v4_range(address_v4(network().to_uint() + 1), broadcast()); +} + +bool network_v4::is_subnet_of(const network_v4& other) const +{ + if (other.prefix_length_ >= prefix_length_) + return false; // Only real subsets are allowed. + const network_v4 me(address_, other.prefix_length_); + return other.canonical() == me.canonical(); +} + +std::string network_v4::to_string() const +{ + boost::system::error_code ec; + std::string addr = to_string(ec); + boost::asio::detail::throw_error(ec); + return addr; +} + +std::string network_v4::to_string(boost::system::error_code& ec) const +{ + ec = boost::system::error_code(); + char prefix_len[16]; +#if defined(BOOST_ASIO_HAS_SECURE_RTL) + sprintf_s(prefix_len, sizeof(prefix_len), "/%u", prefix_length_); +#else // defined(BOOST_ASIO_HAS_SECURE_RTL) + sprintf(prefix_len, "/%u", prefix_length_); +#endif // defined(BOOST_ASIO_HAS_SECURE_RTL) + return address_.to_string() + prefix_len; +} + +network_v4 make_network_v4(const char* str) +{ + return make_network_v4(std::string(str)); +} + +network_v4 make_network_v4(const char* str, boost::system::error_code& ec) +{ + return make_network_v4(std::string(str), ec); +} + +network_v4 make_network_v4(const std::string& str) +{ + boost::system::error_code ec; + network_v4 net = make_network_v4(str, ec); + boost::asio::detail::throw_error(ec); + return net; +} + +network_v4 make_network_v4(const std::string& str, + boost::system::error_code& ec) +{ + std::string::size_type pos = str.find_first_of("/"); + + if (pos == std::string::npos) + { + ec = boost::asio::error::invalid_argument; + return network_v4(); + } + + if (pos == str.size() - 1) + { + ec = boost::asio::error::invalid_argument; + return network_v4(); + } + + std::string::size_type end = str.find_first_not_of("0123456789", pos + 1); + if (end != std::string::npos) + { + ec = boost::asio::error::invalid_argument; + return network_v4(); + } + + const address_v4 addr = make_address_v4(str.substr(0, pos), ec); + if (ec) + return network_v4(); + + const int prefix_len = std::atoi(str.substr(pos + 1).c_str()); + if (prefix_len < 0 || prefix_len > 32) + { + ec = boost::asio::error::invalid_argument; + return network_v4(); + } + + return network_v4(addr, static_cast<unsigned short>(prefix_len)); +} + +#if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + +network_v4 make_network_v4(string_view str) +{ + return make_network_v4(static_cast<std::string>(str)); +} + +network_v4 make_network_v4(string_view str, + boost::system::error_code& ec) +{ + return make_network_v4(static_cast<std::string>(str), ec); +} + +#endif // defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + +} // namespace ip +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IP_IMPL_NETWORK_V4_IPP diff --git a/boost/asio/ip/impl/network_v6.hpp b/boost/asio/ip/impl/network_v6.hpp new file mode 100644 index 0000000000..c6bac2d2db --- /dev/null +++ b/boost/asio/ip/impl/network_v6.hpp @@ -0,0 +1,55 @@ +// +// ip/impl/network_v6.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IP_IMPL_NETWORK_V6_HPP +#define BOOST_ASIO_IP_IMPL_NETWORK_V6_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +#include <boost/asio/detail/throw_error.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace ip { + +template <typename Elem, typename Traits> +std::basic_ostream<Elem, Traits>& operator<<( + std::basic_ostream<Elem, Traits>& os, const network_v6& addr) +{ + boost::system::error_code ec; + std::string s = addr.to_string(ec); + if (ec) + { + if (os.exceptions() & std::basic_ostream<Elem, Traits>::failbit) + boost::asio::detail::throw_error(ec); + else + os.setstate(std::basic_ostream<Elem, Traits>::failbit); + } + else + for (std::string::iterator i = s.begin(); i != s.end(); ++i) + os << os.widen(*i); + return os; +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#endif // BOOST_ASIO_IP_IMPL_NETWORK_V6_HPP diff --git a/boost/asio/ip/impl/network_v6.ipp b/boost/asio/ip/impl/network_v6.ipp new file mode 100644 index 0000000000..2fb28a2fbc --- /dev/null +++ b/boost/asio/ip/impl/network_v6.ipp @@ -0,0 +1,186 @@ +// +// ip/impl/network_v6.ipp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail 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) +// + +#ifndef BOOST_ASIO_IP_IMPL_NETWORK_V6_IPP +#define BOOST_ASIO_IP_IMPL_NETWORK_V6_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <climits> +#include <cstdio> +#include <cstdlib> +#include <stdexcept> +#include <boost/asio/error.hpp> +#include <boost/asio/detail/throw_error.hpp> +#include <boost/asio/detail/throw_exception.hpp> +#include <boost/asio/ip/network_v6.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace ip { + +network_v6::network_v6(const address_v6& addr, unsigned short prefix_len) + : address_(addr), + prefix_length_(prefix_len) +{ + if (prefix_len > 128) + { + std::out_of_range ex("prefix length too large"); + boost::asio::detail::throw_exception(ex); + } +} + +BOOST_ASIO_DECL address_v6 network_v6::network() const BOOST_ASIO_NOEXCEPT +{ + address_v6::bytes_type bytes(address_.to_bytes()); + for (std::size_t i = 0; i < 16; ++i) + { + if (prefix_length_ <= i * 8) + bytes[i] = 0; + else if (prefix_length_ < (i + 1) * 8) + bytes[i] &= 0xFF00 >> (prefix_length_ % 8); + } + return address_v6(bytes, address_.scope_id()); +} + +address_v6_range network_v6::hosts() const BOOST_ASIO_NOEXCEPT +{ + address_v6::bytes_type begin_bytes(address_.to_bytes()); + address_v6::bytes_type end_bytes(address_.to_bytes()); + for (std::size_t i = 0; i < 16; ++i) + { + if (prefix_length_ <= i * 8) + { + begin_bytes[i] = 0; + end_bytes[i] = 0xFF; + } + else if (prefix_length_ < (i + 1) * 8) + { + begin_bytes[i] &= 0xFF00 >> (prefix_length_ % 8); + end_bytes[i] |= 0xFF >> (prefix_length_ % 8); + } + } + return address_v6_range( + address_v6_iterator(address_v6(begin_bytes, address_.scope_id())), + ++address_v6_iterator(address_v6(end_bytes, address_.scope_id()))); +} + +bool network_v6::is_subnet_of(const network_v6& other) const +{ + if (other.prefix_length_ >= prefix_length_) + return false; // Only real subsets are allowed. + const network_v6 me(address_, other.prefix_length_); + return other.canonical() == me.canonical(); +} + +std::string network_v6::to_string() const +{ + boost::system::error_code ec; + std::string addr = to_string(ec); + boost::asio::detail::throw_error(ec); + return addr; +} + +std::string network_v6::to_string(boost::system::error_code& ec) const +{ + ec = boost::system::error_code(); + char prefix_len[16]; +#if defined(BOOST_ASIO_HAS_SECURE_RTL) + sprintf_s(prefix_len, sizeof(prefix_len), "/%u", prefix_length_); +#else // defined(BOOST_ASIO_HAS_SECURE_RTL) + sprintf(prefix_len, "/%u", prefix_length_); +#endif // defined(BOOST_ASIO_HAS_SECURE_RTL) + return address_.to_string() + prefix_len; +} + +network_v6 make_network_v6(const char* str) +{ + return make_network_v6(std::string(str)); +} + +network_v6 make_network_v6(const char* str, boost::system::error_code& ec) +{ + return make_network_v6(std::string(str), ec); +} + +network_v6 make_network_v6(const std::string& str) +{ + boost::system::error_code ec; + network_v6 net = make_network_v6(str, ec); + boost::asio::detail::throw_error(ec); + return net; +} + +network_v6 make_network_v6(const std::string& str, + boost::system::error_code& ec) +{ + std::string::size_type pos = str.find_first_of("/"); + + if (pos == std::string::npos) + { + ec = boost::asio::error::invalid_argument; + return network_v6(); + } + + if (pos == str.size() - 1) + { + ec = boost::asio::error::invalid_argument; + return network_v6(); + } + + std::string::size_type end = str.find_first_not_of("0123456789", pos + 1); + if (end != std::string::npos) + { + ec = boost::asio::error::invalid_argument; + return network_v6(); + } + + const address_v6 addr = make_address_v6(str.substr(0, pos), ec); + if (ec) + return network_v6(); + + const int prefix_len = std::atoi(str.substr(pos + 1).c_str()); + if (prefix_len < 0 || prefix_len > 128) + { + ec = boost::asio::error::invalid_argument; + return network_v6(); + } + + return network_v6(addr, static_cast<unsigned short>(prefix_len)); +} + +#if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + +network_v6 make_network_v6(string_view str) +{ + return make_network_v6(static_cast<std::string>(str)); +} + +network_v6 make_network_v6(string_view str, + boost::system::error_code& ec) +{ + return make_network_v6(static_cast<std::string>(str), ec); +} + +#endif // defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + +} // namespace ip +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IP_IMPL_NETWORK_V6_IPP diff --git a/boost/asio/ip/multicast.hpp b/boost/asio/ip/multicast.hpp index d82e442116..86c6389096 100644 --- a/boost/asio/ip/multicast.hpp +++ b/boost/asio/ip/multicast.hpp @@ -33,7 +33,7 @@ namespace multicast { * @par Examples * Setting the option to join a multicast group: * @code - * boost::asio::ip::udp::socket socket(io_service); + * boost::asio::ip::udp::socket socket(io_context); * ... * boost::asio::ip::address multicast_address = * boost::asio::ip::address::from_string("225.0.0.1"); @@ -61,7 +61,7 @@ typedef boost::asio::ip::detail::socket_option::multicast_request< * @par Examples * Setting the option to leave a multicast group: * @code - * boost::asio::ip::udp::socket socket(io_service); + * boost::asio::ip::udp::socket socket(io_context); * ... * boost::asio::ip::address multicast_address = * boost::asio::ip::address::from_string("225.0.0.1"); @@ -89,7 +89,7 @@ typedef boost::asio::ip::detail::socket_option::multicast_request< * @par Examples * Setting the option: * @code - * boost::asio::ip::udp::socket socket(io_service); + * boost::asio::ip::udp::socket socket(io_context); * ... * boost::asio::ip::address_v4 local_interface = * boost::asio::ip::address_v4::from_string("1.2.3.4"); @@ -117,7 +117,7 @@ typedef boost::asio::ip::detail::socket_option::network_interface< * @par Examples * Setting the option: * @code - * boost::asio::ip::udp::socket socket(io_service); + * boost::asio::ip::udp::socket socket(io_context); * ... * boost::asio::ip::multicast::hops option(4); * socket.set_option(option); @@ -126,7 +126,7 @@ typedef boost::asio::ip::detail::socket_option::network_interface< * @par * Getting the current option value: * @code - * boost::asio::ip::udp::socket socket(io_service); + * boost::asio::ip::udp::socket socket(io_context); * ... * boost::asio::ip::multicast::hops option; * socket.get_option(option); @@ -154,7 +154,7 @@ typedef boost::asio::ip::detail::socket_option::multicast_hops< * @par Examples * Setting the option: * @code - * boost::asio::ip::udp::socket socket(io_service); + * boost::asio::ip::udp::socket socket(io_context); * ... * boost::asio::ip::multicast::enable_loopback option(true); * socket.set_option(option); @@ -163,7 +163,7 @@ typedef boost::asio::ip::detail::socket_option::multicast_hops< * @par * Getting the current option value: * @code - * boost::asio::ip::udp::socket socket(io_service); + * boost::asio::ip::udp::socket socket(io_context); * ... * boost::asio::ip::multicast::enable_loopback option; * socket.get_option(option); diff --git a/boost/asio/ip/network_v4.hpp b/boost/asio/ip/network_v4.hpp new file mode 100644 index 0000000000..f0b8ecb164 --- /dev/null +++ b/boost/asio/ip/network_v4.hpp @@ -0,0 +1,263 @@ +// +// ip/network_v4.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail 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) +// + +#ifndef BOOST_ASIO_IP_NETWORK_V4_HPP +#define BOOST_ASIO_IP_NETWORK_V4_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <string> +#include <boost/asio/detail/string_view.hpp> +#include <boost/system/error_code.hpp> +#include <boost/asio/ip/address_v4_range.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace ip { + +/// Represents an IPv4 network. +/** + * The boost::asio::ip::network_v4 class provides the ability to use and + * manipulate IP version 4 networks. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +class network_v4 +{ +public: + /// Default constructor. + network_v4() BOOST_ASIO_NOEXCEPT + : address_(), + prefix_length_(0) + { + } + + /// Construct a network based on the specified address and prefix length. + BOOST_ASIO_DECL network_v4(const address_v4& addr, + unsigned short prefix_len); + + /// Construct network based on the specified address and netmask. + BOOST_ASIO_DECL network_v4(const address_v4& addr, + const address_v4& mask); + + /// Copy constructor. + network_v4(const network_v4& other) BOOST_ASIO_NOEXCEPT + : address_(other.address_), + prefix_length_(other.prefix_length_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + network_v4(network_v4&& other) BOOST_ASIO_NOEXCEPT + : address_(BOOST_ASIO_MOVE_CAST(address_v4)(other.address_)), + prefix_length_(other.prefix_length_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assign from another network. + network_v4& operator=(const network_v4& other) BOOST_ASIO_NOEXCEPT + { + address_ = other.address_; + prefix_length_ = other.prefix_length_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move-assign from another network. + network_v4& operator=(network_v4&& other) BOOST_ASIO_NOEXCEPT + { + address_ = BOOST_ASIO_MOVE_CAST(address_v4)(other.address_); + prefix_length_ = other.prefix_length_; + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Obtain the address object specified when the network object was created. + address_v4 address() const BOOST_ASIO_NOEXCEPT + { + return address_; + } + + /// Obtain the prefix length that was specified when the network object was + /// created. + unsigned short prefix_length() const BOOST_ASIO_NOEXCEPT + { + return prefix_length_; + } + + /// Obtain the netmask that was specified when the network object was created. + BOOST_ASIO_DECL address_v4 netmask() const BOOST_ASIO_NOEXCEPT; + + /// Obtain an address object that represents the network address. + address_v4 network() const BOOST_ASIO_NOEXCEPT + { + return address_v4(address_.to_uint() & netmask().to_uint()); + } + + /// Obtain an address object that represents the network's broadcast address. + address_v4 broadcast() const BOOST_ASIO_NOEXCEPT + { + return address_v4(network().to_uint() | (netmask().to_uint() ^ 0xFFFFFFFF)); + } + + /// Obtain an address range corresponding to the hosts in the network. + BOOST_ASIO_DECL address_v4_range hosts() const BOOST_ASIO_NOEXCEPT; + + /// Obtain the true network address, omitting any host bits. + network_v4 canonical() const BOOST_ASIO_NOEXCEPT + { + return network_v4(network(), netmask()); + } + + /// Test if network is a valid host address. + bool is_host() const BOOST_ASIO_NOEXCEPT + { + return prefix_length_ == 32; + } + + /// Test if a network is a real subnet of another network. + BOOST_ASIO_DECL bool is_subnet_of(const network_v4& other) const; + + /// Get the network as an address in dotted decimal format. + BOOST_ASIO_DECL std::string to_string() const; + + /// Get the network as an address in dotted decimal format. + BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; + + /// Compare two networks for equality. + friend bool operator==(const network_v4& a, const network_v4& b) + { + return a.address_ == b.address_ && a.prefix_length_ == b.prefix_length_; + } + + /// Compare two networks for inequality. + friend bool operator!=(const network_v4& a, const network_v4& b) + { + return !(a == b); + } + +private: + address_v4 address_; + unsigned short prefix_length_; +}; + +/// Create an IPv4 network from an address and prefix length. +/** + * @relates address_v4 + */ +inline network_v4 make_network_v4( + const address_v4& addr, unsigned short prefix_len) +{ + return network_v4(addr, prefix_len); +} + +/// Create an IPv4 network from an address and netmask. +/** + * @relates address_v4 + */ +inline network_v4 make_network_v4( + const address_v4& addr, const address_v4& mask) +{ + return network_v4(addr, mask); +} + +/// Create an IPv4 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v4 + */ +BOOST_ASIO_DECL network_v4 make_network_v4(const char* str); + +/// Create an IPv4 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v4 + */ +BOOST_ASIO_DECL network_v4 make_network_v4( + const char* str, boost::system::error_code& ec); + +/// Create an IPv4 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v4 + */ +BOOST_ASIO_DECL network_v4 make_network_v4(const std::string& str); + +/// Create an IPv4 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v4 + */ +BOOST_ASIO_DECL network_v4 make_network_v4( + const std::string& str, boost::system::error_code& ec); + +#if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) \ + || defined(GENERATING_DOCUMENTATION) + +/// Create an IPv4 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v4 + */ +BOOST_ASIO_DECL network_v4 make_network_v4(string_view str); + +/// Create an IPv4 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v4 + */ +BOOST_ASIO_DECL network_v4 make_network_v4( + string_view str, boost::system::error_code& ec); + +#endif // defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + // || defined(GENERATING_DOCUMENTATION) + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Output a network as a string. +/** + * Used to output a human-readable string for a specified network. + * + * @param os The output stream to which the string will be written. + * + * @param net The network to be written. + * + * @return The output stream. + * + * @relates boost::asio::ip::address_v4 + */ +template <typename Elem, typename Traits> +std::basic_ostream<Elem, Traits>& operator<<( + std::basic_ostream<Elem, Traits>& os, const network_v4& net); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +} // namespace ip +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#include <boost/asio/ip/impl/network_v4.hpp> +#if defined(BOOST_ASIO_HEADER_ONLY) +# include <boost/asio/ip/impl/network_v4.ipp> +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_IP_NETWORK_V4_HPP diff --git a/boost/asio/ip/network_v6.hpp b/boost/asio/ip/network_v6.hpp new file mode 100644 index 0000000000..83e67338e6 --- /dev/null +++ b/boost/asio/ip/network_v6.hpp @@ -0,0 +1,237 @@ +// +// ip/network_v6.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail 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) +// + +#ifndef BOOST_ASIO_IP_NETWORK_V6_HPP +#define BOOST_ASIO_IP_NETWORK_V6_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <string> +#include <boost/asio/detail/string_view.hpp> +#include <boost/system/error_code.hpp> +#include <boost/asio/ip/address_v6_range.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace ip { + +/// Represents an IPv6 network. +/** + * The boost::asio::ip::network_v6 class provides the ability to use and + * manipulate IP version 6 networks. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +class network_v6 +{ +public: + /// Default constructor. + network_v6() BOOST_ASIO_NOEXCEPT + : address_(), + prefix_length_(0) + { + } + + /// Construct a network based on the specified address and prefix length. + BOOST_ASIO_DECL network_v6(const address_v6& addr, + unsigned short prefix_len); + + /// Copy constructor. + network_v6(const network_v6& other) BOOST_ASIO_NOEXCEPT + : address_(other.address_), + prefix_length_(other.prefix_length_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + network_v6(network_v6&& other) BOOST_ASIO_NOEXCEPT + : address_(BOOST_ASIO_MOVE_CAST(address_v6)(other.address_)), + prefix_length_(other.prefix_length_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assign from another network. + network_v6& operator=(const network_v6& other) BOOST_ASIO_NOEXCEPT + { + address_ = other.address_; + prefix_length_ = other.prefix_length_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move-assign from another network. + network_v6& operator=(network_v6&& other) BOOST_ASIO_NOEXCEPT + { + address_ = BOOST_ASIO_MOVE_CAST(address_v6)(other.address_); + prefix_length_ = other.prefix_length_; + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Obtain the address object specified when the network object was created. + address_v6 address() const BOOST_ASIO_NOEXCEPT + { + return address_; + } + + /// Obtain the prefix length that was specified when the network object was + /// created. + unsigned short prefix_length() const BOOST_ASIO_NOEXCEPT + { + return prefix_length_; + } + + /// Obtain an address object that represents the network address. + BOOST_ASIO_DECL address_v6 network() const BOOST_ASIO_NOEXCEPT; + + /// Obtain an address range corresponding to the hosts in the network. + BOOST_ASIO_DECL address_v6_range hosts() const BOOST_ASIO_NOEXCEPT; + + /// Obtain the true network address, omitting any host bits. + network_v6 canonical() const BOOST_ASIO_NOEXCEPT + { + return network_v6(network(), prefix_length()); + } + + /// Test if network is a valid host address. + bool is_host() const BOOST_ASIO_NOEXCEPT + { + return prefix_length_ == 128; + } + + /// Test if a network is a real subnet of another network. + BOOST_ASIO_DECL bool is_subnet_of(const network_v6& other) const; + + /// Get the network as an address in dotted decimal format. + BOOST_ASIO_DECL std::string to_string() const; + + /// Get the network as an address in dotted decimal format. + BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; + + /// Compare two networks for equality. + friend bool operator==(const network_v6& a, const network_v6& b) + { + return a.address_ == b.address_ && a.prefix_length_ == b.prefix_length_; + } + + /// Compare two networks for inequality. + friend bool operator!=(const network_v6& a, const network_v6& b) + { + return !(a == b); + } + +private: + address_v6 address_; + unsigned short prefix_length_; +}; + +/// Create an IPv6 network from an address and prefix length. +/** + * @relates address_v6 + */ +inline network_v6 make_network_v6( + const address_v6& addr, unsigned short prefix_len) +{ + return network_v6(addr, prefix_len); +} + +/// Create an IPv6 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v6 + */ +BOOST_ASIO_DECL network_v6 make_network_v6(const char* str); + +/// Create an IPv6 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v6 + */ +BOOST_ASIO_DECL network_v6 make_network_v6( + const char* str, boost::system::error_code& ec); + +/// Create an IPv6 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v6 + */ +BOOST_ASIO_DECL network_v6 make_network_v6(const std::string& str); + +/// Create an IPv6 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v6 + */ +BOOST_ASIO_DECL network_v6 make_network_v6( + const std::string& str, boost::system::error_code& ec); + +#if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) \ + || defined(GENERATING_DOCUMENTATION) + +/// Create an IPv6 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v6 + */ +BOOST_ASIO_DECL network_v6 make_network_v6(string_view str); + +/// Create an IPv6 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v6 + */ +BOOST_ASIO_DECL network_v6 make_network_v6( + string_view str, boost::system::error_code& ec); + +#endif // defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + // || defined(GENERATING_DOCUMENTATION) + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Output a network as a string. +/** + * Used to output a human-readable string for a specified network. + * + * @param os The output stream to which the string will be written. + * + * @param net The network to be written. + * + * @return The output stream. + * + * @relates boost::asio::ip::address_v6 + */ +template <typename Elem, typename Traits> +std::basic_ostream<Elem, Traits>& operator<<( + std::basic_ostream<Elem, Traits>& os, const network_v6& net); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +} // namespace ip +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#include <boost/asio/ip/impl/network_v6.hpp> +#if defined(BOOST_ASIO_HEADER_ONLY) +# include <boost/asio/ip/impl/network_v6.ipp> +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_IP_NETWORK_V6_HPP diff --git a/boost/asio/ip/resolver_base.hpp b/boost/asio/ip/resolver_base.hpp new file mode 100644 index 0000000000..596a8221dc --- /dev/null +++ b/boost/asio/ip/resolver_base.hpp @@ -0,0 +1,131 @@ +// +// ip/resolver_base.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IP_RESOLVER_BASE_HPP +#define BOOST_ASIO_IP_RESOLVER_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/socket_types.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace ip { + +/// The resolver_base class is used as a base for the basic_resolver class +/// templates to provide a common place to define the flag constants. +class resolver_base +{ +public: +#if defined(GENERATING_DOCUMENTATION) + /// A bitmask type (C++ Std [lib.bitmask.types]). + typedef unspecified flags; + + /// Determine the canonical name of the host specified in the query. + static const flags canonical_name = implementation_defined; + + /// Indicate that returned endpoint is intended for use as a locally bound + /// socket endpoint. + static const flags passive = implementation_defined; + + /// Host name should be treated as a numeric string defining an IPv4 or IPv6 + /// address and no name resolution should be attempted. + static const flags numeric_host = implementation_defined; + + /// Service name should be treated as a numeric string defining a port number + /// and no name resolution should be attempted. + static const flags numeric_service = implementation_defined; + + /// If the query protocol family is specified as IPv6, return IPv4-mapped + /// IPv6 addresses on finding no IPv6 addresses. + static const flags v4_mapped = implementation_defined; + + /// If used with v4_mapped, return all matching IPv6 and IPv4 addresses. + static const flags all_matching = implementation_defined; + + /// Only return IPv4 addresses if a non-loopback IPv4 address is configured + /// for the system. Only return IPv6 addresses if a non-loopback IPv6 address + /// is configured for the system. + static const flags address_configured = implementation_defined; +#else + enum flags + { + canonical_name = BOOST_ASIO_OS_DEF(AI_CANONNAME), + passive = BOOST_ASIO_OS_DEF(AI_PASSIVE), + numeric_host = BOOST_ASIO_OS_DEF(AI_NUMERICHOST), + numeric_service = BOOST_ASIO_OS_DEF(AI_NUMERICSERV), + v4_mapped = BOOST_ASIO_OS_DEF(AI_V4MAPPED), + all_matching = BOOST_ASIO_OS_DEF(AI_ALL), + address_configured = BOOST_ASIO_OS_DEF(AI_ADDRCONFIG) + }; + + // Implement bitmask operations as shown in C++ Std [lib.bitmask.types]. + + friend flags operator&(flags x, flags y) + { + return static_cast<flags>( + static_cast<unsigned int>(x) & static_cast<unsigned int>(y)); + } + + friend flags operator|(flags x, flags y) + { + return static_cast<flags>( + static_cast<unsigned int>(x) | static_cast<unsigned int>(y)); + } + + friend flags operator^(flags x, flags y) + { + return static_cast<flags>( + static_cast<unsigned int>(x) ^ static_cast<unsigned int>(y)); + } + + friend flags operator~(flags x) + { + return static_cast<flags>(~static_cast<unsigned int>(x)); + } + + friend flags& operator&=(flags& x, flags y) + { + x = x & y; + return x; + } + + friend flags& operator|=(flags& x, flags y) + { + x = x | y; + return x; + } + + friend flags& operator^=(flags& x, flags y) + { + x = x ^ y; + return x; + } +#endif + +protected: + /// Protected destructor to prevent deletion through this type. + ~resolver_base() + { + } +}; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IP_RESOLVER_BASE_HPP diff --git a/boost/asio/ip/resolver_query_base.hpp b/boost/asio/ip/resolver_query_base.hpp index fd74059772..99d6e29f39 100644 --- a/boost/asio/ip/resolver_query_base.hpp +++ b/boost/asio/ip/resolver_query_base.hpp @@ -16,7 +16,7 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/detail/socket_types.hpp> +#include <boost/asio/ip/resolver_base.hpp> #include <boost/asio/detail/push_options.hpp> @@ -27,95 +27,8 @@ namespace ip { /// The resolver_query_base class is used as a base for the /// basic_resolver_query class templates to provide a common place to define /// the flag constants. -class resolver_query_base +class resolver_query_base : public resolver_base { -public: -#if defined(GENERATING_DOCUMENTATION) - /// A bitmask type (C++ Std [lib.bitmask.types]). - typedef unspecified flags; - - /// Determine the canonical name of the host specified in the query. - static const flags canonical_name = implementation_defined; - - /// Indicate that returned endpoint is intended for use as a locally bound - /// socket endpoint. - static const flags passive = implementation_defined; - - /// Host name should be treated as a numeric string defining an IPv4 or IPv6 - /// address and no name resolution should be attempted. - static const flags numeric_host = implementation_defined; - - /// Service name should be treated as a numeric string defining a port number - /// and no name resolution should be attempted. - static const flags numeric_service = implementation_defined; - - /// If the query protocol family is specified as IPv6, return IPv4-mapped - /// IPv6 addresses on finding no IPv6 addresses. - static const flags v4_mapped = implementation_defined; - - /// If used with v4_mapped, return all matching IPv6 and IPv4 addresses. - static const flags all_matching = implementation_defined; - - /// Only return IPv4 addresses if a non-loopback IPv4 address is configured - /// for the system. Only return IPv6 addresses if a non-loopback IPv6 address - /// is configured for the system. - static const flags address_configured = implementation_defined; -#else - enum flags - { - canonical_name = BOOST_ASIO_OS_DEF(AI_CANONNAME), - passive = BOOST_ASIO_OS_DEF(AI_PASSIVE), - numeric_host = BOOST_ASIO_OS_DEF(AI_NUMERICHOST), - numeric_service = BOOST_ASIO_OS_DEF(AI_NUMERICSERV), - v4_mapped = BOOST_ASIO_OS_DEF(AI_V4MAPPED), - all_matching = BOOST_ASIO_OS_DEF(AI_ALL), - address_configured = BOOST_ASIO_OS_DEF(AI_ADDRCONFIG) - }; - - // Implement bitmask operations as shown in C++ Std [lib.bitmask.types]. - - friend flags operator&(flags x, flags y) - { - return static_cast<flags>( - static_cast<unsigned int>(x) & static_cast<unsigned int>(y)); - } - - friend flags operator|(flags x, flags y) - { - return static_cast<flags>( - static_cast<unsigned int>(x) | static_cast<unsigned int>(y)); - } - - friend flags operator^(flags x, flags y) - { - return static_cast<flags>( - static_cast<unsigned int>(x) ^ static_cast<unsigned int>(y)); - } - - friend flags operator~(flags x) - { - return static_cast<flags>(~static_cast<unsigned int>(x)); - } - - friend flags& operator&=(flags& x, flags y) - { - x = x & y; - return x; - } - - friend flags& operator|=(flags& x, flags y) - { - x = x | y; - return x; - } - - friend flags& operator^=(flags& x, flags y) - { - x = x ^ y; - return x; - } -#endif - protected: /// Protected destructor to prevent deletion through this type. ~resolver_query_base() diff --git a/boost/asio/ip/resolver_service.hpp b/boost/asio/ip/resolver_service.hpp index b4aa4d25bb..83ad490348 100644 --- a/boost/asio/ip/resolver_service.hpp +++ b/boost/asio/ip/resolver_service.hpp @@ -16,11 +16,15 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #include <boost/asio/async_result.hpp> #include <boost/system/error_code.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/ip/basic_resolver_iterator.hpp> #include <boost/asio/ip/basic_resolver_query.hpp> +#include <boost/asio/ip/basic_resolver_results.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/winrt_resolver_service.hpp> @@ -38,7 +42,7 @@ namespace ip { template <typename InternetProtocol> class resolver_service #if defined(GENERATING_DOCUMENTATION) - : public boost::asio::io_service::service + : public boost::asio::io_context::service #else : public boost::asio::detail::service_base< resolver_service<InternetProtocol> > @@ -47,7 +51,7 @@ class resolver_service public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. - static boost::asio::io_service::id id; + static boost::asio::io_context::id id; #endif /// The protocol type. @@ -62,6 +66,9 @@ public: /// The iterator type. typedef basic_resolver_iterator<InternetProtocol> iterator_type; + /// The results type. + typedef basic_resolver_results<InternetProtocol> results_type; + private: // The type of the platform-specific implementation. #if defined(BOOST_ASIO_WINDOWS_RUNTIME) @@ -80,11 +87,11 @@ public: typedef typename service_impl_type::implementation_type implementation_type; #endif - /// Construct a new resolver service for the specified io_service. - explicit resolver_service(boost::asio::io_service& io_service) + /// Construct a new resolver service for the specified io_context. + explicit resolver_service(boost::asio::io_context& io_context) : boost::asio::detail::service_base< - resolver_service<InternetProtocol> >(io_service), - service_impl_(io_service) + resolver_service<InternetProtocol> >(io_context), + service_impl_(io_context) { } @@ -94,6 +101,23 @@ public: service_impl_.construct(impl); } +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a new resolver implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + service_impl_.move_construct(impl, other_impl); + } + + /// Move-assign from another resolver implementation. + void move_assign(implementation_type& impl, + resolver_service& other_service, + implementation_type& other_impl) + { + service_impl_.move_assign(impl, other_service.service_impl_, other_impl); + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Destroy a resolver implementation. void destroy(implementation_type& impl) { @@ -107,7 +131,7 @@ public: } /// Resolve a query to a list of entries. - iterator_type resolve(implementation_type& impl, const query_type& query, + results_type resolve(implementation_type& impl, const query_type& query, boost::system::error_code& ec) { return service_impl_.resolve(impl, query, ec); @@ -116,21 +140,20 @@ public: /// Asynchronously resolve a query to a list of entries. template <typename ResolveHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, - void (boost::system::error_code, iterator_type)) + void (boost::system::error_code, results_type)) async_resolve(implementation_type& impl, const query_type& query, BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) { - boost::asio::detail::async_result_init< - ResolveHandler, void (boost::system::error_code, iterator_type)> init( - BOOST_ASIO_MOVE_CAST(ResolveHandler)(handler)); + boost::asio::async_completion<ResolveHandler, + void (boost::system::error_code, results_type)> init(handler); - service_impl_.async_resolve(impl, query, init.handler); + service_impl_.async_resolve(impl, query, init.completion_handler); return init.result.get(); } /// Resolve an endpoint to a list of entries. - iterator_type resolve(implementation_type& impl, + results_type resolve(implementation_type& impl, const endpoint_type& endpoint, boost::system::error_code& ec) { return service_impl_.resolve(impl, endpoint, ec); @@ -139,30 +162,29 @@ public: /// Asynchronously resolve an endpoint to a list of entries. template <typename ResolveHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, - void (boost::system::error_code, iterator_type)) + void (boost::system::error_code, results_type)) async_resolve(implementation_type& impl, const endpoint_type& endpoint, BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) { - boost::asio::detail::async_result_init< - ResolveHandler, void (boost::system::error_code, iterator_type)> init( - BOOST_ASIO_MOVE_CAST(ResolveHandler)(handler)); + boost::asio::async_completion<ResolveHandler, + void (boost::system::error_code, results_type)> init(handler); - service_impl_.async_resolve(impl, endpoint, init.handler); + service_impl_.async_resolve(impl, endpoint, init.completion_handler); return init.result.get(); } private: // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { - service_impl_.shutdown_service(); + service_impl_.shutdown(); } // Perform any fork-related housekeeping. - void fork_service(boost::asio::io_service::fork_event event) + void notify_fork(boost::asio::io_context::fork_event event) { - service_impl_.fork_service(event); + service_impl_.notify_fork(event); } // The platform-specific implementation. @@ -175,4 +197,6 @@ private: #include <boost/asio/detail/pop_options.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_IP_RESOLVER_SERVICE_HPP diff --git a/boost/asio/ip/tcp.hpp b/boost/asio/ip/tcp.hpp index 079ec46a25..d6bb59644b 100644 --- a/boost/asio/ip/tcp.hpp +++ b/boost/asio/ip/tcp.hpp @@ -100,7 +100,7 @@ public: * @par Examples * Setting the option: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::ip::tcp::no_delay option(true); * socket.set_option(option); @@ -109,7 +109,7 @@ public: * @par * Getting the current option value: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::ip::tcp::no_delay option; * socket.get_option(option); diff --git a/boost/asio/ip/unicast.hpp b/boost/asio/ip/unicast.hpp index 4a9df8bfd2..809bcacc85 100644 --- a/boost/asio/ip/unicast.hpp +++ b/boost/asio/ip/unicast.hpp @@ -33,7 +33,7 @@ namespace unicast { * @par Examples * Setting the option: * @code - * boost::asio::ip::udp::socket socket(io_service); + * boost::asio::ip::udp::socket socket(io_context); * ... * boost::asio::ip::unicast::hops option(4); * socket.set_option(option); @@ -42,7 +42,7 @@ namespace unicast { * @par * Getting the current option value: * @code - * boost::asio::ip::udp::socket socket(io_service); + * boost::asio::ip::udp::socket socket(io_context); * ... * boost::asio::ip::unicast::hops option; * socket.get_option(option); diff --git a/boost/asio/ip/v6_only.hpp b/boost/asio/ip/v6_only.hpp index b22c9a5db8..5dc6ff0874 100644 --- a/boost/asio/ip/v6_only.hpp +++ b/boost/asio/ip/v6_only.hpp @@ -32,7 +32,7 @@ namespace ip { * @par Examples * Setting the option: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::ip::v6_only option(true); * socket.set_option(option); @@ -41,7 +41,7 @@ namespace ip { * @par * Getting the current option value: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::ip::v6_only option; * socket.get_option(option); diff --git a/boost/asio/is_executor.hpp b/boost/asio/is_executor.hpp new file mode 100644 index 0000000000..4983c5385c --- /dev/null +++ b/boost/asio/is_executor.hpp @@ -0,0 +1,48 @@ +// +// is_executor.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_IS_EXECUTOR_HPP +#define BOOST_ASIO_IS_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/is_executor.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +/// The is_executor trait detects whether a type T meets the Executor type +/// requirements. +/** + * Class template @c is_executor is a UnaryTypeTrait that is derived from @c + * true_type if the type @c T meets the syntactic requirements for Executor, + * otherwise @c false_type. + */ +template <typename T> +struct is_executor +#if defined(GENERATING_DOCUMENTATION) + : integral_constant<bool, automatically_determined> +#else // defined(GENERATING_DOCUMENTATION) + : boost::asio::detail::is_executor<T> +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_IS_EXECUTOR_HPP diff --git a/boost/asio/local/connect_pair.hpp b/boost/asio/local/connect_pair.hpp index 333c758783..18417856c7 100644 --- a/boost/asio/local/connect_pair.hpp +++ b/boost/asio/local/connect_pair.hpp @@ -33,32 +33,32 @@ namespace asio { namespace local { /// Create a pair of connected sockets. -template <typename Protocol, typename SocketService1, typename SocketService2> +template <typename Protocol BOOST_ASIO_SVC_TPARAM BOOST_ASIO_SVC_TPARAM1> void connect_pair( - basic_socket<Protocol, SocketService1>& socket1, - basic_socket<Protocol, SocketService2>& socket2); + basic_socket<Protocol BOOST_ASIO_SVC_TARG>& socket1, + basic_socket<Protocol BOOST_ASIO_SVC_TARG1>& socket2); /// Create a pair of connected sockets. -template <typename Protocol, typename SocketService1, typename SocketService2> -boost::system::error_code connect_pair( - basic_socket<Protocol, SocketService1>& socket1, - basic_socket<Protocol, SocketService2>& socket2, +template <typename Protocol BOOST_ASIO_SVC_TPARAM BOOST_ASIO_SVC_TPARAM1> +BOOST_ASIO_SYNC_OP_VOID connect_pair( + basic_socket<Protocol BOOST_ASIO_SVC_TARG>& socket1, + basic_socket<Protocol BOOST_ASIO_SVC_TARG1>& socket2, boost::system::error_code& ec); -template <typename Protocol, typename SocketService1, typename SocketService2> +template <typename Protocol BOOST_ASIO_SVC_TPARAM BOOST_ASIO_SVC_TPARAM1> inline void connect_pair( - basic_socket<Protocol, SocketService1>& socket1, - basic_socket<Protocol, SocketService2>& socket2) + basic_socket<Protocol BOOST_ASIO_SVC_TARG>& socket1, + basic_socket<Protocol BOOST_ASIO_SVC_TARG1>& socket2) { boost::system::error_code ec; connect_pair(socket1, socket2, ec); boost::asio::detail::throw_error(ec, "connect_pair"); } -template <typename Protocol, typename SocketService1, typename SocketService2> -inline boost::system::error_code connect_pair( - basic_socket<Protocol, SocketService1>& socket1, - basic_socket<Protocol, SocketService2>& socket2, +template <typename Protocol BOOST_ASIO_SVC_TPARAM BOOST_ASIO_SVC_TPARAM1> +inline BOOST_ASIO_SYNC_OP_VOID connect_pair( + basic_socket<Protocol BOOST_ASIO_SVC_TARG>& socket1, + basic_socket<Protocol BOOST_ASIO_SVC_TARG1>& socket2, boost::system::error_code& ec) { // Check that this function is only being used with a UNIX domain socket. @@ -71,27 +71,29 @@ inline boost::system::error_code connect_pair( if (boost::asio::detail::socket_ops::socketpair(protocol.family(), protocol.type(), protocol.protocol(), sv, ec) == boost::asio::detail::socket_error_retval) - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); - if (socket1.assign(protocol, sv[0], ec)) + socket1.assign(protocol, sv[0], ec); + if (ec) { boost::system::error_code temp_ec; boost::asio::detail::socket_ops::state_type state[2] = { 0, 0 }; boost::asio::detail::socket_ops::close(sv[0], state[0], true, temp_ec); boost::asio::detail::socket_ops::close(sv[1], state[1], true, temp_ec); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } - if (socket2.assign(protocol, sv[1], ec)) + socket2.assign(protocol, sv[1], ec); + if (ec) { boost::system::error_code temp_ec; socket1.close(temp_ec); boost::asio::detail::socket_ops::state_type state = 0; boost::asio::detail::socket_ops::close(sv[1], state, true, temp_ec); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } // namespace local diff --git a/boost/asio/local/detail/impl/endpoint.ipp b/boost/asio/local/detail/impl/endpoint.ipp index 4173a8242e..d668e8badc 100644 --- a/boost/asio/local/detail/impl/endpoint.ipp +++ b/boost/asio/local/detail/impl/endpoint.ipp @@ -109,7 +109,8 @@ void endpoint::init(const char* path_name, std::size_t path_length) using namespace std; // For memcpy. data_.local = boost::asio::detail::sockaddr_un_type(); data_.local.sun_family = AF_UNIX; - memcpy(data_.local.sun_path, path_name, path_length); + if (path_length > 0) + memcpy(data_.local.sun_path, path_name, path_length); path_length_ = path_length; // NUL-terminate normal path names. Names that start with a NUL are in the diff --git a/boost/asio/packaged_task.hpp b/boost/asio/packaged_task.hpp new file mode 100644 index 0000000000..586de13b7b --- /dev/null +++ b/boost/asio/packaged_task.hpp @@ -0,0 +1,128 @@ +// +// packaged_task.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_PACKAGED_TASK_HPP +#define BOOST_ASIO_PACKAGED_TASK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_HAS_STD_FUTURE) \ + || defined(GENERATING_DOCUMENTATION) + +#include <future> +#include <boost/asio/async_result.hpp> +#include <boost/asio/detail/type_traits.hpp> +#include <boost/asio/detail/variadic_templates.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) \ + || defined(GENERATING_DOCUMENTATION) + +/// Partial specialisation of @c async_result for @c std::packaged_task. +template <typename Result, typename... Args, typename Signature> +class async_result<std::packaged_task<Result(Args...)>, Signature> +{ +public: + /// The packaged task is the concrete completion handler type. + typedef std::packaged_task<Result(Args...)> completion_handler_type; + + /// The return type of the initiating function is the future obtained from + /// the packaged task. + typedef std::future<Result> return_type; + + /// The constructor extracts the future from the packaged task. + explicit async_result(completion_handler_type& h) + : future_(h.get_future()) + { + } + + /// Returns the packaged task's future. + return_type get() + { + return std::move(future_); + } + +private: + return_type future_; +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + +template <typename Result, typename Signature> +struct async_result<std::packaged_task<Result()>, Signature> +{ + typedef std::packaged_task<Result()> completion_handler_type; + typedef std::future<Result> return_type; + + explicit async_result(completion_handler_type& h) + : future_(h.get_future()) + { + } + + return_type get() + { + return std::move(future_); + } + +private: + return_type future_; +}; + +#define BOOST_ASIO_PRIVATE_ASYNC_RESULT_DEF(n) \ + template <typename Result, \ + BOOST_ASIO_VARIADIC_TPARAMS(n), typename Signature> \ + class async_result< \ + std::packaged_task<Result(BOOST_ASIO_VARIADIC_TARGS(n))>, Signature> \ + { \ + public: \ + typedef std::packaged_task< \ + Result(BOOST_ASIO_VARIADIC_TARGS(n))> \ + completion_handler_type; \ + \ + typedef std::future<Result> return_type; \ + \ + explicit async_result(completion_handler_type& h) \ + : future_(h.get_future()) \ + { \ + } \ + \ + return_type get() \ + { \ + return std::move(future_); \ + } \ + \ + private: \ + return_type future_; \ + }; \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ASYNC_RESULT_DEF) +#undef BOOST_ASIO_PRIVATE_ASYNC_RESULT_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // defined(BOOST_ASIO_HAS_STD_FUTURE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_PACKAGED_TASK_HPP diff --git a/boost/asio/placeholders.hpp b/boost/asio/placeholders.hpp index 8714e3454a..0bc72769a1 100644 --- a/boost/asio/placeholders.hpp +++ b/boost/asio/placeholders.hpp @@ -41,10 +41,20 @@ unspecified bytes_transferred; /// An argument placeholder, for use with boost::bind(), that corresponds to /// the iterator argument of a handler for asynchronous functions such as -/// boost::asio::basic_resolver::async_resolve. +/// boost::asio::async_connect. unspecified iterator; /// An argument placeholder, for use with boost::bind(), that corresponds to +/// the results argument of a handler for asynchronous functions such as +/// boost::asio::basic_resolver::async_resolve. +unspecified results; + +/// An argument placeholder, for use with boost::bind(), that corresponds to +/// the results argument of a handler for asynchronous functions such as +/// boost::asio::async_connect. +unspecified endpoint; + +/// An argument placeholder, for use with boost::bind(), that corresponds to /// the signal_number argument of a handler for asynchronous functions such as /// boost::asio::signal_set::async_wait. unspecified signal_number; @@ -67,6 +77,16 @@ inline boost::arg<2> iterator() return boost::arg<2>(); } +inline boost::arg<2> results() +{ + return boost::arg<2>(); +} + +inline boost::arg<2> endpoint() +{ + return boost::arg<2>(); +} + inline boost::arg<2> signal_number() { return boost::arg<2>(); @@ -95,6 +115,10 @@ static boost::arg<2>& bytes_transferred = boost::asio::placeholders::detail::placeholder<2>::get(); static boost::arg<2>& iterator = boost::asio::placeholders::detail::placeholder<2>::get(); +static boost::arg<2>& results + = boost::asio::placeholders::detail::placeholder<2>::get(); +static boost::arg<2>& endpoint + = boost::asio::placeholders::detail::placeholder<2>::get(); static boost::arg<2>& signal_number = boost::asio::placeholders::detail::placeholder<2>::get(); @@ -108,6 +132,10 @@ namespace = boost::asio::placeholders::detail::placeholder<2>::get(); boost::arg<2>& iterator = boost::asio::placeholders::detail::placeholder<2>::get(); + boost::arg<2>& results + = boost::asio::placeholders::detail::placeholder<2>::get(); + boost::arg<2>& endpoint + = boost::asio::placeholders::detail::placeholder<2>::get(); boost::arg<2>& signal_number = boost::asio::placeholders::detail::placeholder<2>::get(); } // namespace diff --git a/boost/asio/posix/basic_descriptor.hpp b/boost/asio/posix/basic_descriptor.hpp index a857c237a3..2bb8a04efa 100644 --- a/boost/asio/posix/basic_descriptor.hpp +++ b/boost/asio/posix/basic_descriptor.hpp @@ -17,6 +17,8 @@ #include <boost/asio/detail/config.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) @@ -46,10 +48,6 @@ class basic_descriptor public descriptor_base { public: - /// (Deprecated: Use native_handle_type.) The native representation of a - /// descriptor. - typedef typename DescriptorService::native_handle_type native_type; - /// The native representation of a descriptor. typedef typename DescriptorService::native_handle_type native_handle_type; @@ -60,12 +58,12 @@ public: /** * This constructor creates a descriptor without opening it. * - * @param io_service The io_service object that the descriptor will use to + * @param io_context The io_context object that the descriptor will use to * dispatch handlers for any asynchronous operations performed on the * descriptor. */ - explicit basic_descriptor(boost::asio::io_service& io_service) - : basic_io_object<DescriptorService>(io_service) + explicit basic_descriptor(boost::asio::io_context& io_context) + : basic_io_object<DescriptorService>(io_context) { } @@ -74,7 +72,7 @@ public: * This constructor creates a descriptor object to hold an existing native * descriptor. * - * @param io_service The io_service object that the descriptor will use to + * @param io_context The io_context object that the descriptor will use to * dispatch handlers for any asynchronous operations performed on the * descriptor. * @@ -82,9 +80,9 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_descriptor(boost::asio::io_service& io_service, + basic_descriptor(boost::asio::io_context& io_context, const native_handle_type& native_descriptor) - : basic_io_object<DescriptorService>(io_service) + : basic_io_object<DescriptorService>(io_context) { boost::system::error_code ec; this->get_service().assign(this->get_implementation(), @@ -101,7 +99,7 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_descriptor(io_service&) constructor. + * constructed using the @c basic_descriptor(io_context&) constructor. */ basic_descriptor(basic_descriptor&& other) : basic_io_object<DescriptorService>( @@ -117,7 +115,7 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_descriptor(io_service&) constructor. + * constructed using the @c basic_descriptor(io_context&) constructor. */ basic_descriptor& operator=(basic_descriptor&& other) { @@ -179,17 +177,18 @@ public: * * @param ec Set to indicate what error occurred, if any. */ - boost::system::error_code assign(const native_handle_type& native_descriptor, + BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& native_descriptor, boost::system::error_code& ec) { - return this->get_service().assign( + this->get_service().assign( this->get_implementation(), native_descriptor, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the descriptor is open. bool is_open() const { - return this->get_service().is_open(this->implementation); + return this->get_service().is_open(this->get_implementation()); } /// Close the descriptor. @@ -217,21 +216,10 @@ public: * @param ec Set to indicate what error occurred, if any. Note that, even if * the function indicates an error, the underlying descriptor is closed. */ - boost::system::error_code close(boost::system::error_code& ec) - { - return this->get_service().close(this->get_implementation(), ec); - } - - /// (Deprecated: Use native_handle().) Get the native descriptor - /// representation. - /** - * This function may be used to obtain the underlying representation of the - * descriptor. This is intended to allow access to native descriptor - * functionality that is not otherwise provided. - */ - native_type native() + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) { - return this->get_service().native_handle(this->implementation); + this->get_service().close(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get the native descriptor representation. @@ -242,7 +230,7 @@ public: */ native_handle_type native_handle() { - return this->get_service().native_handle(this->implementation); + return this->get_service().native_handle(this->get_implementation()); } /// Release ownership of the native descriptor implementation. @@ -257,7 +245,7 @@ public: */ native_handle_type release() { - return this->get_service().release(this->implementation); + return this->get_service().release(this->get_implementation()); } /// Cancel all asynchronous operations associated with the descriptor. @@ -283,9 +271,10 @@ public: * * @param ec Set to indicate what error occurred, if any. */ - boost::system::error_code cancel(boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) { - return this->get_service().cancel(this->get_implementation(), ec); + this->get_service().cancel(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Perform an IO control command on the descriptor. @@ -303,7 +292,7 @@ public: * @par Example * Getting the number of bytes ready to read: * @code - * boost::asio::posix::stream_descriptor descriptor(io_service); + * boost::asio::posix::stream_descriptor descriptor(io_context); * ... * boost::asio::posix::stream_descriptor::bytes_readable command; * descriptor.io_control(command); @@ -333,7 +322,7 @@ public: * @par Example * Getting the number of bytes ready to read: * @code - * boost::asio::posix::stream_descriptor descriptor(io_service); + * boost::asio::posix::stream_descriptor descriptor(io_context); * ... * boost::asio::posix::stream_descriptor::bytes_readable command; * boost::system::error_code ec; @@ -346,11 +335,11 @@ public: * @endcode */ template <typename IoControlCommand> - boost::system::error_code io_control(IoControlCommand& command, + BOOST_ASIO_SYNC_OP_VOID io_control(IoControlCommand& command, boost::system::error_code& ec) { - return this->get_service().io_control( - this->get_implementation(), command, ec); + this->get_service().io_control(this->get_implementation(), command, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the descriptor. @@ -366,7 +355,7 @@ public: */ bool non_blocking() const { - return this->get_service().non_blocking(this->implementation); + return this->get_service().non_blocking(this->get_implementation()); } /// Sets the non-blocking mode of the descriptor. @@ -402,11 +391,11 @@ public: * operations. Asynchronous operations will never fail with the error * boost::asio::error::would_block. */ - boost::system::error_code non_blocking( + BOOST_ASIO_SYNC_OP_VOID non_blocking( bool mode, boost::system::error_code& ec) { - return this->get_service().non_blocking( - this->get_implementation(), mode, ec); + this->get_service().non_blocking(this->get_implementation(), mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the native descriptor implementation. @@ -425,7 +414,8 @@ public: */ bool native_non_blocking() const { - return this->get_service().native_non_blocking(this->implementation); + return this->get_service().native_non_blocking( + this->get_implementation()); } /// Sets the non-blocking mode of the native descriptor implementation. @@ -466,11 +456,111 @@ public: * function fails with boost::asio::error::invalid_argument, as the * combination does not make sense. */ - boost::system::error_code native_non_blocking( + BOOST_ASIO_SYNC_OP_VOID native_non_blocking( bool mode, boost::system::error_code& ec) { - return this->get_service().native_non_blocking( + this->get_service().native_non_blocking( this->get_implementation(), mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Wait for the descriptor to become ready to read, ready to write, or to + /// have pending error conditions. + /** + * This function is used to perform a blocking wait for a descriptor to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired descriptor state. + * + * @par Example + * Waiting for a descriptor to become readable. + * @code + * boost::asio::posix::stream_descriptor descriptor(io_context); + * ... + * descriptor.wait(boost::asio::posix::stream_descriptor::wait_read); + * @endcode + */ + void wait(wait_type w) + { + boost::system::error_code ec; + this->get_service().wait(this->get_implementation(), w, ec); + boost::asio::detail::throw_error(ec, "wait"); + } + + /// Wait for the descriptor to become ready to read, ready to write, or to + /// have pending error conditions. + /** + * This function is used to perform a blocking wait for a descriptor to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired descriptor state. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * Waiting for a descriptor to become readable. + * @code + * boost::asio::posix::stream_descriptor descriptor(io_context); + * ... + * boost::system::error_code ec; + * descriptor.wait(boost::asio::posix::stream_descriptor::wait_read, ec); + * @endcode + */ + BOOST_ASIO_SYNC_OP_VOID wait(wait_type w, boost::system::error_code& ec) + { + this->get_service().wait(this->get_implementation(), w, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Asynchronously wait for the descriptor to become ready to read, ready to + /// write, or to have pending error conditions. + /** + * This function is used to perform an asynchronous wait for a descriptor to + * enter a ready to read, write or error condition state. + * + * @param w Specifies the desired descriptor state. + * + * @param handler The handler to be called when the wait operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error // Result of operation + * ); @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 + * boost::asio::io_context::post(). + * + * @par Example + * @code + * void wait_handler(const boost::system::error_code& error) + * { + * if (!error) + * { + * // Wait succeeded. + * } + * } + * + * ... + * + * boost::asio::posix::stream_descriptor descriptor(io_context); + * ... + * descriptor.async_wait( + * boost::asio::posix::stream_descriptor::wait_read, + * wait_handler); + * @endcode + */ + template <typename WaitHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(wait_type w, BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WaitHandler. + BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + return this->get_service().async_wait(this->get_implementation(), + w, BOOST_ASIO_MOVE_CAST(WaitHandler)(handler)); } protected: @@ -489,4 +579,6 @@ protected: #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_HPP diff --git a/boost/asio/posix/basic_stream_descriptor.hpp b/boost/asio/posix/basic_stream_descriptor.hpp index 4baacb519b..ca88e31159 100644 --- a/boost/asio/posix/basic_stream_descriptor.hpp +++ b/boost/asio/posix/basic_stream_descriptor.hpp @@ -17,6 +17,8 @@ #include <boost/asio/detail/config.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) @@ -50,10 +52,6 @@ class basic_stream_descriptor : public basic_descriptor<StreamDescriptorService> { public: - /// (Deprecated: Use native_handle_type.) The native representation of a - /// descriptor. - typedef typename StreamDescriptorService::native_handle_type native_type; - /// The native representation of a descriptor. typedef typename StreamDescriptorService::native_handle_type native_handle_type; @@ -64,12 +62,12 @@ public: * descriptor needs to be opened and then connected or accepted before data * can be sent or received on it. * - * @param io_service The io_service object that the stream descriptor will + * @param io_context The io_context object that the stream descriptor will * use to dispatch handlers for any asynchronous operations performed on the * descriptor. */ - explicit basic_stream_descriptor(boost::asio::io_service& io_service) - : basic_descriptor<StreamDescriptorService>(io_service) + explicit basic_stream_descriptor(boost::asio::io_context& io_context) + : basic_descriptor<StreamDescriptorService>(io_context) { } @@ -78,7 +76,7 @@ public: * This constructor creates a stream descriptor object to hold an existing * native descriptor. * - * @param io_service The io_service object that the stream descriptor will + * @param io_context The io_context object that the stream descriptor will * use to dispatch handlers for any asynchronous operations performed on the * descriptor. * @@ -86,9 +84,9 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_stream_descriptor(boost::asio::io_service& io_service, + basic_stream_descriptor(boost::asio::io_context& io_context, const native_handle_type& native_descriptor) - : basic_descriptor<StreamDescriptorService>(io_service, native_descriptor) + : basic_descriptor<StreamDescriptorService>(io_context, native_descriptor) { } @@ -101,7 +99,7 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_stream_descriptor(io_service&) constructor. + * constructed using the @c basic_stream_descriptor(io_context&) constructor. */ basic_stream_descriptor(basic_stream_descriptor&& other) : basic_descriptor<StreamDescriptorService>( @@ -118,7 +116,7 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_stream_descriptor(io_service&) constructor. + * constructed using the @c basic_stream_descriptor(io_context&) constructor. */ basic_stream_descriptor& operator=(basic_stream_descriptor&& other) { @@ -209,7 +207,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The write operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all @@ -321,7 +319,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The read operation may not read all of the requested number of bytes. * Consider using the @ref async_read function if you need to ensure that the @@ -361,4 +359,6 @@ public: #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP diff --git a/boost/asio/posix/descriptor.hpp b/boost/asio/posix/descriptor.hpp new file mode 100644 index 0000000000..be67663eb6 --- /dev/null +++ b/boost/asio/posix/descriptor.hpp @@ -0,0 +1,646 @@ +// +// posix/descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_POSIX_DESCRIPTOR_HPP +#define BOOST_ASIO_POSIX_DESCRIPTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> + +#if !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + +#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ + || defined(GENERATING_DOCUMENTATION) + +#include <boost/asio/async_result.hpp> +#include <boost/asio/basic_io_object.hpp> +#include <boost/asio/detail/handler_type_requirements.hpp> +#include <boost/asio/detail/reactive_descriptor_service.hpp> +#include <boost/asio/detail/throw_error.hpp> +#include <boost/asio/error.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/posix/descriptor_base.hpp> + +#if defined(BOOST_ASIO_HAS_MOVE) +# include <utility> +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#define BOOST_ASIO_SVC_T boost::asio::detail::reactive_descriptor_service + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace posix { + +/// Provides POSIX descriptor functionality. +/** + * The posix::descriptor class template provides the ability to wrap a + * POSIX descriptor. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +class descriptor + : BOOST_ASIO_SVC_ACCESS basic_io_object<BOOST_ASIO_SVC_T>, + public descriptor_base +{ +public: + /// The type of the executor associated with the object. + typedef io_context::executor_type executor_type; + + /// The native representation of a descriptor. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef BOOST_ASIO_SVC_T::native_handle_type native_handle_type; +#endif + + /// A descriptor is always the lowest layer. + typedef descriptor lowest_layer_type; + + /// Construct a descriptor without opening it. + /** + * This constructor creates a descriptor without opening it. + * + * @param io_context The io_context object that the descriptor will use to + * dispatch handlers for any asynchronous operations performed on the + * descriptor. + */ + explicit descriptor(boost::asio::io_context& io_context) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) + { + } + + /// Construct a descriptor on an existing native descriptor. + /** + * This constructor creates a descriptor object to hold an existing native + * descriptor. + * + * @param io_context The io_context object that the descriptor will use to + * dispatch handlers for any asynchronous operations performed on the + * descriptor. + * + * @param native_descriptor A native descriptor. + * + * @throws boost::system::system_error Thrown on failure. + */ + descriptor(boost::asio::io_context& io_context, + const native_handle_type& native_descriptor) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) + { + boost::system::error_code ec; + this->get_service().assign(this->get_implementation(), + native_descriptor, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a descriptor from another. + /** + * This constructor moves a descriptor from one object to another. + * + * @param other The other descriptor object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c descriptor(io_context&) constructor. + */ + descriptor(descriptor&& other) + : basic_io_object<BOOST_ASIO_SVC_T>(std::move(other)) + { + } + + /// Move-assign a descriptor from another. + /** + * This assignment operator moves a descriptor from one object to another. + * + * @param other The other descriptor object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c descriptor(io_context&) constructor. + */ + descriptor& operator=(descriptor&& other) + { + basic_io_object<BOOST_ASIO_SVC_T>::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_context() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_service() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_service(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_executor(); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since a descriptor cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since a descriptor cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + + /// Assign an existing native descriptor to the descriptor. + /* + * This function opens the descriptor to hold an existing native descriptor. + * + * @param native_descriptor A native descriptor. + * + * @throws boost::system::system_error Thrown on failure. + */ + void assign(const native_handle_type& native_descriptor) + { + boost::system::error_code ec; + this->get_service().assign(this->get_implementation(), + native_descriptor, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native descriptor to the descriptor. + /* + * This function opens the descriptor to hold an existing native descriptor. + * + * @param native_descriptor A native descriptor. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& native_descriptor, + boost::system::error_code& ec) + { + this->get_service().assign( + this->get_implementation(), native_descriptor, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the descriptor is open. + bool is_open() const + { + return this->get_service().is_open(this->get_implementation()); + } + + /// Close the descriptor. + /** + * This function is used to close the descriptor. Any asynchronous read or + * write operations will be cancelled immediately, and will complete with the + * boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. Note that, even if + * the function indicates an error, the underlying descriptor is closed. + */ + void close() + { + boost::system::error_code ec; + this->get_service().close(this->get_implementation(), ec); + boost::asio::detail::throw_error(ec, "close"); + } + + /// Close the descriptor. + /** + * This function is used to close the descriptor. Any asynchronous read or + * write operations will be cancelled immediately, and will complete with the + * boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. Note that, even if + * the function indicates an error, the underlying descriptor is closed. + */ + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) + { + this->get_service().close(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get the native descriptor representation. + /** + * This function may be used to obtain the underlying representation of the + * descriptor. This is intended to allow access to native descriptor + * functionality that is not otherwise provided. + */ + native_handle_type native_handle() + { + return this->get_service().native_handle(this->get_implementation()); + } + + /// Release ownership of the native descriptor implementation. + /** + * This function may be used to obtain the underlying representation of the + * descriptor. After calling this function, @c is_open() returns false. The + * caller is responsible for closing the descriptor. + * + * All outstanding asynchronous read or write operations will finish + * immediately, and the handlers for cancelled operations will be passed the + * boost::asio::error::operation_aborted error. + */ + native_handle_type release() + { + return this->get_service().release(this->get_implementation()); + } + + /// Cancel all asynchronous operations associated with the descriptor. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. + */ + void cancel() + { + boost::system::error_code ec; + this->get_service().cancel(this->get_implementation(), ec); + boost::asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the descriptor. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) + { + this->get_service().cancel(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Perform an IO control command on the descriptor. + /** + * This function is used to execute an IO control command on the descriptor. + * + * @param command The IO control command to be performed on the descriptor. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa IoControlCommand @n + * boost::asio::posix::descriptor_base::bytes_readable @n + * boost::asio::posix::descriptor_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * boost::asio::posix::stream_descriptor descriptor(io_context); + * ... + * boost::asio::posix::stream_descriptor::bytes_readable command; + * descriptor.io_control(command); + * std::size_t bytes_readable = command.get(); + * @endcode + */ + template <typename IoControlCommand> + void io_control(IoControlCommand& command) + { + boost::system::error_code ec; + this->get_service().io_control(this->get_implementation(), command, ec); + boost::asio::detail::throw_error(ec, "io_control"); + } + + /// Perform an IO control command on the descriptor. + /** + * This function is used to execute an IO control command on the descriptor. + * + * @param command The IO control command to be performed on the descriptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa IoControlCommand @n + * boost::asio::posix::descriptor_base::bytes_readable @n + * boost::asio::posix::descriptor_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * boost::asio::posix::stream_descriptor descriptor(io_context); + * ... + * boost::asio::posix::stream_descriptor::bytes_readable command; + * boost::system::error_code ec; + * descriptor.io_control(command, ec); + * if (ec) + * { + * // An error occurred. + * } + * std::size_t bytes_readable = command.get(); + * @endcode + */ + template <typename IoControlCommand> + BOOST_ASIO_SYNC_OP_VOID io_control(IoControlCommand& command, + boost::system::error_code& ec) + { + this->get_service().io_control(this->get_implementation(), command, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Gets the non-blocking mode of the descriptor. + /** + * @returns @c true if the descriptor's synchronous operations will fail with + * boost::asio::error::would_block if they are unable to perform the requested + * operation immediately. If @c false, synchronous operations will block + * until complete. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * boost::asio::error::would_block. + */ + bool non_blocking() const + { + return this->get_service().non_blocking(this->get_implementation()); + } + + /// Sets the non-blocking mode of the descriptor. + /** + * @param mode If @c true, the descriptor's synchronous operations will fail + * with boost::asio::error::would_block if they are unable to perform the + * requested operation immediately. If @c false, synchronous operations will + * block until complete. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * boost::asio::error::would_block. + */ + void non_blocking(bool mode) + { + boost::system::error_code ec; + this->get_service().non_blocking(this->get_implementation(), mode, ec); + boost::asio::detail::throw_error(ec, "non_blocking"); + } + + /// Sets the non-blocking mode of the descriptor. + /** + * @param mode If @c true, the descriptor's synchronous operations will fail + * with boost::asio::error::would_block if they are unable to perform the + * requested operation immediately. If @c false, synchronous operations will + * block until complete. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * boost::asio::error::would_block. + */ + BOOST_ASIO_SYNC_OP_VOID non_blocking( + bool mode, boost::system::error_code& ec) + { + this->get_service().non_blocking(this->get_implementation(), mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Gets the non-blocking mode of the native descriptor implementation. + /** + * This function is used to retrieve the non-blocking mode of the underlying + * native descriptor. This mode has no effect on the behaviour of the + * descriptor object's synchronous operations. + * + * @returns @c true if the underlying descriptor is in non-blocking mode and + * direct system calls may fail with boost::asio::error::would_block (or the + * equivalent system error). + * + * @note The current non-blocking mode is cached by the descriptor object. + * Consequently, the return value may be incorrect if the non-blocking mode + * was set directly on the native descriptor. + */ + bool native_non_blocking() const + { + return this->get_service().native_non_blocking( + this->get_implementation()); + } + + /// Sets the non-blocking mode of the native descriptor implementation. + /** + * This function is used to modify the non-blocking mode of the underlying + * native descriptor. It has no effect on the behaviour of the descriptor + * object's synchronous operations. + * + * @param mode If @c true, the underlying descriptor is put into non-blocking + * mode and direct system calls may fail with boost::asio::error::would_block + * (or the equivalent system error). + * + * @throws boost::system::system_error Thrown on failure. If the @c mode is + * @c false, but the current value of @c non_blocking() is @c true, this + * function fails with boost::asio::error::invalid_argument, as the + * combination does not make sense. + */ + void native_non_blocking(bool mode) + { + boost::system::error_code ec; + this->get_service().native_non_blocking( + this->get_implementation(), mode, ec); + boost::asio::detail::throw_error(ec, "native_non_blocking"); + } + + /// Sets the non-blocking mode of the native descriptor implementation. + /** + * This function is used to modify the non-blocking mode of the underlying + * native descriptor. It has no effect on the behaviour of the descriptor + * object's synchronous operations. + * + * @param mode If @c true, the underlying descriptor is put into non-blocking + * mode and direct system calls may fail with boost::asio::error::would_block + * (or the equivalent system error). + * + * @param ec Set to indicate what error occurred, if any. If the @c mode is + * @c false, but the current value of @c non_blocking() is @c true, this + * function fails with boost::asio::error::invalid_argument, as the + * combination does not make sense. + */ + BOOST_ASIO_SYNC_OP_VOID native_non_blocking( + bool mode, boost::system::error_code& ec) + { + this->get_service().native_non_blocking( + this->get_implementation(), mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Wait for the descriptor to become ready to read, ready to write, or to + /// have pending error conditions. + /** + * This function is used to perform a blocking wait for a descriptor to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired descriptor state. + * + * @par Example + * Waiting for a descriptor to become readable. + * @code + * boost::asio::posix::stream_descriptor descriptor(io_context); + * ... + * descriptor.wait(boost::asio::posix::stream_descriptor::wait_read); + * @endcode + */ + void wait(wait_type w) + { + boost::system::error_code ec; + this->get_service().wait(this->get_implementation(), w, ec); + boost::asio::detail::throw_error(ec, "wait"); + } + + /// Wait for the descriptor to become ready to read, ready to write, or to + /// have pending error conditions. + /** + * This function is used to perform a blocking wait for a descriptor to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired descriptor state. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * Waiting for a descriptor to become readable. + * @code + * boost::asio::posix::stream_descriptor descriptor(io_context); + * ... + * boost::system::error_code ec; + * descriptor.wait(boost::asio::posix::stream_descriptor::wait_read, ec); + * @endcode + */ + BOOST_ASIO_SYNC_OP_VOID wait(wait_type w, boost::system::error_code& ec) + { + this->get_service().wait(this->get_implementation(), w, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Asynchronously wait for the descriptor to become ready to read, ready to + /// write, or to have pending error conditions. + /** + * This function is used to perform an asynchronous wait for a descriptor to + * enter a ready to read, write or error condition state. + * + * @param w Specifies the desired descriptor state. + * + * @param handler The handler to be called when the wait operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error // Result of operation + * ); @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 + * boost::asio::io_context::post(). + * + * @par Example + * @code + * void wait_handler(const boost::system::error_code& error) + * { + * if (!error) + * { + * // Wait succeeded. + * } + * } + * + * ... + * + * boost::asio::posix::stream_descriptor descriptor(io_context); + * ... + * descriptor.async_wait( + * boost::asio::posix::stream_descriptor::wait_read, + * wait_handler); + * @endcode + */ + template <typename WaitHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(wait_type w, BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WaitHandler. + BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + async_completion<WaitHandler, + void (boost::system::error_code)> init(handler); + + this->get_service().async_wait( + this->get_implementation(), w, init.completion_handler); + + return init.result.get(); + } + +protected: + /// Protected destructor to prevent deletion through this type. + /** + * This function destroys the descriptor, cancelling any outstanding + * asynchronous wait operations associated with the descriptor as if by + * calling @c cancel. + */ + ~descriptor() + { + } +}; + +} // namespace posix +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#undef BOOST_ASIO_SVC_T + +#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + // || defined(GENERATING_DOCUMENTATION) + +#endif // !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + +#endif // BOOST_ASIO_POSIX_DESCRIPTOR_HPP diff --git a/boost/asio/posix/descriptor_base.hpp b/boost/asio/posix/descriptor_base.hpp index e23af43bc8..3e547fe87b 100644 --- a/boost/asio/posix/descriptor_base.hpp +++ b/boost/asio/posix/descriptor_base.hpp @@ -29,33 +29,26 @@ namespace boost { namespace asio { namespace posix { -/// The descriptor_base class is used as a base for the basic_stream_descriptor -/// class template so that we have a common place to define the associated -/// IO control commands. +/// The descriptor_base class is used as a base for the descriptor class as a +/// place to define the associated IO control commands. class descriptor_base { public: - /// (Deprecated: Use non_blocking().) IO control command to set the blocking - /// mode of the descriptor. + /// Wait types. /** - * Implements the FIONBIO IO control command. - * - * @par Example - * @code - * boost::asio::posix::stream_descriptor descriptor(io_service); - * ... - * boost::asio::descriptor_base::non_blocking_io command(true); - * descriptor.io_control(command); - * @endcode - * - * @par Concepts: - * IoControlCommand. + * For use with descriptor::wait() and descriptor::async_wait(). */ -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined non_blocking_io; -#else - typedef boost::asio::detail::io_control::non_blocking_io non_blocking_io; -#endif + enum wait_type + { + /// Wait for a descriptor to become ready to read. + wait_read, + + /// Wait for a descriptor to become ready to write. + wait_write, + + /// Wait for a descriptor to have error conditions pending. + wait_error + }; /// IO control command to get the amount of data that can be read without /// blocking. @@ -64,7 +57,7 @@ public: * * @par Example * @code - * boost::asio::posix::stream_descriptor descriptor(io_service); + * boost::asio::posix::stream_descriptor descriptor(io_context); * ... * boost::asio::descriptor_base::bytes_readable command(true); * descriptor.io_control(command); diff --git a/boost/asio/posix/stream_descriptor.hpp b/boost/asio/posix/stream_descriptor.hpp index d6d1344702..86db187ded 100644 --- a/boost/asio/posix/stream_descriptor.hpp +++ b/boost/asio/posix/stream_descriptor.hpp @@ -16,18 +16,341 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> +#include <boost/asio/posix/descriptor.hpp> #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) -#include <boost/asio/posix/basic_stream_descriptor.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/posix/basic_stream_descriptor.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) namespace boost { namespace asio { namespace posix { -/// Typedef for the typical usage of a stream-oriented descriptor. +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +// Typedef for the typical usage of a stream-oriented descriptor. typedef basic_stream_descriptor<> stream_descriptor; +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +/// Provides stream-oriented descriptor functionality. +/** + * The posix::stream_descriptor class template provides asynchronous and + * blocking stream-oriented descriptor functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +class stream_descriptor + : public descriptor +{ +public: + /// Construct a stream_descriptor without opening it. + /** + * This constructor creates a stream descriptor without opening it. The + * descriptor needs to be opened and then connected or accepted before data + * can be sent or received on it. + * + * @param io_context The io_context object that the stream descriptor will + * use to dispatch handlers for any asynchronous operations performed on the + * descriptor. + */ + explicit stream_descriptor(boost::asio::io_context& io_context) + : descriptor(io_context) + { + } + + /// Construct a stream_descriptor on an existing native descriptor. + /** + * This constructor creates a stream descriptor object to hold an existing + * native descriptor. + * + * @param io_context The io_context object that the stream descriptor will + * use to dispatch handlers for any asynchronous operations performed on the + * descriptor. + * + * @param native_descriptor The new underlying descriptor implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + stream_descriptor(boost::asio::io_context& io_context, + const native_handle_type& native_descriptor) + : descriptor(io_context, native_descriptor) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a stream_descriptor from another. + /** + * This constructor moves a stream descriptor from one object to another. + * + * @param other The other stream_descriptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c stream_descriptor(io_context&) constructor. + */ + stream_descriptor(stream_descriptor&& other) + : descriptor(std::move(other)) + { + } + + /// Move-assign a stream_descriptor from another. + /** + * This assignment operator moves a stream descriptor from one object to + * another. + * + * @param other The other stream_descriptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c stream_descriptor(io_context&) constructor. + */ + stream_descriptor& operator=(stream_descriptor&& other) + { + descriptor::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Write some data to the descriptor. + /** + * This function is used to write data to the stream descriptor. The function + * call will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the descriptor. + * + * @returns The number of bytes written. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * descriptor.write_some(boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename ConstBufferSequence> + std::size_t write_some(const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->get_service().write_some( + this->get_implementation(), buffers, ec); + boost::asio::detail::throw_error(ec, "write_some"); + return s; + } + + /// Write some data to the descriptor. + /** + * This function is used to write data to the stream descriptor. The function + * call will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the descriptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + */ + template <typename ConstBufferSequence> + std::size_t write_some(const ConstBufferSequence& buffers, + boost::system::error_code& ec) + { + return this->get_service().write_some( + this->get_implementation(), buffers, ec); + } + + /// Start an asynchronous write. + /** + * This function is used to asynchronously write data to the stream + * descriptor. The function call always returns immediately. + * + * @param buffers One or more data buffers to be written to the descriptor. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @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 + * boost::asio::io_context::post(). + * + * @note The write operation may not transmit all of the data to the peer. + * Consider using the @ref async_write function if you need to ensure that all + * data is written before the asynchronous operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * descriptor.async_write_some(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename ConstBufferSequence, typename WriteHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + boost::asio::async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_write_some( + this->get_implementation(), buffers, init.completion_handler); + + return init.result.get(); + } + + /// Read some data from the descriptor. + /** + * This function is used to read data from the stream descriptor. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * descriptor.read_some(boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename MutableBufferSequence> + std::size_t read_some(const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->get_service().read_some( + this->get_implementation(), buffers, ec); + boost::asio::detail::throw_error(ec, "read_some"); + return s; + } + + /// Read some data from the descriptor. + /** + * This function is used to read data from the stream descriptor. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + */ + template <typename MutableBufferSequence> + std::size_t read_some(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + { + return this->get_service().read_some( + this->get_implementation(), buffers, ec); + } + + /// Start an asynchronous read. + /** + * This function is used to asynchronously read data from the stream + * descriptor. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @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 + * boost::asio::io_context::post(). + * + * @note The read operation may not read all of the requested number of bytes. + * Consider using the @ref async_read function if you need to ensure that the + * requested amount of data is read before the asynchronous operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * descriptor.async_read_some(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename MutableBufferSequence, typename ReadHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + boost::asio::async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_read_some( + this->get_implementation(), buffers, init.completion_handler); + + return init.result.get(); + } +}; +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } // namespace posix } // namespace asio diff --git a/boost/asio/posix/stream_descriptor_service.hpp b/boost/asio/posix/stream_descriptor_service.hpp index e42580d3f3..0648781505 100644 --- a/boost/asio/posix/stream_descriptor_service.hpp +++ b/boost/asio/posix/stream_descriptor_service.hpp @@ -17,13 +17,15 @@ #include <boost/asio/detail/config.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) #include <cstddef> #include <boost/asio/async_result.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/reactive_descriptor_service.hpp> #include <boost/asio/detail/push_options.hpp> @@ -35,7 +37,7 @@ namespace posix { /// Default service implementation for a stream descriptor. class stream_descriptor_service #if defined(GENERATING_DOCUMENTATION) - : public boost::asio::io_service::service + : public boost::asio::io_context::service #else : public boost::asio::detail::service_base<stream_descriptor_service> #endif @@ -43,7 +45,7 @@ class stream_descriptor_service public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. - static boost::asio::io_service::id id; + static boost::asio::io_context::id id; #endif private: @@ -58,13 +60,6 @@ public: typedef service_impl_type::implementation_type implementation_type; #endif - /// (Deprecated: Use native_handle_type.) The native descriptor type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_type; -#else - typedef service_impl_type::native_handle_type native_type; -#endif - /// The native descriptor type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; @@ -72,10 +67,10 @@ public: typedef service_impl_type::native_handle_type native_handle_type; #endif - /// Construct a new stream descriptor service for the specified io_service. - explicit stream_descriptor_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base<stream_descriptor_service>(io_service), - service_impl_(io_service) + /// Construct a new stream descriptor service for the specified io_context. + explicit stream_descriptor_service(boost::asio::io_context& io_context) + : boost::asio::detail::service_base<stream_descriptor_service>(io_context), + service_impl_(io_context) { } @@ -109,11 +104,12 @@ public: } /// Assign an existing native descriptor to a stream descriptor. - boost::system::error_code assign(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID assign(implementation_type& impl, const native_handle_type& native_descriptor, boost::system::error_code& ec) { - return service_impl_.assign(impl, native_descriptor, ec); + service_impl_.assign(impl, native_descriptor, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the descriptor is open. @@ -123,17 +119,11 @@ public: } /// Close a stream descriptor implementation. - boost::system::error_code close(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID close(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.close(impl, ec); - } - - /// (Deprecated: Use native_handle().) Get the native descriptor - /// implementation. - native_type native(implementation_type& impl) - { - return service_impl_.native_handle(impl); + service_impl_.close(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get the native descriptor implementation. @@ -149,18 +139,20 @@ public: } /// Cancel all asynchronous operations associated with the descriptor. - boost::system::error_code cancel(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID cancel(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.cancel(impl, ec); + service_impl_.cancel(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Perform an IO control command on the descriptor. template <typename IoControlCommand> - boost::system::error_code io_control(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID io_control(implementation_type& impl, IoControlCommand& command, boost::system::error_code& ec) { - return service_impl_.io_control(impl, command, ec); + service_impl_.io_control(impl, command, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the descriptor. @@ -170,10 +162,11 @@ public: } /// Sets the non-blocking mode of the descriptor. - boost::system::error_code non_blocking(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID non_blocking(implementation_type& impl, bool mode, boost::system::error_code& ec) { - return service_impl_.non_blocking(impl, mode, ec); + service_impl_.non_blocking(impl, mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the native descriptor implementation. @@ -183,10 +176,36 @@ public: } /// Sets the non-blocking mode of the native descriptor implementation. - boost::system::error_code native_non_blocking(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID native_non_blocking(implementation_type& impl, bool mode, boost::system::error_code& ec) { - return service_impl_.native_non_blocking(impl, mode, ec); + service_impl_.native_non_blocking(impl, mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Wait for the descriptor to become ready to read, ready to write, or to + /// have pending error conditions. + BOOST_ASIO_SYNC_OP_VOID wait(implementation_type& impl, + descriptor_base::wait_type w, boost::system::error_code& ec) + { + service_impl_.wait(impl, w, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Asynchronously wait for the descriptor to become ready to read, ready to + /// write, or to have pending error conditions. + template <typename WaitHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(implementation_type& impl, descriptor_base::wait_type w, + BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + async_completion<WaitHandler, + void (boost::system::error_code)> init(handler); + + service_impl_.async_wait(impl, w, init.completion_handler); + + return init.result.get(); } /// Write the given data to the stream. @@ -205,11 +224,10 @@ public: const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - boost::asio::detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + boost::asio::async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); - service_impl_.async_write_some(impl, buffers, init.handler); + service_impl_.async_write_some(impl, buffers, init.completion_handler); return init.result.get(); } @@ -230,20 +248,19 @@ public: const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - boost::asio::detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + boost::asio::async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); - service_impl_.async_read_some(impl, buffers, init.handler); + service_impl_.async_read_some(impl, buffers, init.completion_handler); return init.result.get(); } private: // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { - service_impl_.shutdown_service(); + service_impl_.shutdown(); } // The platform-specific implementation. @@ -259,4 +276,6 @@ private: #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP diff --git a/boost/asio/post.hpp b/boost/asio/post.hpp new file mode 100644 index 0000000000..65e858fd88 --- /dev/null +++ b/boost/asio/post.hpp @@ -0,0 +1,109 @@ +// +// post.hpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_POST_HPP +#define BOOST_ASIO_POST_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/async_result.hpp> +#include <boost/asio/detail/type_traits.hpp> +#include <boost/asio/execution_context.hpp> +#include <boost/asio/is_executor.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +/// Submits a completion token or function object for execution. +/** + * This function submits an object for execution using the object's associated + * executor. The function object is queued for execution, and is never called + * from the current thread prior to returning from <tt>post()</tt>. + * + * This function has the following effects: + * + * @li Constructs a function object handler of type @c Handler, initialized + * with <tt>handler(forward<CompletionToken>(token))</tt>. + * + * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, + * initializing the object as <tt>result(handler)</tt>. + * + * @li Obtains the handler's associated executor object @c ex by performing + * <tt>get_associated_executor(handler)</tt>. + * + * @li Obtains the handler's associated allocator object @c alloc by performing + * <tt>get_associated_allocator(handler)</tt>. + * + * @li Performs <tt>ex.post(std::move(handler), alloc)</tt>. + * + * @li Returns <tt>result.get()</tt>. + */ +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( + BOOST_ASIO_MOVE_ARG(CompletionToken) token); + +/// Submits a completion token or function object for execution. +/** + * This function submits an object for execution using the specified executor. + * The function object is queued for execution, and is never called from the + * current thread prior to returning from <tt>post()</tt>. + * + * This function has the following effects: + * + * @li Constructs a function object handler of type @c Handler, initialized + * with <tt>handler(forward<CompletionToken>(token))</tt>. + * + * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, + * initializing the object as <tt>result(handler)</tt>. + * + * @li Obtains the handler's associated executor object @c ex1 by performing + * <tt>get_associated_executor(handler)</tt>. + * + * @li Creates a work object @c w by performing <tt>make_work(ex1)</tt>. + * + * @li Obtains the handler's associated allocator object @c alloc by performing + * <tt>get_associated_allocator(handler)</tt>. + * + * @li Constructs a function object @c f with a function call operator that + * performs <tt>ex1.dispatch(std::move(handler), alloc)</tt> followed by + * <tt>w.reset()</tt>. + * + * @li Performs <tt>Executor(ex).post(std::move(f), alloc)</tt>. + * + * @li Returns <tt>result.get()</tt>. + */ +template <typename Executor, typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( + const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_executor<Executor>::value>::type* = 0); + +/// Submits a completion token or function object for execution. +/** + * @returns <tt>post(ctx.get_executor(), forward<CompletionToken>(token))</tt>. + */ +template <typename ExecutionContext, typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( + ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if<is_convertible< + ExecutionContext&, execution_context&>::value>::type* = 0); + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#include <boost/asio/impl/post.hpp> + +#endif // BOOST_ASIO_POST_HPP diff --git a/boost/asio/raw_socket_service.hpp b/boost/asio/raw_socket_service.hpp index 06880d5abb..9a777013e2 100644 --- a/boost/asio/raw_socket_service.hpp +++ b/boost/asio/raw_socket_service.hpp @@ -16,11 +16,14 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #include <cstddef> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/null_socket_service.hpp> @@ -39,7 +42,7 @@ namespace asio { template <typename Protocol> class raw_socket_service #if defined(GENERATING_DOCUMENTATION) - : public boost::asio::io_service::service + : public boost::asio::io_context::service #else : public boost::asio::detail::service_base<raw_socket_service<Protocol> > #endif @@ -47,7 +50,7 @@ class raw_socket_service public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. - static boost::asio::io_service::id id; + static boost::asio::io_context::id id; #endif /// The protocol type. @@ -74,13 +77,6 @@ public: typedef typename service_impl_type::implementation_type implementation_type; #endif - /// (Deprecated: Use native_handle_type.) The native socket type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_type; -#else - typedef typename service_impl_type::native_handle_type native_type; -#endif - /// The native socket type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; @@ -88,11 +84,11 @@ public: typedef typename service_impl_type::native_handle_type native_handle_type; #endif - /// Construct a new raw socket service for the specified io_service. - explicit raw_socket_service(boost::asio::io_service& io_service) + /// Construct a new raw socket service for the specified io_context. + explicit raw_socket_service(boost::asio::io_context& io_context) : boost::asio::detail::service_base< - raw_socket_service<Protocol> >(io_service), - service_impl_(io_service) + raw_socket_service<Protocol> >(io_context), + service_impl_(io_context) { } @@ -143,22 +139,23 @@ public: } // Open a new raw socket implementation. - boost::system::error_code open(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID open(implementation_type& impl, const protocol_type& protocol, boost::system::error_code& ec) { if (protocol.type() == BOOST_ASIO_OS_DEF(SOCK_RAW)) service_impl_.open(impl, protocol, ec); else ec = boost::asio::error::invalid_argument; - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Assign an existing native socket to a raw socket. - boost::system::error_code assign(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID assign(implementation_type& impl, const protocol_type& protocol, const native_handle_type& native_socket, boost::system::error_code& ec) { - return service_impl_.assign(impl, protocol, native_socket, ec); + service_impl_.assign(impl, protocol, native_socket, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the socket is open. @@ -168,16 +165,18 @@ public: } /// Close a raw socket implementation. - boost::system::error_code close(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID close(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.close(impl, ec); + service_impl_.close(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } - /// (Deprecated: Use native_handle().) Get the native socket implementation. - native_type native(implementation_type& impl) + /// Release ownership of the underlying socket. + native_handle_type release(implementation_type& impl, + boost::system::error_code& ec) { - return service_impl_.native_handle(impl); + return service_impl_.release(impl, ec); } /// Get the native socket implementation. @@ -187,10 +186,11 @@ public: } /// Cancel all asynchronous operations associated with the socket. - boost::system::error_code cancel(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID cancel(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.cancel(impl, ec); + service_impl_.cancel(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the socket is at the out-of-band data mark. @@ -208,17 +208,19 @@ public: } // Bind the raw socket to the specified local endpoint. - boost::system::error_code bind(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID bind(implementation_type& impl, const endpoint_type& endpoint, boost::system::error_code& ec) { - return service_impl_.bind(impl, endpoint, ec); + service_impl_.bind(impl, endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Connect the raw socket to the specified endpoint. - boost::system::error_code connect(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID connect(implementation_type& impl, const endpoint_type& peer_endpoint, boost::system::error_code& ec) { - return service_impl_.connect(impl, peer_endpoint, ec); + service_impl_.connect(impl, peer_endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Start an asynchronous connect. @@ -229,37 +231,39 @@ public: const endpoint_type& peer_endpoint, BOOST_ASIO_MOVE_ARG(ConnectHandler) handler) { - detail::async_result_init< - ConnectHandler, void (boost::system::error_code)> init( - BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler)); + async_completion<ConnectHandler, + void (boost::system::error_code)> init(handler); - service_impl_.async_connect(impl, peer_endpoint, init.handler); + service_impl_.async_connect(impl, peer_endpoint, init.completion_handler); return init.result.get(); } /// Set a socket option. template <typename SettableSocketOption> - boost::system::error_code set_option(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID set_option(implementation_type& impl, const SettableSocketOption& option, boost::system::error_code& ec) { - return service_impl_.set_option(impl, option, ec); + service_impl_.set_option(impl, option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get a socket option. template <typename GettableSocketOption> - boost::system::error_code get_option(const implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID get_option(const implementation_type& impl, GettableSocketOption& option, boost::system::error_code& ec) const { - return service_impl_.get_option(impl, option, ec); + service_impl_.get_option(impl, option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Perform an IO control command on the socket. template <typename IoControlCommand> - boost::system::error_code io_control(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID io_control(implementation_type& impl, IoControlCommand& command, boost::system::error_code& ec) { - return service_impl_.io_control(impl, command, ec); + service_impl_.io_control(impl, command, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the socket. @@ -269,10 +273,11 @@ public: } /// Sets the non-blocking mode of the socket. - boost::system::error_code non_blocking(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID non_blocking(implementation_type& impl, bool mode, boost::system::error_code& ec) { - return service_impl_.non_blocking(impl, mode, ec); + service_impl_.non_blocking(impl, mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the native socket implementation. @@ -282,10 +287,11 @@ public: } /// Sets the non-blocking mode of the native socket implementation. - boost::system::error_code native_non_blocking(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID native_non_blocking(implementation_type& impl, bool mode, boost::system::error_code& ec) { - return service_impl_.native_non_blocking(impl, mode, ec); + service_impl_.native_non_blocking(impl, mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get the local endpoint. @@ -303,10 +309,36 @@ public: } /// Disable sends or receives on the socket. - boost::system::error_code shutdown(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID shutdown(implementation_type& impl, socket_base::shutdown_type what, boost::system::error_code& ec) { - return service_impl_.shutdown(impl, what, ec); + service_impl_.shutdown(impl, what, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Wait for the socket to become ready to read, ready to write, or to have + /// pending error conditions. + BOOST_ASIO_SYNC_OP_VOID wait(implementation_type& impl, + socket_base::wait_type w, boost::system::error_code& ec) + { + service_impl_.wait(impl, w, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Asynchronously wait for the socket to become ready to read, ready to + /// write, or to have pending error conditions. + template <typename WaitHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(implementation_type& impl, socket_base::wait_type w, + BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + async_completion<WaitHandler, + void (boost::system::error_code)> init(handler); + + service_impl_.async_wait(impl, w, init.completion_handler); + + return init.result.get(); } /// Send the given data to the peer. @@ -326,11 +358,10 @@ public: socket_base::message_flags flags, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); - service_impl_.async_send(impl, buffers, flags, init.handler); + service_impl_.async_send(impl, buffers, flags, init.completion_handler); return init.result.get(); } @@ -353,12 +384,11 @@ public: socket_base::message_flags flags, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); service_impl_.async_send_to(impl, buffers, - destination, flags, init.handler); + destination, flags, init.completion_handler); return init.result.get(); } @@ -381,11 +411,10 @@ public: socket_base::message_flags flags, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); - service_impl_.async_receive(impl, buffers, flags, init.handler); + service_impl_.async_receive(impl, buffers, flags, init.completion_handler); return init.result.get(); } @@ -409,21 +438,20 @@ public: socket_base::message_flags flags, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); service_impl_.async_receive_from(impl, buffers, - sender_endpoint, flags, init.handler); + sender_endpoint, flags, init.completion_handler); return init.result.get(); } private: // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { - service_impl_.shutdown_service(); + service_impl_.shutdown(); } // The platform-specific implementation. @@ -435,4 +463,6 @@ private: #include <boost/asio/detail/pop_options.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_RAW_SOCKET_SERVICE_HPP diff --git a/boost/asio/read.hpp b/boost/asio/read.hpp index 0db29b7831..d03ed5a73d 100644 --- a/boost/asio/read.hpp +++ b/boost/asio/read.hpp @@ -18,9 +18,13 @@ #include <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/async_result.hpp> -#include <boost/asio/basic_streambuf_fwd.hpp> +#include <boost/asio/buffer.hpp> #include <boost/asio/error.hpp> +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +# include <boost/asio/basic_streambuf_fwd.hpp> +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + #include <boost/asio/detail/push_options.hpp> namespace boost { @@ -71,7 +75,10 @@ namespace asio { * boost::asio::transfer_all()); @endcode */ template <typename SyncReadStream, typename MutableBufferSequence> -std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers); +std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type* = 0); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -111,7 +118,10 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers); */ template <typename SyncReadStream, typename MutableBufferSequence> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, - boost::system::error_code& ec); + boost::system::error_code& ec, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type* = 0); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -162,7 +172,10 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, template <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, - CompletionCondition completion_condition); + CompletionCondition completion_condition, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type* = 0); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -206,8 +219,171 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, template <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, - CompletionCondition completion_condition, boost::system::error_code& ec); + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type* = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This overload is equivalent to calling: + * @code boost::asio::read( + * s, buffers, + * boost::asio::transfer_all()); @endcode + */ +template <typename SyncReadStream, typename DynamicBuffer> +std::size_t read(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type* = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The supplied buffer is full (that is, it has reached maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @note This overload is equivalent to calling: + * @code boost::asio::read( + * s, buffers, + * boost::asio::transfer_all(), ec); @endcode + */ +template <typename SyncReadStream, typename DynamicBuffer> +std::size_t read(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type* = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + */ +template <typename SyncReadStream, typename DynamicBuffer, + typename CompletionCondition> +std::size_t read(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type* = 0); +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template <typename SyncReadStream, typename DynamicBuffer, + typename CompletionCondition> +std::size_t read(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type* = 0); + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) /// Attempt to read a certain amount of data from a stream before returning. @@ -351,6 +527,7 @@ std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b, CompletionCondition completion_condition, boost::system::error_code& ec); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) /*@}*/ /** @@ -404,7 +581,7 @@ std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * To read into a single data buffer use the @ref buffer function as follows: @@ -426,7 +603,10 @@ template <typename AsyncReadStream, typename MutableBufferSequence, BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type* = 0); /// Start an asynchronous operation to read a certain amount of data from a /// stream. @@ -479,7 +659,7 @@ async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * To read into a single data buffer use the @ref buffer function as follows: @@ -497,8 +677,143 @@ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_mutable_buffer_sequence<MutableBufferSequence>::value + >::type* = 0); + +/// Start an asynchronous operation to read a certain amount of data from a +/// stream. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions is + * true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. The + * program must ensure that the stream performs no other read operations (such + * as async_read, the stream's async_read_some function, or any other composed + * operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes copied into the + * // buffers. If an error occurred, + * // this will be the number of + * // bytes successfully transferred + * // prior to the error. + * ); @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 + * boost::asio::io_context::post(). + * + * @note This overload is equivalent to calling: + * @code boost::asio::async_read( + * s, buffers, + * boost::asio::transfer_all(), + * handler); @endcode + */ +template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type* = 0); + +/// Start an asynchronous operation to read a certain amount of data from a +/// stream. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions is + * true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. The + * program must ensure that the stream performs no other read operations (such + * as async_read, the stream's async_read_some function, or any other composed + * operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_read_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's async_read_some function. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes copied into the + * // buffers. If an error occurred, + * // this will be the number of + * // bytes successfully transferred + * // prior to the error. + * ); @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 + * boost::asio::io_context::post(). + */ +template <typename AsyncReadStream, typename DynamicBuffer, + typename CompletionCondition, typename ReadHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type* = 0); +#if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) /// Start an asynchronous operation to read a certain amount of data from a @@ -541,7 +856,7 @@ async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note This overload is equivalent to calling: * @code boost::asio::async_read( @@ -609,7 +924,7 @@ async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). */ template <typename AsyncReadStream, typename Allocator, typename CompletionCondition, typename ReadHandler> @@ -620,6 +935,7 @@ async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, BOOST_ASIO_MOVE_ARG(ReadHandler) handler); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) /*@}*/ diff --git a/boost/asio/read_at.hpp b/boost/asio/read_at.hpp index 03f6c155c1..fc10c8115e 100644 --- a/boost/asio/read_at.hpp +++ b/boost/asio/read_at.hpp @@ -18,10 +18,13 @@ #include <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/async_result.hpp> -#include <boost/asio/basic_streambuf_fwd.hpp> #include <boost/asio/detail/cstdint.hpp> #include <boost/asio/error.hpp> +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +# include <boost/asio/basic_streambuf_fwd.hpp> +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + #include <boost/asio/detail/push_options.hpp> namespace boost { @@ -230,6 +233,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition, boost::system::error_code& ec); +#if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) /// Attempt to read a certain amount of data at the specified offset before @@ -385,6 +389,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, CompletionCondition completion_condition, boost::system::error_code& ec); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) /*@}*/ /** @@ -437,7 +442,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * To read into a single data buffer use the @ref buffer function as follows: @@ -515,7 +520,7 @@ async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * To read into a single data buffer use the @ref buffer function as follows: @@ -536,6 +541,7 @@ async_read_at(AsyncRandomAccessReadDevice& d, CompletionCondition completion_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler); +#if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) /// Start an asynchronous operation to read a certain amount of data at the @@ -575,7 +581,7 @@ async_read_at(AsyncRandomAccessReadDevice& d, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note This overload is equivalent to calling: * @code boost::asio::async_read_at( @@ -641,7 +647,7 @@ async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). */ template <typename AsyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition, typename ReadHandler> @@ -653,6 +659,7 @@ async_read_at(AsyncRandomAccessReadDevice& d, BOOST_ASIO_MOVE_ARG(ReadHandler) handler); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) /*@}*/ diff --git a/boost/asio/read_until.hpp b/boost/asio/read_until.hpp index 3ed288fc2c..12f82c7808 100644 --- a/boost/asio/read_until.hpp +++ b/boost/asio/read_until.hpp @@ -16,17 +16,18 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> - -#if !defined(BOOST_ASIO_NO_IOSTREAM) - #include <cstddef> #include <string> #include <boost/asio/async_result.hpp> -#include <boost/asio/basic_streambuf.hpp> #include <boost/asio/detail/regex_fwd.hpp> +#include <boost/asio/detail/string_view.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +# include <boost/asio/basic_streambuf_fwd.hpp> +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + #include <boost/asio/detail/push_options.hpp> namespace boost { @@ -67,11 +68,482 @@ struct is_match_condition /** * @defgroup read_until boost::asio::read_until * - * @brief Read data into a streambuf until it contains a delimiter, matches a - * regular expression, or a function object indicates a match. + * @brief Read data into a dynamic buffer sequence, or into a streambuf, until + * it contains a delimiter, matches a regular expression, or a function object + * indicates a match. */ /*@{*/ +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter character. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + * + * @par Example + * To read data into a @c std::string until a newline is encountered: + * @code std::string data; + * std::string n = boost::asio::read_until(s, + * boost::asio::dynamic_buffer(data), '\n'); + * std::string line = data.substr(0, n); + * data.erase(0, n); @endcode + * After the @c read_until operation completes successfully, the string @c data + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c b as + * follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template <typename SyncReadStream, typename DynamicBuffer> +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, char delim); + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter character. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. Returns 0 if an error occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + */ +template <typename SyncReadStream, typename DynamicBuffer> +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + char delim, boost::system::error_code& ec); + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter string. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + * + * @par Example + * To read data into a @c std::string until a CR-LF sequence is encountered: + * @code std::string data; + * std::string n = boost::asio::read_until(s, + * boost::asio::dynamic_buffer(data), "\r\n"); + * std::string line = data.substr(0, n); + * data.erase(0, n); @endcode + * After the @c read_until operation completes successfully, the string @c data + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c b as + * follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template <typename SyncReadStream, typename DynamicBuffer> +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim); + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter string. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. Returns 0 if an error occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + */ +template <typename SyncReadStream, typename DynamicBuffer> +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, + boost::system::error_code& ec); + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) \ + || defined(GENERATING_DOCUMENTATION) + +/// Read data into a dynamic buffer sequence until some part of the data it +/// contains matches a regular expression. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains some data + * that matches a regular expression. The call will block until one of the + * following conditions is true: + * + * @li A substring of the dynamic buffer sequence's get area matches the + * regular expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains data that matches the regular expression, the function returns + * immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param expr The regular expression. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the substring that matches the regular expression. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the regular + * expression. An application will typically leave that data in the dynamic + * buffer sequence for a subsequent read_until operation to examine. + * + * @par Example + * To read data into a @c std::string until a CR-LF sequence is encountered: + * @code std::string data; + * std::string n = boost::asio::read_until(s, + * boost::asio::dynamic_buffer(data), boost::regex("\r\n")); + * std::string line = data.substr(0, n); + * data.erase(0, n); @endcode + * After the @c read_until operation completes successfully, the string @c data + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c b as + * follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template <typename SyncReadStream, typename DynamicBuffer> +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + const boost::regex& expr); + +/// Read data into a dynamic buffer sequence until some part of the data it +/// contains matches a regular expression. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains some data + * that matches a regular expression. The call will block until one of the + * following conditions is true: + * + * @li A substring of the dynamic buffer sequence's get area matches the + * regular expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains data that matches the regular expression, the function returns + * immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param expr The regular expression. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the substring that matches the regular expression. Returns 0 + * if an error occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the regular + * expression. An application will typically leave that data in the dynamic + * buffer sequence for a subsequent read_until operation to examine. + */ +template <typename SyncReadStream, typename DynamicBuffer> +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + const boost::regex& expr, boost::system::error_code& ec); + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + // || defined(GENERATING_DOCUMENTATION) + +/// Read data into a dynamic buffer sequence until a function object indicates a +/// match. + +/** + * This function is used to read data into the specified dynamic buffer + * sequence until a user-defined match condition function object, when applied + * to the data contained in the dynamic buffer sequence, indicates a successful + * match. The call will block until one of the following conditions is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the match condition function object already indicates + * a match, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair<iterator, bool> match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator<typename DynamicBuffer::const_buffers_type> + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @returns The number of bytes in the dynamic_buffer's get area that + * have been fully consumed by the match function. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the function object. + * An application will typically leave that data in the dynamic buffer sequence + * for a subsequent read_until operation to examine. + + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + * + * @par Examples + * To read data into a dynamic buffer sequence until whitespace is encountered: + * @code typedef boost::asio::buffers_iterator< + * boost::asio::const_buffers_1> iterator; + * + * std::pair<iterator, bool> + * match_whitespace(iterator begin, iterator end) + * { + * iterator i = begin; + * while (i != end) + * if (std::isspace(*i++)) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * ... + * std::string data; + * boost::asio::read_until(s, data, match_whitespace); + * @endcode + * + * To read data into a @c std::string until a matching character is found: + * @code class match_char + * { + * public: + * explicit match_char(char c) : c_(c) {} + * + * template <typename Iterator> + * std::pair<Iterator, bool> operator()( + * Iterator begin, Iterator end) const + * { + * Iterator i = begin; + * while (i != end) + * if (c_ == *i++) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * + * private: + * char c_; + * }; + * + * namespace asio { + * template <> struct is_match_condition<match_char> + * : public boost::true_type {}; + * } // namespace asio + * ... + * std::string data; + * boost::asio::read_until(s, data, match_char('a')); + * @endcode + */ +template <typename SyncReadStream, + typename DynamicBuffer, typename MatchCondition> +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + MatchCondition match_condition, + typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0); + +/// Read data into a dynamic buffer sequence until a function object indicates a +/// match. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until a user-defined match condition function object, when applied + * to the data contained in the dynamic buffer sequence, indicates a successful + * match. The call will block until one of the following conditions is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the match condition function object already indicates + * a match, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair<iterator, bool> match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator<DynamicBuffer::const_buffers_type> + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area that + * have been fully consumed by the match function. Returns 0 if an error + * occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the function object. + * An application will typically leave that data in the dynamic buffer sequence + * for a subsequent read_until operation to examine. + * + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + */ +template <typename SyncReadStream, + typename DynamicBuffer, typename MatchCondition> +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + MatchCondition match_condition, boost::system::error_code& ec, + typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0); + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + /// Read data into a streambuf until it contains a specified delimiter. /** * This function is used to read data into the specified streambuf until the @@ -113,8 +585,8 @@ struct is_match_condition * contains the delimiter: * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the - * delimiter, so that the string @c line contains: - * @code { 'a', 'b', ..., 'c', '\n' } @endcode + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent @@ -200,8 +672,8 @@ std::size_t read_until(SyncReadStream& s, * contains the delimiter: * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the - * delimiter, so that the string @c line contains: - * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent @@ -209,7 +681,8 @@ std::size_t read_until(SyncReadStream& s, */ template <typename SyncReadStream, typename Allocator> std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, const std::string& delim); + boost::asio::basic_streambuf<Allocator>& b, + BOOST_ASIO_STRING_VIEW_PARAM delim); /// Read data into a streambuf until it contains a specified delimiter. /** @@ -243,8 +716,8 @@ std::size_t read_until(SyncReadStream& s, */ template <typename SyncReadStream, typename Allocator> std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, const std::string& delim, - boost::system::error_code& ec); + boost::asio::basic_streambuf<Allocator>& b, + BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec); #if defined(BOOST_ASIO_HAS_BOOST_REGEX) \ || defined(GENERATING_DOCUMENTATION) @@ -292,8 +765,8 @@ std::size_t read_until(SyncReadStream& s, * contains the data which matched the regular expression: * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the - * match, so that the string @c line contains: - * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent @@ -387,7 +860,8 @@ std::size_t read_until(SyncReadStream& s, * * @note After a successful read_until operation, the streambuf may contain * additional data beyond that which matched the function object. An application - * will typically leave that data in the streambuf for a subsequent + * will typically leave that data in the streambuf for a subsequent read_until + * operation to examine. * * @note The default implementation of the @c is_match_condition type trait * evaluates to true for function pointers and function objects with a @@ -491,7 +965,8 @@ std::size_t read_until(SyncReadStream& s, * * @note After a successful read_until operation, the streambuf may contain * additional data beyond that which matched the function object. An application - * will typically leave that data in the streambuf for a subsequent + * will typically leave that data in the streambuf for a subsequent read_until + * operation to examine. * * @note The default implementation of the @c is_match_condition type trait * evaluates to true for function pointers and function objects with a @@ -504,16 +979,440 @@ std::size_t read_until(SyncReadStream& s, MatchCondition match_condition, boost::system::error_code& ec, typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0); +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + /*@}*/ /** * @defgroup async_read_until boost::asio::async_read_until * - * @brief Start an asynchronous operation to read data into a streambuf until it - * contains a delimiter, matches a regular expression, or a function object - * indicates a match. + * @brief Start an asynchronous operation to read data into a dynamic buffer + * sequence, or into a streambuf, until it contains a delimiter, matches a + * regular expression, or a function object indicates a match. */ /*@{*/ +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until it contains a specified delimiter. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until the dynamic buffer sequence's get area contains the + * specified delimiter. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. If + * the dynamic buffer sequence's get area already contains the delimiter, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param delim The delimiter character. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // The number of bytes in the dynamic buffer sequence's + * // get area up to and including the delimiter. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @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 + * boost::asio::io_context::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond the delimiter. An application + * will typically leave that data in the dynamic buffer sequence for a + * subsequent async_read_until operation to examine. + * + * @par Example + * To asynchronously read data into a @c std::string until a newline is + * encountered: + * @code std::string data; + * ... + * void handler(const boost::system::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::string line = data.substr(0, n); + * data.erase(0, n); + * ... + * } + * } + * ... + * boost::asio::async_read_until(s, data, '\n', handler); @endcode + * After the @c async_read_until operation completes successfully, the buffer + * @c data contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c data + * as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + */ +template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until it contains a specified delimiter. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until the dynamic buffer sequence's get area contains the + * specified delimiter. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. If + * the dynamic buffer sequence's get area already contains the delimiter, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param delim The delimiter string. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // The number of bytes in the dynamic buffer sequence's + * // get area up to and including the delimiter. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @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 + * boost::asio::io_context::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond the delimiter. An application + * will typically leave that data in the dynamic buffer sequence for a + * subsequent async_read_until operation to examine. + * + * @par Example + * To asynchronously read data into a @c std::string until a CR-LF sequence is + * encountered: + * @code std::string data; + * ... + * void handler(const boost::system::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::string line = data.substr(0, n); + * data.erase(0, n); + * ... + * } + * } + * ... + * boost::asio::async_read_until(s, data, "\r\n", handler); @endcode + * After the @c async_read_until operation completes successfully, the string + * @c data contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the string @c data + * as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + */ +template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) \ + || defined(GENERATING_DOCUMENTATION) + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until some part of its data matches a regular expression. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until the dynamic buffer sequence's get area contains some + * data that matches a regular expression. The function call always returns + * immediately. The asynchronous operation will continue until one of the + * following conditions is true: + * + * @li A substring of the dynamic buffer sequence's get area matches the regular + * expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. If + * the dynamic buffer sequence's get area already contains data that matches + * the regular expression, this asynchronous operation completes immediately. + * The program must ensure that the stream performs no other read operations + * (such as async_read, async_read_until, the stream's async_read_some + * function, or any other composed operations that perform reads) until this + * operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param expr The regular expression. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // The number of bytes in the dynamic buffer + * // sequence's get area up to and including the + * // substring that matches the regular expression. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @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 + * boost::asio::io_context::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond that which matched the regular + * expression. An application will typically leave that data in the dynamic + * buffer sequence for a subsequent async_read_until operation to examine. + * + * @par Example + * To asynchronously read data into a @c std::string until a CR-LF sequence is + * encountered: + * @code std::string data; + * ... + * void handler(const boost::system::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::string line = data.substr(0, n); + * data.erase(0, n); + * ... + * } + * } + * ... + * boost::asio::async_read_until(s, data, + * boost::regex("\r\n"), handler); @endcode + * After the @c async_read_until operation completes successfully, the string + * @c data contains the data which matched the regular expression: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the match, + * so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the string @c data + * as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + */ +template <typename AsyncReadStream, + typename DynamicBuffer, typename ReadHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + const boost::regex& expr, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + // || defined(GENERATING_DOCUMENTATION) + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until a function object indicates a match. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until a user-defined match condition function object, when + * applied to the data contained in the dynamic buffer sequence, indicates a + * successful match. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a <em>composed operation</em>. If + * the match condition function object already indicates a match, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair<iterator, bool> match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator<typename DynamicBuffer::const_buffers_type> + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // The number of bytes in the dynamic buffer sequence's + * // get area that have been fully consumed by the match + * // function. O if an error occurred. + * std::size_t bytes_transferred + * ); @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 + * boost::asio::io_context::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond that which matched the function + * object. An application will typically leave that data in the dynamic buffer + * sequence for a subsequent async_read_until operation to examine. + * + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + * + * @par Examples + * To asynchronously read data into a @c std::string until whitespace is + * encountered: + * @code typedef boost::asio::buffers_iterator< + * boost::asio::const_buffers_1> iterator; + * + * std::pair<iterator, bool> + * match_whitespace(iterator begin, iterator end) + * { + * iterator i = begin; + * while (i != end) + * if (std::isspace(*i++)) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * ... + * void handler(const boost::system::error_code& e, std::size_t size); + * ... + * std::string data; + * boost::asio::async_read_until(s, data, match_whitespace, handler); + * @endcode + * + * To asynchronously read data into a @c std::string until a matching character + * is found: + * @code class match_char + * { + * public: + * explicit match_char(char c) : c_(c) {} + * + * template <typename Iterator> + * std::pair<Iterator, bool> operator()( + * Iterator begin, Iterator end) const + * { + * Iterator i = begin; + * while (i != end) + * if (c_ == *i++) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * + * private: + * char c_; + * }; + * + * namespace asio { + * template <> struct is_match_condition<match_char> + * : public boost::true_type {}; + * } // namespace asio + * ... + * void handler(const boost::system::error_code& e, std::size_t size); + * ... + * std::string data; + * boost::asio::async_read_until(s, data, match_char('a'), handler); + * @endcode + */ +template <typename AsyncReadStream, typename DynamicBuffer, + typename MatchCondition, typename ReadHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0); + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + /// Start an asynchronous operation to read data into a streambuf until it /// contains a specified delimiter. /** @@ -558,7 +1457,7 @@ std::size_t read_until(SyncReadStream& s, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note After a successful async_read_until operation, the streambuf may * contain additional data beyond the delimiter. An application will typically @@ -585,8 +1484,8 @@ std::size_t read_until(SyncReadStream& s, * @c b contains the delimiter: * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the - * delimiter, so that the string @c line contains: - * @code { 'a', 'b', ..., 'c', '\n' } @endcode + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent @@ -643,7 +1542,7 @@ async_read_until(AsyncReadStream& s, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note After a successful async_read_until operation, the streambuf may * contain additional data beyond the delimiter. An application will typically @@ -670,8 +1569,8 @@ async_read_until(AsyncReadStream& s, * @c b contains the delimiter: * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the - * delimiter, so that the string @c line contains: - * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent @@ -681,7 +1580,8 @@ template <typename AsyncReadStream, typename Allocator, typename ReadHandler> BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, - boost::asio::basic_streambuf<Allocator>& b, const std::string& delim, + boost::asio::basic_streambuf<Allocator>& b, + BOOST_ASIO_STRING_VIEW_PARAM delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler); #if defined(BOOST_ASIO_HAS_BOOST_REGEX) \ @@ -734,7 +1634,7 @@ async_read_until(AsyncReadStream& s, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note After a successful async_read_until operation, the streambuf may * contain additional data beyond that which matched the regular expression. An @@ -762,8 +1662,8 @@ async_read_until(AsyncReadStream& s, * @c b contains the data which matched the regular expression: * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the - * match, so that the string @c line contains: - * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent @@ -836,7 +1736,7 @@ async_read_until(AsyncReadStream& s, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note After a successful async_read_until operation, the streambuf may * contain additional data beyond that which matched the function object. An @@ -911,6 +1811,9 @@ async_read_until(AsyncReadStream& s, MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, typename enable_if<is_match_condition<MatchCondition>::value>::type* = 0); +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + /*@}*/ } // namespace asio @@ -920,6 +1823,4 @@ async_read_until(AsyncReadStream& s, #include <boost/asio/impl/read_until.hpp> -#endif // !defined(BOOST_ASIO_NO_IOSTREAM) - #endif // BOOST_ASIO_READ_UNTIL_HPP diff --git a/boost/asio/seq_packet_socket_service.hpp b/boost/asio/seq_packet_socket_service.hpp index fcccafe5ec..4688f3026a 100644 --- a/boost/asio/seq_packet_socket_service.hpp +++ b/boost/asio/seq_packet_socket_service.hpp @@ -16,11 +16,14 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #include <cstddef> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/null_socket_service.hpp> @@ -39,7 +42,7 @@ namespace asio { template <typename Protocol> class seq_packet_socket_service #if defined(GENERATING_DOCUMENTATION) - : public boost::asio::io_service::service + : public boost::asio::io_context::service #else : public boost::asio::detail::service_base< seq_packet_socket_service<Protocol> > @@ -48,7 +51,7 @@ class seq_packet_socket_service public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. - static boost::asio::io_service::id id; + static boost::asio::io_context::id id; #endif /// The protocol type. @@ -75,13 +78,6 @@ public: typedef typename service_impl_type::implementation_type implementation_type; #endif - /// (Deprecated: Use native_handle_type.) The native socket type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_type; -#else - typedef typename service_impl_type::native_handle_type native_type; -#endif - /// The native socket type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; @@ -90,11 +86,11 @@ public: #endif /// Construct a new sequenced packet socket service for the specified - /// io_service. - explicit seq_packet_socket_service(boost::asio::io_service& io_service) + /// io_context. + explicit seq_packet_socket_service(boost::asio::io_context& io_context) : boost::asio::detail::service_base< - seq_packet_socket_service<Protocol> >(io_service), - service_impl_(io_service) + seq_packet_socket_service<Protocol> >(io_context), + service_impl_(io_context) { } @@ -145,22 +141,23 @@ public: } /// Open a sequenced packet socket. - boost::system::error_code open(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID open(implementation_type& impl, const protocol_type& protocol, boost::system::error_code& ec) { if (protocol.type() == BOOST_ASIO_OS_DEF(SOCK_SEQPACKET)) service_impl_.open(impl, protocol, ec); else ec = boost::asio::error::invalid_argument; - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Assign an existing native socket to a sequenced packet socket. - boost::system::error_code assign(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID assign(implementation_type& impl, const protocol_type& protocol, const native_handle_type& native_socket, boost::system::error_code& ec) { - return service_impl_.assign(impl, protocol, native_socket, ec); + service_impl_.assign(impl, protocol, native_socket, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the socket is open. @@ -170,16 +167,18 @@ public: } /// Close a sequenced packet socket implementation. - boost::system::error_code close(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID close(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.close(impl, ec); + service_impl_.close(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } - /// (Deprecated: Use native_handle().) Get the native socket implementation. - native_type native(implementation_type& impl) + /// Release ownership of the underlying socket. + native_handle_type release(implementation_type& impl, + boost::system::error_code& ec) { - return service_impl_.native_handle(impl); + return service_impl_.release(impl, ec); } /// Get the native socket implementation. @@ -189,10 +188,11 @@ public: } /// Cancel all asynchronous operations associated with the socket. - boost::system::error_code cancel(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID cancel(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.cancel(impl, ec); + service_impl_.cancel(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the socket is at the out-of-band data mark. @@ -210,17 +210,19 @@ public: } /// Bind the sequenced packet socket to the specified local endpoint. - boost::system::error_code bind(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID bind(implementation_type& impl, const endpoint_type& endpoint, boost::system::error_code& ec) { - return service_impl_.bind(impl, endpoint, ec); + service_impl_.bind(impl, endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Connect the sequenced packet socket to the specified endpoint. - boost::system::error_code connect(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID connect(implementation_type& impl, const endpoint_type& peer_endpoint, boost::system::error_code& ec) { - return service_impl_.connect(impl, peer_endpoint, ec); + service_impl_.connect(impl, peer_endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Start an asynchronous connect. @@ -231,37 +233,39 @@ public: const endpoint_type& peer_endpoint, BOOST_ASIO_MOVE_ARG(ConnectHandler) handler) { - detail::async_result_init< - ConnectHandler, void (boost::system::error_code)> init( - BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler)); + async_completion<ConnectHandler, + void (boost::system::error_code)> init(handler); - service_impl_.async_connect(impl, peer_endpoint, init.handler); + service_impl_.async_connect(impl, peer_endpoint, init.completion_handler); return init.result.get(); } /// Set a socket option. template <typename SettableSocketOption> - boost::system::error_code set_option(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID set_option(implementation_type& impl, const SettableSocketOption& option, boost::system::error_code& ec) { - return service_impl_.set_option(impl, option, ec); + service_impl_.set_option(impl, option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get a socket option. template <typename GettableSocketOption> - boost::system::error_code get_option(const implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID get_option(const implementation_type& impl, GettableSocketOption& option, boost::system::error_code& ec) const { - return service_impl_.get_option(impl, option, ec); + service_impl_.get_option(impl, option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Perform an IO control command on the socket. template <typename IoControlCommand> - boost::system::error_code io_control(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID io_control(implementation_type& impl, IoControlCommand& command, boost::system::error_code& ec) { - return service_impl_.io_control(impl, command, ec); + service_impl_.io_control(impl, command, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the socket. @@ -271,10 +275,11 @@ public: } /// Sets the non-blocking mode of the socket. - boost::system::error_code non_blocking(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID non_blocking(implementation_type& impl, bool mode, boost::system::error_code& ec) { - return service_impl_.non_blocking(impl, mode, ec); + service_impl_.non_blocking(impl, mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the native socket implementation. @@ -284,10 +289,11 @@ public: } /// Sets the non-blocking mode of the native socket implementation. - boost::system::error_code native_non_blocking(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID native_non_blocking(implementation_type& impl, bool mode, boost::system::error_code& ec) { - return service_impl_.native_non_blocking(impl, mode, ec); + service_impl_.native_non_blocking(impl, mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get the local endpoint. @@ -305,10 +311,36 @@ public: } /// Disable sends or receives on the socket. - boost::system::error_code shutdown(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID shutdown(implementation_type& impl, socket_base::shutdown_type what, boost::system::error_code& ec) { - return service_impl_.shutdown(impl, what, ec); + service_impl_.shutdown(impl, what, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Wait for the socket to become ready to read, ready to write, or to have + /// pending error conditions. + BOOST_ASIO_SYNC_OP_VOID wait(implementation_type& impl, + socket_base::wait_type w, boost::system::error_code& ec) + { + service_impl_.wait(impl, w, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Asynchronously wait for the socket to become ready to read, ready to + /// write, or to have pending error conditions. + template <typename WaitHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(implementation_type& impl, socket_base::wait_type w, + BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + async_completion<WaitHandler, + void (boost::system::error_code)> init(handler); + + service_impl_.async_wait(impl, w, init.completion_handler); + + return init.result.get(); } /// Send the given data to the peer. @@ -329,11 +361,10 @@ public: socket_base::message_flags flags, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); - service_impl_.async_send(impl, buffers, flags, init.handler); + service_impl_.async_send(impl, buffers, flags, init.completion_handler); return init.result.get(); } @@ -357,21 +388,20 @@ public: socket_base::message_flags& out_flags, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); service_impl_.async_receive_with_flags(impl, - buffers, in_flags, out_flags, init.handler); + buffers, in_flags, out_flags, init.completion_handler); return init.result.get(); } private: // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { - service_impl_.shutdown_service(); + service_impl_.shutdown(); } // The platform-specific implementation. @@ -383,4 +413,6 @@ private: #include <boost/asio/detail/pop_options.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_SEQ_PACKET_SOCKET_SERVICE_HPP diff --git a/boost/asio/serial_port.hpp b/boost/asio/serial_port.hpp index f3b6fb2450..72a52a52b7 100644 --- a/boost/asio/serial_port.hpp +++ b/boost/asio/serial_port.hpp @@ -21,17 +21,750 @@ #if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) -#include <boost/asio/basic_serial_port.hpp> +#include <string> +#include <boost/asio/async_result.hpp> +#include <boost/asio/basic_io_object.hpp> +#include <boost/asio/detail/handler_type_requirements.hpp> +#include <boost/asio/detail/throw_error.hpp> +#include <boost/asio/error.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/serial_port_base.hpp> + +#if defined(BOOST_ASIO_HAS_MOVE) +# include <utility> +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/basic_serial_port.hpp> +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# if defined(BOOST_ASIO_HAS_IOCP) +# include <boost/asio/detail/win_iocp_serial_port_service.hpp> +# define BOOST_ASIO_SVC_T detail::win_iocp_serial_port_service +# else +# include <boost/asio/detail/reactive_serial_port_service.hpp> +# define BOOST_ASIO_SVC_T detail::reactive_serial_port_service +# endif +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + +#include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { -/// Typedef for the typical usage of a serial port. +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +// Typedef for the typical usage of a serial port. typedef basic_serial_port<> serial_port; +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +/// Provides serial port functionality. +/** + * The serial_port class provides a wrapper over serial port functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +class serial_port + : BOOST_ASIO_SVC_ACCESS basic_io_object<BOOST_ASIO_SVC_T>, + public serial_port_base +{ +public: + /// The type of the executor associated with the object. + typedef io_context::executor_type executor_type; + + /// The native representation of a serial port. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef BOOST_ASIO_SVC_T::native_handle_type native_handle_type; +#endif + + /// A basic_serial_port is always the lowest layer. + typedef serial_port lowest_layer_type; + + /// Construct a serial_port without opening it. + /** + * This constructor creates a serial port without opening it. + * + * @param io_context The io_context object that the serial port will use to + * dispatch handlers for any asynchronous operations performed on the port. + */ + explicit serial_port(boost::asio::io_context& io_context) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) + { + } + + /// Construct and open a serial_port. + /** + * This constructor creates and opens a serial port for the specified device + * name. + * + * @param io_context The io_context object that the serial port will use to + * dispatch handlers for any asynchronous operations performed on the port. + * + * @param device The platform-specific device name for this serial + * port. + */ + explicit serial_port(boost::asio::io_context& io_context, + const char* device) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) + { + boost::system::error_code ec; + this->get_service().open(this->get_implementation(), device, ec); + boost::asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a serial_port. + /** + * This constructor creates and opens a serial port for the specified device + * name. + * + * @param io_context The io_context object that the serial port will use to + * dispatch handlers for any asynchronous operations performed on the port. + * + * @param device The platform-specific device name for this serial + * port. + */ + explicit serial_port(boost::asio::io_context& io_context, + const std::string& device) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) + { + boost::system::error_code ec; + this->get_service().open(this->get_implementation(), device, ec); + boost::asio::detail::throw_error(ec, "open"); + } + + /// Construct a serial_port on an existing native serial port. + /** + * This constructor creates a serial port object to hold an existing native + * serial port. + * + * @param io_context The io_context object that the serial port will use to + * dispatch handlers for any asynchronous operations performed on the port. + * + * @param native_serial_port A native serial port. + * + * @throws boost::system::system_error Thrown on failure. + */ + serial_port(boost::asio::io_context& io_context, + const native_handle_type& native_serial_port) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) + { + boost::system::error_code ec; + this->get_service().assign(this->get_implementation(), + native_serial_port, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a serial_port from another. + /** + * This constructor moves a serial port from one object to another. + * + * @param other The other serial_port object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c serial_port(io_context&) constructor. + */ + serial_port(serial_port&& other) + : basic_io_object<BOOST_ASIO_SVC_T>(std::move(other)) + { + } + + /// Move-assign a serial_port from another. + /** + * This assignment operator moves a serial port from one object to another. + * + * @param other The other serial_port object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c serial_port(io_context&) constructor. + */ + serial_port& operator=(serial_port&& other) + { + basic_io_object<BOOST_ASIO_SVC_T>::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the serial port. + /** + * This function destroys the serial port, cancelling any outstanding + * asynchronous wait operations associated with the serial port as if by + * calling @c cancel. + */ + ~serial_port() + { + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_context() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_service() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_service(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_executor(); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since a serial_port cannot contain any further layers, it simply + * returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since a serial_port cannot contain any further layers, it simply + * returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + + /// Open the serial port using the specified device name. + /** + * This function opens the serial port for the specified device name. + * + * @param device The platform-specific device name. + * + * @throws boost::system::system_error Thrown on failure. + */ + void open(const std::string& device) + { + boost::system::error_code ec; + this->get_service().open(this->get_implementation(), device, ec); + boost::asio::detail::throw_error(ec, "open"); + } + + /// Open the serial port using the specified device name. + /** + * This function opens the serial port using the given platform-specific + * device name. + * + * @param device The platform-specific device name. + * + * @param ec Set the indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID open(const std::string& device, + boost::system::error_code& ec) + { + this->get_service().open(this->get_implementation(), device, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Assign an existing native serial port to the serial port. + /* + * This function opens the serial port to hold an existing native serial port. + * + * @param native_serial_port A native serial port. + * + * @throws boost::system::system_error Thrown on failure. + */ + void assign(const native_handle_type& native_serial_port) + { + boost::system::error_code ec; + this->get_service().assign(this->get_implementation(), + native_serial_port, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native serial port to the serial port. + /* + * This function opens the serial port to hold an existing native serial port. + * + * @param native_serial_port A native serial port. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& native_serial_port, + boost::system::error_code& ec) + { + this->get_service().assign(this->get_implementation(), + native_serial_port, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the serial port is open. + bool is_open() const + { + return this->get_service().is_open(this->get_implementation()); + } + + /// Close the serial port. + /** + * This function is used to close the serial port. Any asynchronous read or + * write operations will be cancelled immediately, and will complete with the + * boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. + */ + void close() + { + boost::system::error_code ec; + this->get_service().close(this->get_implementation(), ec); + boost::asio::detail::throw_error(ec, "close"); + } + + /// Close the serial port. + /** + * This function is used to close the serial port. Any asynchronous read or + * write operations will be cancelled immediately, and will complete with the + * boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) + { + this->get_service().close(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get the native serial port representation. + /** + * This function may be used to obtain the underlying representation of the + * serial port. This is intended to allow access to native serial port + * functionality that is not otherwise provided. + */ + native_handle_type native_handle() + { + return this->get_service().native_handle(this->get_implementation()); + } + + /// Cancel all asynchronous operations associated with the serial port. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. + */ + void cancel() + { + boost::system::error_code ec; + this->get_service().cancel(this->get_implementation(), ec); + boost::asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the serial port. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) + { + this->get_service().cancel(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Send a break sequence to the serial port. + /** + * This function causes a break sequence of platform-specific duration to be + * sent out the serial port. + * + * @throws boost::system::system_error Thrown on failure. + */ + void send_break() + { + boost::system::error_code ec; + this->get_service().send_break(this->get_implementation(), ec); + boost::asio::detail::throw_error(ec, "send_break"); + } + + /// Send a break sequence to the serial port. + /** + * This function causes a break sequence of platform-specific duration to be + * sent out the serial port. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID send_break(boost::system::error_code& ec) + { + this->get_service().send_break(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Set an option on the serial port. + /** + * This function is used to set an option on the serial port. + * + * @param option The option value to be set on the serial port. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa SettableSerialPortOption @n + * boost::asio::serial_port_base::baud_rate @n + * boost::asio::serial_port_base::flow_control @n + * boost::asio::serial_port_base::parity @n + * boost::asio::serial_port_base::stop_bits @n + * boost::asio::serial_port_base::character_size + */ + template <typename SettableSerialPortOption> + void set_option(const SettableSerialPortOption& option) + { + boost::system::error_code ec; + this->get_service().set_option(this->get_implementation(), option, ec); + boost::asio::detail::throw_error(ec, "set_option"); + } + + /// Set an option on the serial port. + /** + * This function is used to set an option on the serial port. + * + * @param option The option value to be set on the serial port. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa SettableSerialPortOption @n + * boost::asio::serial_port_base::baud_rate @n + * boost::asio::serial_port_base::flow_control @n + * boost::asio::serial_port_base::parity @n + * boost::asio::serial_port_base::stop_bits @n + * boost::asio::serial_port_base::character_size + */ + template <typename SettableSerialPortOption> + BOOST_ASIO_SYNC_OP_VOID set_option(const SettableSerialPortOption& option, + boost::system::error_code& ec) + { + this->get_service().set_option(this->get_implementation(), option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get an option from the serial port. + /** + * This function is used to get the current value of an option on the serial + * port. + * + * @param option The option value to be obtained from the serial port. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa GettableSerialPortOption @n + * boost::asio::serial_port_base::baud_rate @n + * boost::asio::serial_port_base::flow_control @n + * boost::asio::serial_port_base::parity @n + * boost::asio::serial_port_base::stop_bits @n + * boost::asio::serial_port_base::character_size + */ + template <typename GettableSerialPortOption> + void get_option(GettableSerialPortOption& option) + { + boost::system::error_code ec; + this->get_service().get_option(this->get_implementation(), option, ec); + boost::asio::detail::throw_error(ec, "get_option"); + } + + /// Get an option from the serial port. + /** + * This function is used to get the current value of an option on the serial + * port. + * + * @param option The option value to be obtained from the serial port. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa GettableSerialPortOption @n + * boost::asio::serial_port_base::baud_rate @n + * boost::asio::serial_port_base::flow_control @n + * boost::asio::serial_port_base::parity @n + * boost::asio::serial_port_base::stop_bits @n + * boost::asio::serial_port_base::character_size + */ + template <typename GettableSerialPortOption> + BOOST_ASIO_SYNC_OP_VOID get_option(GettableSerialPortOption& option, + boost::system::error_code& ec) + { + this->get_service().get_option(this->get_implementation(), option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Write some data to the serial port. + /** + * This function is used to write data to the serial port. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the serial port. + * + * @returns The number of bytes written. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * serial_port.write_some(boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename ConstBufferSequence> + std::size_t write_some(const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->get_service().write_some( + this->get_implementation(), buffers, ec); + boost::asio::detail::throw_error(ec, "write_some"); + return s; + } + + /// Write some data to the serial port. + /** + * This function is used to write data to the serial port. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the serial port. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + */ + template <typename ConstBufferSequence> + std::size_t write_some(const ConstBufferSequence& buffers, + boost::system::error_code& ec) + { + return this->get_service().write_some( + this->get_implementation(), buffers, ec); + } + + /// Start an asynchronous write. + /** + * This function is used to asynchronously write data to the serial port. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be written to the serial port. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @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 + * boost::asio::io_context::post(). + * + * @note The write operation may not transmit all of the data to the peer. + * Consider using the @ref async_write function if you need to ensure that all + * data is written before the asynchronous operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * serial_port.async_write_some(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename ConstBufferSequence, typename WriteHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_write_some( + this->get_implementation(), buffers, init.completion_handler); + + return init.result.get(); + } + + /// Read some data from the serial port. + /** + * This function is used to read data from the serial port. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * serial_port.read_some(boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename MutableBufferSequence> + std::size_t read_some(const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->get_service().read_some( + this->get_implementation(), buffers, ec); + boost::asio::detail::throw_error(ec, "read_some"); + return s; + } + + /// Read some data from the serial port. + /** + * This function is used to read data from the serial port. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + */ + template <typename MutableBufferSequence> + std::size_t read_some(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + { + return this->get_service().read_some( + this->get_implementation(), buffers, ec); + } + + /// Start an asynchronous read. + /** + * This function is used to asynchronously read data from the serial port. + * The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @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 + * boost::asio::io_context::post(). + * + * @note The read operation may not read all of the requested number of bytes. + * Consider using the @ref async_read function if you need to ensure that the + * requested amount of data is read before the asynchronous operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * serial_port.async_read_some(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename MutableBufferSequence, typename ReadHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_read_some( + this->get_implementation(), buffers, init.completion_handler); + + return init.result.get(); + } +}; +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } // namespace asio } // namespace boost +#include <boost/asio/detail/pop_options.hpp> + +#if !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# undef BOOST_ASIO_SVC_T +#endif // !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) diff --git a/boost/asio/serial_port_base.hpp b/boost/asio/serial_port_base.hpp index 884c7ba95d..b2a8367023 100644 --- a/boost/asio/serial_port_base.hpp +++ b/boost/asio/serial_port_base.hpp @@ -55,10 +55,10 @@ public: public: explicit baud_rate(unsigned int rate = 0); unsigned int value() const; - BOOST_ASIO_DECL boost::system::error_code store( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const; - BOOST_ASIO_DECL boost::system::error_code load( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec); private: @@ -75,10 +75,10 @@ public: enum type { none, software, hardware }; BOOST_ASIO_DECL explicit flow_control(type t = none); type value() const; - BOOST_ASIO_DECL boost::system::error_code store( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const; - BOOST_ASIO_DECL boost::system::error_code load( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec); private: @@ -95,10 +95,10 @@ public: enum type { none, odd, even }; BOOST_ASIO_DECL explicit parity(type t = none); type value() const; - BOOST_ASIO_DECL boost::system::error_code store( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const; - BOOST_ASIO_DECL boost::system::error_code load( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec); private: @@ -115,10 +115,10 @@ public: enum type { one, onepointfive, two }; BOOST_ASIO_DECL explicit stop_bits(type t = one); type value() const; - BOOST_ASIO_DECL boost::system::error_code store( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const; - BOOST_ASIO_DECL boost::system::error_code load( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec); private: @@ -134,10 +134,10 @@ public: public: BOOST_ASIO_DECL explicit character_size(unsigned int t = 8); unsigned int value() const; - BOOST_ASIO_DECL boost::system::error_code store( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const; - BOOST_ASIO_DECL boost::system::error_code load( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec); private: diff --git a/boost/asio/serial_port_service.hpp b/boost/asio/serial_port_service.hpp index 20cb288b1b..88a1f16e4a 100644 --- a/boost/asio/serial_port_service.hpp +++ b/boost/asio/serial_port_service.hpp @@ -17,6 +17,8 @@ #include <boost/asio/detail/config.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) @@ -26,7 +28,7 @@ #include <boost/asio/detail/reactive_serial_port_service.hpp> #include <boost/asio/detail/win_iocp_serial_port_service.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/serial_port_base.hpp> #include <boost/asio/detail/push_options.hpp> @@ -37,7 +39,7 @@ namespace asio { /// Default service implementation for a serial port. class serial_port_service #if defined(GENERATING_DOCUMENTATION) - : public boost::asio::io_service::service + : public boost::asio::io_context::service #else : public boost::asio::detail::service_base<serial_port_service> #endif @@ -45,7 +47,7 @@ class serial_port_service public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. - static boost::asio::io_service::id id; + static boost::asio::io_context::id id; #endif private: @@ -64,13 +66,6 @@ public: typedef service_impl_type::implementation_type implementation_type; #endif - /// (Deprecated: Use native_handle_type.) The native handle type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_type; -#else - typedef service_impl_type::native_handle_type native_type; -#endif - /// The native handle type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; @@ -78,10 +73,10 @@ public: typedef service_impl_type::native_handle_type native_handle_type; #endif - /// Construct a new serial port service for the specified io_service. - explicit serial_port_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base<serial_port_service>(io_service), - service_impl_(io_service) + /// Construct a new serial port service for the specified io_context. + explicit serial_port_service(boost::asio::io_context& io_context) + : boost::asio::detail::service_base<serial_port_service>(io_context), + service_impl_(io_context) { } @@ -115,17 +110,19 @@ public: } /// Open a serial port. - boost::system::error_code open(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID open(implementation_type& impl, const std::string& device, boost::system::error_code& ec) { - return service_impl_.open(impl, device, ec); + service_impl_.open(impl, device, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Assign an existing native handle to a serial port. - boost::system::error_code assign(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID assign(implementation_type& impl, const native_handle_type& handle, boost::system::error_code& ec) { - return service_impl_.assign(impl, handle, ec); + service_impl_.assign(impl, handle, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the handle is open. @@ -135,16 +132,11 @@ public: } /// Close a serial port implementation. - boost::system::error_code close(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID close(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.close(impl, ec); - } - - /// (Deprecated: Use native_handle().) Get the native handle implementation. - native_type native(implementation_type& impl) - { - return service_impl_.native_handle(impl); + service_impl_.close(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get the native handle implementation. @@ -154,33 +146,37 @@ public: } /// Cancel all asynchronous operations associated with the handle. - boost::system::error_code cancel(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID cancel(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.cancel(impl, ec); + service_impl_.cancel(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Set a serial port option. template <typename SettableSerialPortOption> - boost::system::error_code set_option(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID set_option(implementation_type& impl, const SettableSerialPortOption& option, boost::system::error_code& ec) { - return service_impl_.set_option(impl, option, ec); + service_impl_.set_option(impl, option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get a serial port option. template <typename GettableSerialPortOption> - boost::system::error_code get_option(const implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID get_option(const implementation_type& impl, GettableSerialPortOption& option, boost::system::error_code& ec) const { - return service_impl_.get_option(impl, option, ec); + service_impl_.get_option(impl, option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Send a break sequence to the serial port. - boost::system::error_code send_break(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID send_break(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.send_break(impl, ec); + service_impl_.send_break(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Write the given data to the stream. @@ -199,11 +195,10 @@ public: const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); - service_impl_.async_write_some(impl, buffers, init.handler); + service_impl_.async_write_some(impl, buffers, init.completion_handler); return init.result.get(); } @@ -224,20 +219,19 @@ public: const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); - service_impl_.async_read_some(impl, buffers, init.handler); + service_impl_.async_read_some(impl, buffers, init.completion_handler); return init.result.get(); } private: // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { - service_impl_.shutdown_service(); + service_impl_.shutdown(); } // The platform-specific implementation. @@ -252,4 +246,6 @@ private: #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_SERIAL_PORT_SERVICE_HPP diff --git a/boost/asio/signal_set.hpp b/boost/asio/signal_set.hpp index 422e4fca49..6d724e3fd2 100644 --- a/boost/asio/signal_set.hpp +++ b/boost/asio/signal_set.hpp @@ -16,13 +16,432 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/basic_signal_set.hpp> + +#include <boost/asio/async_result.hpp> +#include <boost/asio/basic_io_object.hpp> +#include <boost/asio/detail/handler_type_requirements.hpp> +#include <boost/asio/detail/throw_error.hpp> +#include <boost/asio/error.hpp> +#include <boost/asio/io_context.hpp> + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/basic_signal_set.hpp> +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/detail/signal_set_service.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) namespace boost { namespace asio { -/// Typedef for the typical usage of a signal set. +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +// Typedef for the typical usage of a signal set. typedef basic_signal_set<> signal_set; +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +/// Provides signal functionality. +/** + * The signal_set class provides the ability to perform an asynchronous wait + * for one or more signals to occur. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Example + * Performing an asynchronous wait: + * @code + * void handler( + * const boost::system::error_code& error, + * int signal_number) + * { + * if (!error) + * { + * // A signal occurred. + * } + * } + * + * ... + * + * // Construct a signal set registered for process termination. + * boost::asio::signal_set signals(io_context, SIGINT, SIGTERM); + * + * // Start an asynchronous wait for one of the signals to occur. + * signals.async_wait(handler); + * @endcode + * + * @par Queueing of signal notifications + * + * If a signal is registered with a signal_set, and the signal occurs when + * there are no waiting handlers, then the signal notification is queued. The + * next async_wait operation on that signal_set will dequeue the notification. + * If multiple notifications are queued, subsequent async_wait operations + * dequeue them one at a time. Signal notifications are dequeued in order of + * ascending signal number. + * + * If a signal number is removed from a signal_set (using the @c remove or @c + * erase member functions) then any queued notifications for that signal are + * discarded. + * + * @par Multiple registration of signals + * + * The same signal number may be registered with different signal_set objects. + * When the signal occurs, one handler is called for each signal_set object. + * + * Note that multiple registration only works for signals that are registered + * using Asio. The application must not also register a signal handler using + * functions such as @c signal() or @c sigaction(). + * + * @par Signal masking on POSIX platforms + * + * POSIX allows signals to be blocked using functions such as @c sigprocmask() + * and @c pthread_sigmask(). For signals to be delivered, programs must ensure + * that any signals registered using signal_set objects are unblocked in at + * least one thread. + */ +class signal_set + : BOOST_ASIO_SVC_ACCESS basic_io_object<detail::signal_set_service> +{ +public: + /// The type of the executor associated with the object. + typedef io_context::executor_type executor_type; + + /// Construct a signal set without adding any signals. + /** + * This constructor creates a signal set without registering for any signals. + * + * @param io_context The io_context object that the signal set will use to + * dispatch handlers for any asynchronous operations performed on the set. + */ + explicit signal_set(boost::asio::io_context& io_context) + : basic_io_object<detail::signal_set_service>(io_context) + { + } + + /// Construct a signal set and add one signal. + /** + * This constructor creates a signal set and registers for one signal. + * + * @param io_context The io_context object that the signal set will use to + * dispatch handlers for any asynchronous operations performed on the set. + * + * @param signal_number_1 The signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code boost::asio::signal_set signals(io_context); + * signals.add(signal_number_1); @endcode + */ + signal_set(boost::asio::io_context& io_context, int signal_number_1) + : basic_io_object<detail::signal_set_service>(io_context) + { + boost::system::error_code ec; + this->get_service().add(this->get_implementation(), signal_number_1, ec); + boost::asio::detail::throw_error(ec, "add"); + } + + /// Construct a signal set and add two signals. + /** + * This constructor creates a signal set and registers for two signals. + * + * @param io_context The io_context object that the signal set will use to + * dispatch handlers for any asynchronous operations performed on the set. + * + * @param signal_number_1 The first signal number to be added. + * + * @param signal_number_2 The second signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code boost::asio::signal_set signals(io_context); + * signals.add(signal_number_1); + * signals.add(signal_number_2); @endcode + */ + signal_set(boost::asio::io_context& io_context, int signal_number_1, + int signal_number_2) + : basic_io_object<detail::signal_set_service>(io_context) + { + boost::system::error_code ec; + this->get_service().add(this->get_implementation(), signal_number_1, ec); + boost::asio::detail::throw_error(ec, "add"); + this->get_service().add(this->get_implementation(), signal_number_2, ec); + boost::asio::detail::throw_error(ec, "add"); + } + + /// Construct a signal set and add three signals. + /** + * This constructor creates a signal set and registers for three signals. + * + * @param io_context The io_context object that the signal set will use to + * dispatch handlers for any asynchronous operations performed on the set. + * + * @param signal_number_1 The first signal number to be added. + * + * @param signal_number_2 The second signal number to be added. + * + * @param signal_number_3 The third signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code boost::asio::signal_set signals(io_context); + * signals.add(signal_number_1); + * signals.add(signal_number_2); + * signals.add(signal_number_3); @endcode + */ + signal_set(boost::asio::io_context& io_context, int signal_number_1, + int signal_number_2, int signal_number_3) + : basic_io_object<detail::signal_set_service>(io_context) + { + boost::system::error_code ec; + this->get_service().add(this->get_implementation(), signal_number_1, ec); + boost::asio::detail::throw_error(ec, "add"); + this->get_service().add(this->get_implementation(), signal_number_2, ec); + boost::asio::detail::throw_error(ec, "add"); + this->get_service().add(this->get_implementation(), signal_number_3, ec); + boost::asio::detail::throw_error(ec, "add"); + } + + /// Destroys the signal set. + /** + * This function destroys the signal set, cancelling any outstanding + * asynchronous wait operations associated with the signal set as if by + * calling @c cancel. + */ + ~signal_set() + { + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_context() + { + return basic_io_object<detail::signal_set_service>::get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_service() + { + return basic_io_object<detail::signal_set_service>::get_io_service(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return basic_io_object<detail::signal_set_service>::get_executor(); + } + + /// Add a signal to a signal_set. + /** + * This function adds the specified signal to the set. It has no effect if the + * signal is already in the set. + * + * @param signal_number The signal to be added to the set. + * + * @throws boost::system::system_error Thrown on failure. + */ + void add(int signal_number) + { + boost::system::error_code ec; + this->get_service().add(this->get_implementation(), signal_number, ec); + boost::asio::detail::throw_error(ec, "add"); + } + + /// Add a signal to a signal_set. + /** + * This function adds the specified signal to the set. It has no effect if the + * signal is already in the set. + * + * @param signal_number The signal to be added to the set. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID add(int signal_number, + boost::system::error_code& ec) + { + this->get_service().add(this->get_implementation(), signal_number, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Remove a signal from a signal_set. + /** + * This function removes the specified signal from the set. It has no effect + * if the signal is not in the set. + * + * @param signal_number The signal to be removed from the set. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note Removes any notifications that have been queued for the specified + * signal number. + */ + void remove(int signal_number) + { + boost::system::error_code ec; + this->get_service().remove(this->get_implementation(), signal_number, ec); + boost::asio::detail::throw_error(ec, "remove"); + } + + /// Remove a signal from a signal_set. + /** + * This function removes the specified signal from the set. It has no effect + * if the signal is not in the set. + * + * @param signal_number The signal to be removed from the set. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Removes any notifications that have been queued for the specified + * signal number. + */ + BOOST_ASIO_SYNC_OP_VOID remove(int signal_number, + boost::system::error_code& ec) + { + this->get_service().remove(this->get_implementation(), signal_number, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Remove all signals from a signal_set. + /** + * This function removes all signals from the set. It has no effect if the set + * is already empty. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note Removes all queued notifications. + */ + void clear() + { + boost::system::error_code ec; + this->get_service().clear(this->get_implementation(), ec); + boost::asio::detail::throw_error(ec, "clear"); + } + + /// Remove all signals from a signal_set. + /** + * This function removes all signals from the set. It has no effect if the set + * is already empty. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Removes all queued notifications. + */ + BOOST_ASIO_SYNC_OP_VOID clear(boost::system::error_code& ec) + { + this->get_service().clear(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Cancel all operations associated with the signal set. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the signal set. The handler for each cancelled + * operation will be invoked with the boost::asio::error::operation_aborted + * error code. + * + * Cancellation does not alter the set of registered signals. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note If a registered signal occurred before cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + void cancel() + { + boost::system::error_code ec; + this->get_service().cancel(this->get_implementation(), ec); + boost::asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all operations associated with the signal set. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the signal set. The handler for each cancelled + * operation will be invoked with the boost::asio::error::operation_aborted + * error code. + * + * Cancellation does not alter the set of registered signals. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note If a registered signal occurred before cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) + { + this->get_service().cancel(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Start an asynchronous operation to wait for a signal to be delivered. + /** + * This function may be used to initiate an asynchronous wait against the + * signal set. It always returns immediately. + * + * For each call to async_wait(), the supplied handler will be called exactly + * once. The handler will be called when: + * + * @li One of the registered signals in the signal set occurs; or + * + * @li The signal set was cancelled, in which case the handler is passed the + * error code boost::asio::error::operation_aborted. + * + * @param handler The handler to be called when the signal occurs. Copies + * will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * int signal_number // Indicates which signal occurred. + * ); @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 + * boost::asio::io_context::post(). + */ + template <typename SignalHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(SignalHandler, + void (boost::system::error_code, int)) + async_wait(BOOST_ASIO_MOVE_ARG(SignalHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a SignalHandler. + BOOST_ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check; + + async_completion<SignalHandler, + void (boost::system::error_code, int)> init(handler); + + this->get_service().async_wait(this->get_implementation(), + init.completion_handler); + + return init.result.get(); + } +}; +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } // namespace asio } // namespace boost diff --git a/boost/asio/signal_set_service.hpp b/boost/asio/signal_set_service.hpp index 632eaf0aca..705b32cc42 100644 --- a/boost/asio/signal_set_service.hpp +++ b/boost/asio/signal_set_service.hpp @@ -16,10 +16,13 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #include <boost/asio/async_result.hpp> #include <boost/asio/detail/signal_set_service.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -29,7 +32,7 @@ namespace asio { /// Default service implementation for a signal set. class signal_set_service #if defined(GENERATING_DOCUMENTATION) - : public boost::asio::io_service::service + : public boost::asio::io_context::service #else : public boost::asio::detail::service_base<signal_set_service> #endif @@ -37,7 +40,7 @@ class signal_set_service public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. - static boost::asio::io_service::id id; + static boost::asio::io_context::id id; #endif public: @@ -48,10 +51,10 @@ public: typedef detail::signal_set_service::implementation_type implementation_type; #endif - /// Construct a new signal set service for the specified io_service. - explicit signal_set_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base<signal_set_service>(io_service), - service_impl_(io_service) + /// Construct a new signal set service for the specified io_context. + explicit signal_set_service(boost::asio::io_context& io_context) + : boost::asio::detail::service_base<signal_set_service>(io_context), + service_impl_(io_context) { } @@ -68,31 +71,35 @@ public: } /// Add a signal to a signal_set. - boost::system::error_code add(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID add(implementation_type& impl, int signal_number, boost::system::error_code& ec) { - return service_impl_.add(impl, signal_number, ec); + service_impl_.add(impl, signal_number, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Remove a signal to a signal_set. - boost::system::error_code remove(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID remove(implementation_type& impl, int signal_number, boost::system::error_code& ec) { - return service_impl_.remove(impl, signal_number, ec); + service_impl_.remove(impl, signal_number, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Remove all signals from a signal_set. - boost::system::error_code clear(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID clear(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.clear(impl, ec); + service_impl_.clear(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Cancel all operations associated with the signal set. - boost::system::error_code cancel(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID cancel(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.cancel(impl, ec); + service_impl_.cancel(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } // Start an asynchronous operation to wait for a signal to be delivered. @@ -102,26 +109,25 @@ public: async_wait(implementation_type& impl, BOOST_ASIO_MOVE_ARG(SignalHandler) handler) { - detail::async_result_init< - SignalHandler, void (boost::system::error_code, int)> init( - BOOST_ASIO_MOVE_CAST(SignalHandler)(handler)); + async_completion<SignalHandler, + void (boost::system::error_code, int)> init(handler); - service_impl_.async_wait(impl, init.handler); + service_impl_.async_wait(impl, init.completion_handler); return init.result.get(); } private: // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { - service_impl_.shutdown_service(); + service_impl_.shutdown(); } // Perform any fork-related housekeeping. - void fork_service(boost::asio::io_service::fork_event event) + void notify_fork(boost::asio::io_context::fork_event event) { - service_impl_.fork_service(event); + service_impl_.notify_fork(event); } // The platform-specific implementation. @@ -133,4 +139,6 @@ private: #include <boost/asio/detail/pop_options.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_SIGNAL_SET_SERVICE_HPP diff --git a/boost/asio/socket_acceptor_service.hpp b/boost/asio/socket_acceptor_service.hpp index e00c76c901..34adc178df 100644 --- a/boost/asio/socket_acceptor_service.hpp +++ b/boost/asio/socket_acceptor_service.hpp @@ -16,10 +16,13 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #include <boost/asio/basic_socket.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/null_socket_service.hpp> @@ -38,7 +41,7 @@ namespace asio { template <typename Protocol> class socket_acceptor_service #if defined(GENERATING_DOCUMENTATION) - : public boost::asio::io_service::service + : public boost::asio::io_context::service #else : public boost::asio::detail::service_base<socket_acceptor_service<Protocol> > #endif @@ -46,7 +49,7 @@ class socket_acceptor_service public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. - static boost::asio::io_service::id id; + static boost::asio::io_context::id id; #endif /// The protocol type. @@ -73,13 +76,6 @@ public: typedef typename service_impl_type::implementation_type implementation_type; #endif - /// (Deprecated: Use native_handle_type.) The native acceptor type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_type; -#else - typedef typename service_impl_type::native_handle_type native_type; -#endif - /// The native acceptor type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; @@ -87,11 +83,11 @@ public: typedef typename service_impl_type::native_handle_type native_handle_type; #endif - /// Construct a new socket acceptor service for the specified io_service. - explicit socket_acceptor_service(boost::asio::io_service& io_service) + /// Construct a new socket acceptor service for the specified io_context. + explicit socket_acceptor_service(boost::asio::io_context& io_context) : boost::asio::detail::service_base< - socket_acceptor_service<Protocol> >(io_service), - service_impl_(io_service) + socket_acceptor_service<Protocol> >(io_context), + service_impl_(io_context) { } @@ -142,18 +138,20 @@ public: } /// Open a new socket acceptor implementation. - boost::system::error_code open(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID open(implementation_type& impl, const protocol_type& protocol, boost::system::error_code& ec) { - return service_impl_.open(impl, protocol, ec); + service_impl_.open(impl, protocol, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Assign an existing native acceptor to a socket acceptor. - boost::system::error_code assign(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID assign(implementation_type& impl, const protocol_type& protocol, const native_handle_type& native_acceptor, boost::system::error_code& ec) { - return service_impl_.assign(impl, protocol, native_acceptor, ec); + service_impl_.assign(impl, protocol, native_acceptor, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the acceptor is open. @@ -163,38 +161,43 @@ public: } /// Cancel all asynchronous operations associated with the acceptor. - boost::system::error_code cancel(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID cancel(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.cancel(impl, ec); + service_impl_.cancel(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Bind the socket acceptor to the specified local endpoint. - boost::system::error_code bind(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID bind(implementation_type& impl, const endpoint_type& endpoint, boost::system::error_code& ec) { - return service_impl_.bind(impl, endpoint, ec); + service_impl_.bind(impl, endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Place the socket acceptor into the state where it will listen for new /// connections. - boost::system::error_code listen(implementation_type& impl, int backlog, + BOOST_ASIO_SYNC_OP_VOID listen(implementation_type& impl, int backlog, boost::system::error_code& ec) { - return service_impl_.listen(impl, backlog, ec); + service_impl_.listen(impl, backlog, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Close a socket acceptor implementation. - boost::system::error_code close(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID close(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.close(impl, ec); + service_impl_.close(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } - /// (Deprecated: Use native_handle().) Get the native acceptor implementation. - native_type native(implementation_type& impl) + /// Release ownership of the underlying acceptor. + native_handle_type release(implementation_type& impl, + boost::system::error_code& ec) { - return service_impl_.native_handle(impl); + return service_impl_.release(impl, ec); } /// Get the native acceptor implementation. @@ -205,26 +208,29 @@ public: /// Set a socket option. template <typename SettableSocketOption> - boost::system::error_code set_option(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID set_option(implementation_type& impl, const SettableSocketOption& option, boost::system::error_code& ec) { - return service_impl_.set_option(impl, option, ec); + service_impl_.set_option(impl, option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get a socket option. template <typename GettableSocketOption> - boost::system::error_code get_option(const implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID get_option(const implementation_type& impl, GettableSocketOption& option, boost::system::error_code& ec) const { - return service_impl_.get_option(impl, option, ec); + service_impl_.get_option(impl, option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Perform an IO control command on the socket. template <typename IoControlCommand> - boost::system::error_code io_control(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID io_control(implementation_type& impl, IoControlCommand& command, boost::system::error_code& ec) { - return service_impl_.io_control(impl, command, ec); + service_impl_.io_control(impl, command, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the acceptor. @@ -234,10 +240,11 @@ public: } /// Sets the non-blocking mode of the acceptor. - boost::system::error_code non_blocking(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID non_blocking(implementation_type& impl, bool mode, boost::system::error_code& ec) { - return service_impl_.non_blocking(impl, mode, ec); + service_impl_.non_blocking(impl, mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the native acceptor implementation. @@ -247,10 +254,11 @@ public: } /// Sets the non-blocking mode of the native acceptor implementation. - boost::system::error_code native_non_blocking(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID native_non_blocking(implementation_type& impl, bool mode, boost::system::error_code& ec) { - return service_impl_.native_non_blocking(impl, mode, ec); + service_impl_.native_non_blocking(impl, mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get the local endpoint. @@ -260,15 +268,51 @@ public: return service_impl_.local_endpoint(impl, ec); } + /// Wait for the acceptor to become ready to read, ready to write, or to have + /// pending error conditions. + BOOST_ASIO_SYNC_OP_VOID wait(implementation_type& impl, + socket_base::wait_type w, boost::system::error_code& ec) + { + service_impl_.wait(impl, w, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Asynchronously wait for the acceptor to become ready to read, ready to + /// write, or to have pending error conditions. + template <typename WaitHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(implementation_type& impl, socket_base::wait_type w, + BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + async_completion<WaitHandler, + void (boost::system::error_code)> init(handler); + + service_impl_.async_wait(impl, w, init.completion_handler); + + return init.result.get(); + } + /// Accept a new connection. template <typename Protocol1, typename SocketService> - boost::system::error_code accept(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID accept(implementation_type& impl, basic_socket<Protocol1, SocketService>& peer, endpoint_type* peer_endpoint, boost::system::error_code& ec, typename enable_if<is_convertible<Protocol, Protocol1>::value>::type* = 0) { - return service_impl_.accept(impl, peer, peer_endpoint, ec); + service_impl_.accept(impl, peer, peer_endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Accept a new connection. + typename Protocol::socket accept(implementation_type& impl, + io_context* peer_io_context, endpoint_type* peer_endpoint, + boost::system::error_code& ec) + { + return service_impl_.accept(impl, peer_io_context, peer_endpoint, ec); } +#endif // defined(BOOST_ASIO_HAS_MOVE) /// Start an asynchronous accept. template <typename Protocol1, typename SocketService, typename AcceptHandler> @@ -280,20 +324,40 @@ public: BOOST_ASIO_MOVE_ARG(AcceptHandler) handler, typename enable_if<is_convertible<Protocol, Protocol1>::value>::type* = 0) { - detail::async_result_init< - AcceptHandler, void (boost::system::error_code)> init( - BOOST_ASIO_MOVE_CAST(AcceptHandler)(handler)); + async_completion<AcceptHandler, + void (boost::system::error_code)> init(handler); + + service_impl_.async_accept(impl, + peer, peer_endpoint, init.completion_handler); + + return init.result.get(); + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Start an asynchronous accept. + template <typename MoveAcceptHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + void (boost::system::error_code, typename Protocol::socket)) + async_accept(implementation_type& impl, + boost::asio::io_context* peer_io_context, endpoint_type* peer_endpoint, + BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler) + { + async_completion<MoveAcceptHandler, + void (boost::system::error_code, + typename Protocol::socket)> init(handler); - service_impl_.async_accept(impl, peer, peer_endpoint, init.handler); + service_impl_.async_accept(impl, + peer_io_context, peer_endpoint, init.completion_handler); return init.result.get(); } +#endif // defined(BOOST_ASIO_HAS_MOVE) private: // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { - service_impl_.shutdown_service(); + service_impl_.shutdown(); } // The platform-specific implementation. @@ -305,4 +369,6 @@ private: #include <boost/asio/detail/pop_options.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_SOCKET_ACCEPTOR_SERVICE_HPP diff --git a/boost/asio/socket_base.hpp b/boost/asio/socket_base.hpp index 7adbf5abfd..9c7518e68e 100644 --- a/boost/asio/socket_base.hpp +++ b/boost/asio/socket_base.hpp @@ -76,6 +76,22 @@ public: message_end_of_record = BOOST_ASIO_OS_DEF(MSG_EOR)); #endif + /// Wait types. + /** + * For use with basic_socket::wait() and basic_socket::async_wait(). + */ + enum wait_type + { + /// Wait for a socket to become ready to read. + wait_read, + + /// Wait for a socket to become ready to write. + wait_write, + + /// Wait for a socket to have error conditions pending. + wait_error + }; + /// Socket option to permit sending of broadcast messages. /** * Implements the SOL_SOCKET/SO_BROADCAST socket option. @@ -83,7 +99,7 @@ public: * @par Examples * Setting the option: * @code - * boost::asio::ip::udp::socket socket(io_service); + * boost::asio::ip::udp::socket socket(io_context); * ... * boost::asio::socket_base::broadcast option(true); * socket.set_option(option); @@ -92,7 +108,7 @@ public: * @par * Getting the current option value: * @code - * boost::asio::ip::udp::socket socket(io_service); + * boost::asio::ip::udp::socket socket(io_context); * ... * boost::asio::socket_base::broadcast option; * socket.get_option(option); @@ -117,7 +133,7 @@ public: * @par Examples * Setting the option: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::socket_base::debug option(true); * socket.set_option(option); @@ -126,7 +142,7 @@ public: * @par * Getting the current option value: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::socket_base::debug option; * socket.get_option(option); @@ -150,7 +166,7 @@ public: * @par Examples * Setting the option: * @code - * boost::asio::ip::udp::socket socket(io_service); + * boost::asio::ip::udp::socket socket(io_context); * ... * boost::asio::socket_base::do_not_route option(true); * socket.set_option(option); @@ -159,7 +175,7 @@ public: * @par * Getting the current option value: * @code - * boost::asio::ip::udp::socket socket(io_service); + * boost::asio::ip::udp::socket socket(io_context); * ... * boost::asio::socket_base::do_not_route option; * socket.get_option(option); @@ -184,7 +200,7 @@ public: * @par Examples * Setting the option: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::socket_base::keep_alive option(true); * socket.set_option(option); @@ -193,7 +209,7 @@ public: * @par * Getting the current option value: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::socket_base::keep_alive option; * socket.get_option(option); @@ -217,7 +233,7 @@ public: * @par Examples * Setting the option: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::socket_base::send_buffer_size option(8192); * socket.set_option(option); @@ -226,7 +242,7 @@ public: * @par * Getting the current option value: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::socket_base::send_buffer_size option; * socket.get_option(option); @@ -251,7 +267,7 @@ public: * @par Examples * Setting the option: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::socket_base::send_low_watermark option(1024); * socket.set_option(option); @@ -260,7 +276,7 @@ public: * @par * Getting the current option value: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::socket_base::send_low_watermark option; * socket.get_option(option); @@ -285,7 +301,7 @@ public: * @par Examples * Setting the option: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::socket_base::receive_buffer_size option(8192); * socket.set_option(option); @@ -294,7 +310,7 @@ public: * @par * Getting the current option value: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::socket_base::receive_buffer_size option; * socket.get_option(option); @@ -319,7 +335,7 @@ public: * @par Examples * Setting the option: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::socket_base::receive_low_watermark option(1024); * socket.set_option(option); @@ -328,7 +344,7 @@ public: * @par * Getting the current option value: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::socket_base::receive_low_watermark option; * socket.get_option(option); @@ -354,7 +370,7 @@ public: * @par Examples * Setting the option: * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... * boost::asio::socket_base::reuse_address option(true); * acceptor.set_option(option); @@ -363,7 +379,7 @@ public: * @par * Getting the current option value: * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... * boost::asio::socket_base::reuse_address option; * acceptor.get_option(option); @@ -389,7 +405,7 @@ public: * @par Examples * Setting the option: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::socket_base::linger option(true, 30); * socket.set_option(option); @@ -398,7 +414,7 @@ public: * @par * Getting the current option value: * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::socket_base::linger option; * socket.get_option(option); @@ -417,6 +433,40 @@ public: linger; #endif + /// Socket option for putting received out-of-band data inline. + /** + * Implements the SOL_SOCKET/SO_OOBINLINE socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::tcp::socket socket(io_context); + * ... + * boost::asio::socket_base::out_of_band_inline option(true); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::tcp::socket socket(io_context); + * ... + * boost::asio::socket_base::out_of_band_inline option; + * socket.get_option(option); + * bool value = option.value(); + * @endcode + * + * @par Concepts: + * Socket_Option, Boolean_Socket_Option. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined out_of_band_inline; +#else + typedef boost::asio::detail::socket_option::boolean< + BOOST_ASIO_OS_DEF(SOL_SOCKET), BOOST_ASIO_OS_DEF(SO_OOBINLINE)> + out_of_band_inline; +#endif + /// Socket option to report aborted connections on accept. /** * Implements a custom socket option that determines whether or not an accept @@ -426,7 +476,7 @@ public: * @par Examples * Setting the option: * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... * boost::asio::socket_base::enable_connection_aborted option(true); * acceptor.set_option(option); @@ -435,7 +485,7 @@ public: * @par * Getting the current option value: * @code - * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::acceptor acceptor(io_context); * ... * boost::asio::socket_base::enable_connection_aborted option; * acceptor.get_option(option); @@ -454,28 +504,6 @@ public: enable_connection_aborted; #endif - /// (Deprecated: Use non_blocking().) IO control command to - /// set the blocking mode of the socket. - /** - * Implements the FIONBIO IO control command. - * - * @par Example - * @code - * boost::asio::ip::tcp::socket socket(io_service); - * ... - * boost::asio::socket_base::non_blocking_io command(true); - * socket.io_control(command); - * @endcode - * - * @par Concepts: - * IO_Control_Command, Boolean_IO_Control_Command. - */ -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined non_blocking_io; -#else - typedef boost::asio::detail::io_control::non_blocking_io non_blocking_io; -#endif - /// IO control command to get the amount of data that can be read without /// blocking. /** @@ -483,7 +511,7 @@ public: * * @par Example * @code - * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::socket socket(io_context); * ... * boost::asio::socket_base::bytes_readable command(true); * socket.io_control(command); @@ -501,11 +529,22 @@ public: /// The maximum length of the queue of pending incoming connections. #if defined(GENERATING_DOCUMENTATION) + static const int max_listen_connections = implementation_defined; +#else + BOOST_ASIO_STATIC_CONSTANT(int, max_listen_connections + = BOOST_ASIO_OS_DEF(SOMAXCONN)); +#endif + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use max_listen_connections.) The maximum length of the queue + /// of pending incoming connections. +#if defined(GENERATING_DOCUMENTATION) static const int max_connections = implementation_defined; #else BOOST_ASIO_STATIC_CONSTANT(int, max_connections = BOOST_ASIO_OS_DEF(SOMAXCONN)); #endif +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) protected: /// Protected destructor to prevent deletion through this type. diff --git a/boost/asio/spawn.hpp b/boost/asio/spawn.hpp index 966bd3efcc..093b4ec350 100644 --- a/boost/asio/spawn.hpp +++ b/boost/asio/spawn.hpp @@ -17,9 +17,13 @@ #include <boost/asio/detail/config.hpp> #include <boost/coroutine/all.hpp> -#include <boost/asio/detail/weak_ptr.hpp> +#include <boost/asio/bind_executor.hpp> +#include <boost/asio/detail/memory.hpp> +#include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/wrapped_handler.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/executor.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/is_executor.hpp> #include <boost/asio/strand.hpp> #include <boost/asio/detail/push_options.hpp> @@ -95,6 +99,19 @@ public: { } + /// Construct a yield context from another yield context type. + /** + * Requires that OtherHandler be convertible to Handler. + */ + template <typename OtherHandler> + basic_yield_context(const basic_yield_context<OtherHandler>& other) + : coro_(other.coro_), + ca_(other.ca_), + handler_(other.handler_), + ec_(other.ec_) + { + } + /// Return a yield context that sets the specified error_code. /** * By default, when a yield context is used with an asynchronous operation, a @@ -126,7 +143,7 @@ private: #endif // defined(GENERATING_DOCUMENTATION) detail::weak_ptr<callee_type> coro_; caller_type& ca_; - Handler& handler_; + Handler handler_; boost::system::error_code* ec_; }; @@ -135,9 +152,7 @@ private: typedef basic_yield_context<unspecified> yield_context; #else // defined(GENERATING_DOCUMENTATION) typedef basic_yield_context< - detail::wrapped_handler< - io_service::strand, void(*)(), - detail::is_continuation_if_running> > yield_context; + executor_binder<void(*)(), executor> > yield_context; #endif // defined(GENERATING_DOCUMENTATION) /** @@ -181,6 +196,21 @@ typedef basic_yield_context< /** * This function is used to launch a new coroutine. * + * @param function The coroutine function. The function must have the signature: + * @code void function(basic_yield_context<Handler> yield); @endcode + * + * @param attributes Boost.Coroutine attributes used to customise the coroutine. + */ +template <typename Function> +void spawn(BOOST_ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes + = boost::coroutines::attributes()); + +/// Start a new stackful coroutine, calling the specified handler when it +/// completes. +/** + * This function is used to launch a new coroutine. + * * @param handler A handler to be called when the coroutine exits. More * importantly, the handler provides an execution context (via the the handler * invocation hook) for the coroutine. The handler must have the signature: @@ -195,7 +225,9 @@ template <typename Handler, typename Function> void spawn(BOOST_ASIO_MOVE_ARG(Handler) handler, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes - = boost::coroutines::attributes()); + = boost::coroutines::attributes(), + typename enable_if<!is_executor<typename decay<Handler>::type>::value && + !is_convertible<Handler&, execution_context&>::value>::type* = 0); /// Start a new stackful coroutine, inheriting the execution context of another. /** @@ -218,31 +250,49 @@ void spawn(basic_yield_context<Handler> ctx, const boost::coroutines::attributes& attributes = boost::coroutines::attributes()); -/// Start a new stackful coroutine that executes in the context of a strand. +/// Start a new stackful coroutine that executes on a given executor. /** * This function is used to launch a new coroutine. * - * @param strand Identifies a strand. By starting multiple coroutines on the - * same strand, the implementation ensures that none of those coroutines can - * execute simultaneously. + * @param ex Identifies the executor that will run the coroutine. The new + * coroutine is implicitly given its own strand within this executor. * * @param function The coroutine function. The function must have the signature: * @code void function(yield_context yield); @endcode * * @param attributes Boost.Coroutine attributes used to customise the coroutine. */ -template <typename Function> -void spawn(boost::asio::io_service::strand strand, +template <typename Function, typename Executor> +void spawn(const Executor& ex, + BOOST_ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes + = boost::coroutines::attributes(), + typename enable_if<is_executor<Executor>::value>::type* = 0); + +/// Start a new stackful coroutine that executes on a given strand. +/** + * This function is used to launch a new coroutine. + * + * @param ex Identifies the strand that will run the coroutine. + * + * @param function The coroutine function. The function must have the signature: + * @code void function(yield_context yield); @endcode + * + * @param attributes Boost.Coroutine attributes used to customise the coroutine. + */ +template <typename Function, typename Executor> +void spawn(const strand<Executor>& ex, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes()); -/// Start a new stackful coroutine that executes on a given io_service. +/// Start a new stackful coroutine that executes in the context of a strand. /** * This function is used to launch a new coroutine. * - * @param io_service Identifies the io_service that will run the coroutine. The - * new coroutine is implicitly given its own strand within this io_service. + * @param s Identifies a strand. By starting multiple coroutines on the same + * strand, the implementation ensures that none of those coroutines can execute + * simultaneously. * * @param function The coroutine function. The function must have the signature: * @code void function(yield_context yield); @endcode @@ -250,11 +300,32 @@ void spawn(boost::asio::io_service::strand strand, * @param attributes Boost.Coroutine attributes used to customise the coroutine. */ template <typename Function> -void spawn(boost::asio::io_service& io_service, +void spawn(const boost::asio::io_context::strand& s, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes()); +/// Start a new stackful coroutine that executes on a given execution context. +/** + * This function is used to launch a new coroutine. + * + * @param ctx Identifies the execution context that will run the coroutine. The + * new coroutine is implicitly given its own strand within this execution + * context. + * + * @param function The coroutine function. The function must have the signature: + * @code void function(yield_context yield); @endcode + * + * @param attributes Boost.Coroutine attributes used to customise the coroutine. + */ +template <typename Function, typename ExecutionContext> +void spawn(ExecutionContext& ctx, + BOOST_ASIO_MOVE_ARG(Function) function, + const boost::coroutines::attributes& attributes + = boost::coroutines::attributes(), + typename enable_if<is_convertible< + ExecutionContext&, execution_context&>::value>::type* = 0); + /*@}*/ } // namespace asio diff --git a/boost/asio/ssl.hpp b/boost/asio/ssl.hpp index f82bdc043d..6fc10a92f3 100644 --- a/boost/asio/ssl.hpp +++ b/boost/asio/ssl.hpp @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include <boost/asio/ssl/basic_context.hpp> #include <boost/asio/ssl/context.hpp> #include <boost/asio/ssl/context_base.hpp> -#include <boost/asio/ssl/context_service.hpp> #include <boost/asio/ssl/error.hpp> #include <boost/asio/ssl/rfc2818_verification.hpp> #include <boost/asio/ssl/stream.hpp> #include <boost/asio/ssl/stream_base.hpp> -#include <boost/asio/ssl/stream_service.hpp> #include <boost/asio/ssl/verify_context.hpp> #include <boost/asio/ssl/verify_mode.hpp> diff --git a/boost/asio/ssl/context.hpp b/boost/asio/ssl/context.hpp index 8bab40ab3e..6869c0f011 100644 --- a/boost/asio/ssl/context.hpp +++ b/boost/asio/ssl/context.hpp @@ -17,20 +17,15 @@ #include <boost/asio/detail/config.hpp> -#if defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/ssl/basic_context.hpp> -# include <boost/asio/ssl/context_service.hpp> -#else // defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <string> -# include <boost/asio/buffer.hpp> -# include <boost/asio/io_service.hpp> -# include <boost/asio/ssl/context_base.hpp> -# include <boost/asio/ssl/detail/openssl_types.hpp> -# include <boost/asio/ssl/detail/openssl_init.hpp> -# include <boost/asio/ssl/detail/password_callback.hpp> -# include <boost/asio/ssl/detail/verify_callback.hpp> -# include <boost/asio/ssl/verify_mode.hpp> -#endif // defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <string> +#include <boost/asio/buffer.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ssl/context_base.hpp> +#include <boost/asio/ssl/detail/openssl_types.hpp> +#include <boost/asio/ssl/detail/openssl_init.hpp> +#include <boost/asio/ssl/detail/password_callback.hpp> +#include <boost/asio/ssl/detail/verify_callback.hpp> +#include <boost/asio/ssl/verify_mode.hpp> #include <boost/asio/detail/push_options.hpp> @@ -38,13 +33,6 @@ namespace boost { namespace asio { namespace ssl { -#if defined(BOOST_ASIO_ENABLE_OLD_SSL) - -/// Typedef for the typical usage of context. -typedef basic_context<context_service> context; - -#else // defined(BOOST_ASIO_ENABLE_OLD_SSL) - class context : public context_base, private noncopyable @@ -53,15 +41,9 @@ public: /// The native handle type of the SSL context. typedef SSL_CTX* native_handle_type; - /// (Deprecated: Use native_handle_type.) The native type of the SSL context. - typedef SSL_CTX* impl_type; - /// Constructor. BOOST_ASIO_DECL explicit context(method m); - /// Deprecated constructor taking a reference to an io_service object. - BOOST_ASIO_DECL context(boost::asio::io_service&, method m); - #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-construct a context from another. /** @@ -101,15 +83,6 @@ public: */ BOOST_ASIO_DECL native_handle_type native_handle(); - /// (Deprecated: Use native_handle().) Get the underlying implementation in - /// the native type. - /** - * This function may be used to obtain the underlying implementation of the - * context. This is intended to allow access to context functionality that is - * not otherwise provided. - */ - BOOST_ASIO_DECL impl_type impl(); - /// Clear options on the context. /** * This function may be used to configure the SSL options used by the context. @@ -136,7 +109,7 @@ public: * * @note Calls @c SSL_CTX_clear_options. */ - BOOST_ASIO_DECL boost::system::error_code clear_options(options o, + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID clear_options(options o, boost::system::error_code& ec); /// Set options on the context. @@ -165,7 +138,7 @@ public: * * @note Calls @c SSL_CTX_set_options. */ - BOOST_ASIO_DECL boost::system::error_code set_options(options o, + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID set_options(options o, boost::system::error_code& ec); /// Set the peer verification mode. @@ -194,7 +167,7 @@ public: * * @note Calls @c SSL_CTX_set_verify. */ - BOOST_ASIO_DECL boost::system::error_code set_verify_mode( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID set_verify_mode( verify_mode v, boost::system::error_code& ec); /// Set the peer verification depth. @@ -223,7 +196,7 @@ public: * * @note Calls @c SSL_CTX_set_verify_depth. */ - BOOST_ASIO_DECL boost::system::error_code set_verify_depth( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID set_verify_depth( int depth, boost::system::error_code& ec); /// Set the callback used to verify peer certificates. @@ -266,7 +239,7 @@ public: * @note Calls @c SSL_CTX_set_verify. */ template <typename VerifyCallback> - boost::system::error_code set_verify_callback(VerifyCallback callback, + BOOST_ASIO_SYNC_OP_VOID set_verify_callback(VerifyCallback callback, boost::system::error_code& ec); /// Load a certification authority file for performing verification. @@ -295,7 +268,7 @@ public: * * @note Calls @c SSL_CTX_load_verify_locations. */ - BOOST_ASIO_DECL boost::system::error_code load_verify_file( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID load_verify_file( const std::string& filename, boost::system::error_code& ec); /// Add certification authority for performing verification. @@ -324,7 +297,7 @@ public: * * @note Calls @c SSL_CTX_get_cert_store and @c X509_STORE_add_cert. */ - BOOST_ASIO_DECL boost::system::error_code add_certificate_authority( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID add_certificate_authority( const const_buffer& ca, boost::system::error_code& ec); /// Configures the context to use the default directories for finding @@ -351,7 +324,7 @@ public: * * @note Calls @c SSL_CTX_set_default_verify_paths. */ - BOOST_ASIO_DECL boost::system::error_code set_default_verify_paths( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID set_default_verify_paths( boost::system::error_code& ec); /// Add a directory containing certificate authority files to be used for @@ -384,7 +357,7 @@ public: * * @note Calls @c SSL_CTX_load_verify_locations. */ - BOOST_ASIO_DECL boost::system::error_code add_verify_path( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID add_verify_path( const std::string& path, boost::system::error_code& ec); /// Use a certificate from a memory buffer. @@ -414,7 +387,7 @@ public: * * @note Calls @c SSL_CTX_use_certificate or SSL_CTX_use_certificate_ASN1. */ - BOOST_ASIO_DECL boost::system::error_code use_certificate( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_certificate( const const_buffer& certificate, file_format format, boost::system::error_code& ec); @@ -445,7 +418,7 @@ public: * * @note Calls @c SSL_CTX_use_certificate_file. */ - BOOST_ASIO_DECL boost::system::error_code use_certificate_file( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_certificate_file( const std::string& filename, file_format format, boost::system::error_code& ec); @@ -475,7 +448,7 @@ public: * * @note Calls @c SSL_CTX_use_certificate and SSL_CTX_add_extra_chain_cert. */ - BOOST_ASIO_DECL boost::system::error_code use_certificate_chain( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_certificate_chain( const const_buffer& chain, boost::system::error_code& ec); /// Use a certificate chain from a file. @@ -504,7 +477,7 @@ public: * * @note Calls @c SSL_CTX_use_certificate_chain_file. */ - BOOST_ASIO_DECL boost::system::error_code use_certificate_chain_file( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_certificate_chain_file( const std::string& filename, boost::system::error_code& ec); /// Use a private key from a memory buffer. @@ -534,7 +507,7 @@ public: * * @note Calls @c SSL_CTX_use_PrivateKey or SSL_CTX_use_PrivateKey_ASN1. */ - BOOST_ASIO_DECL boost::system::error_code use_private_key( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_private_key( const const_buffer& private_key, file_format format, boost::system::error_code& ec); @@ -565,7 +538,7 @@ public: * * @note Calls @c SSL_CTX_use_PrivateKey_file. */ - BOOST_ASIO_DECL boost::system::error_code use_private_key_file( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_private_key_file( const std::string& filename, file_format format, boost::system::error_code& ec); @@ -598,7 +571,7 @@ public: * * @note Calls @c SSL_CTX_use_RSAPrivateKey or SSL_CTX_use_RSAPrivateKey_ASN1. */ - BOOST_ASIO_DECL boost::system::error_code use_rsa_private_key( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_rsa_private_key( const const_buffer& private_key, file_format format, boost::system::error_code& ec); @@ -631,7 +604,7 @@ public: * * @note Calls @c SSL_CTX_use_RSAPrivateKey_file. */ - BOOST_ASIO_DECL boost::system::error_code use_rsa_private_key_file( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_rsa_private_key_file( const std::string& filename, file_format format, boost::system::error_code& ec); @@ -663,7 +636,7 @@ public: * * @note Calls @c SSL_CTX_set_tmp_dh. */ - BOOST_ASIO_DECL boost::system::error_code use_tmp_dh( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_tmp_dh( const const_buffer& dh, boost::system::error_code& ec); /// Use the specified file to obtain the temporary Diffie-Hellman parameters. @@ -692,7 +665,7 @@ public: * * @note Calls @c SSL_CTX_set_tmp_dh. */ - BOOST_ASIO_DECL boost::system::error_code use_tmp_dh_file( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_tmp_dh_file( const std::string& filename, boost::system::error_code& ec); /// Set the password callback. @@ -733,7 +706,7 @@ public: * @note Calls @c SSL_CTX_set_default_passwd_cb. */ template <typename PasswordCallback> - boost::system::error_code set_password_callback(PasswordCallback callback, + BOOST_ASIO_SYNC_OP_VOID set_password_callback(PasswordCallback callback, boost::system::error_code& ec); private: @@ -744,7 +717,7 @@ private: struct dh_cleanup; // Helper function used to set a peer certificate verification callback. - BOOST_ASIO_DECL boost::system::error_code do_set_verify_callback( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID do_set_verify_callback( detail::verify_callback_base* callback, boost::system::error_code& ec); // Callback used when the SSL implementation wants to verify a certificate. @@ -752,7 +725,7 @@ private: int preverified, X509_STORE_CTX* ctx); // Helper function used to set a password callback. - BOOST_ASIO_DECL boost::system::error_code do_set_password_callback( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID do_set_password_callback( detail::password_callback_base* callback, boost::system::error_code& ec); // Callback used when the SSL implementation wants a password. @@ -760,7 +733,7 @@ private: char* buf, int size, int purpose, void* data); // Helper function to set the temporary Diffie-Hellman parameters from a BIO. - BOOST_ASIO_DECL boost::system::error_code do_use_tmp_dh( + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID do_use_tmp_dh( BIO* bio, boost::system::error_code& ec); // Helper function to make a BIO from a memory buffer. @@ -773,8 +746,6 @@ private: boost::asio::ssl::detail::openssl_init<> init_; }; -#endif // defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace ssl } // namespace asio } // namespace boost diff --git a/boost/asio/ssl/detail/buffered_handshake_op.hpp b/boost/asio/ssl/detail/buffered_handshake_op.hpp index b40fe5d69d..926e896ae9 100644 --- a/boost/asio/ssl/detail/buffered_handshake_op.hpp +++ b/boost/asio/ssl/detail/buffered_handshake_op.hpp @@ -17,9 +17,7 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/ssl/detail/engine.hpp> -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <boost/asio/ssl/detail/engine.hpp> #include <boost/asio/detail/push_options.hpp> @@ -28,8 +26,6 @@ namespace asio { namespace ssl { namespace detail { -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) - template <typename ConstBufferSequence> class buffered_handshake_op { @@ -46,8 +42,27 @@ public: boost::system::error_code& ec, std::size_t& bytes_transferred) const { - typename ConstBufferSequence::const_iterator iter = buffers_.begin(); - typename ConstBufferSequence::const_iterator end = buffers_.end(); + return this->process(eng, ec, bytes_transferred, + boost::asio::buffer_sequence_begin(buffers_), + boost::asio::buffer_sequence_end(buffers_)); + } + + template <typename Handler> + void call_handler(Handler& handler, + const boost::system::error_code& ec, + const std::size_t& bytes_transferred) const + { + handler(ec, bytes_transferred); + } + +private: + template <typename Iterator> + engine::want process(engine& eng, + boost::system::error_code& ec, + std::size_t& bytes_transferred, + Iterator begin, Iterator end) const + { + Iterator iter = begin; std::size_t accumulated_size = 0; for (;;) @@ -63,9 +78,9 @@ public: const_buffer buffer(*iter); // Skip over any buffers which have already been consumed by the engine. - if (bytes_transferred >= accumulated_size + buffer_size(buffer)) + if (bytes_transferred >= accumulated_size + buffer.size()) { - accumulated_size += buffer_size(buffer); + accumulated_size += buffer.size(); ++iter; continue; } @@ -78,30 +93,19 @@ public: // Pass the buffer to the engine, and update the bytes transferred to // reflect the total number of bytes consumed so far. - bytes_transferred += buffer_size(buffer); + bytes_transferred += buffer.size(); buffer = eng.put_input(buffer); - bytes_transferred -= buffer_size(buffer); + bytes_transferred -= buffer.size(); break; } } } - template <typename Handler> - void call_handler(Handler& handler, - const boost::system::error_code& ec, - const std::size_t& bytes_transferred) const - { - handler(ec, bytes_transferred); - } - -private: stream_base::handshake_type type_; ConstBufferSequence buffers_; std::size_t total_buffer_size_; }; -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace detail } // namespace ssl } // namespace asio diff --git a/boost/asio/ssl/detail/engine.hpp b/boost/asio/ssl/detail/engine.hpp index f31a4a7287..bcd516dc49 100644 --- a/boost/asio/ssl/detail/engine.hpp +++ b/boost/asio/ssl/detail/engine.hpp @@ -17,14 +17,12 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/buffer.hpp> -# include <boost/asio/detail/static_mutex.hpp> -# include <boost/asio/ssl/detail/openssl_types.hpp> -# include <boost/asio/ssl/detail/verify_callback.hpp> -# include <boost/asio/ssl/stream_base.hpp> -# include <boost/asio/ssl/verify_mode.hpp> -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <boost/asio/buffer.hpp> +#include <boost/asio/detail/static_mutex.hpp> +#include <boost/asio/ssl/detail/openssl_types.hpp> +#include <boost/asio/ssl/detail/verify_callback.hpp> +#include <boost/asio/ssl/stream_base.hpp> +#include <boost/asio/ssl/verify_mode.hpp> #include <boost/asio/detail/push_options.hpp> @@ -33,8 +31,6 @@ namespace asio { namespace ssl { namespace detail { -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) - class engine { public: @@ -98,7 +94,7 @@ public: boost::system::error_code& ec, std::size_t& bytes_transferred); // Get output data to be written to the transport. - BOOST_ASIO_DECL boost::asio::mutable_buffers_1 get_output( + BOOST_ASIO_DECL boost::asio::mutable_buffer get_output( const boost::asio::mutable_buffer& data); // Put input data that was read from the transport. @@ -120,9 +116,11 @@ private: BOOST_ASIO_DECL static int verify_callback_function( int preverified, X509_STORE_CTX* ctx); +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) // The SSL_accept function may not be thread safe. This mutex is used to // protect all calls to the SSL_accept function. BOOST_ASIO_DECL static boost::asio::detail::static_mutex& accept_mutex(); +#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) // Perform one operation. Returns >= 0 on success or error, want_read if the // operation needs more input, or want_write if it needs to write some output @@ -150,8 +148,6 @@ private: BIO* ext_bio_; }; -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace detail } // namespace ssl } // namespace asio diff --git a/boost/asio/ssl/detail/handshake_op.hpp b/boost/asio/ssl/detail/handshake_op.hpp index dc61b702f0..de947520f3 100644 --- a/boost/asio/ssl/detail/handshake_op.hpp +++ b/boost/asio/ssl/detail/handshake_op.hpp @@ -17,9 +17,7 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/ssl/detail/engine.hpp> -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <boost/asio/ssl/detail/engine.hpp> #include <boost/asio/detail/push_options.hpp> @@ -28,8 +26,6 @@ namespace asio { namespace ssl { namespace detail { -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) - class handshake_op { public: @@ -58,8 +54,6 @@ private: stream_base::handshake_type type_; }; -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace detail } // namespace ssl } // namespace asio diff --git a/boost/asio/ssl/detail/impl/engine.ipp b/boost/asio/ssl/detail/impl/engine.ipp index f7d869c56d..3133f91301 100644 --- a/boost/asio/ssl/detail/impl/engine.ipp +++ b/boost/asio/ssl/detail/impl/engine.ipp @@ -17,13 +17,11 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/detail/throw_error.hpp> -# include <boost/asio/error.hpp> -# include <boost/asio/ssl/detail/engine.hpp> -# include <boost/asio/ssl/error.hpp> -# include <boost/asio/ssl/verify_context.hpp> -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <boost/asio/detail/throw_error.hpp> +#include <boost/asio/error.hpp> +#include <boost/asio/ssl/detail/engine.hpp> +#include <boost/asio/ssl/error.hpp> +#include <boost/asio/ssl/verify_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -32,8 +30,6 @@ namespace asio { namespace ssl { namespace detail { -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) - engine::engine(SSL_CTX* context) : ssl_(::SSL_new(context)) { @@ -45,7 +41,9 @@ engine::engine(SSL_CTX* context) boost::asio::detail::throw_error(ec, "engine"); } +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) accept_mutex().init(); +#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) ::SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE); ::SSL_set_mode(ssl_, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); @@ -146,37 +144,35 @@ engine::want engine::shutdown(boost::system::error_code& ec) engine::want engine::write(const boost::asio::const_buffer& data, boost::system::error_code& ec, std::size_t& bytes_transferred) { - if (boost::asio::buffer_size(data) == 0) + if (data.size() == 0) { ec = boost::system::error_code(); return engine::want_nothing; } return perform(&engine::do_write, - const_cast<void*>(boost::asio::buffer_cast<const void*>(data)), - boost::asio::buffer_size(data), ec, &bytes_transferred); + const_cast<void*>(data.data()), + data.size(), ec, &bytes_transferred); } engine::want engine::read(const boost::asio::mutable_buffer& data, boost::system::error_code& ec, std::size_t& bytes_transferred) { - if (boost::asio::buffer_size(data) == 0) + if (data.size() == 0) { ec = boost::system::error_code(); return engine::want_nothing; } - return perform(&engine::do_read, - boost::asio::buffer_cast<void*>(data), - boost::asio::buffer_size(data), ec, &bytes_transferred); + return perform(&engine::do_read, data.data(), + data.size(), ec, &bytes_transferred); } -boost::asio::mutable_buffers_1 engine::get_output( +boost::asio::mutable_buffer engine::get_output( const boost::asio::mutable_buffer& data) { int length = ::BIO_read(ext_bio_, - boost::asio::buffer_cast<void*>(data), - static_cast<int>(boost::asio::buffer_size(data))); + data.data(), static_cast<int>(data.size())); return boost::asio::buffer(data, length > 0 ? static_cast<std::size_t>(length) : 0); @@ -186,8 +182,7 @@ boost::asio::const_buffer engine::put_input( const boost::asio::const_buffer& data) { int length = ::BIO_write(ext_bio_, - boost::asio::buffer_cast<const void*>(data), - static_cast<int>(boost::asio::buffer_size(data))); + data.data(), static_cast<int>(data.size())); return boost::asio::buffer(data + (length > 0 ? static_cast<std::size_t>(length) : 0)); @@ -210,7 +205,7 @@ const boost::system::error_code& engine::map_error_code( // SSL v2 doesn't provide a protocol-level shutdown, so an eof on the // underlying transport is passed through. #if (OPENSSL_VERSION_NUMBER < 0x10100000L) - if (ssl_->version == SSL2_VERSION) + if (SSL_version(ssl_) == SSL2_VERSION) return ec; #endif // (OPENSSL_VERSION_NUMBER < 0x10100000L) @@ -223,11 +218,13 @@ const boost::system::error_code& engine::map_error_code( return ec; } +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) boost::asio::detail::static_mutex& engine::accept_mutex() { static boost::asio::detail::static_mutex mutex = BOOST_ASIO_STATIC_MUTEX_INIT; return mutex; } +#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) engine::want engine::perform(int (engine::* op)(void*, std::size_t), void* data, std::size_t length, boost::system::error_code& ec, @@ -286,7 +283,9 @@ engine::want engine::perform(int (engine::* op)(void*, std::size_t), int engine::do_accept(void*, std::size_t) { +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) boost::asio::detail::static_mutex::scoped_lock lock(accept_mutex()); +#endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) return ::SSL_accept(ssl_); } @@ -315,8 +314,6 @@ int engine::do_write(void* data, std::size_t length) length < INT_MAX ? static_cast<int>(length) : INT_MAX); } -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace detail } // namespace ssl } // namespace asio diff --git a/boost/asio/ssl/detail/impl/openssl_init.ipp b/boost/asio/ssl/detail/impl/openssl_init.ipp index 725f5a75ee..dd3dd328b5 100644 --- a/boost/asio/ssl/detail/impl/openssl_init.ipp +++ b/boost/asio/ssl/detail/impl/openssl_init.ipp @@ -79,9 +79,8 @@ public: #elif (OPENSSL_VERSION_NUMBER < 0x10100000L) ::ERR_remove_thread_state(NULL); #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) -#if !defined(SSL_OP_NO_COMPRESSION) \ - && (OPENSSL_VERSION_NUMBER >= 0x10002000L) \ - && (OPENSSL_VERSION_NUMBER < 0x10100000L) +#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) \ + && (OPENSSL_VERSION_NUMBER < 0x10100000L) ::SSL_COMP_free_compression_methods(); #endif // (OPENSSL_VERSION_NUMBER >= 0x10002000L) // && (OPENSSL_VERSION_NUMBER < 0x10100000L) diff --git a/boost/asio/ssl/detail/io.hpp b/boost/asio/ssl/detail/io.hpp index 3dbe4520ef..ec1464cce8 100644 --- a/boost/asio/ssl/detail/io.hpp +++ b/boost/asio/ssl/detail/io.hpp @@ -17,11 +17,9 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/ssl/detail/engine.hpp> -# include <boost/asio/ssl/detail/stream_core.hpp> -# include <boost/asio/write.hpp> -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <boost/asio/ssl/detail/engine.hpp> +#include <boost/asio/ssl/detail/stream_core.hpp> +#include <boost/asio/write.hpp> #include <boost/asio/detail/push_options.hpp> @@ -30,8 +28,6 @@ namespace asio { namespace ssl { namespace detail { -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) - template <typename Stream, typename Operation> std::size_t io(Stream& next_layer, stream_core& core, const Operation& op, boost::system::error_code& ec) @@ -43,7 +39,7 @@ std::size_t io(Stream& next_layer, stream_core& core, // If the input buffer is empty then we need to read some more data from // the underlying transport. - if (boost::asio::buffer_size(core.input_) == 0) + if (core.input_.size() == 0) core.input_ = boost::asio::buffer(core.input_buffer_, next_layer.read_some(core.input_buffer_, ec)); @@ -143,7 +139,7 @@ public: // If the input buffer already has data in it we can pass it to the // engine and then retry the operation immediately. - if (boost::asio::buffer_size(core_.input_) != 0) + if (core_.input_.size() != 0) { core_.input_ = core_.engine_.put_input(core_.input_); continue; @@ -153,7 +149,7 @@ public: // cannot allow more than one read operation at a time on the // underlying transport. The pending_read_ timer's expiry is set to // pos_infin if a read is in progress, and neg_infin otherwise. - if (core_.pending_read_.expires_at() == core_.neg_infin()) + if (core_.expiry(core_.pending_read_) == core_.neg_infin()) { // Prevent other read operations from being started. core_.pending_read_.expires_at(core_.pos_infin()); @@ -180,7 +176,7 @@ public: // cannot allow more than one write operation at a time on the // underlying transport. The pending_write_ timer's expiry is set to // pos_infin if a write is in progress, and neg_infin otherwise. - if (core_.pending_write_.expires_at() == core_.neg_infin()) + if (core_.expiry(core_.pending_write_) == core_.neg_infin()) { // Prevent other write operations from being started. core_.pending_write_.expires_at(core_.pos_infin()); @@ -206,7 +202,7 @@ public: // have to keep in mind that this function might be being called from // the async operation's initiating function. In this case we're not // allowed to call the handler directly. Instead, issue a zero-sized - // read so the handler runs "as-if" posted using io_service::post(). + // read so the handler runs "as-if" posted using io_context::post(). if (start) { next_layer_.async_read_some( @@ -288,7 +284,7 @@ public: Handler handler_; }; -template <typename Stream, typename Operation, typename Handler> +template <typename Stream, typename Operation, typename Handler> inline void* asio_handler_allocate(std::size_t size, io_op<Stream, Operation, Handler>* this_handler) { @@ -339,10 +335,37 @@ inline void async_io(Stream& next_layer, stream_core& core, boost::system::error_code(), 0, 1); } -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace detail } // namespace ssl + +template <typename Stream, typename Operation, + typename Handler, typename Allocator> +struct associated_allocator< + ssl::detail::io_op<Stream, Operation, Handler>, Allocator> +{ + typedef typename associated_allocator<Handler, Allocator>::type type; + + static type get(const ssl::detail::io_op<Stream, Operation, Handler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator<Handler, Allocator>::get(h.handler_, a); + } +}; + +template <typename Stream, typename Operation, + typename Handler, typename Executor> +struct associated_executor< + ssl::detail::io_op<Stream, Operation, Handler>, Executor> +{ + typedef typename associated_executor<Handler, Executor>::type type; + + static type get(const ssl::detail::io_op<Stream, Operation, Handler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor<Handler, Executor>::get(h.handler_, ex); + } +}; + } // namespace asio } // namespace boost diff --git a/boost/asio/ssl/detail/openssl_init.hpp b/boost/asio/ssl/detail/openssl_init.hpp index fd0432e589..d23febd4a6 100644 --- a/boost/asio/ssl/detail/openssl_init.hpp +++ b/boost/asio/ssl/detail/openssl_init.hpp @@ -17,8 +17,8 @@ #include <boost/asio/detail/config.hpp> #include <cstring> +#include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/noncopyable.hpp> -#include <boost/asio/detail/shared_ptr.hpp> #include <boost/asio/ssl/detail/openssl_types.hpp> #include <boost/asio/detail/push_options.hpp> diff --git a/boost/asio/ssl/detail/password_callback.hpp b/boost/asio/ssl/detail/password_callback.hpp index 5df01946ba..707670c8d4 100644 --- a/boost/asio/ssl/detail/password_callback.hpp +++ b/boost/asio/ssl/detail/password_callback.hpp @@ -17,11 +17,9 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <cstddef> -# include <string> -# include <boost/asio/ssl/context_base.hpp> -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <cstddef> +#include <string> +#include <boost/asio/ssl/context_base.hpp> #include <boost/asio/detail/push_options.hpp> @@ -30,8 +28,6 @@ namespace asio { namespace ssl { namespace detail { -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) - class password_callback_base { public: @@ -62,8 +58,6 @@ private: PasswordCallback callback_; }; -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace detail } // namespace ssl } // namespace asio diff --git a/boost/asio/ssl/detail/read_op.hpp b/boost/asio/ssl/detail/read_op.hpp index f0b5d6ddf9..d465f0ce15 100644 --- a/boost/asio/ssl/detail/read_op.hpp +++ b/boost/asio/ssl/detail/read_op.hpp @@ -17,10 +17,8 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/detail/buffer_sequence_adapter.hpp> -# include <boost/asio/ssl/detail/engine.hpp> -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <boost/asio/detail/buffer_sequence_adapter.hpp> +#include <boost/asio/ssl/detail/engine.hpp> #include <boost/asio/detail/push_options.hpp> @@ -29,8 +27,6 @@ namespace asio { namespace ssl { namespace detail { -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) - template <typename MutableBufferSequence> class read_op { @@ -63,8 +59,6 @@ private: MutableBufferSequence buffers_; }; -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace detail } // namespace ssl } // namespace asio diff --git a/boost/asio/ssl/detail/shutdown_op.hpp b/boost/asio/ssl/detail/shutdown_op.hpp index 3a3f761c08..91acc9fb2a 100644 --- a/boost/asio/ssl/detail/shutdown_op.hpp +++ b/boost/asio/ssl/detail/shutdown_op.hpp @@ -17,9 +17,7 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/ssl/detail/engine.hpp> -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <boost/asio/ssl/detail/engine.hpp> #include <boost/asio/detail/push_options.hpp> @@ -28,8 +26,6 @@ namespace asio { namespace ssl { namespace detail { -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) - class shutdown_op { public: @@ -50,8 +46,6 @@ public: } }; -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace detail } // namespace ssl } // namespace asio diff --git a/boost/asio/ssl/detail/stream_core.hpp b/boost/asio/ssl/detail/stream_core.hpp index 70d1feddbb..95993e5f4e 100644 --- a/boost/asio/ssl/detail/stream_core.hpp +++ b/boost/asio/ssl/detail/stream_core.hpp @@ -17,15 +17,13 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) -# if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) -# include <boost/asio/deadline_timer.hpp> -# else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) -# include <boost/asio/steady_timer.hpp> -# endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) -# include <boost/asio/ssl/detail/engine.hpp> -# include <boost/asio/buffer.hpp> -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +# include <boost/asio/deadline_timer.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +# include <boost/asio/steady_timer.hpp> +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +#include <boost/asio/ssl/detail/engine.hpp> +#include <boost/asio/buffer.hpp> #include <boost/asio/detail/push_options.hpp> @@ -34,18 +32,16 @@ namespace asio { namespace ssl { namespace detail { -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) - struct stream_core { // According to the OpenSSL documentation, this is the buffer size that is // sufficient to hold the largest possible TLS record. enum { max_tls_record_size = 17 * 1024 }; - stream_core(SSL_CTX* context, boost::asio::io_service& io_service) + stream_core(SSL_CTX* context, boost::asio::io_context& io_context) : engine_(context), - pending_read_(io_service), - pending_write_(io_service), + pending_read_(io_context), + pending_write_(io_context), output_buffer_space_(max_tls_record_size), output_buffer_(boost::asio::buffer(output_buffer_space_)), input_buffer_space_(max_tls_record_size), @@ -80,6 +76,13 @@ struct stream_core { return boost::posix_time::pos_infin; } + + // Helper function to get a timer's expiry time. + static boost::asio::deadline_timer::time_type expiry( + const boost::asio::deadline_timer& timer) + { + return timer.expires_at(); + } #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) // Timer used for storing queued read operations. boost::asio::steady_timer pending_read_; @@ -98,26 +101,31 @@ struct stream_core { return (boost::asio::steady_timer::time_point::max)(); } + + // Helper function to get a timer's expiry time. + static boost::asio::steady_timer::time_point expiry( + const boost::asio::steady_timer& timer) + { + return timer.expiry(); + } #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) // Buffer space used to prepare output intended for the transport. std::vector<unsigned char> output_buffer_space_; // A buffer that may be used to prepare output intended for the transport. - const boost::asio::mutable_buffers_1 output_buffer_; + const boost::asio::mutable_buffer output_buffer_; // Buffer space used to read input intended for the engine. std::vector<unsigned char> input_buffer_space_; // A buffer that may be used to read input intended for the engine. - const boost::asio::mutable_buffers_1 input_buffer_; + const boost::asio::mutable_buffer input_buffer_; // The buffer pointing to the engine's unconsumed input. boost::asio::const_buffer input_; }; -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace detail } // namespace ssl } // namespace asio diff --git a/boost/asio/ssl/detail/verify_callback.hpp b/boost/asio/ssl/detail/verify_callback.hpp index c4bea7c215..ea1a436b22 100644 --- a/boost/asio/ssl/detail/verify_callback.hpp +++ b/boost/asio/ssl/detail/verify_callback.hpp @@ -17,9 +17,7 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/ssl/verify_context.hpp> -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <boost/asio/ssl/verify_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -28,8 +26,6 @@ namespace asio { namespace ssl { namespace detail { -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) - class verify_callback_base { public: @@ -58,8 +54,6 @@ private: VerifyCallback callback_; }; -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace detail } // namespace ssl } // namespace asio diff --git a/boost/asio/ssl/detail/write_op.hpp b/boost/asio/ssl/detail/write_op.hpp index c04eda86d2..b30f0c3787 100644 --- a/boost/asio/ssl/detail/write_op.hpp +++ b/boost/asio/ssl/detail/write_op.hpp @@ -17,10 +17,8 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/detail/buffer_sequence_adapter.hpp> -# include <boost/asio/ssl/detail/engine.hpp> -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <boost/asio/detail/buffer_sequence_adapter.hpp> +#include <boost/asio/ssl/detail/engine.hpp> #include <boost/asio/detail/push_options.hpp> @@ -29,8 +27,6 @@ namespace asio { namespace ssl { namespace detail { -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) - template <typename ConstBufferSequence> class write_op { @@ -63,8 +59,6 @@ private: ConstBufferSequence buffers_; }; -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace detail } // namespace ssl } // namespace asio diff --git a/boost/asio/ssl/impl/context.hpp b/boost/asio/ssl/impl/context.hpp index 52547d0437..a207a73fa7 100644 --- a/boost/asio/ssl/impl/context.hpp +++ b/boost/asio/ssl/impl/context.hpp @@ -18,9 +18,7 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/detail/throw_error.hpp> -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/push_options.hpp> @@ -28,8 +26,6 @@ namespace boost { namespace asio { namespace ssl { -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) - template <typename VerifyCallback> void context::set_verify_callback(VerifyCallback callback) { @@ -39,11 +35,12 @@ void context::set_verify_callback(VerifyCallback callback) } template <typename VerifyCallback> -boost::system::error_code context::set_verify_callback( +BOOST_ASIO_SYNC_OP_VOID context::set_verify_callback( VerifyCallback callback, boost::system::error_code& ec) { - return do_set_verify_callback( + do_set_verify_callback( new detail::verify_callback<VerifyCallback>(callback), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } template <typename PasswordCallback> @@ -55,15 +52,14 @@ void context::set_password_callback(PasswordCallback callback) } template <typename PasswordCallback> -boost::system::error_code context::set_password_callback( +BOOST_ASIO_SYNC_OP_VOID context::set_password_callback( PasswordCallback callback, boost::system::error_code& ec) { - return do_set_password_callback( + do_set_password_callback( new detail::password_callback<PasswordCallback>(callback), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace ssl } // namespace asio } // namespace boost diff --git a/boost/asio/ssl/impl/context.ipp b/boost/asio/ssl/impl/context.ipp index a1fb9a578b..f50ce454ea 100644 --- a/boost/asio/ssl/impl/context.ipp +++ b/boost/asio/ssl/impl/context.ipp @@ -18,13 +18,11 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <cstring> -# include <boost/asio/detail/throw_error.hpp> -# include <boost/asio/error.hpp> -# include <boost/asio/ssl/context.hpp> -# include <boost/asio/ssl/error.hpp> -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <cstring> +#include <boost/asio/detail/throw_error.hpp> +#include <boost/asio/error.hpp> +#include <boost/asio/ssl/context.hpp> +#include <boost/asio/ssl/error.hpp> #include <boost/asio/detail/push_options.hpp> @@ -32,8 +30,6 @@ namespace boost { namespace asio { namespace ssl { -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) - struct context::bio_cleanup { BIO* p; @@ -326,14 +322,6 @@ context::context(context::method m) set_options(no_compression); } -context::context(boost::asio::io_service&, context::method m) - : handle_(0) -{ - context tmp(m); - handle_ = tmp.handle_; - tmp.handle_ = 0; -} - #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) context::context(context&& other) { @@ -390,11 +378,6 @@ context::native_handle_type context::native_handle() return handle_; } -context::impl_type context::impl() -{ - return handle_; -} - void context::clear_options(context::options o) { boost::system::error_code ec; @@ -402,7 +385,7 @@ void context::clear_options(context::options o) boost::asio::detail::throw_error(ec, "clear_options"); } -boost::system::error_code context::clear_options( +BOOST_ASIO_SYNC_OP_VOID context::clear_options( context::options o, boost::system::error_code& ec) { #if (OPENSSL_VERSION_NUMBER >= 0x009080DFL) \ @@ -426,7 +409,7 @@ boost::system::error_code context::clear_options( ec = boost::asio::error::operation_not_supported; #endif // (OPENSSL_VERSION_NUMBER >= 0x009080DFL) // && (OPENSSL_VERSION_NUMBER != 0x00909000L) - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::set_options(context::options o) @@ -436,7 +419,7 @@ void context::set_options(context::options o) boost::asio::detail::throw_error(ec, "set_options"); } -boost::system::error_code context::set_options( +BOOST_ASIO_SYNC_OP_VOID context::set_options( context::options o, boost::system::error_code& ec) { #if !defined(SSL_OP_NO_COMPRESSION) @@ -453,7 +436,7 @@ boost::system::error_code context::set_options( ::SSL_CTX_set_options(handle_, o); ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::set_verify_mode(verify_mode v) @@ -463,13 +446,13 @@ void context::set_verify_mode(verify_mode v) boost::asio::detail::throw_error(ec, "set_verify_mode"); } -boost::system::error_code context::set_verify_mode( +BOOST_ASIO_SYNC_OP_VOID context::set_verify_mode( verify_mode v, boost::system::error_code& ec) { ::SSL_CTX_set_verify(handle_, v, ::SSL_CTX_get_verify_callback(handle_)); ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::set_verify_depth(int depth) @@ -479,13 +462,13 @@ void context::set_verify_depth(int depth) boost::asio::detail::throw_error(ec, "set_verify_depth"); } -boost::system::error_code context::set_verify_depth( +BOOST_ASIO_SYNC_OP_VOID context::set_verify_depth( int depth, boost::system::error_code& ec) { ::SSL_CTX_set_verify_depth(handle_, depth); ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::load_verify_file(const std::string& filename) @@ -495,7 +478,7 @@ void context::load_verify_file(const std::string& filename) boost::asio::detail::throw_error(ec, "load_verify_file"); } -boost::system::error_code context::load_verify_file( +BOOST_ASIO_SYNC_OP_VOID context::load_verify_file( const std::string& filename, boost::system::error_code& ec) { ::ERR_clear_error(); @@ -505,11 +488,11 @@ boost::system::error_code context::load_verify_file( ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::add_certificate_authority(const const_buffer& ca) @@ -519,7 +502,7 @@ void context::add_certificate_authority(const const_buffer& ca) boost::asio::detail::throw_error(ec, "add_certificate_authority"); } -boost::system::error_code context::add_certificate_authority( +BOOST_ASIO_SYNC_OP_VOID context::add_certificate_authority( const const_buffer& ca, boost::system::error_code& ec) { ::ERR_clear_error(); @@ -535,7 +518,7 @@ boost::system::error_code context::add_certificate_authority( if (::X509_STORE_add_cert(store, cert.p) == 1) { ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } } @@ -544,7 +527,7 @@ boost::system::error_code context::add_certificate_authority( ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::set_default_verify_paths() @@ -554,7 +537,7 @@ void context::set_default_verify_paths() boost::asio::detail::throw_error(ec, "set_default_verify_paths"); } -boost::system::error_code context::set_default_verify_paths( +BOOST_ASIO_SYNC_OP_VOID context::set_default_verify_paths( boost::system::error_code& ec) { ::ERR_clear_error(); @@ -564,11 +547,11 @@ boost::system::error_code context::set_default_verify_paths( ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::add_verify_path(const std::string& path) @@ -578,7 +561,7 @@ void context::add_verify_path(const std::string& path) boost::asio::detail::throw_error(ec, "add_verify_path"); } -boost::system::error_code context::add_verify_path( +BOOST_ASIO_SYNC_OP_VOID context::add_verify_path( const std::string& path, boost::system::error_code& ec) { ::ERR_clear_error(); @@ -588,11 +571,11 @@ boost::system::error_code context::add_verify_path( ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_certificate( @@ -603,7 +586,7 @@ void context::use_certificate( boost::asio::detail::throw_error(ec, "use_certificate"); } -boost::system::error_code context::use_certificate( +BOOST_ASIO_SYNC_OP_VOID context::use_certificate( const const_buffer& certificate, file_format format, boost::system::error_code& ec) { @@ -612,11 +595,11 @@ boost::system::error_code context::use_certificate( if (format == context_base::asn1) { if (::SSL_CTX_use_certificate_ASN1(handle_, - static_cast<int>(buffer_size(certificate)), - buffer_cast<const unsigned char*>(certificate)) == 1) + static_cast<int>(certificate.size()), + static_cast<const unsigned char*>(certificate.data())) == 1) { ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } else if (format == context_base::pem) @@ -630,7 +613,7 @@ boost::system::error_code context::use_certificate( if (::SSL_CTX_use_certificate(handle_, cert.p) == 1) { ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } } @@ -638,13 +621,13 @@ boost::system::error_code context::use_certificate( else { ec = boost::asio::error::invalid_argument; - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_certificate_file( @@ -655,7 +638,7 @@ void context::use_certificate_file( boost::asio::detail::throw_error(ec, "use_certificate_file"); } -boost::system::error_code context::use_certificate_file( +BOOST_ASIO_SYNC_OP_VOID context::use_certificate_file( const std::string& filename, file_format format, boost::system::error_code& ec) { @@ -671,7 +654,7 @@ boost::system::error_code context::use_certificate_file( default: { ec = boost::asio::error::invalid_argument; - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } @@ -682,11 +665,11 @@ boost::system::error_code context::use_certificate_file( ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_certificate_chain(const const_buffer& chain) @@ -696,7 +679,7 @@ void context::use_certificate_chain(const const_buffer& chain) boost::asio::detail::throw_error(ec, "use_certificate_chain"); } -boost::system::error_code context::use_certificate_chain( +BOOST_ASIO_SYNC_OP_VOID context::use_certificate_chain( const const_buffer& chain, boost::system::error_code& ec) { ::ERR_clear_error(); @@ -719,7 +702,7 @@ boost::system::error_code context::use_certificate_chain( { ec = boost::system::error_code(ERR_R_PEM_LIB, boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } int result = ::SSL_CTX_use_certificate(handle_, cert.p); @@ -728,7 +711,7 @@ boost::system::error_code context::use_certificate_chain( ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } #if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && !defined(LIBRESSL_VERSION_NUMBER) @@ -750,7 +733,7 @@ boost::system::error_code context::use_certificate_chain( ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } @@ -760,14 +743,14 @@ boost::system::error_code context::use_certificate_chain( { ::ERR_clear_error(); ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_certificate_chain_file(const std::string& filename) @@ -777,7 +760,7 @@ void context::use_certificate_chain_file(const std::string& filename) boost::asio::detail::throw_error(ec, "use_certificate_chain_file"); } -boost::system::error_code context::use_certificate_chain_file( +BOOST_ASIO_SYNC_OP_VOID context::use_certificate_chain_file( const std::string& filename, boost::system::error_code& ec) { ::ERR_clear_error(); @@ -787,11 +770,11 @@ boost::system::error_code context::use_certificate_chain_file( ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_private_key( @@ -802,7 +785,7 @@ void context::use_private_key( boost::asio::detail::throw_error(ec, "use_private_key"); } -boost::system::error_code context::use_private_key( +BOOST_ASIO_SYNC_OP_VOID context::use_private_key( const const_buffer& private_key, context::file_format format, boost::system::error_code& ec) { @@ -833,7 +816,7 @@ boost::system::error_code context::use_private_key( default: { ec = boost::asio::error::invalid_argument; - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } @@ -842,7 +825,7 @@ boost::system::error_code context::use_private_key( if (::SSL_CTX_use_PrivateKey(handle_, evp_private_key.p) == 1) { ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } } @@ -850,7 +833,7 @@ boost::system::error_code context::use_private_key( ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_private_key_file( @@ -869,7 +852,7 @@ void context::use_rsa_private_key( boost::asio::detail::throw_error(ec, "use_rsa_private_key"); } -boost::system::error_code context::use_rsa_private_key( +BOOST_ASIO_SYNC_OP_VOID context::use_rsa_private_key( const const_buffer& private_key, context::file_format format, boost::system::error_code& ec) { @@ -900,7 +883,7 @@ boost::system::error_code context::use_rsa_private_key( default: { ec = boost::asio::error::invalid_argument; - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } @@ -909,7 +892,7 @@ boost::system::error_code context::use_rsa_private_key( if (::SSL_CTX_use_RSAPrivateKey(handle_, rsa_private_key.p) == 1) { ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } } @@ -917,10 +900,10 @@ boost::system::error_code context::use_rsa_private_key( ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } -boost::system::error_code context::use_private_key_file( +BOOST_ASIO_SYNC_OP_VOID context::use_private_key_file( const std::string& filename, context::file_format format, boost::system::error_code& ec) { @@ -936,7 +919,7 @@ boost::system::error_code context::use_private_key_file( default: { ec = boost::asio::error::invalid_argument; - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } @@ -947,11 +930,11 @@ boost::system::error_code context::use_private_key_file( ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_rsa_private_key_file( @@ -962,7 +945,7 @@ void context::use_rsa_private_key_file( boost::asio::detail::throw_error(ec, "use_rsa_private_key_file"); } -boost::system::error_code context::use_rsa_private_key_file( +BOOST_ASIO_SYNC_OP_VOID context::use_rsa_private_key_file( const std::string& filename, context::file_format format, boost::system::error_code& ec) { @@ -978,7 +961,7 @@ boost::system::error_code context::use_rsa_private_key_file( default: { ec = boost::asio::error::invalid_argument; - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } @@ -990,11 +973,11 @@ boost::system::error_code context::use_rsa_private_key_file( ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_tmp_dh(const const_buffer& dh) @@ -1004,7 +987,7 @@ void context::use_tmp_dh(const const_buffer& dh) boost::asio::detail::throw_error(ec, "use_tmp_dh"); } -boost::system::error_code context::use_tmp_dh( +BOOST_ASIO_SYNC_OP_VOID context::use_tmp_dh( const const_buffer& dh, boost::system::error_code& ec) { ::ERR_clear_error(); @@ -1018,7 +1001,7 @@ boost::system::error_code context::use_tmp_dh( ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_tmp_dh_file(const std::string& filename) @@ -1028,7 +1011,7 @@ void context::use_tmp_dh_file(const std::string& filename) boost::asio::detail::throw_error(ec, "use_tmp_dh_file"); } -boost::system::error_code context::use_tmp_dh_file( +BOOST_ASIO_SYNC_OP_VOID context::use_tmp_dh_file( const std::string& filename, boost::system::error_code& ec) { ::ERR_clear_error(); @@ -1042,10 +1025,10 @@ boost::system::error_code context::use_tmp_dh_file( ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } -boost::system::error_code context::do_use_tmp_dh( +BOOST_ASIO_SYNC_OP_VOID context::do_use_tmp_dh( BIO* bio, boost::system::error_code& ec) { ::ERR_clear_error(); @@ -1056,17 +1039,17 @@ boost::system::error_code context::do_use_tmp_dh( if (::SSL_CTX_set_tmp_dh(handle_, dh.p) == 1) { ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } -boost::system::error_code context::do_set_verify_callback( +BOOST_ASIO_SYNC_OP_VOID context::do_set_verify_callback( detail::verify_callback_base* callback, boost::system::error_code& ec) { if (SSL_CTX_get_app_data(handle_)) @@ -1082,7 +1065,7 @@ boost::system::error_code context::do_set_verify_callback( &context::verify_callback_function); ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } int context::verify_callback_function(int preverified, X509_STORE_CTX* ctx) @@ -1111,7 +1094,7 @@ int context::verify_callback_function(int preverified, X509_STORE_CTX* ctx) return 0; } -boost::system::error_code context::do_set_password_callback( +BOOST_ASIO_SYNC_OP_VOID context::do_set_password_callback( detail::password_callback_base* callback, boost::system::error_code& ec) { #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) @@ -1129,7 +1112,7 @@ boost::system::error_code context::do_set_password_callback( SSL_CTX_set_default_passwd_cb(handle_, &context::password_callback_function); ec = boost::system::error_code(); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } int context::password_callback_function( @@ -1162,12 +1145,10 @@ int context::password_callback_function( BIO* context::make_buffer_bio(const const_buffer& b) { return ::BIO_new_mem_buf( - const_cast<void*>(buffer_cast<const void*>(b)), - static_cast<int>(buffer_size(b))); + const_cast<void*>(b.data()), + static_cast<int>(b.size())); } -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace ssl } // namespace asio } // namespace boost diff --git a/boost/asio/ssl/impl/rfc2818_verification.ipp b/boost/asio/ssl/impl/rfc2818_verification.ipp index 7f22806735..d759ce567c 100644 --- a/boost/asio/ssl/impl/rfc2818_verification.ipp +++ b/boost/asio/ssl/impl/rfc2818_verification.ipp @@ -17,13 +17,11 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <cctype> -# include <cstring> -# include <boost/asio/ip/address.hpp> -# include <boost/asio/ssl/rfc2818_verification.hpp> -# include <boost/asio/ssl/detail/openssl_types.hpp> -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <cctype> +#include <cstring> +#include <boost/asio/ip/address.hpp> +#include <boost/asio/ssl/rfc2818_verification.hpp> +#include <boost/asio/ssl/detail/openssl_types.hpp> #include <boost/asio/detail/push_options.hpp> @@ -31,8 +29,6 @@ namespace boost { namespace asio { namespace ssl { -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) - bool rfc2818_verification::operator()( bool preverified, verify_context& ctx) const { @@ -50,7 +46,7 @@ bool rfc2818_verification::operator()( // Try converting the host name to an address. If it is an address then we // need to look for an IP address in the certificate rather than a host name. boost::system::error_code ec; - ip::address address = ip::address::from_string(host_, ec); + ip::address address = ip::make_address(host_, ec); bool is_address = !ec; X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); @@ -157,8 +153,6 @@ bool rfc2818_verification::match_pattern(const char* pattern, return p == p_end && !*h; } -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace ssl } // namespace asio } // namespace boost diff --git a/boost/asio/ssl/old/basic_context.hpp b/boost/asio/ssl/old/basic_context.hpp deleted file mode 100644 index d8703b21ae..0000000000 --- a/boost/asio/ssl/old/basic_context.hpp +++ /dev/null @@ -1,436 +0,0 @@ -// -// ssl/old/basic_context.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2017 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) -// - -#ifndef BOOST_ASIO_SSL_OLD_BASIC_CONTEXT_HPP -#define BOOST_ASIO_SSL_OLD_BASIC_CONTEXT_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include <boost/asio/detail/config.hpp> -#include <string> -#include <boost/noncopyable.hpp> -#include <boost/asio/detail/throw_error.hpp> -#include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> -#include <boost/asio/ssl/context_base.hpp> - -#include <boost/asio/detail/push_options.hpp> - -namespace boost { -namespace asio { -namespace ssl { -namespace old { - -/// SSL context. -template <typename Service> -class basic_context - : public context_base, - private boost::noncopyable -{ -public: - /// The type of the service that will be used to provide context operations. - typedef Service service_type; - - /// The native implementation type of the SSL context. - typedef typename service_type::impl_type impl_type; - - /// Constructor. - basic_context(boost::asio::io_service& io_service, method m) - : service_(boost::asio::use_service<Service>(io_service)), - impl_(service_.null()) - { - service_.create(impl_, m); - } - - /// Destructor. - ~basic_context() - { - service_.destroy(impl_); - } - - /// Get the underlying implementation in the native type. - /** - * This function may be used to obtain the underlying implementation of the - * context. This is intended to allow access to context functionality that is - * not otherwise provided. - */ - impl_type impl() - { - return impl_; - } - - /// Set options on the context. - /** - * This function may be used to configure the SSL options used by the context. - * - * @param o A bitmask of options. The available option values are defined in - * the context_base class. The options are bitwise-ored with any existing - * value for the options. - * - * @throws boost::system::system_error Thrown on failure. - */ - void set_options(options o) - { - boost::system::error_code ec; - service_.set_options(impl_, o, ec); - boost::asio::detail::throw_error(ec); - } - - /// Set options on the context. - /** - * This function may be used to configure the SSL options used by the context. - * - * @param o A bitmask of options. The available option values are defined in - * the context_base class. The options are bitwise-ored with any existing - * value for the options. - * - * @param ec Set to indicate what error occurred, if any. - */ - boost::system::error_code set_options(options o, - boost::system::error_code& ec) - { - return service_.set_options(impl_, o, ec); - } - - /// Set the peer verification mode. - /** - * This function may be used to configure the peer verification mode used by - * the context. - * - * @param v A bitmask of peer verification modes. The available verify_mode - * values are defined in the context_base class. - * - * @throws boost::system::system_error Thrown on failure. - */ - void set_verify_mode(verify_mode v) - { - boost::system::error_code ec; - service_.set_verify_mode(impl_, v, ec); - boost::asio::detail::throw_error(ec); - } - - /// Set the peer verification mode. - /** - * This function may be used to configure the peer verification mode used by - * the context. - * - * @param v A bitmask of peer verification modes. The available verify_mode - * values are defined in the context_base class. - * - * @param ec Set to indicate what error occurred, if any. - */ - boost::system::error_code set_verify_mode(verify_mode v, - boost::system::error_code& ec) - { - return service_.set_verify_mode(impl_, v, ec); - } - - /// Load a certification authority file for performing verification. - /** - * This function is used to load one or more trusted certification authorities - * from a file. - * - * @param filename The name of a file containing certification authority - * certificates in PEM format. - * - * @throws boost::system::system_error Thrown on failure. - */ - void load_verify_file(const std::string& filename) - { - boost::system::error_code ec; - service_.load_verify_file(impl_, filename, ec); - boost::asio::detail::throw_error(ec); - } - - /// Load a certification authority file for performing verification. - /** - * This function is used to load the certificates for one or more trusted - * certification authorities from a file. - * - * @param filename The name of a file containing certification authority - * certificates in PEM format. - * - * @param ec Set to indicate what error occurred, if any. - */ - boost::system::error_code load_verify_file(const std::string& filename, - boost::system::error_code& ec) - { - return service_.load_verify_file(impl_, filename, ec); - } - - /// Add a directory containing certificate authority files to be used for - /// performing verification. - /** - * This function is used to specify the name of a directory containing - * certification authority certificates. Each file in the directory must - * contain a single certificate. The files must be named using the subject - * name's hash and an extension of ".0". - * - * @param path The name of a directory containing the certificates. - * - * @throws boost::system::system_error Thrown on failure. - */ - void add_verify_path(const std::string& path) - { - boost::system::error_code ec; - service_.add_verify_path(impl_, path, ec); - boost::asio::detail::throw_error(ec); - } - - /// Add a directory containing certificate authority files to be used for - /// performing verification. - /** - * This function is used to specify the name of a directory containing - * certification authority certificates. Each file in the directory must - * contain a single certificate. The files must be named using the subject - * name's hash and an extension of ".0". - * - * @param path The name of a directory containing the certificates. - * - * @param ec Set to indicate what error occurred, if any. - */ - boost::system::error_code add_verify_path(const std::string& path, - boost::system::error_code& ec) - { - return service_.add_verify_path(impl_, path, ec); - } - - /// Use a certificate from a file. - /** - * This function is used to load a certificate into the context from a file. - * - * @param filename The name of the file containing the certificate. - * - * @param format The file format (ASN.1 or PEM). - * - * @throws boost::system::system_error Thrown on failure. - */ - void use_certificate_file(const std::string& filename, file_format format) - { - boost::system::error_code ec; - service_.use_certificate_file(impl_, filename, format, ec); - boost::asio::detail::throw_error(ec); - } - - /// Use a certificate from a file. - /** - * This function is used to load a certificate into the context from a file. - * - * @param filename The name of the file containing the certificate. - * - * @param format The file format (ASN.1 or PEM). - * - * @param ec Set to indicate what error occurred, if any. - */ - boost::system::error_code use_certificate_file(const std::string& filename, - file_format format, boost::system::error_code& ec) - { - return service_.use_certificate_file(impl_, filename, format, ec); - } - - /// Use a certificate chain from a file. - /** - * This function is used to load a certificate chain into the context from a - * file. - * - * @param filename The name of the file containing the certificate. The file - * must use the PEM format. - * - * @throws boost::system::system_error Thrown on failure. - */ - void use_certificate_chain_file(const std::string& filename) - { - boost::system::error_code ec; - service_.use_certificate_chain_file(impl_, filename, ec); - boost::asio::detail::throw_error(ec); - } - - /// Use a certificate chain from a file. - /** - * This function is used to load a certificate chain into the context from a - * file. - * - * @param filename The name of the file containing the certificate. The file - * must use the PEM format. - * - * @param ec Set to indicate what error occurred, if any. - */ - boost::system::error_code use_certificate_chain_file( - const std::string& filename, boost::system::error_code& ec) - { - return service_.use_certificate_chain_file(impl_, filename, ec); - } - - /// Use a private key from a file. - /** - * This function is used to load a private key into the context from a file. - * - * @param filename The name of the file containing the private key. - * - * @param format The file format (ASN.1 or PEM). - * - * @throws boost::system::system_error Thrown on failure. - */ - void use_private_key_file(const std::string& filename, file_format format) - { - boost::system::error_code ec; - service_.use_private_key_file(impl_, filename, format, ec); - boost::asio::detail::throw_error(ec); - } - - /// Use a private key from a file. - /** - * This function is used to load a private key into the context from a file. - * - * @param filename The name of the file containing the private key. - * - * @param format The file format (ASN.1 or PEM). - * - * @param ec Set to indicate what error occurred, if any. - */ - boost::system::error_code use_private_key_file(const std::string& filename, - file_format format, boost::system::error_code& ec) - { - return service_.use_private_key_file(impl_, filename, format, ec); - } - - /// Use an RSA private key from a file. - /** - * This function is used to load an RSA private key into the context from a - * file. - * - * @param filename The name of the file containing the RSA private key. - * - * @param format The file format (ASN.1 or PEM). - * - * @throws boost::system::system_error Thrown on failure. - */ - void use_rsa_private_key_file(const std::string& filename, file_format format) - { - boost::system::error_code ec; - service_.use_rsa_private_key_file(impl_, filename, format, ec); - boost::asio::detail::throw_error(ec); - } - - /// Use an RSA private key from a file. - /** - * This function is used to load an RSA private key into the context from a - * file. - * - * @param filename The name of the file containing the RSA private key. - * - * @param format The file format (ASN.1 or PEM). - * - * @param ec Set to indicate what error occurred, if any. - */ - boost::system::error_code use_rsa_private_key_file( - const std::string& filename, file_format format, - boost::system::error_code& ec) - { - return service_.use_rsa_private_key_file(impl_, filename, format, ec); - } - - /// Use the specified file to obtain the temporary Diffie-Hellman parameters. - /** - * This function is used to load Diffie-Hellman parameters into the context - * from a file. - * - * @param filename The name of the file containing the Diffie-Hellman - * parameters. The file must use the PEM format. - * - * @throws boost::system::system_error Thrown on failure. - */ - void use_tmp_dh_file(const std::string& filename) - { - boost::system::error_code ec; - service_.use_tmp_dh_file(impl_, filename, ec); - boost::asio::detail::throw_error(ec); - } - - /// Use the specified file to obtain the temporary Diffie-Hellman parameters. - /** - * This function is used to load Diffie-Hellman parameters into the context - * from a file. - * - * @param filename The name of the file containing the Diffie-Hellman - * parameters. The file must use the PEM format. - * - * @param ec Set to indicate what error occurred, if any. - */ - boost::system::error_code use_tmp_dh_file(const std::string& filename, - boost::system::error_code& ec) - { - return service_.use_tmp_dh_file(impl_, filename, ec); - } - - /// Set the password callback. - /** - * This function is used to specify a callback function to obtain password - * information about an encrypted key in PEM format. - * - * @param callback The function object to be used for obtaining the password. - * The function signature of the handler must be: - * @code std::string password_callback( - * std::size_t max_length, // The maximum size for a password. - * password_purpose purpose // Whether password is for reading or writing. - * ); @endcode - * The return value of the callback is a string containing the password. - * - * @throws boost::system::system_error Thrown on failure. - */ - template <typename PasswordCallback> - void set_password_callback(PasswordCallback callback) - { - boost::system::error_code ec; - service_.set_password_callback(impl_, callback, ec); - boost::asio::detail::throw_error(ec); - } - - /// Set the password callback. - /** - * This function is used to specify a callback function to obtain password - * information about an encrypted key in PEM format. - * - * @param callback The function object to be used for obtaining the password. - * The function signature of the handler must be: - * @code std::string password_callback( - * std::size_t max_length, // The maximum size for a password. - * password_purpose purpose // Whether password is for reading or writing. - * ); @endcode - * The return value of the callback is a string containing the password. - * - * @param ec Set to indicate what error occurred, if any. - */ - template <typename PasswordCallback> - boost::system::error_code set_password_callback(PasswordCallback callback, - boost::system::error_code& ec) - { - return service_.set_password_callback(impl_, callback, ec); - } - -private: - /// The backend service implementation. - service_type& service_; - - /// The underlying native implementation. - impl_type impl_; -}; - -} // namespace old -} // namespace ssl -} // namespace asio -} // namespace boost - -#include <boost/asio/detail/pop_options.hpp> - -#endif // BOOST_ASIO_SSL_OLD_BASIC_CONTEXT_HPP diff --git a/boost/asio/ssl/old/context_service.hpp b/boost/asio/ssl/old/context_service.hpp deleted file mode 100644 index 1d9fbc0751..0000000000 --- a/boost/asio/ssl/old/context_service.hpp +++ /dev/null @@ -1,176 +0,0 @@ -// -// ssl/old/context_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2017 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) -// - -#ifndef BOOST_ASIO_SSL_OLD_CONTEXT_SERVICE_HPP -#define BOOST_ASIO_SSL_OLD_CONTEXT_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include <boost/asio/detail/config.hpp> -#include <string> -#include <boost/noncopyable.hpp> -#include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> -#include <boost/asio/ssl/context_base.hpp> -#include <boost/asio/ssl/old/detail/openssl_context_service.hpp> - -#include <boost/asio/detail/push_options.hpp> - -namespace boost { -namespace asio { -namespace ssl { -namespace old { - -/// Default service implementation for a context. -class context_service -#if defined(GENERATING_DOCUMENTATION) - : public boost::asio::io_service::service -#else - : public boost::asio::detail::service_base<context_service> -#endif -{ -private: - // The type of the platform-specific implementation. - typedef old::detail::openssl_context_service service_impl_type; - -public: -#if defined(GENERATING_DOCUMENTATION) - /// The unique service identifier. - static boost::asio::io_service::id id; -#endif - - /// The type of the context. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined impl_type; -#else - typedef service_impl_type::impl_type impl_type; -#endif - - /// Constructor. - explicit context_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base<context_service>(io_service), - service_impl_(boost::asio::use_service<service_impl_type>(io_service)) - { - } - - /// Return a null context implementation. - impl_type null() const - { - return service_impl_.null(); - } - - /// Create a new context implementation. - void create(impl_type& impl, context_base::method m) - { - service_impl_.create(impl, m); - } - - /// Destroy a context implementation. - void destroy(impl_type& impl) - { - service_impl_.destroy(impl); - } - - /// Set options on the context. - boost::system::error_code set_options(impl_type& impl, - context_base::options o, boost::system::error_code& ec) - { - return service_impl_.set_options(impl, o, ec); - } - - /// Set peer verification mode. - boost::system::error_code set_verify_mode(impl_type& impl, - context_base::verify_mode v, boost::system::error_code& ec) - { - return service_impl_.set_verify_mode(impl, v, ec); - } - - /// Load a certification authority file for performing verification. - boost::system::error_code load_verify_file(impl_type& impl, - const std::string& filename, boost::system::error_code& ec) - { - return service_impl_.load_verify_file(impl, filename, ec); - } - - /// Add a directory containing certification authority files to be used for - /// performing verification. - boost::system::error_code add_verify_path(impl_type& impl, - const std::string& path, boost::system::error_code& ec) - { - return service_impl_.add_verify_path(impl, path, ec); - } - - /// Use a certificate from a file. - boost::system::error_code use_certificate_file(impl_type& impl, - const std::string& filename, context_base::file_format format, - boost::system::error_code& ec) - { - return service_impl_.use_certificate_file(impl, filename, format, ec); - } - - /// Use a certificate chain from a file. - boost::system::error_code use_certificate_chain_file(impl_type& impl, - const std::string& filename, boost::system::error_code& ec) - { - return service_impl_.use_certificate_chain_file(impl, filename, ec); - } - - /// Use a private key from a file. - boost::system::error_code use_private_key_file(impl_type& impl, - const std::string& filename, context_base::file_format format, - boost::system::error_code& ec) - { - return service_impl_.use_private_key_file(impl, filename, format, ec); - } - - /// Use an RSA private key from a file. - boost::system::error_code use_rsa_private_key_file(impl_type& impl, - const std::string& filename, context_base::file_format format, - boost::system::error_code& ec) - { - return service_impl_.use_rsa_private_key_file(impl, filename, format, ec); - } - - /// Use the specified file to obtain the temporary Diffie-Hellman parameters. - boost::system::error_code use_tmp_dh_file(impl_type& impl, - const std::string& filename, boost::system::error_code& ec) - { - return service_impl_.use_tmp_dh_file(impl, filename, ec); - } - - /// Set the password callback. - template <typename PasswordCallback> - boost::system::error_code set_password_callback(impl_type& impl, - PasswordCallback callback, boost::system::error_code& ec) - { - return service_impl_.set_password_callback(impl, callback, ec); - } - -private: - // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - } - - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; -}; - -} // namespace old -} // namespace ssl -} // namespace asio -} // namespace boost - -#include <boost/asio/detail/pop_options.hpp> - -#endif // BOOST_ASIO_SSL_OLD_CONTEXT_SERVICE_HPP diff --git a/boost/asio/ssl/old/detail/openssl_context_service.hpp b/boost/asio/ssl/old/detail/openssl_context_service.hpp deleted file mode 100644 index dd54c3297b..0000000000 --- a/boost/asio/ssl/old/detail/openssl_context_service.hpp +++ /dev/null @@ -1,396 +0,0 @@ -// -// ssl/old/detail/openssl_context_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2017 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) -// - -#ifndef BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP -#define BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include <boost/asio/detail/config.hpp> -#include <cstring> -#include <string> -#include <boost/function.hpp> -#include <boost/asio/detail/throw_error.hpp> -#include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> -#include <boost/asio/ssl/context_base.hpp> -#include <boost/asio/ssl/detail/openssl_init.hpp> -#include <boost/asio/ssl/detail/openssl_types.hpp> - -#include <boost/asio/detail/push_options.hpp> - -namespace boost { -namespace asio { -namespace ssl { -namespace old { -namespace detail { - -class openssl_context_service - : public boost::asio::detail::service_base<openssl_context_service> -{ -public: - // The native type of the context. - typedef ::SSL_CTX* impl_type; - - // The type for the password callback function object. - typedef boost::function<std::string(std::size_t, - context_base::password_purpose)> password_callback_type; - - // Constructor. - openssl_context_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base<openssl_context_service>(io_service) - { - } - - // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - } - - // Return a null context implementation. - static impl_type null() - { - return 0; - } - - // Create a new context implementation. - void create(impl_type& impl, context_base::method m) - { - switch (m) - { -#if defined(OPENSSL_NO_SSL2) - case context_base::sslv2: - case context_base::sslv2_client: - case context_base::sslv2_server: - boost::asio::detail::throw_error(boost::asio::error::invalid_argument); - break; -#else // defined(OPENSSL_NO_SSL2) - case context_base::sslv2: - impl = ::SSL_CTX_new(::SSLv2_method()); - break; - case context_base::sslv2_client: - impl = ::SSL_CTX_new(::SSLv2_client_method()); - break; - case context_base::sslv2_server: - impl = ::SSL_CTX_new(::SSLv2_server_method()); - break; -#endif // defined(OPENSSL_NO_SSL2) -#if defined(OPENSSL_NO_SSL3) - case context_base::sslv3: - case context_base::sslv3_client: - case context_base::sslv3_server: - boost::asio::detail::throw_error(boost::asio::error::invalid_argument); - break; -#else // defined(OPENSSL_NO_SSL3) - case context_base::sslv3: - impl = ::SSL_CTX_new(::SSLv3_method()); - break; - case context_base::sslv3_client: - impl = ::SSL_CTX_new(::SSLv3_client_method()); - break; - case context_base::sslv3_server: - impl = ::SSL_CTX_new(::SSLv3_server_method()); - break; -#endif // defined(OPENSSL_NO_SSL3) - case context_base::tlsv1: - impl = ::SSL_CTX_new(::TLSv1_method()); - break; - case context_base::tlsv1_client: - impl = ::SSL_CTX_new(::TLSv1_client_method()); - break; - case context_base::tlsv1_server: - impl = ::SSL_CTX_new(::TLSv1_server_method()); - break; - case context_base::sslv23: - impl = ::SSL_CTX_new(::SSLv23_method()); - break; - case context_base::sslv23_client: - impl = ::SSL_CTX_new(::SSLv23_client_method()); - break; - case context_base::sslv23_server: - impl = ::SSL_CTX_new(::SSLv23_server_method()); - break; - default: - impl = ::SSL_CTX_new(0); - break; - } - } - - // Destroy a context implementation. - void destroy(impl_type& impl) - { - if (impl != null()) - { - if (impl->default_passwd_callback_userdata) - { - password_callback_type* callback = - static_cast<password_callback_type*>( - impl->default_passwd_callback_userdata); - delete callback; - impl->default_passwd_callback_userdata = 0; - } - - ::SSL_CTX_free(impl); - impl = null(); - } - } - - // Set options on the context. - boost::system::error_code set_options(impl_type& impl, - context_base::options o, boost::system::error_code& ec) - { - ::SSL_CTX_set_options(impl, o); - - ec = boost::system::error_code(); - return ec; - } - - // Set peer verification mode. - boost::system::error_code set_verify_mode(impl_type& impl, - context_base::verify_mode v, boost::system::error_code& ec) - { - ::SSL_CTX_set_verify(impl, v, 0); - - ec = boost::system::error_code(); - return ec; - } - - // Load a certification authority file for performing verification. - boost::system::error_code load_verify_file(impl_type& impl, - const std::string& filename, boost::system::error_code& ec) - { - if (::SSL_CTX_load_verify_locations(impl, filename.c_str(), 0) != 1) - { - ec = boost::asio::error::invalid_argument; - return ec; - } - - ec = boost::system::error_code(); - return ec; - } - - // Add a directory containing certification authority files to be used for - // performing verification. - boost::system::error_code add_verify_path(impl_type& impl, - const std::string& path, boost::system::error_code& ec) - { - if (::SSL_CTX_load_verify_locations(impl, 0, path.c_str()) != 1) - { - ec = boost::asio::error::invalid_argument; - return ec; - } - - ec = boost::system::error_code(); - return ec; - } - - // Use a certificate from a file. - boost::system::error_code use_certificate_file(impl_type& impl, - const std::string& filename, context_base::file_format format, - boost::system::error_code& ec) - { - int file_type; - switch (format) - { - case context_base::asn1: - file_type = SSL_FILETYPE_ASN1; - break; - case context_base::pem: - file_type = SSL_FILETYPE_PEM; - break; - default: - { - ec = boost::asio::error::invalid_argument; - return ec; - } - } - - if (::SSL_CTX_use_certificate_file(impl, filename.c_str(), file_type) != 1) - { - ec = boost::asio::error::invalid_argument; - return ec; - } - - ec = boost::system::error_code(); - return ec; - } - - // Use a certificate chain from a file. - boost::system::error_code use_certificate_chain_file(impl_type& impl, - const std::string& filename, boost::system::error_code& ec) - { - if (::SSL_CTX_use_certificate_chain_file(impl, filename.c_str()) != 1) - { - ec = boost::asio::error::invalid_argument; - return ec; - } - - ec = boost::system::error_code(); - return ec; - } - - // Use a private key from a file. - boost::system::error_code use_private_key_file(impl_type& impl, - const std::string& filename, context_base::file_format format, - boost::system::error_code& ec) - { - int file_type; - switch (format) - { - case context_base::asn1: - file_type = SSL_FILETYPE_ASN1; - break; - case context_base::pem: - file_type = SSL_FILETYPE_PEM; - break; - default: - { - ec = boost::asio::error::invalid_argument; - return ec; - } - } - - if (::SSL_CTX_use_PrivateKey_file(impl, filename.c_str(), file_type) != 1) - { - ec = boost::asio::error::invalid_argument; - return ec; - } - - ec = boost::system::error_code(); - return ec; - } - - // Use an RSA private key from a file. - boost::system::error_code use_rsa_private_key_file(impl_type& impl, - const std::string& filename, context_base::file_format format, - boost::system::error_code& ec) - { - int file_type; - switch (format) - { - case context_base::asn1: - file_type = SSL_FILETYPE_ASN1; - break; - case context_base::pem: - file_type = SSL_FILETYPE_PEM; - break; - default: - { - ec = boost::asio::error::invalid_argument; - return ec; - } - } - - if (::SSL_CTX_use_RSAPrivateKey_file( - impl, filename.c_str(), file_type) != 1) - { - ec = boost::asio::error::invalid_argument; - return ec; - } - - ec = boost::system::error_code(); - return ec; - } - - // Use the specified file to obtain the temporary Diffie-Hellman parameters. - boost::system::error_code use_tmp_dh_file(impl_type& impl, - const std::string& filename, boost::system::error_code& ec) - { - ::BIO* bio = ::BIO_new_file(filename.c_str(), "r"); - if (!bio) - { - ec = boost::asio::error::invalid_argument; - return ec; - } - - ::DH* dh = ::PEM_read_bio_DHparams(bio, 0, 0, 0); - if (!dh) - { - ::BIO_free(bio); - ec = boost::asio::error::invalid_argument; - return ec; - } - - ::BIO_free(bio); - int result = ::SSL_CTX_set_tmp_dh(impl, dh); - ::DH_free(dh); - if (result != 1) - { - ec = boost::asio::error::invalid_argument; - return ec; - } - - ec = boost::system::error_code(); - return ec; - } - - static int password_callback(char* buf, int size, int purpose, void* data) - { - using namespace std; // For strncat and strlen. - - if (data) - { - password_callback_type* callback = - static_cast<password_callback_type*>(data); - std::string passwd = (*callback)(static_cast<std::size_t>(size), - purpose ? context_base::for_writing : context_base::for_reading); - *buf = '\0'; - strncat(buf, passwd.c_str(), size); - return strlen(buf); - } - - return 0; - } - - // Set the password callback. - template <typename Password_Callback> - boost::system::error_code set_password_callback(impl_type& impl, - Password_Callback callback, boost::system::error_code& ec) - { - // Allocate callback function object if not already present. - if (impl->default_passwd_callback_userdata) - { - password_callback_type* callback_function = - static_cast<password_callback_type*>( - impl->default_passwd_callback_userdata); - *callback_function = callback; - } - else - { - password_callback_type* callback_function = - new password_callback_type(callback); - impl->default_passwd_callback_userdata = callback_function; - } - - // Set the password callback. - SSL_CTX_set_default_passwd_cb(impl, - &openssl_context_service::password_callback); - - ec = boost::system::error_code(); - return ec; - } - -private: - // Ensure openssl is initialised. - boost::asio::ssl::detail::openssl_init<> init_; -}; - -} // namespace detail -} // namespace old -} // namespace ssl -} // namespace asio -} // namespace boost - -#include <boost/asio/detail/pop_options.hpp> - -#endif // BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP diff --git a/boost/asio/ssl/old/detail/openssl_operation.hpp b/boost/asio/ssl/old/detail/openssl_operation.hpp deleted file mode 100644 index 6835f5ff6a..0000000000 --- a/boost/asio/ssl/old/detail/openssl_operation.hpp +++ /dev/null @@ -1,526 +0,0 @@ -// -// ssl/old/detail/openssl_operation.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster 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) -// - -#ifndef BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_OPERATION_HPP -#define BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_OPERATION_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include <boost/asio/detail/config.hpp> -#include <boost/function.hpp> -#include <boost/bind.hpp> -#include <boost/asio/buffer.hpp> -#include <boost/asio/detail/assert.hpp> -#include <boost/asio/detail/socket_ops.hpp> -#include <boost/asio/placeholders.hpp> -#include <boost/asio/ssl/detail/openssl_types.hpp> -#include <boost/asio/ssl/error.hpp> -#include <boost/asio/strand.hpp> -#include <boost/system/system_error.hpp> -#include <boost/asio/write.hpp> - -#include <boost/asio/detail/push_options.hpp> - -namespace boost { -namespace asio { -namespace ssl { -namespace old { -namespace detail { - -typedef boost::function<int (::SSL*)> ssl_primitive_func; -typedef boost::function<void (const boost::system::error_code&, int)> - user_handler_func; - -// Network send_/recv buffer implementation -// -// -class net_buffer -{ - static const int NET_BUF_SIZE = 16*1024 + 256; // SSL record size + spare - - unsigned char buf_[NET_BUF_SIZE]; - unsigned char* data_start_; - unsigned char* data_end_; - -public: - net_buffer() - { - data_start_ = data_end_ = buf_; - } - unsigned char* get_unused_start() { return data_end_; } - unsigned char* get_data_start() { return data_start_; } - size_t get_unused_len() { return (NET_BUF_SIZE - (data_end_ - buf_)); } - size_t get_data_len() { return (data_end_ - data_start_); } - void data_added(size_t count) - { - data_end_ += count; - data_end_ = data_end_ > (buf_ + NET_BUF_SIZE)? - (buf_ + NET_BUF_SIZE): - data_end_; - } - void data_removed(size_t count) - { - data_start_ += count; - if (data_start_ >= data_end_) reset(); - } - void reset() { data_start_ = buf_; data_end_ = buf_; } - bool has_data() { return (data_start_ < data_end_); } -}; // class net_buffer - -// -// Operation class -// -// -template <typename Stream> -class openssl_operation -{ -public: - - // Constructor for asynchronous operations - openssl_operation(ssl_primitive_func primitive, - Stream& socket, - net_buffer& recv_buf, - SSL* session, - BIO* ssl_bio, - user_handler_func handler, - boost::asio::io_service::strand& strand - ) - : primitive_(primitive) - , user_handler_(handler) - , strand_(&strand) - , recv_buf_(recv_buf) - , socket_(socket) - , ssl_bio_(ssl_bio) - , session_(session) - { - write_ = boost::bind( - &openssl_operation::do_async_write, - this, boost::arg<1>(), boost::arg<2>() - ); - read_ = boost::bind( - &openssl_operation::do_async_read, - this - ); - handler_= boost::bind( - &openssl_operation::async_user_handler, - this, boost::arg<1>(), boost::arg<2>() - ); - } - - // Constructor for synchronous operations - openssl_operation(ssl_primitive_func primitive, - Stream& socket, - net_buffer& recv_buf, - SSL* session, - BIO* ssl_bio) - : primitive_(primitive) - , strand_(0) - , recv_buf_(recv_buf) - , socket_(socket) - , ssl_bio_(ssl_bio) - , session_(session) - { - write_ = boost::bind( - &openssl_operation::do_sync_write, - this, boost::arg<1>(), boost::arg<2>() - ); - read_ = boost::bind( - &openssl_operation::do_sync_read, - this - ); - handler_ = boost::bind( - &openssl_operation::sync_user_handler, - this, boost::arg<1>(), boost::arg<2>() - ); - } - - // Start operation - // In case of asynchronous it returns 0, in sync mode returns success code - // or throws an error... - int start() - { - int rc = primitive_( session_ ); - - bool is_operation_done = (rc > 0); - // For connect/accept/shutdown, the operation - // is done, when return code is 1 - // for write, it is done, when is retcode > 0 - // for read, it is done when retcode > 0 - - int error_code = !is_operation_done ? - ::SSL_get_error( session_, rc ) : - 0; - int sys_error_code = ERR_get_error(); - - if (error_code == SSL_ERROR_SSL) - return handler_(boost::system::error_code( - sys_error_code, boost::asio::error::get_ssl_category()), rc); - - bool is_read_needed = (error_code == SSL_ERROR_WANT_READ); - bool is_write_needed = (error_code == SSL_ERROR_WANT_WRITE || - ::BIO_ctrl_pending( ssl_bio_ )); - bool is_shut_down_received = - ((::SSL_get_shutdown( session_ ) & SSL_RECEIVED_SHUTDOWN) == - SSL_RECEIVED_SHUTDOWN); - bool is_shut_down_sent = - ((::SSL_get_shutdown( session_ ) & SSL_SENT_SHUTDOWN) == - SSL_SENT_SHUTDOWN); - - if (is_shut_down_sent && is_shut_down_received - && is_operation_done && !is_write_needed) - // SSL connection is shut down cleanly - return handler_(boost::system::error_code(), 1); - - if (is_shut_down_received && !is_operation_done) - // Shutdown has been requested, while we were reading or writing... - // abort our action... - return handler_(boost::asio::error::shut_down, 0); - - if (!is_operation_done && !is_read_needed && !is_write_needed - && !is_shut_down_sent) - { - // The operation has failed... It is not completed and does - // not want network communication nor does want to send shutdown out... - if (error_code == SSL_ERROR_SYSCALL) - { - return handler_(boost::system::error_code( - sys_error_code, boost::asio::error::system_category), rc); - } - else - { - return handler_(boost::system::error_code( - sys_error_code, boost::asio::error::get_ssl_category()), rc); - } - } - - if (!is_operation_done && !is_write_needed) - { - // We may have left over data that we can pass to SSL immediately - if (recv_buf_.get_data_len() > 0) - { - // Pass the buffered data to SSL - int written = ::BIO_write - ( - ssl_bio_, - recv_buf_.get_data_start(), - recv_buf_.get_data_len() - ); - - if (written > 0) - { - recv_buf_.data_removed(written); - } - else if (written < 0) - { - if (!BIO_should_retry(ssl_bio_)) - { - // Some serios error with BIO.... - return handler_(boost::asio::error::no_recovery, 0); - } - } - - return start(); - } - else if (is_read_needed || (is_shut_down_sent && !is_shut_down_received)) - { - return read_(); - } - } - - // Continue with operation, flush any SSL data out to network... - return write_(is_operation_done, rc); - } - -// Private implementation -private: - typedef boost::function<int (const boost::system::error_code&, int)> - int_handler_func; - typedef boost::function<int (bool, int)> write_func; - typedef boost::function<int ()> read_func; - - ssl_primitive_func primitive_; - user_handler_func user_handler_; - boost::asio::io_service::strand* strand_; - write_func write_; - read_func read_; - int_handler_func handler_; - - net_buffer send_buf_; // buffers for network IO - - // The recv buffer is owned by the stream, not the operation, since there can - // be left over bytes after passing the data up to the application, and these - // bytes need to be kept around for the next read operation issued by the - // application. - net_buffer& recv_buf_; - - Stream& socket_; - BIO* ssl_bio_; - SSL* session_; - - // - int sync_user_handler(const boost::system::error_code& error, int rc) - { - if (!error) - return rc; - - throw boost::system::system_error(error); - } - - int async_user_handler(boost::system::error_code error, int rc) - { - if (rc < 0) - { - if (!error) - error = boost::asio::error::no_recovery; - rc = 0; - } - - user_handler_(error, rc); - return 0; - } - - // Writes bytes asynchronously from SSL to NET - int do_async_write(bool is_operation_done, int rc) - { - int len = ::BIO_ctrl_pending( ssl_bio_ ); - if ( len ) - { - // There is something to write into net, do it... - len = (int)send_buf_.get_unused_len() > len? - len: - send_buf_.get_unused_len(); - - if (len == 0) - { - // In case our send buffer is full, we have just to wait until - // previous send to complete... - return 0; - } - - // Read outgoing data from bio - len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len); - - if (len > 0) - { - unsigned char *data_start = send_buf_.get_unused_start(); - send_buf_.data_added(len); - - BOOST_ASIO_ASSERT(strand_); - boost::asio::async_write - ( - socket_, - boost::asio::buffer(data_start, len), - strand_->wrap - ( - boost::bind - ( - &openssl_operation::async_write_handler, - this, - is_operation_done, - rc, - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred - ) - ) - ); - - return 0; - } - else if (!BIO_should_retry(ssl_bio_)) - { - // Seems like fatal error - // reading from SSL BIO has failed... - handler_(boost::asio::error::no_recovery, 0); - return 0; - } - } - - if (is_operation_done) - { - // Finish the operation, with success - handler_(boost::system::error_code(), rc); - return 0; - } - - // OPeration is not done and writing to net has been made... - // start operation again - start(); - - return 0; - } - - void async_write_handler(bool is_operation_done, int rc, - const boost::system::error_code& error, size_t bytes_sent) - { - if (!error) - { - // Remove data from send buffer - send_buf_.data_removed(bytes_sent); - - if (is_operation_done) - handler_(boost::system::error_code(), rc); - else - // Since the operation was not completed, try it again... - start(); - } - else - handler_(error, rc); - } - - int do_async_read() - { - // Wait for new data - BOOST_ASIO_ASSERT(strand_); - socket_.async_read_some - ( - boost::asio::buffer(recv_buf_.get_unused_start(), - recv_buf_.get_unused_len()), - strand_->wrap - ( - boost::bind - ( - &openssl_operation::async_read_handler, - this, - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred - ) - ) - ); - return 0; - } - - void async_read_handler(const boost::system::error_code& error, - size_t bytes_recvd) - { - if (!error) - { - recv_buf_.data_added(bytes_recvd); - - // Pass the received data to SSL - int written = ::BIO_write - ( - ssl_bio_, - recv_buf_.get_data_start(), - recv_buf_.get_data_len() - ); - - if (written > 0) - { - recv_buf_.data_removed(written); - } - else if (written < 0) - { - if (!BIO_should_retry(ssl_bio_)) - { - // Some serios error with BIO.... - handler_(boost::asio::error::no_recovery, 0); - return; - } - } - - // and try the SSL primitive again - start(); - } - else - { - // Error in network level... - // SSL can't continue either... - handler_(error, 0); - } - } - - // Syncronous functions... - int do_sync_write(bool is_operation_done, int rc) - { - int len = ::BIO_ctrl_pending( ssl_bio_ ); - if ( len ) - { - // There is something to write into net, do it... - len = (int)send_buf_.get_unused_len() > len? - len: - send_buf_.get_unused_len(); - - // Read outgoing data from bio - len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len); - - if (len > 0) - { - size_t sent_len = boost::asio::write( - socket_, - boost::asio::buffer(send_buf_.get_unused_start(), len) - ); - - send_buf_.data_added(len); - send_buf_.data_removed(sent_len); - } - else if (!BIO_should_retry(ssl_bio_)) - { - // Seems like fatal error - // reading from SSL BIO has failed... - throw boost::system::system_error(boost::asio::error::no_recovery); - } - } - - if (is_operation_done) - // Finish the operation, with success - return rc; - - // Operation is not finished, start again. - return start(); - } - - int do_sync_read() - { - size_t len = socket_.read_some - ( - boost::asio::buffer(recv_buf_.get_unused_start(), - recv_buf_.get_unused_len()) - ); - - // Write data to ssl - recv_buf_.data_added(len); - - // Pass the received data to SSL - int written = ::BIO_write - ( - ssl_bio_, - recv_buf_.get_data_start(), - recv_buf_.get_data_len() - ); - - if (written > 0) - { - recv_buf_.data_removed(written); - } - else if (written < 0) - { - if (!BIO_should_retry(ssl_bio_)) - { - // Some serios error with BIO.... - throw boost::system::system_error(boost::asio::error::no_recovery); - } - } - - // Try the operation again - return start(); - } -}; // class openssl_operation - -} // namespace detail -} // namespace old -} // namespace ssl -} // namespace asio -} // namespace boost - -#include <boost/asio/detail/pop_options.hpp> - -#endif // BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_OPERATION_HPP diff --git a/boost/asio/ssl/old/detail/openssl_stream_service.hpp b/boost/asio/ssl/old/detail/openssl_stream_service.hpp deleted file mode 100644 index afccf3652a..0000000000 --- a/boost/asio/ssl/old/detail/openssl_stream_service.hpp +++ /dev/null @@ -1,573 +0,0 @@ -// -// ssl/old/detail/stream_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2017 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) -// - -#ifndef BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP -#define BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include <boost/asio/detail/config.hpp> -#include <cstddef> -#include <climits> -#include <memory> -#include <boost/config.hpp> -#include <boost/noncopyable.hpp> -#include <boost/function.hpp> -#include <boost/bind.hpp> -#include <boost/asio/detail/buffer_sequence_adapter.hpp> -#include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> -#include <boost/asio/ssl/basic_context.hpp> -#include <boost/asio/ssl/stream_base.hpp> -#include <boost/asio/ssl/old/detail/openssl_operation.hpp> -#include <boost/asio/ssl/detail/openssl_types.hpp> -#include <boost/asio/strand.hpp> -#include <boost/system/system_error.hpp> - -#include <boost/asio/detail/push_options.hpp> - -namespace boost { -namespace asio { -namespace ssl { -namespace old { -namespace detail { - -class openssl_stream_service - : public boost::asio::detail::service_base<openssl_stream_service> -{ -private: - enum { max_buffer_size = INT_MAX }; - - //Base handler for asyncrhonous operations - template <typename Stream> - class base_handler - { - public: - typedef boost::function< - void (const boost::system::error_code&, size_t)> func_t; - - base_handler(boost::asio::io_service& io_service) - : op_(NULL) - , io_service_(io_service) - , work_(io_service) - {} - - void do_func(const boost::system::error_code& error, size_t size) - { - func_(error, size); - } - - void set_operation(openssl_operation<Stream>* op) { op_ = op; } - void set_func(func_t func) { func_ = func; } - - ~base_handler() - { - delete op_; - } - - private: - func_t func_; - openssl_operation<Stream>* op_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; - }; // class base_handler - - // Handler for asynchronous IO (write/read) operations - template<typename Stream, typename Handler> - class io_handler - : public base_handler<Stream> - { - public: - io_handler(Handler handler, boost::asio::io_service& io_service) - : base_handler<Stream>(io_service) - , handler_(handler) - { - this->set_func(boost::bind( - &io_handler<Stream, Handler>::handler_impl, - this, boost::arg<1>(), boost::arg<2>() )); - } - - private: - Handler handler_; - void handler_impl(const boost::system::error_code& error, size_t size) - { - std::auto_ptr<io_handler<Stream, Handler> > this_ptr(this); - handler_(error, size); - } - }; // class io_handler - - // Handler for asyncrhonous handshake (connect, accept) functions - template <typename Stream, typename Handler> - class handshake_handler - : public base_handler<Stream> - { - public: - handshake_handler(Handler handler, boost::asio::io_service& io_service) - : base_handler<Stream>(io_service) - , handler_(handler) - { - this->set_func(boost::bind( - &handshake_handler<Stream, Handler>::handler_impl, - this, boost::arg<1>(), boost::arg<2>() )); - } - - private: - Handler handler_; - void handler_impl(const boost::system::error_code& error, size_t) - { - std::auto_ptr<handshake_handler<Stream, Handler> > this_ptr(this); - handler_(error); - } - - }; // class handshake_handler - - // Handler for asyncrhonous shutdown - template <typename Stream, typename Handler> - class shutdown_handler - : public base_handler<Stream> - { - public: - shutdown_handler(Handler handler, boost::asio::io_service& io_service) - : base_handler<Stream>(io_service), - handler_(handler) - { - this->set_func(boost::bind( - &shutdown_handler<Stream, Handler>::handler_impl, - this, boost::arg<1>(), boost::arg<2>() )); - } - - private: - Handler handler_; - void handler_impl(const boost::system::error_code& error, size_t) - { - std::auto_ptr<shutdown_handler<Stream, Handler> > this_ptr(this); - handler_(error); - } - }; // class shutdown_handler - -public: - // The implementation type. - typedef struct impl_struct - { - ::SSL* ssl; - ::BIO* ext_bio; - net_buffer recv_buf; - } * impl_type; - - // Construct a new stream socket service for the specified io_service. - explicit openssl_stream_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base<openssl_stream_service>(io_service), - strand_(io_service) - { - } - - // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - } - - // Return a null stream implementation. - impl_type null() const - { - return 0; - } - - // Create a new stream implementation. - template <typename Stream, typename Context_Service> - void create(impl_type& impl, Stream& /*next_layer*/, - basic_context<Context_Service>& context) - { - impl = new impl_struct; - impl->ssl = ::SSL_new(context.impl()); - ::SSL_set_mode(impl->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE); - ::SSL_set_mode(impl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - ::BIO* int_bio = 0; - impl->ext_bio = 0; - ::BIO_new_bio_pair(&int_bio, 8192, &impl->ext_bio, 8192); - ::SSL_set_bio(impl->ssl, int_bio, int_bio); - } - - // Destroy a stream implementation. - template <typename Stream> - void destroy(impl_type& impl, Stream& /*next_layer*/) - { - if (impl != 0) - { - ::BIO_free(impl->ext_bio); - ::SSL_free(impl->ssl); - delete impl; - impl = 0; - } - } - - // Perform SSL handshaking. - template <typename Stream> - boost::system::error_code handshake(impl_type& impl, Stream& next_layer, - stream_base::handshake_type type, boost::system::error_code& ec) - { - try - { - openssl_operation<Stream> op( - type == stream_base::client ? - &ssl_wrap<mutex_type>::SSL_connect: - &ssl_wrap<mutex_type>::SSL_accept, - next_layer, - impl->recv_buf, - impl->ssl, - impl->ext_bio); - op.start(); - } - catch (boost::system::system_error& e) - { - ec = e.code(); - return ec; - } - - ec = boost::system::error_code(); - return ec; - } - - // Start an asynchronous SSL handshake. - template <typename Stream, typename Handler> - void async_handshake(impl_type& impl, Stream& next_layer, - stream_base::handshake_type type, Handler handler) - { - typedef handshake_handler<Stream, Handler> connect_handler; - - connect_handler* local_handler = - new connect_handler(handler, get_io_service()); - - openssl_operation<Stream>* op = new openssl_operation<Stream> - ( - type == stream_base::client ? - &ssl_wrap<mutex_type>::SSL_connect: - &ssl_wrap<mutex_type>::SSL_accept, - next_layer, - impl->recv_buf, - impl->ssl, - impl->ext_bio, - boost::bind - ( - &base_handler<Stream>::do_func, - local_handler, - boost::arg<1>(), - boost::arg<2>() - ), - strand_ - ); - local_handler->set_operation(op); - - strand_.post(boost::bind(&openssl_operation<Stream>::start, op)); - } - - // Shut down SSL on the stream. - template <typename Stream> - boost::system::error_code shutdown(impl_type& impl, Stream& next_layer, - boost::system::error_code& ec) - { - try - { - openssl_operation<Stream> op( - &ssl_wrap<mutex_type>::SSL_shutdown, - next_layer, - impl->recv_buf, - impl->ssl, - impl->ext_bio); - op.start(); - } - catch (boost::system::system_error& e) - { - ec = e.code(); - return ec; - } - - ec = boost::system::error_code(); - return ec; - } - - // Asynchronously shut down SSL on the stream. - template <typename Stream, typename Handler> - void async_shutdown(impl_type& impl, Stream& next_layer, Handler handler) - { - typedef shutdown_handler<Stream, Handler> disconnect_handler; - - disconnect_handler* local_handler = - new disconnect_handler(handler, get_io_service()); - - openssl_operation<Stream>* op = new openssl_operation<Stream> - ( - &ssl_wrap<mutex_type>::SSL_shutdown, - next_layer, - impl->recv_buf, - impl->ssl, - impl->ext_bio, - boost::bind - ( - &base_handler<Stream>::do_func, - local_handler, - boost::arg<1>(), - boost::arg<2>() - ), - strand_ - ); - local_handler->set_operation(op); - - strand_.post(boost::bind(&openssl_operation<Stream>::start, op)); - } - - // Write some data to the stream. - template <typename Stream, typename Const_Buffers> - std::size_t write_some(impl_type& impl, Stream& next_layer, - const Const_Buffers& buffers, boost::system::error_code& ec) - { - size_t bytes_transferred = 0; - try - { - boost::asio::const_buffer buffer = - boost::asio::detail::buffer_sequence_adapter< - boost::asio::const_buffer, Const_Buffers>::first(buffers); - - std::size_t buffer_size = boost::asio::buffer_size(buffer); - if (buffer_size > max_buffer_size) - buffer_size = max_buffer_size; - else if (buffer_size == 0) - { - ec = boost::system::error_code(); - return 0; - } - - boost::function<int (SSL*)> send_func = - boost::bind(boost::type<int>(), &::SSL_write, boost::arg<1>(), - boost::asio::buffer_cast<const void*>(buffer), - static_cast<int>(buffer_size)); - openssl_operation<Stream> op( - send_func, - next_layer, - impl->recv_buf, - impl->ssl, - impl->ext_bio - ); - bytes_transferred = static_cast<size_t>(op.start()); - } - catch (boost::system::system_error& e) - { - ec = e.code(); - return 0; - } - - ec = boost::system::error_code(); - return bytes_transferred; - } - - // Start an asynchronous write. - template <typename Stream, typename Const_Buffers, typename Handler> - void async_write_some(impl_type& impl, Stream& next_layer, - const Const_Buffers& buffers, Handler handler) - { - typedef io_handler<Stream, Handler> send_handler; - - boost::asio::const_buffer buffer = - boost::asio::detail::buffer_sequence_adapter< - boost::asio::const_buffer, Const_Buffers>::first(buffers); - - std::size_t buffer_size = boost::asio::buffer_size(buffer); - if (buffer_size > max_buffer_size) - buffer_size = max_buffer_size; - else if (buffer_size == 0) - { - get_io_service().post(boost::asio::detail::bind_handler( - handler, boost::system::error_code(), 0)); - return; - } - - send_handler* local_handler = new send_handler(handler, get_io_service()); - - boost::function<int (SSL*)> send_func = - boost::bind(boost::type<int>(), &::SSL_write, boost::arg<1>(), - boost::asio::buffer_cast<const void*>(buffer), - static_cast<int>(buffer_size)); - - openssl_operation<Stream>* op = new openssl_operation<Stream> - ( - send_func, - next_layer, - impl->recv_buf, - impl->ssl, - impl->ext_bio, - boost::bind - ( - &base_handler<Stream>::do_func, - local_handler, - boost::arg<1>(), - boost::arg<2>() - ), - strand_ - ); - local_handler->set_operation(op); - - strand_.post(boost::bind(&openssl_operation<Stream>::start, op)); - } - - // Read some data from the stream. - template <typename Stream, typename Mutable_Buffers> - std::size_t read_some(impl_type& impl, Stream& next_layer, - const Mutable_Buffers& buffers, boost::system::error_code& ec) - { - size_t bytes_transferred = 0; - try - { - boost::asio::mutable_buffer buffer = - boost::asio::detail::buffer_sequence_adapter< - boost::asio::mutable_buffer, Mutable_Buffers>::first(buffers); - - std::size_t buffer_size = boost::asio::buffer_size(buffer); - if (buffer_size > max_buffer_size) - buffer_size = max_buffer_size; - else if (buffer_size == 0) - { - ec = boost::system::error_code(); - return 0; - } - - boost::function<int (SSL*)> recv_func = - boost::bind(boost::type<int>(), &::SSL_read, boost::arg<1>(), - boost::asio::buffer_cast<void*>(buffer), - static_cast<int>(buffer_size)); - openssl_operation<Stream> op(recv_func, - next_layer, - impl->recv_buf, - impl->ssl, - impl->ext_bio - ); - - bytes_transferred = static_cast<size_t>(op.start()); - } - catch (boost::system::system_error& e) - { - ec = e.code(); - return 0; - } - - ec = boost::system::error_code(); - return bytes_transferred; - } - - // Start an asynchronous read. - template <typename Stream, typename Mutable_Buffers, typename Handler> - void async_read_some(impl_type& impl, Stream& next_layer, - const Mutable_Buffers& buffers, Handler handler) - { - typedef io_handler<Stream, Handler> recv_handler; - - boost::asio::mutable_buffer buffer = - boost::asio::detail::buffer_sequence_adapter< - boost::asio::mutable_buffer, Mutable_Buffers>::first(buffers); - - std::size_t buffer_size = boost::asio::buffer_size(buffer); - if (buffer_size > max_buffer_size) - buffer_size = max_buffer_size; - else if (buffer_size == 0) - { - get_io_service().post(boost::asio::detail::bind_handler( - handler, boost::system::error_code(), 0)); - return; - } - - recv_handler* local_handler = new recv_handler(handler, get_io_service()); - - boost::function<int (SSL*)> recv_func = - boost::bind(boost::type<int>(), &::SSL_read, boost::arg<1>(), - boost::asio::buffer_cast<void*>(buffer), - static_cast<int>(buffer_size)); - - openssl_operation<Stream>* op = new openssl_operation<Stream> - ( - recv_func, - next_layer, - impl->recv_buf, - impl->ssl, - impl->ext_bio, - boost::bind - ( - &base_handler<Stream>::do_func, - local_handler, - boost::arg<1>(), - boost::arg<2>() - ), - strand_ - ); - local_handler->set_operation(op); - - strand_.post(boost::bind(&openssl_operation<Stream>::start, op)); - } - - // Peek at the incoming data on the stream. - template <typename Stream, typename Mutable_Buffers> - std::size_t peek(impl_type& /*impl*/, Stream& /*next_layer*/, - const Mutable_Buffers& /*buffers*/, boost::system::error_code& ec) - { - ec = boost::system::error_code(); - return 0; - } - - // Determine the amount of data that may be read without blocking. - template <typename Stream> - std::size_t in_avail(impl_type& /*impl*/, Stream& /*next_layer*/, - boost::system::error_code& ec) - { - ec = boost::system::error_code(); - return 0; - } - -private: - boost::asio::io_service::strand strand_; - - typedef boost::asio::detail::mutex mutex_type; - - template<typename Mutex> - struct ssl_wrap - { - static Mutex ssl_mutex_; - - static int SSL_accept(SSL *ssl) - { - typename Mutex::scoped_lock lock(ssl_mutex_); - return ::SSL_accept(ssl); - } - - static int SSL_connect(SSL *ssl) - { - typename Mutex::scoped_lock lock(ssl_mutex_); - return ::SSL_connect(ssl); - } - - static int SSL_shutdown(SSL *ssl) - { - typename Mutex::scoped_lock lock(ssl_mutex_); - return ::SSL_shutdown(ssl); - } - }; -}; - -template<typename Mutex> -Mutex openssl_stream_service::ssl_wrap<Mutex>::ssl_mutex_; - -} // namespace detail -} // namespace old -} // namespace ssl -} // namespace asio -} // namespace boost - -#include <boost/asio/detail/pop_options.hpp> - -#endif // BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP diff --git a/boost/asio/ssl/old/stream.hpp b/boost/asio/ssl/old/stream.hpp deleted file mode 100644 index a8c570ee08..0000000000 --- a/boost/asio/ssl/old/stream.hpp +++ /dev/null @@ -1,503 +0,0 @@ -// -// ssl/old/stream.hpp -// ~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2017 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) -// - -#ifndef BOOST_ASIO_SSL_OLD_STREAM_HPP -#define BOOST_ASIO_SSL_OLD_STREAM_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include <boost/asio/detail/config.hpp> -#include <cstddef> -#include <boost/noncopyable.hpp> -#include <boost/asio/detail/throw_error.hpp> -#include <boost/asio/detail/type_traits.hpp> -#include <boost/asio/error.hpp> -#include <boost/asio/ssl/basic_context.hpp> -#include <boost/asio/ssl/stream_base.hpp> -#include <boost/asio/ssl/stream_service.hpp> - -#include <boost/asio/detail/push_options.hpp> - -namespace boost { -namespace asio { -namespace ssl { -namespace old { - -/// Provides stream-oriented functionality using SSL. -/** - * The stream class template provides asynchronous and blocking stream-oriented - * functionality using SSL. - * - * @par Thread Safety - * @e Distinct @e objects: Safe.@n - * @e Shared @e objects: Unsafe. - * - * @par Example - * To use the SSL stream template with an ip::tcp::socket, you would write: - * @code - * boost::asio::io_service io_service; - * boost::asio::ssl::context context(io_service, boost::asio::ssl::context::sslv23); - * boost::asio::ssl::stream<boost::asio::ip::tcp::socket> sock(io_service, context); - * @endcode - * - * @par Concepts: - * AsyncReadStream, AsyncWriteStream, Stream, SyncRead_Stream, SyncWriteStream. - */ -template <typename Stream, typename Service = old::stream_service> -class stream - : public stream_base, - private boost::noncopyable -{ -public: - /// The type of the next layer. - typedef typename remove_reference<Stream>::type next_layer_type; - - /// The type of the lowest layer. - typedef typename next_layer_type::lowest_layer_type lowest_layer_type; - - /// The type of the service that will be used to provide stream operations. - typedef Service service_type; - - /// The native implementation type of the stream. - typedef typename service_type::impl_type impl_type; - - /// Construct a stream. - /** - * This constructor creates a stream and initialises the underlying stream - * object. - * - * @param arg The argument to be passed to initialise the underlying stream. - * - * @param context The SSL context to be used for the stream. - */ - template <typename Arg, typename Context_Service> - explicit stream(Arg& arg, basic_context<Context_Service>& context) - : next_layer_(arg), - service_(boost::asio::use_service<Service>(next_layer_.get_io_service())), - impl_(service_.null()) - { - service_.create(impl_, next_layer_, context); - } - - /// Destructor. - ~stream() - { - service_.destroy(impl_, next_layer_); - } - - /// Get the io_service associated with the object. - /** - * This function may be used to obtain the io_service object that the stream - * uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_service object that stream will use to - * dispatch handlers. Ownership is not transferred to the caller. - */ - boost::asio::io_service& get_io_service() - { - return next_layer_.get_io_service(); - } - - /// Get a reference to the next layer. - /** - * This function returns a reference to the next layer in a stack of stream - * layers. - * - * @return A reference to the next layer in the stack of stream layers. - * Ownership is not transferred to the caller. - */ - next_layer_type& next_layer() - { - return next_layer_; - } - - /// Get a reference to the lowest layer. - /** - * This function returns a reference to the lowest layer in a stack of - * stream layers. - * - * @return A reference to the lowest layer in the stack of stream layers. - * Ownership is not transferred to the caller. - */ - lowest_layer_type& lowest_layer() - { - return next_layer_.lowest_layer(); - } - - /// Get a const reference to the lowest layer. - /** - * This function returns a const reference to the lowest layer in a stack of - * stream layers. - * - * @return A const reference to the lowest layer in the stack of stream - * layers. Ownership is not transferred to the caller. - */ - const lowest_layer_type& lowest_layer() const - { - return next_layer_.lowest_layer(); - } - - /// Get the underlying implementation in the native type. - /** - * This function may be used to obtain the underlying implementation of the - * context. This is intended to allow access to stream functionality that is - * not otherwise provided. - */ - impl_type impl() - { - return impl_; - } - - /// Perform SSL handshaking. - /** - * This function is used to perform SSL handshaking on the stream. The - * function call will block until handshaking is complete or an error occurs. - * - * @param type The type of handshaking to be performed, i.e. as a client or as - * a server. - * - * @throws boost::system::system_error Thrown on failure. - */ - void handshake(handshake_type type) - { - boost::system::error_code ec; - service_.handshake(impl_, next_layer_, type, ec); - boost::asio::detail::throw_error(ec); - } - - /// Perform SSL handshaking. - /** - * This function is used to perform SSL handshaking on the stream. The - * function call will block until handshaking is complete or an error occurs. - * - * @param type The type of handshaking to be performed, i.e. as a client or as - * a server. - * - * @param ec Set to indicate what error occurred, if any. - */ - boost::system::error_code handshake(handshake_type type, - boost::system::error_code& ec) - { - return service_.handshake(impl_, next_layer_, type, ec); - } - - /// Start an asynchronous SSL handshake. - /** - * This function is used to asynchronously perform an SSL handshake on the - * stream. This function call always returns immediately. - * - * @param type The type of handshaking to be performed, i.e. as a client or as - * a server. - * - * @param handler The handler to be called when the handshake operation - * completes. Copies will be made of the handler as required. The equivalent - * function signature of the handler must be: - * @code void handler( - * const boost::system::error_code& error // Result of operation. - * ); @endcode - */ - template <typename HandshakeHandler> - void async_handshake(handshake_type type, HandshakeHandler handler) - { - service_.async_handshake(impl_, next_layer_, type, handler); - } - - /// Shut down SSL on the stream. - /** - * This function is used to shut down SSL on the stream. The function call - * will block until SSL has been shut down or an error occurs. - * - * @throws boost::system::system_error Thrown on failure. - */ - void shutdown() - { - boost::system::error_code ec; - service_.shutdown(impl_, next_layer_, ec); - boost::asio::detail::throw_error(ec); - } - - /// Shut down SSL on the stream. - /** - * This function is used to shut down SSL on the stream. The function call - * will block until SSL has been shut down or an error occurs. - * - * @param ec Set to indicate what error occurred, if any. - */ - boost::system::error_code shutdown(boost::system::error_code& ec) - { - return service_.shutdown(impl_, next_layer_, ec); - } - - /// Asynchronously shut down SSL on the stream. - /** - * This function is used to asynchronously shut down SSL on the stream. This - * function call always returns immediately. - * - * @param handler The handler to be called when the handshake operation - * completes. Copies will be made of the handler as required. The equivalent - * function signature of the handler must be: - * @code void handler( - * const boost::system::error_code& error // Result of operation. - * ); @endcode - */ - template <typename ShutdownHandler> - void async_shutdown(ShutdownHandler handler) - { - service_.async_shutdown(impl_, next_layer_, handler); - } - - /// Write some data to the stream. - /** - * This function is used to write data on the stream. The function call will - * block until one or more bytes of data has been written successfully, or - * until an error occurs. - * - * @param buffers The data to be written. - * - * @returns The number of bytes written. - * - * @throws boost::system::system_error Thrown on failure. - * - * @note The write_some operation may not transmit all of the data to the - * peer. Consider using the @ref write function if you need to ensure that all - * data is written before the blocking operation completes. - */ - template <typename ConstBufferSequence> - std::size_t write_some(const ConstBufferSequence& buffers) - { - boost::system::error_code ec; - std::size_t s = service_.write_some(impl_, next_layer_, buffers, ec); - boost::asio::detail::throw_error(ec); - return s; - } - - /// Write some data to the stream. - /** - * This function is used to write data on the stream. The function call will - * block until one or more bytes of data has been written successfully, or - * until an error occurs. - * - * @param buffers The data to be written to the stream. - * - * @param ec Set to indicate what error occurred, if any. - * - * @returns The number of bytes written. Returns 0 if an error occurred. - * - * @note The write_some operation may not transmit all of the data to the - * peer. Consider using the @ref write function if you need to ensure that all - * data is written before the blocking operation completes. - */ - template <typename ConstBufferSequence> - std::size_t write_some(const ConstBufferSequence& buffers, - boost::system::error_code& ec) - { - return service_.write_some(impl_, next_layer_, buffers, ec); - } - - /// Start an asynchronous write. - /** - * This function is used to asynchronously write one or more bytes of data to - * the stream. The function call always returns immediately. - * - * @param buffers The data to be written to the stream. Although the buffers - * object may be copied as necessary, ownership of the underlying buffers is - * retained by the caller, which must guarantee that they remain valid until - * the handler is called. - * - * @param handler The handler to be called when the write operation completes. - * Copies will be made of the handler as required. The equivalent function - * signature of the handler must be: - * @code void handler( - * const boost::system::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes written. - * ); @endcode - * - * @note The async_write_some operation may not transmit all of the data to - * the peer. Consider using the @ref async_write function if you need to - * ensure that all data is written before the blocking operation completes. - */ - template <typename ConstBufferSequence, typename WriteHandler> - void async_write_some(const ConstBufferSequence& buffers, - WriteHandler handler) - { - service_.async_write_some(impl_, next_layer_, buffers, handler); - } - - /// Read some data from the stream. - /** - * This function is used to read data from the stream. The function call will - * block until one or more bytes of data has been read successfully, or until - * an error occurs. - * - * @param buffers The buffers into which the data will be read. - * - * @returns The number of bytes read. - * - * @throws boost::system::system_error Thrown on failure. - * - * @note The read_some operation may not read all of the requested number of - * bytes. Consider using the @ref read function if you need to ensure that the - * requested amount of data is read before the blocking operation completes. - */ - template <typename MutableBufferSequence> - std::size_t read_some(const MutableBufferSequence& buffers) - { - boost::system::error_code ec; - std::size_t s = service_.read_some(impl_, next_layer_, buffers, ec); - boost::asio::detail::throw_error(ec); - return s; - } - - /// Read some data from the stream. - /** - * This function is used to read data from the stream. The function call will - * block until one or more bytes of data has been read successfully, or until - * an error occurs. - * - * @param buffers The buffers into which the data will be read. - * - * @param ec Set to indicate what error occurred, if any. - * - * @returns The number of bytes read. Returns 0 if an error occurred. - * - * @note The read_some operation may not read all of the requested number of - * bytes. Consider using the @ref read function if you need to ensure that the - * requested amount of data is read before the blocking operation completes. - */ - template <typename MutableBufferSequence> - std::size_t read_some(const MutableBufferSequence& buffers, - boost::system::error_code& ec) - { - return service_.read_some(impl_, next_layer_, buffers, ec); - } - - /// Start an asynchronous read. - /** - * This function is used to asynchronously read one or more bytes of data from - * the stream. The function call always returns immediately. - * - * @param buffers The buffers into which the data will be read. Although the - * buffers object may be copied as necessary, ownership of the underlying - * buffers is retained by the caller, which must guarantee that they remain - * valid until the handler is called. - * - * @param handler The handler to be called when the read operation completes. - * Copies will be made of the handler as required. The equivalent function - * signature of the handler must be: - * @code void handler( - * const boost::system::error_code& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes read. - * ); @endcode - * - * @note The async_read_some operation may not read all of the requested - * number of bytes. Consider using the @ref async_read function if you need to - * ensure that the requested amount of data is read before the asynchronous - * operation completes. - */ - template <typename MutableBufferSequence, typename ReadHandler> - void async_read_some(const MutableBufferSequence& buffers, - ReadHandler handler) - { - service_.async_read_some(impl_, next_layer_, buffers, handler); - } - - /// Peek at the incoming data on the stream. - /** - * This function is used to peek at the incoming data on the stream, without - * removing it from the input queue. The function call will block until data - * has been read successfully or an error occurs. - * - * @param buffers The buffers into which the data will be read. - * - * @returns The number of bytes read. - * - * @throws boost::system::system_error Thrown on failure. - */ - template <typename MutableBufferSequence> - std::size_t peek(const MutableBufferSequence& buffers) - { - boost::system::error_code ec; - std::size_t s = service_.peek(impl_, next_layer_, buffers, ec); - boost::asio::detail::throw_error(ec); - return s; - } - - /// Peek at the incoming data on the stream. - /** - * This function is used to peek at the incoming data on the stream, withoutxi - * removing it from the input queue. The function call will block until data - * has been read successfully or an error occurs. - * - * @param buffers The buffers into which the data will be read. - * - * @param ec Set to indicate what error occurred, if any. - * - * @returns The number of bytes read. Returns 0 if an error occurred. - */ - template <typename MutableBufferSequence> - std::size_t peek(const MutableBufferSequence& buffers, - boost::system::error_code& ec) - { - return service_.peek(impl_, next_layer_, buffers, ec); - } - - /// Determine the amount of data that may be read without blocking. - /** - * This function is used to determine the amount of data, in bytes, that may - * be read from the stream without blocking. - * - * @returns The number of bytes of data that can be read without blocking. - * - * @throws boost::system::system_error Thrown on failure. - */ - std::size_t in_avail() - { - boost::system::error_code ec; - std::size_t s = service_.in_avail(impl_, next_layer_, ec); - boost::asio::detail::throw_error(ec); - return s; - } - - /// Determine the amount of data that may be read without blocking. - /** - * This function is used to determine the amount of data, in bytes, that may - * be read from the stream without blocking. - * - * @param ec Set to indicate what error occurred, if any. - * - * @returns The number of bytes of data that can be read without blocking. - */ - std::size_t in_avail(boost::system::error_code& ec) - { - return service_.in_avail(impl_, next_layer_, ec); - } - -private: - /// The next layer. - Stream next_layer_; - - /// The backend service implementation. - service_type& service_; - - /// The underlying native implementation. - impl_type impl_; -}; - -} // namespace old -} // namespace ssl -} // namespace asio -} // namespace boost - -#include <boost/asio/detail/pop_options.hpp> - -#endif // BOOST_ASIO_SSL_OLD_STREAM_HPP diff --git a/boost/asio/ssl/old/stream_service.hpp b/boost/asio/ssl/old/stream_service.hpp deleted file mode 100644 index 282687c2ea..0000000000 --- a/boost/asio/ssl/old/stream_service.hpp +++ /dev/null @@ -1,186 +0,0 @@ -// -// ssl/old/stream_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2017 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) -// - -#ifndef BOOST_ASIO_SSL_OLD_STREAM_SERVICE_HPP -#define BOOST_ASIO_SSL_OLD_STREAM_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include <boost/asio/detail/config.hpp> -#include <cstddef> -#include <boost/noncopyable.hpp> -#include <boost/asio/io_service.hpp> -#include <boost/asio/ssl/basic_context.hpp> -#include <boost/asio/ssl/old/detail/openssl_stream_service.hpp> -#include <boost/asio/ssl/stream_base.hpp> - -#include <boost/asio/detail/push_options.hpp> - -namespace boost { -namespace asio { -namespace ssl { -namespace old { - -/// Default service implementation for an SSL stream. -class stream_service -#if defined(GENERATING_DOCUMENTATION) - : public boost::asio::io_service::service -#else - : public boost::asio::detail::service_base<stream_service> -#endif -{ -private: - // The type of the platform-specific implementation. - typedef old::detail::openssl_stream_service service_impl_type; - -public: -#if defined(GENERATING_DOCUMENTATION) - /// The unique service identifier. - static boost::asio::io_service::id id; -#endif - - /// The type of a stream implementation. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined impl_type; -#else - typedef service_impl_type::impl_type impl_type; -#endif - - /// Construct a new stream service for the specified io_service. - explicit stream_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base<stream_service>(io_service), - service_impl_(boost::asio::use_service<service_impl_type>(io_service)) - { - } - - /// Return a null stream implementation. - impl_type null() const - { - return service_impl_.null(); - } - - /// Create a new stream implementation. - template <typename Stream, typename Context_Service> - void create(impl_type& impl, Stream& next_layer, - basic_context<Context_Service>& context) - { - service_impl_.create(impl, next_layer, context); - } - - /// Destroy a stream implementation. - template <typename Stream> - void destroy(impl_type& impl, Stream& next_layer) - { - service_impl_.destroy(impl, next_layer); - } - - /// Perform SSL handshaking. - template <typename Stream> - boost::system::error_code handshake(impl_type& impl, Stream& next_layer, - stream_base::handshake_type type, boost::system::error_code& ec) - { - return service_impl_.handshake(impl, next_layer, type, ec); - } - - /// Start an asynchronous SSL handshake. - template <typename Stream, typename HandshakeHandler> - void async_handshake(impl_type& impl, Stream& next_layer, - stream_base::handshake_type type, HandshakeHandler handler) - { - service_impl_.async_handshake(impl, next_layer, type, handler); - } - - /// Shut down SSL on the stream. - template <typename Stream> - boost::system::error_code shutdown(impl_type& impl, Stream& next_layer, - boost::system::error_code& ec) - { - return service_impl_.shutdown(impl, next_layer, ec); - } - - /// Asynchronously shut down SSL on the stream. - template <typename Stream, typename ShutdownHandler> - void async_shutdown(impl_type& impl, Stream& next_layer, - ShutdownHandler handler) - { - service_impl_.async_shutdown(impl, next_layer, handler); - } - - /// Write some data to the stream. - template <typename Stream, typename ConstBufferSequence> - std::size_t write_some(impl_type& impl, Stream& next_layer, - const ConstBufferSequence& buffers, boost::system::error_code& ec) - { - return service_impl_.write_some(impl, next_layer, buffers, ec); - } - - /// Start an asynchronous write. - template <typename Stream, typename ConstBufferSequence, - typename WriteHandler> - void async_write_some(impl_type& impl, Stream& next_layer, - const ConstBufferSequence& buffers, WriteHandler handler) - { - service_impl_.async_write_some(impl, next_layer, buffers, handler); - } - - /// Read some data from the stream. - template <typename Stream, typename MutableBufferSequence> - std::size_t read_some(impl_type& impl, Stream& next_layer, - const MutableBufferSequence& buffers, boost::system::error_code& ec) - { - return service_impl_.read_some(impl, next_layer, buffers, ec); - } - - /// Start an asynchronous read. - template <typename Stream, typename MutableBufferSequence, - typename ReadHandler> - void async_read_some(impl_type& impl, Stream& next_layer, - const MutableBufferSequence& buffers, ReadHandler handler) - { - service_impl_.async_read_some(impl, next_layer, buffers, handler); - } - - /// Peek at the incoming data on the stream. - template <typename Stream, typename MutableBufferSequence> - std::size_t peek(impl_type& impl, Stream& next_layer, - const MutableBufferSequence& buffers, boost::system::error_code& ec) - { - return service_impl_.peek(impl, next_layer, buffers, ec); - } - - /// Determine the amount of data that may be read without blocking. - template <typename Stream> - std::size_t in_avail(impl_type& impl, Stream& next_layer, - boost::system::error_code& ec) - { - return service_impl_.in_avail(impl, next_layer, ec); - } - -private: - // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - } - - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; -}; - -} // namespace old -} // namespace ssl -} // namespace asio -} // namespace boost - -#include <boost/asio/detail/pop_options.hpp> - -#endif // BOOST_ASIO_SSL_OLD_STREAM_SERVICE_HPP diff --git a/boost/asio/ssl/rfc2818_verification.hpp b/boost/asio/ssl/rfc2818_verification.hpp index 21b0bca317..62919d79bf 100644 --- a/boost/asio/ssl/rfc2818_verification.hpp +++ b/boost/asio/ssl/rfc2818_verification.hpp @@ -17,11 +17,9 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <string> -# include <boost/asio/ssl/detail/openssl_types.hpp> -# include <boost/asio/ssl/verify_context.hpp> -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <string> +#include <boost/asio/ssl/detail/openssl_types.hpp> +#include <boost/asio/ssl/verify_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -29,8 +27,6 @@ namespace boost { namespace asio { namespace ssl { -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) - /// Verifies a certificate against a hostname according to the rules described /// in RFC 2818. /** @@ -47,9 +43,9 @@ namespace ssl { * ctx.set_default_verify_paths(); * * // Open a socket and connect it to the remote host. - * boost::asio::io_service io_service; - * ssl_socket sock(io_service, ctx); - * tcp::resolver resolver(io_service); + * boost::asio::io_context io_context; + * ssl_socket sock(io_context, ctx); + * tcp::resolver resolver(io_context); * tcp::resolver::query query("host.name", "https"); * boost::asio::connect(sock.lowest_layer(), resolver.resolve(query)); * sock.lowest_layer().set_option(tcp::no_delay(true)); @@ -87,8 +83,6 @@ private: std::string host_; }; -#endif // defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace ssl } // namespace asio } // namespace boost diff --git a/boost/asio/ssl/stream.hpp b/boost/asio/ssl/stream.hpp index 1b883d3245..860538156c 100644 --- a/boost/asio/ssl/stream.hpp +++ b/boost/asio/ssl/stream.hpp @@ -17,24 +17,20 @@ #include <boost/asio/detail/config.hpp> -#if defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/ssl/old/stream.hpp> -#else // defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/async_result.hpp> -# include <boost/asio/detail/buffer_sequence_adapter.hpp> -# include <boost/asio/detail/handler_type_requirements.hpp> -# include <boost/asio/detail/noncopyable.hpp> -# include <boost/asio/detail/type_traits.hpp> -# include <boost/asio/ssl/context.hpp> -# include <boost/asio/ssl/detail/buffered_handshake_op.hpp> -# include <boost/asio/ssl/detail/handshake_op.hpp> -# include <boost/asio/ssl/detail/io.hpp> -# include <boost/asio/ssl/detail/read_op.hpp> -# include <boost/asio/ssl/detail/shutdown_op.hpp> -# include <boost/asio/ssl/detail/stream_core.hpp> -# include <boost/asio/ssl/detail/write_op.hpp> -# include <boost/asio/ssl/stream_base.hpp> -#endif // defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <boost/asio/async_result.hpp> +#include <boost/asio/detail/buffer_sequence_adapter.hpp> +#include <boost/asio/detail/handler_type_requirements.hpp> +#include <boost/asio/detail/noncopyable.hpp> +#include <boost/asio/detail/type_traits.hpp> +#include <boost/asio/ssl/context.hpp> +#include <boost/asio/ssl/detail/buffered_handshake_op.hpp> +#include <boost/asio/ssl/detail/handshake_op.hpp> +#include <boost/asio/ssl/detail/io.hpp> +#include <boost/asio/ssl/detail/read_op.hpp> +#include <boost/asio/ssl/detail/shutdown_op.hpp> +#include <boost/asio/ssl/detail/stream_core.hpp> +#include <boost/asio/ssl/detail/write_op.hpp> +#include <boost/asio/ssl/stream_base.hpp> #include <boost/asio/detail/push_options.hpp> @@ -42,12 +38,6 @@ namespace boost { namespace asio { namespace ssl { -#if defined(BOOST_ASIO_ENABLE_OLD_SSL) - -using boost::asio::ssl::old::stream; - -#else // defined(BOOST_ASIO_ENABLE_OLD_SSL) - /// Provides stream-oriented functionality using SSL. /** * The stream class template provides asynchronous and blocking stream-oriented @@ -62,9 +52,9 @@ using boost::asio::ssl::old::stream; * @par Example * To use the SSL stream template with an ip::tcp::socket, you would write: * @code - * boost::asio::io_service io_service; + * boost::asio::io_context io_context; * boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23); - * boost::asio::ssl::stream<asio:ip::tcp::socket> sock(io_service, ctx); + * boost::asio::ssl::stream<asio:ip::tcp::socket> sock(io_context, ctx); * @endcode * * @par Concepts: @@ -85,15 +75,16 @@ public: SSL* ssl; }; - /// (Deprecated: Use native_handle_type.) The underlying implementation type. - typedef impl_struct* impl_type; - /// The type of the next layer. typedef typename remove_reference<Stream>::type next_layer_type; /// The type of the lowest layer. typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + /// The type of the executor associated with the object. + typedef typename lowest_layer_type::executor_type executor_type; + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Construct a stream. /** * This constructor creates a stream and initialises the underlying stream @@ -104,30 +95,58 @@ public: * @param ctx The SSL context to be used for the stream. */ template <typename Arg> + stream(Arg&& arg, context& ctx) + : next_layer_(BOOST_ASIO_MOVE_CAST(Arg)(arg)), + core_(ctx.native_handle(), + next_layer_.lowest_layer().get_executor().context()) + { + } +#else // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + template <typename Arg> stream(Arg& arg, context& ctx) : next_layer_(arg), - core_(ctx.native_handle(), next_layer_.lowest_layer().get_io_service()) + core_(ctx.native_handle(), + next_layer_.lowest_layer().get_executor().context()) { - backwards_compatible_impl_.ssl = core_.engine_.native_handle(); } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Destructor. + /** + * @note A @c stream object must not be destroyed while there are pending + * asynchronous operations associated with it. + */ ~stream() { } - /// Get the io_service associated with the object. + /// Get the executor associated with the object. /** - * This function may be used to obtain the io_service object that the stream + * This function may be used to obtain the executor object that the stream * uses to dispatch handlers for asynchronous operations. * - * @return A reference to the io_service object that stream will use to - * dispatch handlers. Ownership is not transferred to the caller. + * @return A copy of the executor that stream will use to dispatch handlers. */ - boost::asio::io_service& get_io_service() + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return next_layer_.lowest_layer().get_executor(); + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + boost::asio::io_context& get_io_context() + { + return next_layer_.lowest_layer().get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + boost::asio::io_context& get_io_service() { return next_layer_.lowest_layer().get_io_service(); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Get the underlying implementation in the native type. /** @@ -140,7 +159,7 @@ public: * suitable for passing to functions such as @c SSL_get_verify_result and * @c SSL_get_peer_certificate: * @code - * boost::asio::ssl::stream<asio:ip::tcp::socket> sock(io_service, ctx); + * boost::asio::ssl::stream<asio:ip::tcp::socket> sock(io_context, ctx); * * // ... establish connection and perform handshake ... * @@ -158,18 +177,6 @@ public: return core_.engine_.native_handle(); } - /// (Deprecated: Use native_handle().) Get the underlying implementation in - /// the native type. - /** - * This function may be used to obtain the underlying implementation of the - * context. This is intended to allow access to stream functionality that is - * not otherwise provided. - */ - impl_type impl() - { - return &backwards_compatible_impl_; - } - /// Get a reference to the next layer. /** * This function returns a reference to the next layer in a stack of stream @@ -253,10 +260,11 @@ public: * * @note Calls @c SSL_set_verify. */ - boost::system::error_code set_verify_mode( + BOOST_ASIO_SYNC_OP_VOID set_verify_mode( verify_mode v, boost::system::error_code& ec) { - return core_.engine_.set_verify_mode(v, ec); + core_.engine_.set_verify_mode(v, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Set the peer verification depth. @@ -290,10 +298,11 @@ public: * * @note Calls @c SSL_set_verify_depth. */ - boost::system::error_code set_verify_depth( + BOOST_ASIO_SYNC_OP_VOID set_verify_depth( int depth, boost::system::error_code& ec) { - return core_.engine_.set_verify_depth(depth, ec); + core_.engine_.set_verify_depth(depth, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Set the callback used to verify peer certificates. @@ -341,11 +350,12 @@ public: * @note Calls @c SSL_set_verify. */ template <typename VerifyCallback> - boost::system::error_code set_verify_callback(VerifyCallback callback, + BOOST_ASIO_SYNC_OP_VOID set_verify_callback(VerifyCallback callback, boost::system::error_code& ec) { - return core_.engine_.set_verify_callback( + core_.engine_.set_verify_callback( new detail::verify_callback<VerifyCallback>(callback), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Perform SSL handshaking. @@ -375,11 +385,11 @@ public: * * @param ec Set to indicate what error occurred, if any. */ - boost::system::error_code handshake(handshake_type type, + BOOST_ASIO_SYNC_OP_VOID handshake(handshake_type type, boost::system::error_code& ec) { detail::io(next_layer_, core_, detail::handshake_op(type), ec); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Perform SSL handshaking. @@ -415,12 +425,12 @@ public: * @param ec Set to indicate what error occurred, if any. */ template <typename ConstBufferSequence> - boost::system::error_code handshake(handshake_type type, + BOOST_ASIO_SYNC_OP_VOID handshake(handshake_type type, const ConstBufferSequence& buffers, boost::system::error_code& ec) { detail::io(next_layer_, core_, detail::buffered_handshake_op<ConstBufferSequence>(type, buffers), ec); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Start an asynchronous SSL handshake. @@ -448,12 +458,11 @@ public: // not meet the documented type requirements for a HandshakeHandler. BOOST_ASIO_HANDSHAKE_HANDLER_CHECK(HandshakeHandler, handler) type_check; - boost::asio::detail::async_result_init< - HandshakeHandler, void (boost::system::error_code)> init( - BOOST_ASIO_MOVE_CAST(HandshakeHandler)(handler)); + boost::asio::async_completion<HandshakeHandler, + void (boost::system::error_code)> init(handler); detail::async_io(next_layer_, core_, - detail::handshake_op(type), init.handler); + detail::handshake_op(type), init.completion_handler); return init.result.get(); } @@ -490,13 +499,12 @@ public: BOOST_ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( BufferedHandshakeHandler, handler) type_check; - boost::asio::detail::async_result_init<BufferedHandshakeHandler, - void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(BufferedHandshakeHandler)(handler)); + boost::asio::async_completion<BufferedHandshakeHandler, + void (boost::system::error_code, std::size_t)> init(handler); detail::async_io(next_layer_, core_, detail::buffered_handshake_op<ConstBufferSequence>(type, buffers), - init.handler); + init.completion_handler); return init.result.get(); } @@ -522,10 +530,10 @@ public: * * @param ec Set to indicate what error occurred, if any. */ - boost::system::error_code shutdown(boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID shutdown(boost::system::error_code& ec) { detail::io(next_layer_, core_, detail::shutdown_op(), ec); - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Asynchronously shut down SSL on the stream. @@ -549,11 +557,11 @@ public: // not meet the documented type requirements for a ShutdownHandler. BOOST_ASIO_SHUTDOWN_HANDLER_CHECK(ShutdownHandler, handler) type_check; - boost::asio::detail::async_result_init< - ShutdownHandler, void (boost::system::error_code)> init( - BOOST_ASIO_MOVE_CAST(ShutdownHandler)(handler)); + boost::asio::async_completion<ShutdownHandler, + void (boost::system::error_code)> init(handler); - detail::async_io(next_layer_, core_, detail::shutdown_op(), init.handler); + detail::async_io(next_layer_, core_, detail::shutdown_op(), + init.completion_handler); return init.result.get(); } @@ -639,12 +647,12 @@ public: // not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - boost::asio::detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + boost::asio::async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); detail::async_io(next_layer_, core_, - detail::write_op<ConstBufferSequence>(buffers), init.handler); + detail::write_op<ConstBufferSequence>(buffers), + init.completion_handler); return init.result.get(); } @@ -731,12 +739,12 @@ public: // not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - boost::asio::detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + boost::asio::async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); detail::async_io(next_layer_, core_, - detail::read_op<MutableBufferSequence>(buffers), init.handler); + detail::read_op<MutableBufferSequence>(buffers), + init.completion_handler); return init.result.get(); } @@ -744,11 +752,8 @@ public: private: Stream next_layer_; detail::stream_core core_; - impl_struct backwards_compatible_impl_; }; -#endif // defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace ssl } // namespace asio } // namespace boost diff --git a/boost/asio/ssl/stream_service.hpp b/boost/asio/ssl/stream_service.hpp deleted file mode 100644 index 39e39f539c..0000000000 --- a/boost/asio/ssl/stream_service.hpp +++ /dev/null @@ -1,42 +0,0 @@ -// -// ssl/stream_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2017 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) -// - -#ifndef BOOST_ASIO_SSL_STREAM_SERVICE_HPP -#define BOOST_ASIO_SSL_STREAM_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include <boost/asio/detail/config.hpp> - -#if defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/ssl/old/stream_service.hpp> -#endif // defined(BOOST_ASIO_ENABLE_OLD_SSL) - -#include <boost/asio/detail/push_options.hpp> - -namespace boost { -namespace asio { -namespace ssl { - -#if defined(BOOST_ASIO_ENABLE_OLD_SSL) - -using boost::asio::ssl::old::stream_service; - -#endif // defined(BOOST_ASIO_ENABLE_OLD_SSL) - -} // namespace ssl -} // namespace asio -} // namespace boost - -#include <boost/asio/detail/pop_options.hpp> - -#endif // BOOST_ASIO_SSL_STREAM_SERVICE_HPP diff --git a/boost/asio/ssl/verify_context.hpp b/boost/asio/ssl/verify_context.hpp index 6b7a884e77..4daf0c7e23 100644 --- a/boost/asio/ssl/verify_context.hpp +++ b/boost/asio/ssl/verify_context.hpp @@ -17,10 +17,8 @@ #include <boost/asio/detail/config.hpp> -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) -# include <boost/asio/detail/noncopyable.hpp> -# include <boost/asio/ssl/detail/openssl_types.hpp> -#endif // !defined(BOOST_ASIO_ENABLE_OLD_SSL) +#include <boost/asio/detail/noncopyable.hpp> +#include <boost/asio/ssl/detail/openssl_types.hpp> #include <boost/asio/detail/push_options.hpp> @@ -28,8 +26,6 @@ namespace boost { namespace asio { namespace ssl { -#if !defined(BOOST_ASIO_ENABLE_OLD_SSL) - /// A simple wrapper around the X509_STORE_CTX type, used during verification of /// a peer certificate. /** @@ -64,8 +60,6 @@ private: native_handle_type handle_; }; -#endif // defined(BOOST_ASIO_ENABLE_OLD_SSL) - } // namespace ssl } // namespace asio } // namespace boost diff --git a/boost/asio/steady_timer.hpp b/boost/asio/steady_timer.hpp index f18ce399ae..af72adbf6e 100644 --- a/boost/asio/steady_timer.hpp +++ b/boost/asio/steady_timer.hpp @@ -17,22 +17,14 @@ #include <boost/asio/detail/config.hpp> -#if defined(BOOST_ASIO_HAS_STD_CHRONO) \ - || defined(BOOST_ASIO_HAS_BOOST_CHRONO) \ - || defined(GENERATING_DOCUMENTATION) - -#if defined(BOOST_ASIO_HAS_STD_CHRONO) -# include <chrono> -#elif defined(BOOST_ASIO_HAS_BOOST_CHRONO) -# include <boost/chrono/system_clocks.hpp> -#endif +#if defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) #include <boost/asio/basic_waitable_timer.hpp> +#include <boost/asio/detail/chrono.hpp> namespace boost { namespace asio { -#if defined(GENERATING_DOCUMENTATION) /// Typedef for a timer based on the steady clock. /** * This typedef uses the C++11 @c <chrono> standard library facility, if @@ -43,21 +35,10 @@ namespace asio { * @endcode */ typedef basic_waitable_timer<chrono::steady_clock> steady_timer; -#elif defined(BOOST_ASIO_HAS_STD_CHRONO) -# if defined(BOOST_ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) -typedef basic_waitable_timer<std::chrono::monotonic_clock> steady_timer; -# else // defined(BOOST_ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) -typedef basic_waitable_timer<std::chrono::steady_clock> steady_timer; -# endif // defined(BOOST_ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) -#elif defined(BOOST_ASIO_HAS_BOOST_CHRONO) -typedef basic_waitable_timer<boost::chrono::steady_clock> steady_timer; -#endif } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_STD_CHRONO) - // || defined(BOOST_ASIO_HAS_BOOST_CHRONO) - // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_STEADY_TIMER_HPP diff --git a/boost/asio/strand.hpp b/boost/asio/strand.hpp index a4f3797e6a..9d0ad058f3 100644 --- a/boost/asio/strand.hpp +++ b/boost/asio/strand.hpp @@ -16,239 +16,273 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> -#include <boost/asio/async_result.hpp> -#include <boost/asio/detail/handler_type_requirements.hpp> -#include <boost/asio/detail/strand_service.hpp> -#include <boost/asio/detail/wrapped_handler.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/detail/strand_executor_service.hpp> +#include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { -/// Provides serialised handler execution. -/** - * The io_service::strand class provides the ability to post and dispatch - * handlers with the guarantee that none of those handlers will execute - * concurrently. - * - * @par Order of handler invocation - * Given: - * - * @li a strand object @c s - * - * @li an object @c a meeting completion handler requirements - * - * @li an object @c a1 which is an arbitrary copy of @c a made by the - * implementation - * - * @li an object @c b meeting completion handler requirements - * - * @li an object @c b1 which is an arbitrary copy of @c b made by the - * implementation - * - * if any of the following conditions are true: - * - * @li @c s.post(a) happens-before @c s.post(b) - * - * @li @c s.post(a) happens-before @c s.dispatch(b), where the latter is - * performed outside the strand - * - * @li @c s.dispatch(a) happens-before @c s.post(b), where the former is - * performed outside the strand - * - * @li @c s.dispatch(a) happens-before @c s.dispatch(b), where both are - * performed outside the strand - * - * then @c asio_handler_invoke(a1, &a1) happens-before - * @c asio_handler_invoke(b1, &b1). - * - * Note that in the following case: - * @code async_op_1(..., s.wrap(a)); - * async_op_2(..., s.wrap(b)); @endcode - * the completion of the first async operation will perform @c s.dispatch(a), - * and the second will perform @c s.dispatch(b), but the order in which those - * are performed is unspecified. That is, you cannot state whether one - * happens-before the other. Therefore none of the above conditions are met and - * no ordering guarantee is made. - * - * @note The implementation makes no guarantee that handlers posted or - * dispatched through different @c strand objects will be invoked concurrently. - * - * @par Thread Safety - * @e Distinct @e objects: Safe.@n - * @e Shared @e objects: Safe. - * - * @par Concepts: - * Dispatcher. - */ -class io_service::strand +/// Provides serialised function invocation for any executor type. +template <typename Executor> +class strand { public: - /// Constructor. + /// The type of the underlying executor. + typedef Executor inner_executor_type; + + /// Default constructor. /** - * Constructs the strand. - * - * @param io_service The io_service object that the strand will use to - * dispatch handlers that are ready to be run. + * This constructor is only valid if the underlying executor type is default + * constructible. */ - explicit strand(boost::asio::io_service& io_service) - : service_(boost::asio::use_service< - boost::asio::detail::strand_service>(io_service)) + strand() + : executor_(), + impl_(use_service<detail::strand_executor_service>( + executor_.context()).create_implementation()) { - service_.construct(impl_); } - /// Destructor. + /// Construct a strand for the specified executor. + explicit strand(const Executor& e) + : executor_(e), + impl_(use_service<detail::strand_executor_service>( + executor_.context()).create_implementation()) + { + } + + /// Copy constructor. + strand(const strand& other) BOOST_ASIO_NOEXCEPT + : executor_(other.executor_), + impl_(other.impl_) + { + } + + /// Converting constructor. /** - * Destroys a strand. - * - * Handlers posted through the strand that have not yet been invoked will - * still be dispatched in a way that meets the guarantee of non-concurrency. + * This constructor is only valid if the @c OtherExecutor type is convertible + * to @c Executor. */ - ~strand() + template <class OtherExecutor> + strand( + const strand<OtherExecutor>& other) BOOST_ASIO_NOEXCEPT + : executor_(other.executor_), + impl_(other.impl_) + { + } + + /// Assignment operator. + strand& operator=(const strand& other) BOOST_ASIO_NOEXCEPT { + executor_ = other.executor_; + impl_ = other.impl_; + return *this; } - /// Get the io_service associated with the strand. + /// Converting assignment operator. /** - * This function may be used to obtain the io_service object that the strand - * uses to dispatch handlers for asynchronous operations. - * - * @return A reference to the io_service object that the strand will use to - * dispatch handlers. Ownership is not transferred to the caller. + * This assignment operator is only valid if the @c OtherExecutor type is + * convertible to @c Executor. */ - boost::asio::io_service& get_io_service() + template <class OtherExecutor> + strand& operator=( + const strand<OtherExecutor>& other) BOOST_ASIO_NOEXCEPT + { + executor_ = other.executor_; + impl_ = other.impl_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move constructor. + strand(strand&& other) BOOST_ASIO_NOEXCEPT + : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)), + impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)) { - return service_.get_io_service(); } - /// Request the strand to invoke the given handler. + /// Converting move constructor. /** - * This function is used to ask the strand to execute the given handler. - * - * The strand object guarantees that handlers posted or dispatched through - * the strand will not be executed concurrently. The handler may be executed - * inside this function if the guarantee can be met. If this function is - * called from within a handler that was posted or dispatched through the same - * strand, then the new handler will be executed immediately. - * - * The strand's guarantee is in addition to the guarantee provided by the - * underlying io_service. The io_service guarantees that the handler will only - * be called in a thread in which the io_service's run member function is - * currently being invoked. - * - * @param handler The handler to be called. The strand will make a copy of the - * handler object as required. The function signature of the handler must be: - * @code void handler(); @endcode + * This constructor is only valid if the @c OtherExecutor type is convertible + * to @c Executor. */ - template <typename CompletionHandler> - BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) - dispatch(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) + template <class OtherExecutor> + strand(strand<OtherExecutor>&& other) BOOST_ASIO_NOEXCEPT + : executor_(BOOST_ASIO_MOVE_CAST(OtherExecutor)(other)), + impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a CompletionHandler. - BOOST_ASIO_COMPLETION_HANDLER_CHECK(CompletionHandler, handler) type_check; + } - detail::async_result_init< - CompletionHandler, void ()> init( - BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); + /// Move assignment operator. + strand& operator=(strand&& other) BOOST_ASIO_NOEXCEPT + { + executor_ = BOOST_ASIO_MOVE_CAST(Executor)(other); + impl_ = BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_); + return *this; + } - service_.dispatch(impl_, init.handler); + /// Converting move assignment operator. + /** + * This assignment operator is only valid if the @c OtherExecutor type is + * convertible to @c Executor. + */ + template <class OtherExecutor> + strand& operator=( + const strand<OtherExecutor>&& other) BOOST_ASIO_NOEXCEPT + { + executor_ = BOOST_ASIO_MOVE_CAST(OtherExecutor)(other); + impl_ = BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destructor. + ~strand() + { + } - return init.result.get(); + /// Obtain the underlying executor. + inner_executor_type get_inner_executor() const BOOST_ASIO_NOEXCEPT + { + return executor_; } - /// Request the strand to invoke the given handler and return - /// immediately. + /// Obtain the underlying execution context. + execution_context& context() const BOOST_ASIO_NOEXCEPT + { + return executor_.context(); + } + + /// Inform the strand that it has some outstanding work to do. /** - * This function is used to ask the strand to execute the given handler, but - * without allowing the strand to call the handler from inside this function. - * - * The strand object guarantees that handlers posted or dispatched through - * the strand will not be executed concurrently. The strand's guarantee is in - * addition to the guarantee provided by the underlying io_service. The - * io_service guarantees that the handler will only be called in a thread in - * which the io_service's run member function is currently being invoked. - * - * @param handler The handler to be called. The strand will make a copy of the - * handler object as required. The function signature of the handler must be: - * @code void handler(); @endcode + * The strand delegates this call to its underlying executor. */ - template <typename CompletionHandler> - BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) - post(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) + void on_work_started() const BOOST_ASIO_NOEXCEPT { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a CompletionHandler. - BOOST_ASIO_COMPLETION_HANDLER_CHECK(CompletionHandler, handler) type_check; + executor_.on_work_started(); + } - detail::async_result_init< - CompletionHandler, void ()> init( - BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); + /// Inform the strand that some work is no longer outstanding. + /** + * The strand delegates this call to its underlying executor. + */ + void on_work_finished() const BOOST_ASIO_NOEXCEPT + { + executor_.on_work_finished(); + } - service_.post(impl_, init.handler); + /// Request the strand to invoke the given function object. + /** + * This function is used to ask the strand to execute the given function + * object on its underlying executor. The function object will be executed + * inside this function if the strand is not otherwise busy and if the + * underlying executor's @c dispatch() function is also able to execute the + * function before returning. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const + { + detail::strand_executor_service::dispatch(impl_, + executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a); + } - return init.result.get(); + /// Request the strand to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object will never be executed inside this function. + * Instead, it will be scheduled by the underlying executor's defer function. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const + { + detail::strand_executor_service::post(impl_, + executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a); } - /// Create a new handler that automatically dispatches the wrapped handler - /// on the strand. + /// Request the strand to invoke the given function object. /** - * This function is used to create a new handler function object that, when - * invoked, will automatically pass the wrapped handler to the strand's - * dispatch function. + * This function is used to ask the executor to execute the given function + * object. The function object will never be executed inside this function. + * Instead, it will be scheduled by the underlying executor's defer function. * - * @param handler The handler to be wrapped. The strand will make a copy of - * the handler object as required. The function signature of the handler must - * be: @code void handler(A1 a1, ... An an); @endcode + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode * - * @return A function object that, when invoked, passes the wrapped handler to - * the strand's dispatch function. Given a function object with the signature: - * @code R f(A1 a1, ... An an); @endcode - * If this function object is passed to the wrap function like so: - * @code strand.wrap(f); @endcode - * then the return value is a function object with the signature - * @code void g(A1 a1, ... An an); @endcode - * that, when invoked, executes code equivalent to: - * @code strand.dispatch(boost::bind(f, a1, ... an)); @endcode + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. */ - template <typename Handler> -#if defined(GENERATING_DOCUMENTATION) - unspecified -#else - detail::wrapped_handler<strand, Handler, detail::is_continuation_if_running> -#endif - wrap(Handler handler) + template <typename Function, typename Allocator> + void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const { - return detail::wrapped_handler<io_service::strand, Handler, - detail::is_continuation_if_running>(*this, handler); + detail::strand_executor_service::defer(impl_, + executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a); } /// Determine whether the strand is running in the current thread. /** - * @return @c true if the current thread is executing a handler that was - * submitted to the strand using post(), dispatch() or wrap(). Otherwise + * @return @c true if the current thread is executing a function that was + * submitted to the strand using post(), dispatch() or defer(). Otherwise * returns @c false. */ - bool running_in_this_thread() const + bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT + { + return detail::strand_executor_service::running_in_this_thread(impl_); + } + + /// Compare two strands for equality. + /** + * Two strands are equal if they refer to the same ordered, non-concurrent + * state. + */ + friend bool operator==(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT + { + return a.impl_ == b.impl_; + } + + /// Compare two strands for inequality. + /** + * Two strands are equal if they refer to the same ordered, non-concurrent + * state. + */ + friend bool operator!=(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT { - return service_.running_in_this_thread(impl_); + return a.impl_ != b.impl_; } private: - boost::asio::detail::strand_service& service_; - boost::asio::detail::strand_service::implementation_type impl_; + Executor executor_; + typedef detail::strand_executor_service::implementation_type + implementation_type; + implementation_type impl_; }; -/// (Deprecated: Use boost::asio::io_service::strand.) Typedef for backwards -/// compatibility. -typedef boost::asio::io_service::strand strand; - } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> +// If both io_context.hpp and strand.hpp have been included, automatically +// include the header file needed for the io_context::strand class. +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +# if defined(BOOST_ASIO_IO_CONTEXT_HPP) +# include <boost/asio/io_context_strand.hpp> +# endif // defined(BOOST_ASIO_IO_CONTEXT_HPP) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + #endif // BOOST_ASIO_STRAND_HPP diff --git a/boost/asio/stream_socket_service.hpp b/boost/asio/stream_socket_service.hpp index 09463f4718..534ce6528b 100644 --- a/boost/asio/stream_socket_service.hpp +++ b/boost/asio/stream_socket_service.hpp @@ -16,11 +16,14 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #include <cstddef> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/winrt_ssocket_service.hpp> @@ -39,7 +42,7 @@ namespace asio { template <typename Protocol> class stream_socket_service #if defined(GENERATING_DOCUMENTATION) - : public boost::asio::io_service::service + : public boost::asio::io_context::service #else : public boost::asio::detail::service_base<stream_socket_service<Protocol> > #endif @@ -47,7 +50,7 @@ class stream_socket_service public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. - static boost::asio::io_service::id id; + static boost::asio::io_context::id id; #endif /// The protocol type. @@ -74,13 +77,6 @@ public: typedef typename service_impl_type::implementation_type implementation_type; #endif - /// (Deprecated: Use native_handle_type.) The native socket type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_type; -#else - typedef typename service_impl_type::native_handle_type native_type; -#endif - /// The native socket type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; @@ -88,11 +84,11 @@ public: typedef typename service_impl_type::native_handle_type native_handle_type; #endif - /// Construct a new stream socket service for the specified io_service. - explicit stream_socket_service(boost::asio::io_service& io_service) + /// Construct a new stream socket service for the specified io_context. + explicit stream_socket_service(boost::asio::io_context& io_context) : boost::asio::detail::service_base< - stream_socket_service<Protocol> >(io_service), - service_impl_(io_service) + stream_socket_service<Protocol> >(io_context), + service_impl_(io_context) { } @@ -143,22 +139,23 @@ public: } /// Open a stream socket. - boost::system::error_code open(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID open(implementation_type& impl, const protocol_type& protocol, boost::system::error_code& ec) { if (protocol.type() == BOOST_ASIO_OS_DEF(SOCK_STREAM)) service_impl_.open(impl, protocol, ec); else ec = boost::asio::error::invalid_argument; - return ec; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Assign an existing native socket to a stream socket. - boost::system::error_code assign(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID assign(implementation_type& impl, const protocol_type& protocol, const native_handle_type& native_socket, boost::system::error_code& ec) { - return service_impl_.assign(impl, protocol, native_socket, ec); + service_impl_.assign(impl, protocol, native_socket, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the socket is open. @@ -168,16 +165,18 @@ public: } /// Close a stream socket implementation. - boost::system::error_code close(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID close(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.close(impl, ec); + service_impl_.close(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } - /// (Deprecated: Use native_handle().) Get the native socket implementation. - native_type native(implementation_type& impl) + /// Release ownership of the underlying socket. + native_handle_type release(implementation_type& impl, + boost::system::error_code& ec) { - return service_impl_.native_handle(impl); + return service_impl_.release(impl, ec); } /// Get the native socket implementation. @@ -187,10 +186,11 @@ public: } /// Cancel all asynchronous operations associated with the socket. - boost::system::error_code cancel(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID cancel(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.cancel(impl, ec); + service_impl_.cancel(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the socket is at the out-of-band data mark. @@ -208,17 +208,19 @@ public: } /// Bind the stream socket to the specified local endpoint. - boost::system::error_code bind(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID bind(implementation_type& impl, const endpoint_type& endpoint, boost::system::error_code& ec) { - return service_impl_.bind(impl, endpoint, ec); + service_impl_.bind(impl, endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Connect the stream socket to the specified endpoint. - boost::system::error_code connect(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID connect(implementation_type& impl, const endpoint_type& peer_endpoint, boost::system::error_code& ec) { - return service_impl_.connect(impl, peer_endpoint, ec); + service_impl_.connect(impl, peer_endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Start an asynchronous connect. @@ -229,37 +231,39 @@ public: const endpoint_type& peer_endpoint, BOOST_ASIO_MOVE_ARG(ConnectHandler) handler) { - detail::async_result_init< - ConnectHandler, void (boost::system::error_code)> init( - BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler)); + async_completion<ConnectHandler, + void (boost::system::error_code)> init(handler); - service_impl_.async_connect(impl, peer_endpoint, init.handler); + service_impl_.async_connect(impl, peer_endpoint, init.completion_handler); return init.result.get(); } /// Set a socket option. template <typename SettableSocketOption> - boost::system::error_code set_option(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID set_option(implementation_type& impl, const SettableSocketOption& option, boost::system::error_code& ec) { - return service_impl_.set_option(impl, option, ec); + service_impl_.set_option(impl, option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get a socket option. template <typename GettableSocketOption> - boost::system::error_code get_option(const implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID get_option(const implementation_type& impl, GettableSocketOption& option, boost::system::error_code& ec) const { - return service_impl_.get_option(impl, option, ec); + service_impl_.get_option(impl, option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Perform an IO control command on the socket. template <typename IoControlCommand> - boost::system::error_code io_control(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID io_control(implementation_type& impl, IoControlCommand& command, boost::system::error_code& ec) { - return service_impl_.io_control(impl, command, ec); + service_impl_.io_control(impl, command, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the socket. @@ -269,10 +273,11 @@ public: } /// Sets the non-blocking mode of the socket. - boost::system::error_code non_blocking(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID non_blocking(implementation_type& impl, bool mode, boost::system::error_code& ec) { - return service_impl_.non_blocking(impl, mode, ec); + service_impl_.non_blocking(impl, mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Gets the non-blocking mode of the native socket implementation. @@ -282,10 +287,11 @@ public: } /// Sets the non-blocking mode of the native socket implementation. - boost::system::error_code native_non_blocking(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID native_non_blocking(implementation_type& impl, bool mode, boost::system::error_code& ec) { - return service_impl_.native_non_blocking(impl, mode, ec); + service_impl_.native_non_blocking(impl, mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get the local endpoint. @@ -303,10 +309,36 @@ public: } /// Disable sends or receives on the socket. - boost::system::error_code shutdown(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID shutdown(implementation_type& impl, socket_base::shutdown_type what, boost::system::error_code& ec) { - return service_impl_.shutdown(impl, what, ec); + service_impl_.shutdown(impl, what, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Wait for the socket to become ready to read, ready to write, or to have + /// pending error conditions. + BOOST_ASIO_SYNC_OP_VOID wait(implementation_type& impl, + socket_base::wait_type w, boost::system::error_code& ec) + { + service_impl_.wait(impl, w, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Asynchronously wait for the socket to become ready to read, ready to + /// write, or to have pending error conditions. + template <typename WaitHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(implementation_type& impl, socket_base::wait_type w, + BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + async_completion<WaitHandler, + void (boost::system::error_code)> init(handler); + + service_impl_.async_wait(impl, w, init.completion_handler); + + return init.result.get(); } /// Send the given data to the peer. @@ -327,11 +359,10 @@ public: socket_base::message_flags flags, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); - service_impl_.async_send(impl, buffers, flags, init.handler); + service_impl_.async_send(impl, buffers, flags, init.completion_handler); return init.result.get(); } @@ -354,20 +385,19 @@ public: socket_base::message_flags flags, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); - service_impl_.async_receive(impl, buffers, flags, init.handler); + service_impl_.async_receive(impl, buffers, flags, init.completion_handler); return init.result.get(); } private: // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { - service_impl_.shutdown_service(); + service_impl_.shutdown(); } // The platform-specific implementation. @@ -379,4 +409,6 @@ private: #include <boost/asio/detail/pop_options.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_STREAM_SOCKET_SERVICE_HPP diff --git a/boost/asio/system_context.hpp b/boost/asio/system_context.hpp new file mode 100644 index 0000000000..8479925e7a --- /dev/null +++ b/boost/asio/system_context.hpp @@ -0,0 +1,80 @@ +// +// system_context.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_SYSTEM_CONTEXT_HPP +#define BOOST_ASIO_SYSTEM_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/scheduler.hpp> +#include <boost/asio/detail/thread_group.hpp> +#include <boost/asio/execution_context.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +class system_executor; + +/// The executor context for the system executor. +class system_context : public execution_context +{ +public: + /// The executor type associated with the context. + typedef system_executor executor_type; + + /// Destructor shuts down all threads in the system thread pool. + BOOST_ASIO_DECL ~system_context(); + + /// Obtain an executor for the context. + executor_type get_executor() BOOST_ASIO_NOEXCEPT; + + /// Signal all threads in the system thread pool to stop. + BOOST_ASIO_DECL void stop(); + + /// Determine whether the system thread pool has been stopped. + BOOST_ASIO_DECL bool stopped() const BOOST_ASIO_NOEXCEPT; + + /// Join all threads in the system thread pool. + BOOST_ASIO_DECL void join(); + +#if defined(GENERATING_DOCUMENTATION) +private: +#endif // defined(GENERATING_DOCUMENTATION) + // Constructor creates all threads in the system thread pool. + BOOST_ASIO_DECL system_context(); + +private: + friend class system_executor; + + struct thread_function; + + // The underlying scheduler. + detail::scheduler& scheduler_; + + // The threads in the system thread pool. + detail::thread_group threads_; +}; + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#include <boost/asio/impl/system_context.hpp> +#if defined(BOOST_ASIO_HEADER_ONLY) +# include <boost/asio/impl/system_context.ipp> +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_SYSTEM_CONTEXT_HPP diff --git a/boost/asio/system_executor.hpp b/boost/asio/system_executor.hpp new file mode 100644 index 0000000000..0d8eb0a535 --- /dev/null +++ b/boost/asio/system_executor.hpp @@ -0,0 +1,131 @@ +// +// system_executor.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_SYSTEM_EXECUTOR_HPP +#define BOOST_ASIO_SYSTEM_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +class system_context; + +/// An executor that uses arbitrary threads. +/** + * The system executor represents an execution context where functions are + * permitted to run on arbitrary threads. The post() and defer() functions + * schedule the function to run on an unspecified system thread pool, and + * dispatch() invokes the function immediately. + */ +class system_executor +{ +public: + /// Obtain the underlying execution context. + system_context& context() const BOOST_ASIO_NOEXCEPT; + + /// Inform the executor that it has some outstanding work to do. + /** + * For the system executor, this is a no-op. + */ + void on_work_started() const BOOST_ASIO_NOEXCEPT + { + } + + /// Inform the executor that some work is no longer outstanding. + /** + * For the system executor, this is a no-op. + */ + void on_work_finished() const BOOST_ASIO_NOEXCEPT + { + } + + /// Request the system executor to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object will always be executed inside this function. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Request the system executor to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object will never be executed inside this function. + * Instead, it will be scheduled to run on an unspecified system thread pool. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Request the system executor to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object will never be executed inside this function. + * Instead, it will be scheduled to run on an unspecified system thread pool. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Compare two executors for equality. + /** + * System executors always compare equal. + */ + friend bool operator==(const system_executor&, + const system_executor&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + /// Compare two executors for inequality. + /** + * System executors always compare equal. + */ + friend bool operator!=(const system_executor&, + const system_executor&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#include <boost/asio/impl/system_executor.hpp> + +#endif // BOOST_ASIO_SYSTEM_EXECUTOR_HPP diff --git a/boost/asio/system_timer.hpp b/boost/asio/system_timer.hpp index e95370dbbc..95c04409b5 100644 --- a/boost/asio/system_timer.hpp +++ b/boost/asio/system_timer.hpp @@ -17,22 +17,14 @@ #include <boost/asio/detail/config.hpp> -#if defined(BOOST_ASIO_HAS_STD_CHRONO) \ - || defined(BOOST_ASIO_HAS_BOOST_CHRONO) \ - || defined(GENERATING_DOCUMENTATION) - -#if defined(BOOST_ASIO_HAS_STD_CHRONO) -# include <chrono> -#elif defined(BOOST_ASIO_HAS_BOOST_CHRONO) -# include <boost/chrono/system_clocks.hpp> -#endif +#if defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) #include <boost/asio/basic_waitable_timer.hpp> +#include <boost/asio/detail/chrono.hpp> namespace boost { namespace asio { -#if defined(GENERATING_DOCUMENTATION) /// Typedef for a timer based on the system clock. /** * This typedef uses the C++11 @c <chrono> standard library facility, if @@ -43,17 +35,10 @@ namespace asio { * @endcode */ typedef basic_waitable_timer<chrono::system_clock> system_timer; -#elif defined(BOOST_ASIO_HAS_STD_CHRONO) -typedef basic_waitable_timer<std::chrono::system_clock> system_timer; -#elif defined(BOOST_ASIO_HAS_BOOST_CHRONO) -typedef basic_waitable_timer<boost::chrono::system_clock> system_timer; -#endif } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_STD_CHRONO) - // || defined(BOOST_ASIO_HAS_BOOST_CHRONO) - // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_SYSTEM_TIMER_HPP diff --git a/boost/asio/thread_pool.hpp b/boost/asio/thread_pool.hpp new file mode 100644 index 0000000000..5e3e7fd529 --- /dev/null +++ b/boost/asio/thread_pool.hpp @@ -0,0 +1,234 @@ +// +// thread_pool.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_THREAD_POOL_HPP +#define BOOST_ASIO_THREAD_POOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/noncopyable.hpp> +#include <boost/asio/detail/scheduler.hpp> +#include <boost/asio/detail/thread_group.hpp> +#include <boost/asio/execution_context.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +/// A simple fixed-size thread pool. +/** + * The thread pool class is an execution context where functions are permitted + * to run on one of a fixed number of threads. + * + * @par Submitting tasks to the pool + * + * To submit functions to the io_context, use the @ref boost::asio::dispatch, + * @ref boost::asio::post or @ref boost::asio::defer free functions. + * + * For example: + * + * @code void my_task() + * { + * ... + * } + * + * ... + * + * // Launch the pool with four threads. + * boost::asio::thread_pool pool(4); + * + * // Submit a function to the pool. + * boost::asio::post(pool, my_task); + * + * // Submit a lambda object to the pool. + * boost::asio::post(pool, + * []() + * { + * ... + * }); + * + * // Wait for all tasks in the pool to complete. + * pool.join(); @endcode + */ +class thread_pool + : public execution_context +{ +public: + class executor_type; + + /// Constructs a pool with an automatically determined number of threads. + BOOST_ASIO_DECL thread_pool(); + + /// Constructs a pool with a specified number of threads. + BOOST_ASIO_DECL thread_pool(std::size_t num_threads); + + /// Destructor. + /** + * Automatically stops and joins the pool, if not explicitly done beforehand. + */ + BOOST_ASIO_DECL ~thread_pool(); + + /// Obtains the executor associated with the pool. + executor_type get_executor() BOOST_ASIO_NOEXCEPT; + + /// Stops the threads. + /** + * This function stops the threads as soon as possible. As a result of calling + * @c stop(), pending function objects may be never be invoked. + */ + BOOST_ASIO_DECL void stop(); + + /// Joins the threads. + /** + * This function blocks until the threads in the pool have completed. If @c + * stop() is not called prior to @c join(), the @c join() call will wait + * until the pool has no more outstanding work. + */ + BOOST_ASIO_DECL void join(); + +private: + friend class executor_type; + struct thread_function; + + // The underlying scheduler. + detail::scheduler& scheduler_; + + // The threads in the pool. + detail::thread_group threads_; +}; + +/// Executor used to submit functions to a thread pool. +class thread_pool::executor_type +{ +public: + /// Obtain the underlying execution context. + thread_pool& context() const BOOST_ASIO_NOEXCEPT; + + /// Inform the thread pool that it has some outstanding work to do. + /** + * This function is used to inform the thread pool that some work has begun. + * This ensures that the thread pool's join() function will not return while + * the work is underway. + */ + void on_work_started() const BOOST_ASIO_NOEXCEPT; + + /// Inform the thread pool that some work is no longer outstanding. + /** + * This function is used to inform the thread pool that some work has + * finished. Once the count of unfinished work reaches zero, the thread + * pool's join() function is permitted to exit. + */ + void on_work_finished() const BOOST_ASIO_NOEXCEPT; + + /// Request the thread pool to invoke the given function object. + /** + * This function is used to ask the thread pool to execute the given function + * object. If the current thread belongs to the pool, @c dispatch() executes + * the function before returning. Otherwise, the function will be scheduled + * to run on the thread pool. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Request the thread pool to invoke the given function object. + /** + * This function is used to ask the thread pool to execute the given function + * object. The function object will never be executed inside @c post(). + * Instead, it will be scheduled to run on the thread pool. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Request the thread pool to invoke the given function object. + /** + * This function is used to ask the thread pool to execute the given function + * object. The function object will never be executed inside @c defer(). + * Instead, it will be scheduled to run on the thread pool. + * + * If the current thread belongs to the thread pool, @c defer() will delay + * scheduling the function object until the current thread returns control to + * the pool. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template <typename Function, typename Allocator> + void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Determine whether the thread pool is running in the current thread. + /** + * @return @c true if the current thread belongs to the pool. Otherwise + * returns @c false. + */ + bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT; + + /// Compare two executors for equality. + /** + * Two executors are equal if they refer to the same underlying thread pool. + */ + friend bool operator==(const executor_type& a, + const executor_type& b) BOOST_ASIO_NOEXCEPT + { + return &a.pool_ == &b.pool_; + } + + /// Compare two executors for inequality. + /** + * Two executors are equal if they refer to the same underlying thread pool. + */ + friend bool operator!=(const executor_type& a, + const executor_type& b) BOOST_ASIO_NOEXCEPT + { + return &a.pool_ != &b.pool_; + } + +private: + friend class thread_pool; + + // Constructor. + explicit executor_type(thread_pool& p) : pool_(p) {} + + // The underlying thread pool. + thread_pool& pool_; +}; + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#include <boost/asio/impl/thread_pool.hpp> +#if defined(BOOST_ASIO_HEADER_ONLY) +# include <boost/asio/impl/thread_pool.ipp> +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_THREAD_POOL_HPP diff --git a/boost/asio/ts/buffer.hpp b/boost/asio/ts/buffer.hpp new file mode 100644 index 0000000000..cc632102b7 --- /dev/null +++ b/boost/asio/ts/buffer.hpp @@ -0,0 +1,24 @@ +// +// ts/buffer.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_TS_BUFFER_HPP +#define BOOST_ASIO_TS_BUFFER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/buffer.hpp> +#include <boost/asio/completion_condition.hpp> +#include <boost/asio/read.hpp> +#include <boost/asio/write.hpp> +#include <boost/asio/read_until.hpp> + +#endif // BOOST_ASIO_TS_BUFFER_HPP diff --git a/boost/asio/ts/executor.hpp b/boost/asio/ts/executor.hpp new file mode 100644 index 0000000000..ac986c0a79 --- /dev/null +++ b/boost/asio/ts/executor.hpp @@ -0,0 +1,35 @@ +// +// ts/executor.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_TS_EXECUTOR_HPP +#define BOOST_ASIO_TS_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/handler_type.hpp> +#include <boost/asio/async_result.hpp> +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/execution_context.hpp> +#include <boost/asio/is_executor.hpp> +#include <boost/asio/associated_executor.hpp> +#include <boost/asio/bind_executor.hpp> +#include <boost/asio/executor_work_guard.hpp> +#include <boost/asio/system_executor.hpp> +#include <boost/asio/executor.hpp> +#include <boost/asio/dispatch.hpp> +#include <boost/asio/post.hpp> +#include <boost/asio/defer.hpp> +#include <boost/asio/strand.hpp> +#include <boost/asio/packaged_task.hpp> +#include <boost/asio/use_future.hpp> + +#endif // BOOST_ASIO_TS_EXECUTOR_HPP diff --git a/boost/asio/ts/internet.hpp b/boost/asio/ts/internet.hpp new file mode 100644 index 0000000000..507f990df3 --- /dev/null +++ b/boost/asio/ts/internet.hpp @@ -0,0 +1,40 @@ +// +// ts/internet.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_TS_INTERNET_HPP +#define BOOST_ASIO_TS_INTERNET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/ip/address.hpp> +#include <boost/asio/ip/address_v4.hpp> +#include <boost/asio/ip/address_v4_iterator.hpp> +#include <boost/asio/ip/address_v4_range.hpp> +#include <boost/asio/ip/address_v6.hpp> +#include <boost/asio/ip/address_v6_iterator.hpp> +#include <boost/asio/ip/address_v6_range.hpp> +#include <boost/asio/ip/bad_address_cast.hpp> +#include <boost/asio/ip/basic_endpoint.hpp> +#include <boost/asio/ip/basic_resolver_query.hpp> +#include <boost/asio/ip/basic_resolver_entry.hpp> +#include <boost/asio/ip/basic_resolver_iterator.hpp> +#include <boost/asio/ip/basic_resolver.hpp> +#include <boost/asio/ip/host_name.hpp> +#include <boost/asio/ip/network_v4.hpp> +#include <boost/asio/ip/network_v6.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/ip/udp.hpp> +#include <boost/asio/ip/v6_only.hpp> +#include <boost/asio/ip/unicast.hpp> +#include <boost/asio/ip/multicast.hpp> + +#endif // BOOST_ASIO_TS_INTERNET_HPP diff --git a/boost/asio/ts/io_context.hpp b/boost/asio/ts/io_context.hpp new file mode 100644 index 0000000000..d5e88607c2 --- /dev/null +++ b/boost/asio/ts/io_context.hpp @@ -0,0 +1,20 @@ +// +// ts/io_context.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_TS_IO_CONTEXT_HPP +#define BOOST_ASIO_TS_IO_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/io_context.hpp> + +#endif // BOOST_ASIO_TS_IO_CONTEXT_HPP diff --git a/boost/asio/ts/net.hpp b/boost/asio/ts/net.hpp new file mode 100644 index 0000000000..0f60da2ee2 --- /dev/null +++ b/boost/asio/ts/net.hpp @@ -0,0 +1,26 @@ +// +// ts/net.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_TS_NET_HPP +#define BOOST_ASIO_TS_NET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/ts/netfwd.hpp> +#include <boost/asio/ts/executor.hpp> +#include <boost/asio/ts/io_context.hpp> +#include <boost/asio/ts/timer.hpp> +#include <boost/asio/ts/buffer.hpp> +#include <boost/asio/ts/socket.hpp> +#include <boost/asio/ts/internet.hpp> + +#endif // BOOST_ASIO_TS_NET_HPP diff --git a/boost/asio/ts/netfwd.hpp b/boost/asio/ts/netfwd.hpp new file mode 100644 index 0000000000..0b084d7e60 --- /dev/null +++ b/boost/asio/ts/netfwd.hpp @@ -0,0 +1,199 @@ +// +// ts/netfwd.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_TS_NETFWD_HPP +#define BOOST_ASIO_TS_NETFWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_HAS_CHRONO) +# include <boost/asio/detail/chrono.hpp> +#endif // defined(BOOST_ASIO_HAS_CHRONO) + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +# include <boost/asio/detail/date_time_fwd.hpp> +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +#if !defined(GENERATING_DOCUMENTATION) + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +class execution_context; + +template <typename T, typename Executor> +class executor_binder; + +template <typename Executor> +class executor_work_guard; + +class system_executor; + +class executor; + +template <typename Executor> +class strand; + +class io_context; + +template <typename Clock> +struct wait_traits; + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +template <typename Time> +struct time_traits; + +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + +template <typename Clock, typename WaitTraits> +class waitable_timer_service; + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +template <typename TimeType, typename TimeTraits> +class deadline_timer_service; + +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + +#if !defined(BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) +#define BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL + +template <typename Clock, + typename WaitTraits = boost::asio::wait_traits<Clock> + BOOST_ASIO_SVC_TPARAM_DEF2(= waitable_timer_service<Clock, WaitTraits>)> +class basic_waitable_timer; + +#endif // !defined(BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) + +#if defined(BOOST_ASIO_HAS_CHRONO) + +typedef basic_waitable_timer<chrono::system_clock> system_timer; + +typedef basic_waitable_timer<chrono::steady_clock> steady_timer; + +typedef basic_waitable_timer<chrono::high_resolution_clock> + high_resolution_timer; + +#endif // defined(BOOST_ASIO_HAS_CHRONO) + +template <class Protocol BOOST_ASIO_SVC_TPARAM> +class basic_socket; + +template <typename Protocol BOOST_ASIO_SVC_TPARAM> +class basic_datagram_socket; + +template <typename Protocol BOOST_ASIO_SVC_TPARAM> +class basic_stream_socket; + +template <typename Protocol BOOST_ASIO_SVC_TPARAM> +class basic_socket_acceptor; + +#if !defined(BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL) +#define BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename Protocol + BOOST_ASIO_SVC_TPARAM_DEF1(= stream_socket_service<Protocol>), +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ + || defined(GENERATING_DOCUMENTATION) + typename Clock = boost::posix_time::ptime, + typename WaitTraits = time_traits<Clock> + BOOST_ASIO_SVC_TPARAM1_DEF2(= deadline_timer_service<Clock, WaitTraits>)> +#else + typename Clock = chrono::steady_clock, + typename WaitTraits = wait_traits<Clock> + BOOST_ASIO_SVC_TPARAM1_DEF1(= steady_timer::service_type)> +#endif +class basic_socket_streambuf; + +#endif // !defined(BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL) + +#if !defined(BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL) +#define BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL + +// Forward declaration with defaulted arguments. +template <typename Protocol + BOOST_ASIO_SVC_TPARAM_DEF1(= stream_socket_service<Protocol>), +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ + || defined(GENERATING_DOCUMENTATION) + typename Clock = boost::posix_time::ptime, + typename WaitTraits = time_traits<Clock> + BOOST_ASIO_SVC_TPARAM1_DEF2(= deadline_timer_service<Clock, WaitTraits>)> +#else + typename Clock = chrono::steady_clock, + typename WaitTraits = wait_traits<Clock> + BOOST_ASIO_SVC_TPARAM1_DEF1(= steady_timer::service_type)> +#endif +class basic_socket_iostream; + +#endif // !defined(BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL) + +namespace ip { + +class address; + +class address_v4; + +class address_v6; + +template <typename Address> +class basic_address_iterator; + +typedef basic_address_iterator<address_v4> address_v4_iterator; + +typedef basic_address_iterator<address_v6> address_v6_iterator; + +template <typename Address> +class basic_address_range; + +typedef basic_address_range<address_v4> address_v4_range; + +typedef basic_address_range<address_v6> address_v6_range; + +class network_v4; + +class network_v6; + +template <typename InternetProtocol> +class basic_endpoint; + +template <typename InternetProtocol> +class basic_resolver_entry; + +template <typename InternetProtocol> +class basic_resolver_results; + +template <typename InternetProtocol BOOST_ASIO_SVC_TPARAM> +class basic_resolver; + +class tcp; + +class udp; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // !defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_TS_NETFWD_HPP diff --git a/boost/asio/ts/socket.hpp b/boost/asio/ts/socket.hpp new file mode 100644 index 0000000000..538bf3c303 --- /dev/null +++ b/boost/asio/ts/socket.hpp @@ -0,0 +1,27 @@ +// +// ts/socket.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_TS_SOCKET_HPP +#define BOOST_ASIO_TS_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/socket_base.hpp> +#include <boost/asio/basic_socket.hpp> +#include <boost/asio/basic_datagram_socket.hpp> +#include <boost/asio/basic_stream_socket.hpp> +#include <boost/asio/basic_socket_acceptor.hpp> +#include <boost/asio/basic_socket_streambuf.hpp> +#include <boost/asio/basic_socket_iostream.hpp> +#include <boost/asio/connect.hpp> + +#endif // BOOST_ASIO_TS_SOCKET_HPP diff --git a/boost/asio/ts/timer.hpp b/boost/asio/ts/timer.hpp new file mode 100644 index 0000000000..a9482838d6 --- /dev/null +++ b/boost/asio/ts/timer.hpp @@ -0,0 +1,26 @@ +// +// ts/timer.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_TS_TIMER_HPP +#define BOOST_ASIO_TS_TIMER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/chrono.hpp> + +#include <boost/asio/wait_traits.hpp> +#include <boost/asio/basic_waitable_timer.hpp> +#include <boost/asio/system_timer.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/asio/high_resolution_timer.hpp> + +#endif // BOOST_ASIO_TS_TIMER_HPP diff --git a/boost/asio/use_future.hpp b/boost/asio/use_future.hpp index e4ce7f7975..4ad61ba0cd 100644 --- a/boost/asio/use_future.hpp +++ b/boost/asio/use_future.hpp @@ -16,12 +16,26 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_HAS_STD_FUTURE) \ + || defined(GENERATING_DOCUMENTATION) + #include <memory> +#include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { +namespace detail { + +template <typename Function, typename Allocator> +class packaged_token; + +template <typename Function, typename Allocator, typename Result> +class packaged_handler; + +} // namespace detail /// Class used to specify that an asynchronous operation should return a future. /** @@ -57,12 +71,21 @@ public: { } - /// Specify an alternate allocator. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use rebind().) Specify an alternate allocator. template <typename OtherAllocator> use_future_t<OtherAllocator> operator[](const OtherAllocator& allocator) const { return use_future_t<OtherAllocator>(allocator); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Specify an alternate allocator. + template <typename OtherAllocator> + use_future_t<OtherAllocator> rebind(const OtherAllocator& allocator) const + { + return use_future_t<OtherAllocator>(allocator); + } /// Obtain allocator. allocator_type get_allocator() const @@ -70,18 +93,59 @@ public: return allocator_; } + /// Wrap a function object in a packaged task. + /** + * The @c package function is used to adapt a function object as a packaged + * task. When this adapter is passed as a completion token to an asynchronous + * operation, the result of the function object is retuned via a std::future. + * + * @par Example + * + * @code std::future<std::size_t> fut = + * my_socket.async_read_some(buffer, + * use_future([](boost::system::error_code ec, std::size_t n) + * { + * return ec ? 0 : n; + * })); + * ... + * std::size_t n = fut.get(); @endcode + */ + template <typename Function> +#if defined(GENERATING_DOCUMENTATION) + unspecified +#else // defined(GENERATING_DOCUMENTATION) + detail::packaged_token<typename decay<Function>::type, Allocator> +#endif // defined(GENERATING_DOCUMENTATION) + operator()(BOOST_ASIO_MOVE_ARG(Function) f) const; + private: - Allocator allocator_; + // Helper type to ensure that use_future can be constexpr default-constructed + // even when std::allocator<void> can't be. + struct std_allocator_void + { + BOOST_ASIO_CONSTEXPR std_allocator_void() + { + } + + operator std::allocator<void>() const + { + return std::allocator<void>(); + } + }; + + typename conditional< + is_same<std::allocator<void>, Allocator>::value, + std_allocator_void, Allocator>::type allocator_; }; /// A special value, similar to std::nothrow. /** * See the documentation for boost::asio::use_future_t for a usage example. */ -#if defined(BOOST_ASIO_MSVC) -__declspec(selectany) use_future_t<> use_future; -#elif defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) constexpr use_future_t<> use_future; +#elif defined(BOOST_ASIO_MSVC) +__declspec(selectany) use_future_t<> use_future; #endif } // namespace asio @@ -91,4 +155,7 @@ constexpr use_future_t<> use_future; #include <boost/asio/impl/use_future.hpp> +#endif // defined(BOOST_ASIO_HAS_STD_FUTURE) + // || defined(GENERATING_DOCUMENTATION) + #endif // BOOST_ASIO_USE_FUTURE_HPP diff --git a/boost/asio/uses_executor.hpp b/boost/asio/uses_executor.hpp new file mode 100644 index 0000000000..0951a86a2d --- /dev/null +++ b/boost/asio/uses_executor.hpp @@ -0,0 +1,73 @@ +// +// uses_executor.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_USES_EXECUTOR_HPP +#define BOOST_ASIO_USES_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> +#include <boost/asio/detail/type_traits.hpp> + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { + +/// A special type, similar to std::nothrow_t, used to disambiguate +/// constructors that accept executor arguments. +/** + * The executor_arg_t struct is an empty structure type used as a unique type + * to disambiguate constructor and function overloading. Specifically, some + * types have constructors with executor_arg_t as the first argument, + * immediately followed by an argument of a type that satisfies the Executor + * type requirements. + */ +struct executor_arg_t +{ + /// Constructor. + BOOST_ASIO_CONSTEXPR executor_arg_t() BOOST_ASIO_NOEXCEPT + { + } +}; + +/// A special value, similar to std::nothrow, used to disambiguate constructors +/// that accept executor arguments. +/** + * See boost::asio::executor_arg_t and boost::asio::uses_executor + * for more information. + */ +#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr executor_arg_t executor_arg; +#elif defined(BOOST_ASIO_MSVC) +__declspec(selectany) executor_arg_t executor_arg; +#endif + +/// The uses_executor trait detects whether a type T has an associated executor +/// that is convertible from type Executor. +/** + * Meets the BinaryTypeTrait requirements. The Asio library provides a + * definition that is derived from false_type. A program may specialize this + * template to derive from true_type for a user-defined type T that can be + * constructed with an executor, where the first argument of a constructor has + * type executor_arg_t and the second argument is convertible from type + * Executor. + */ +template <typename T, typename Executor> +struct uses_executor : false_type {}; + +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#endif // BOOST_ASIO_USES_EXECUTOR_HPP diff --git a/boost/asio/version.hpp b/boost/asio/version.hpp index 76b6440b01..5b78f0fad8 100644 --- a/boost/asio/version.hpp +++ b/boost/asio/version.hpp @@ -18,6 +18,6 @@ // BOOST_ASIO_VERSION % 100 is the sub-minor version // BOOST_ASIO_VERSION / 100 % 1000 is the minor version // BOOST_ASIO_VERSION / 100000 is the major version -#define BOOST_ASIO_VERSION 101010 // 1.10.10 +#define BOOST_ASIO_VERSION 101200 // 1.12.0 #endif // BOOST_ASIO_VERSION_HPP diff --git a/boost/asio/wait_traits.hpp b/boost/asio/wait_traits.hpp index f1a3c18243..76b8593c34 100644 --- a/boost/asio/wait_traits.hpp +++ b/boost/asio/wait_traits.hpp @@ -25,7 +25,7 @@ template <typename Clock> struct wait_traits { /// Convert a clock duration into a duration used for waiting. - /** + /** * @returns @c d. */ static typename Clock::duration to_wait_duration( @@ -33,6 +33,21 @@ struct wait_traits { return d; } + + /// Convert a clock duration into a duration used for waiting. + /** + * @returns @c d. + */ + static typename Clock::duration to_wait_duration( + const typename Clock::time_point& t) + { + typename Clock::time_point now = Clock::now(); + if (now + (Clock::duration::max)() < t) + return (Clock::duration::max)(); + if (now + (Clock::duration::min)() > t) + return (Clock::duration::min)(); + return t - now; + } }; } // namespace asio diff --git a/boost/asio/waitable_timer_service.hpp b/boost/asio/waitable_timer_service.hpp index 139d124ec5..882c6be66a 100644 --- a/boost/asio/waitable_timer_service.hpp +++ b/boost/asio/waitable_timer_service.hpp @@ -16,11 +16,14 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #include <cstddef> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/chrono_time_traits.hpp> #include <boost/asio/detail/deadline_timer_service.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/wait_traits.hpp> #include <boost/asio/detail/push_options.hpp> @@ -33,7 +36,7 @@ template <typename Clock, typename WaitTraits = boost::asio::wait_traits<Clock> > class waitable_timer_service #if defined(GENERATING_DOCUMENTATION) - : public boost::asio::io_service::service + : public boost::asio::io_context::service #else : public boost::asio::detail::service_base< waitable_timer_service<Clock, WaitTraits> > @@ -42,7 +45,7 @@ class waitable_timer_service public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. - static boost::asio::io_service::id id; + static boost::asio::io_context::id id; #endif /// The clock type. @@ -70,11 +73,11 @@ public: typedef typename service_impl_type::implementation_type implementation_type; #endif - /// Construct a new timer service for the specified io_service. - explicit waitable_timer_service(boost::asio::io_service& io_service) + /// Construct a new timer service for the specified io_context. + explicit waitable_timer_service(boost::asio::io_context& io_context) : boost::asio::detail::service_base< - waitable_timer_service<Clock, WaitTraits> >(io_service), - service_impl_(io_service) + waitable_timer_service<Clock, WaitTraits> >(io_context), + service_impl_(io_context) { } @@ -90,6 +93,23 @@ public: service_impl_.destroy(impl); } +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a new timer implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + service_impl_.move_construct(impl, other_impl); + } + + /// Move-assign from another timer implementation. + void move_assign(implementation_type& impl, + waitable_timer_service& other_service, + implementation_type& other_impl) + { + service_impl_.move_assign(impl, other_service.service_impl_, other_impl); + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Cancel any asynchronous wait operations associated with the timer. std::size_t cancel(implementation_type& impl, boost::system::error_code& ec) { @@ -103,10 +123,19 @@ public: return service_impl_.cancel_one(impl, ec); } - /// Get the expiry time for the timer as an absolute time. +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the expiry time for the timer as an + /// absolute time. time_point expires_at(const implementation_type& impl) const { - return service_impl_.expires_at(impl); + return service_impl_.expiry(impl); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the expiry time for the timer as an absolute time. + time_point expiry(const implementation_type& impl) const + { + return service_impl_.expiry(impl); } /// Set the expiry time for the timer as an absolute time. @@ -116,18 +145,30 @@ public: return service_impl_.expires_at(impl, expiry_time, ec); } - /// Get the expiry time for the timer relative to now. + /// Set the expiry time for the timer relative to now. + std::size_t expires_after(implementation_type& impl, + const duration& expiry_time, boost::system::error_code& ec) + { + return service_impl_.expires_after(impl, expiry_time, ec); + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the expiry time for the timer relative to + /// now. duration expires_from_now(const implementation_type& impl) const { - return service_impl_.expires_from_now(impl); + typedef detail::chrono_time_traits<Clock, WaitTraits> traits; + return traits::subtract(service_impl_.expiry(impl), traits::now()); } - /// Set the expiry time for the timer relative to now. + /// (Deprecated: Use expires_after().) Set the expiry time for the timer + /// relative to now. std::size_t expires_from_now(implementation_type& impl, const duration& expiry_time, boost::system::error_code& ec) { - return service_impl_.expires_from_now(impl, expiry_time, ec); + return service_impl_.expires_after(impl, expiry_time, ec); } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) // Perform a blocking wait on the timer. void wait(implementation_type& impl, boost::system::error_code& ec) @@ -142,20 +183,19 @@ public: async_wait(implementation_type& impl, BOOST_ASIO_MOVE_ARG(WaitHandler) handler) { - detail::async_result_init< - WaitHandler, void (boost::system::error_code)> init( - BOOST_ASIO_MOVE_CAST(WaitHandler)(handler)); + async_completion<WaitHandler, + void (boost::system::error_code)> init(handler); - service_impl_.async_wait(impl, init.handler); + service_impl_.async_wait(impl, init.completion_handler); return init.result.get(); } private: // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { - service_impl_.shutdown_service(); + service_impl_.shutdown(); } // The platform-specific implementation. @@ -167,4 +207,6 @@ private: #include <boost/asio/detail/pop_options.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_WAITABLE_TIMER_SERVICE_HPP diff --git a/boost/asio/windows/basic_handle.hpp b/boost/asio/windows/basic_handle.hpp index 6f903fd454..d0eda784e5 100644 --- a/boost/asio/windows/basic_handle.hpp +++ b/boost/asio/windows/basic_handle.hpp @@ -17,6 +17,8 @@ #include <boost/asio/detail/config.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) \ @@ -46,10 +48,6 @@ class basic_handle : public basic_io_object<HandleService> { public: - /// (Deprecated: Use native_handle_type.) The native representation of a - /// handle. - typedef typename HandleService::native_handle_type native_type; - /// The native representation of a handle. typedef typename HandleService::native_handle_type native_handle_type; @@ -60,11 +58,11 @@ public: /** * This constructor creates a handle without opening it. * - * @param io_service The io_service object that the handle will use to + * @param io_context The io_context object that the handle will use to * dispatch handlers for any asynchronous operations performed on the handle. */ - explicit basic_handle(boost::asio::io_service& io_service) - : basic_io_object<HandleService>(io_service) + explicit basic_handle(boost::asio::io_context& io_context) + : basic_io_object<HandleService>(io_context) { } @@ -72,16 +70,16 @@ public: /** * This constructor creates a handle object to hold an existing native handle. * - * @param io_service The io_service object that the handle will use to + * @param io_context The io_context object that the handle will use to * dispatch handlers for any asynchronous operations performed on the handle. * * @param handle A native handle. * * @throws boost::system::system_error Thrown on failure. */ - basic_handle(boost::asio::io_service& io_service, + basic_handle(boost::asio::io_context& io_context, const native_handle_type& handle) - : basic_io_object<HandleService>(io_service) + : basic_io_object<HandleService>(io_context) { boost::system::error_code ec; this->get_service().assign(this->get_implementation(), handle, ec); @@ -96,7 +94,7 @@ public: * @param other The other basic_handle object from which the move will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_handle(io_service&) constructor. + * constructed using the @c basic_handle(io_context&) constructor. */ basic_handle(basic_handle&& other) : basic_io_object<HandleService>( @@ -111,7 +109,7 @@ public: * @param other The other basic_handle object from which the move will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_handle(io_service&) constructor. + * constructed using the @c basic_handle(io_context&) constructor. */ basic_handle& operator=(basic_handle&& other) { @@ -172,10 +170,11 @@ public: * * @param ec Set to indicate what error occurred, if any. */ - boost::system::error_code assign(const native_handle_type& handle, + BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& handle, boost::system::error_code& ec) { - return this->get_service().assign(this->get_implementation(), handle, ec); + this->get_service().assign(this->get_implementation(), handle, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the handle is open. @@ -207,20 +206,10 @@ public: * * @param ec Set to indicate what error occurred, if any. */ - boost::system::error_code close(boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) { - return this->get_service().close(this->get_implementation(), ec); - } - - /// (Deprecated: Use native_handle().) Get the native handle representation. - /** - * This function may be used to obtain the underlying representation of the - * handle. This is intended to allow access to native handle functionality - * that is not otherwise provided. - */ - native_type native() - { - return this->get_service().native_handle(this->get_implementation()); + this->get_service().close(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get the native handle representation. @@ -257,9 +246,10 @@ public: * * @param ec Set to indicate what error occurred, if any. */ - boost::system::error_code cancel(boost::system::error_code& ec) + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) { - return this->get_service().cancel(this->get_implementation(), ec); + this->get_service().cancel(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } protected: @@ -280,4 +270,6 @@ protected: // || defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_WINDOWS_BASIC_HANDLE_HPP diff --git a/boost/asio/windows/basic_object_handle.hpp b/boost/asio/windows/basic_object_handle.hpp index c82c2a7039..0f2f278592 100644 --- a/boost/asio/windows/basic_object_handle.hpp +++ b/boost/asio/windows/basic_object_handle.hpp @@ -18,6 +18,8 @@ #include <boost/asio/detail/config.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) \ || defined(GENERATING_DOCUMENTATION) @@ -53,11 +55,11 @@ public: /** * This constructor creates an object handle without opening it. * - * @param io_service The io_service object that the object handle will use to + * @param io_context The io_context object that the object handle will use to * dispatch handlers for any asynchronous operations performed on the handle. */ - explicit basic_object_handle(boost::asio::io_service& io_service) - : basic_handle<ObjectHandleService>(io_service) + explicit basic_object_handle(boost::asio::io_context& io_context) + : basic_handle<ObjectHandleService>(io_context) { } @@ -66,16 +68,16 @@ public: * This constructor creates an object handle object to hold an existing native * handle. * - * @param io_service The io_service object that the object handle will use to + * @param io_context The io_context object that the object handle will use to * dispatch handlers for any asynchronous operations performed on the handle. * * @param native_handle The new underlying handle implementation. * * @throws boost::system::system_error Thrown on failure. */ - basic_object_handle(boost::asio::io_service& io_service, + basic_object_handle(boost::asio::io_context& io_context, const native_handle_type& native_handle) - : basic_handle<ObjectHandleService>(io_service, native_handle) + : basic_handle<ObjectHandleService>(io_context, native_handle) { } @@ -88,7 +90,7 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_object_handle(io_service&) constructor. + * constructed using the @c basic_object_handle(io_context&) constructor. */ basic_object_handle(basic_object_handle&& other) : basic_handle<ObjectHandleService>( @@ -104,7 +106,7 @@ public: * occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_object_handle(io_service&) constructor. + * constructed using the @c basic_object_handle(io_context&) constructor. */ basic_object_handle& operator=(basic_object_handle&& other) { @@ -156,7 +158,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). */ template <typename WaitHandler> BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, @@ -177,4 +179,6 @@ public: #endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP diff --git a/boost/asio/windows/basic_random_access_handle.hpp b/boost/asio/windows/basic_random_access_handle.hpp index 0d4184fb64..ae071896f8 100644 --- a/boost/asio/windows/basic_random_access_handle.hpp +++ b/boost/asio/windows/basic_random_access_handle.hpp @@ -17,6 +17,8 @@ #include <boost/asio/detail/config.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) @@ -47,10 +49,6 @@ class basic_random_access_handle : public basic_handle<RandomAccessHandleService> { public: - /// (Deprecated: Use native_handle_type.) The native representation of a - /// handle. - typedef typename RandomAccessHandleService::native_handle_type native_type; - /// The native representation of a handle. typedef typename RandomAccessHandleService::native_handle_type native_handle_type; @@ -60,12 +58,12 @@ public: * This constructor creates a random-access handle without opening it. The * handle needs to be opened before data can be written to or read from it. * - * @param io_service The io_service object that the random-access handle will + * @param io_context The io_context object that the random-access handle will * use to dispatch handlers for any asynchronous operations performed on the * handle. */ - explicit basic_random_access_handle(boost::asio::io_service& io_service) - : basic_handle<RandomAccessHandleService>(io_service) + explicit basic_random_access_handle(boost::asio::io_context& io_context) + : basic_handle<RandomAccessHandleService>(io_context) { } @@ -74,7 +72,7 @@ public: * This constructor creates a random-access handle object to hold an existing * native handle. * - * @param io_service The io_service object that the random-access handle will + * @param io_context The io_context object that the random-access handle will * use to dispatch handlers for any asynchronous operations performed on the * handle. * @@ -82,9 +80,9 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - basic_random_access_handle(boost::asio::io_service& io_service, + basic_random_access_handle(boost::asio::io_context& io_context, const native_handle_type& handle) - : basic_handle<RandomAccessHandleService>(io_service, handle) + : basic_handle<RandomAccessHandleService>(io_context, handle) { } @@ -97,7 +95,7 @@ public: * move will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_random_access_handle(io_service&) + * constructed using the @c basic_random_access_handle(io_context&) * constructor. */ basic_random_access_handle(basic_random_access_handle&& other) @@ -115,7 +113,7 @@ public: * move will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_random_access_handle(io_service&) + * constructed using the @c basic_random_access_handle(io_context&) * constructor. */ basic_random_access_handle& operator=(basic_random_access_handle&& other) @@ -214,7 +212,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The write operation may not transmit all of the data to the peer. * Consider using the @ref async_write_at function if you need to ensure that @@ -334,7 +332,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The read operation may not read all of the requested number of bytes. * Consider using the @ref async_read_at function if you need to ensure that @@ -375,4 +373,6 @@ public: #endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP diff --git a/boost/asio/windows/basic_stream_handle.hpp b/boost/asio/windows/basic_stream_handle.hpp index 1b954fffbd..2270847670 100644 --- a/boost/asio/windows/basic_stream_handle.hpp +++ b/boost/asio/windows/basic_stream_handle.hpp @@ -17,6 +17,8 @@ #include <boost/asio/detail/config.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #if defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) @@ -50,10 +52,6 @@ class basic_stream_handle : public basic_handle<StreamHandleService> { public: - /// (Deprecated: Use native_handle_type.) The native representation of a - /// handle. - typedef typename StreamHandleService::native_handle_type native_type; - /// The native representation of a handle. typedef typename StreamHandleService::native_handle_type native_handle_type; @@ -63,11 +61,11 @@ public: * needs to be opened and then connected or accepted before data can be sent * or received on it. * - * @param io_service The io_service object that the stream handle will use to + * @param io_context The io_context object that the stream handle will use to * dispatch handlers for any asynchronous operations performed on the handle. */ - explicit basic_stream_handle(boost::asio::io_service& io_service) - : basic_handle<StreamHandleService>(io_service) + explicit basic_stream_handle(boost::asio::io_context& io_context) + : basic_handle<StreamHandleService>(io_context) { } @@ -76,16 +74,16 @@ public: * This constructor creates a stream handle object to hold an existing native * handle. * - * @param io_service The io_service object that the stream handle will use to + * @param io_context The io_context object that the stream handle will use to * dispatch handlers for any asynchronous operations performed on the handle. * * @param handle The new underlying handle implementation. * * @throws boost::system::system_error Thrown on failure. */ - basic_stream_handle(boost::asio::io_service& io_service, + basic_stream_handle(boost::asio::io_context& io_context, const native_handle_type& handle) - : basic_handle<StreamHandleService>(io_service, handle) + : basic_handle<StreamHandleService>(io_context, handle) { } @@ -98,7 +96,7 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_stream_handle(io_service&) constructor. + * constructed using the @c basic_stream_handle(io_context&) constructor. */ basic_stream_handle(basic_stream_handle&& other) : basic_handle<StreamHandleService>( @@ -115,7 +113,7 @@ public: * will occur. * * @note Following the move, the moved-from object is in the same state as if - * constructed using the @c basic_stream_handle(io_service&) constructor. + * constructed using the @c basic_stream_handle(io_context&) constructor. */ basic_stream_handle& operator=(basic_stream_handle&& other) { @@ -206,7 +204,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The write operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all @@ -318,7 +316,7 @@ public: * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @note The read operation may not read all of the requested number of bytes. * Consider using the @ref async_read function if you need to ensure that the @@ -358,4 +356,6 @@ public: #endif // defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP diff --git a/boost/asio/windows/object_handle.hpp b/boost/asio/windows/object_handle.hpp index 614cc6bf3e..33b252d495 100644 --- a/boost/asio/windows/object_handle.hpp +++ b/boost/asio/windows/object_handle.hpp @@ -21,19 +21,362 @@ #if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) \ || defined(GENERATING_DOCUMENTATION) -#include <boost/asio/windows/basic_object_handle.hpp> +#include <boost/asio/async_result.hpp> +#include <boost/asio/basic_io_object.hpp> +#include <boost/asio/detail/throw_error.hpp> +#include <boost/asio/detail/win_object_handle_service.hpp> +#include <boost/asio/error.hpp> +#include <boost/asio/io_context.hpp> + +#if defined(BOOST_ASIO_HAS_MOVE) +# include <utility> +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/windows/basic_object_handle.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + +#define BOOST_ASIO_SVC_T boost::asio::detail::win_object_handle_service + +#include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace windows { -/// Typedef for the typical usage of an object handle. +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +// Typedef for the typical usage of an object handle. typedef basic_object_handle<> object_handle; +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +/// Provides object-oriented handle functionality. +/** + * The windows::object_handle class provides asynchronous and blocking + * object-oriented handle functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +class object_handle + : BOOST_ASIO_SVC_ACCESS basic_io_object<BOOST_ASIO_SVC_T> +{ +public: + /// The type of the executor associated with the object. + typedef io_context::executor_type executor_type; + + /// The native representation of a handle. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef BOOST_ASIO_SVC_T::native_handle_type native_handle_type; +#endif + + /// An object_handle is always the lowest layer. + typedef object_handle lowest_layer_type; + + /// Construct an object_handle without opening it. + /** + * This constructor creates an object handle without opening it. + * + * @param io_context The io_context object that the object handle will use to + * dispatch handlers for any asynchronous operations performed on the handle. + */ + explicit object_handle(boost::asio::io_context& io_context) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) + { + } + + /// Construct an object_handle on an existing native handle. + /** + * This constructor creates an object handle object to hold an existing native + * handle. + * + * @param io_context The io_context object that the object handle will use to + * dispatch handlers for any asynchronous operations performed on the handle. + * + * @param native_handle The new underlying handle implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + object_handle(boost::asio::io_context& io_context, + const native_handle_type& native_handle) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) + { + boost::system::error_code ec; + this->get_service().assign(this->get_implementation(), native_handle, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct an object_handle from another. + /** + * This constructor moves an object handle from one object to another. + * + * @param other The other object_handle object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c object_handle(io_context&) constructor. + */ + object_handle(object_handle&& other) + : basic_io_object<BOOST_ASIO_SVC_T>(std::move(other)) + { + } + + /// Move-assign an object_handle from another. + /** + * This assignment operator moves an object handle from one object to another. + * + * @param other The other object_handle object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c object_handle(io_context&) constructor. + */ + object_handle& operator=(object_handle&& other) + { + basic_io_object<BOOST_ASIO_SVC_T>::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_context() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_service() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_service(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_executor(); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since an object_handle cannot contain any further layers, it simply + * returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since an object_handle cannot contain any further layers, it simply + * returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + + /// Assign an existing native handle to the handle. + /* + * This function opens the handle to hold an existing native handle. + * + * @param handle A native handle. + * + * @throws boost::system::system_error Thrown on failure. + */ + void assign(const native_handle_type& handle) + { + boost::system::error_code ec; + this->get_service().assign(this->get_implementation(), handle, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native handle to the handle. + /* + * This function opens the handle to hold an existing native handle. + * + * @param handle A native handle. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& handle, + boost::system::error_code& ec) + { + this->get_service().assign(this->get_implementation(), handle, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the handle is open. + bool is_open() const + { + return this->get_service().is_open(this->get_implementation()); + } + + /// Close the handle. + /** + * This function is used to close the handle. Any asynchronous read or write + * operations will be cancelled immediately, and will complete with the + * boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. + */ + void close() + { + boost::system::error_code ec; + this->get_service().close(this->get_implementation(), ec); + boost::asio::detail::throw_error(ec, "close"); + } + + /// Close the handle. + /** + * This function is used to close the handle. Any asynchronous read or write + * operations will be cancelled immediately, and will complete with the + * boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) + { + this->get_service().close(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get the native handle representation. + /** + * This function may be used to obtain the underlying representation of the + * handle. This is intended to allow access to native handle functionality + * that is not otherwise provided. + */ + native_handle_type native_handle() + { + return this->get_service().native_handle(this->get_implementation()); + } + + /// Cancel all asynchronous operations associated with the handle. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. + */ + void cancel() + { + boost::system::error_code ec; + this->get_service().cancel(this->get_implementation(), ec); + boost::asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the handle. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) + { + this->get_service().cancel(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Perform a blocking wait on the object handle. + /** + * This function is used to wait for the object handle to be set to the + * signalled state. This function blocks and does not return until the object + * handle has been set to the signalled state. + * + * @throws boost::system::system_error Thrown on failure. + */ + void wait() + { + boost::system::error_code ec; + this->get_service().wait(this->get_implementation(), ec); + boost::asio::detail::throw_error(ec, "wait"); + } + + /// Perform a blocking wait on the object handle. + /** + * This function is used to wait for the object handle to be set to the + * signalled state. This function blocks and does not return until the object + * handle has been set to the signalled state. + * + * @param ec Set to indicate what error occurred, if any. + */ + void wait(boost::system::error_code& ec) + { + this->get_service().wait(this->get_implementation(), ec); + } + + /// Start an asynchronous wait on the object handle. + /** + * This function is be used to initiate an asynchronous wait against the + * object handle. It always returns immediately. + * + * @param handler The handler to be called when the object handle is set to + * the signalled state. Copies will be made of the handler as required. The + * function signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error // Result of operation. + * ); @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 + * boost::asio::io_context::post(). + */ + template <typename WaitHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + boost::asio::async_completion<WaitHandler, + void (boost::system::error_code)> init(handler); + + this->get_service().async_wait(this->get_implementation(), + init.completion_handler); + + return init.result.get(); + } +}; +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } // namespace windows } // namespace asio } // namespace boost +#include <boost/asio/detail/pop_options.hpp> + +#undef BOOST_ASIO_SVC_T + #endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) // || defined(GENERATING_DOCUMENTATION) diff --git a/boost/asio/windows/object_handle_service.hpp b/boost/asio/windows/object_handle_service.hpp index 26ef6ed507..6932d43c2b 100644 --- a/boost/asio/windows/object_handle_service.hpp +++ b/boost/asio/windows/object_handle_service.hpp @@ -18,13 +18,15 @@ #include <boost/asio/detail/config.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/async_result.hpp> #include <boost/asio/detail/win_object_handle_service.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -35,7 +37,7 @@ namespace windows { /// Default service implementation for an object handle. class object_handle_service #if defined(GENERATING_DOCUMENTATION) - : public boost::asio::io_service::service + : public boost::asio::io_context::service #else : public boost::asio::detail::service_base<object_handle_service> #endif @@ -43,7 +45,7 @@ class object_handle_service public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. - static boost::asio::io_service::id id; + static boost::asio::io_context::id id; #endif private: @@ -65,10 +67,10 @@ public: typedef service_impl_type::native_handle_type native_handle_type; #endif - /// Construct a new object handle service for the specified io_service. - explicit object_handle_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base<object_handle_service>(io_service), - service_impl_(io_service) + /// Construct a new object handle service for the specified io_context. + explicit object_handle_service(boost::asio::io_context& io_context) + : boost::asio::detail::service_base<object_handle_service>(io_context), + service_impl_(io_context) { } @@ -102,10 +104,11 @@ public: } /// Assign an existing native handle to an object handle. - boost::system::error_code assign(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID assign(implementation_type& impl, const native_handle_type& handle, boost::system::error_code& ec) { - return service_impl_.assign(impl, handle, ec); + service_impl_.assign(impl, handle, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the handle is open. @@ -115,10 +118,11 @@ public: } /// Close an object handle implementation. - boost::system::error_code close(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID close(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.close(impl, ec); + service_impl_.close(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get the native handle implementation. @@ -128,10 +132,11 @@ public: } /// Cancel all asynchronous operations associated with the handle. - boost::system::error_code cancel(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID cancel(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.cancel(impl, ec); + service_impl_.cancel(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } // Wait for a signaled state. @@ -147,20 +152,19 @@ public: async_wait(implementation_type& impl, BOOST_ASIO_MOVE_ARG(WaitHandler) handler) { - boost::asio::detail::async_result_init< - WaitHandler, void (boost::system::error_code)> init( - BOOST_ASIO_MOVE_CAST(WaitHandler)(handler)); + boost::asio::async_completion<WaitHandler, + void (boost::system::error_code)> init(handler); - service_impl_.async_wait(impl, init.handler); + service_impl_.async_wait(impl, init.completion_handler); return init.result.get(); } private: // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { - service_impl_.shutdown_service(); + service_impl_.shutdown(); } // The platform-specific implementation. @@ -176,4 +180,6 @@ private: #endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_WINDOWS_OBJECT_HANDLE_SERVICE_HPP diff --git a/boost/asio/windows/overlapped_handle.hpp b/boost/asio/windows/overlapped_handle.hpp new file mode 100644 index 0000000000..a21e11e965 --- /dev/null +++ b/boost/asio/windows/overlapped_handle.hpp @@ -0,0 +1,333 @@ +// +// windows/overlapped_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2017 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) +// + +#ifndef BOOST_ASIO_WINDOWS_OVERLAPPED_HANDLE_HPP +#define BOOST_ASIO_WINDOWS_OVERLAPPED_HANDLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include <boost/asio/detail/config.hpp> + +#if !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + +#if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ + || defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) + +#include <cstddef> +#include <boost/asio/async_result.hpp> +#include <boost/asio/basic_io_object.hpp> +#include <boost/asio/detail/throw_error.hpp> +#include <boost/asio/detail/win_iocp_handle_service.hpp> +#include <boost/asio/error.hpp> +#include <boost/asio/io_context.hpp> + +#if defined(BOOST_ASIO_HAS_MOVE) +# include <utility> +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#define BOOST_ASIO_SVC_T boost::asio::detail::win_iocp_handle_service + +#include <boost/asio/detail/push_options.hpp> + +namespace boost { +namespace asio { +namespace windows { + +/// Provides Windows handle functionality for objects that support +/// overlapped I/O. +/** + * The windows::overlapped_handle class provides the ability to wrap a Windows + * handle. The underlying object referred to by the handle must support + * overlapped I/O. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +class overlapped_handle + : BOOST_ASIO_SVC_ACCESS basic_io_object<BOOST_ASIO_SVC_T> +{ +public: + /// The type of the executor associated with the object. + typedef io_context::executor_type executor_type; + + /// The native representation of a handle. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef BOOST_ASIO_SVC_T::native_handle_type native_handle_type; +#endif + + /// An overlapped_handle is always the lowest layer. + typedef overlapped_handle lowest_layer_type; + + /// Construct an overlapped_handle without opening it. + /** + * This constructor creates a handle without opening it. + * + * @param io_context The io_context object that the handle will use to + * dispatch handlers for any asynchronous operations performed on the handle. + */ + explicit overlapped_handle(boost::asio::io_context& io_context) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) + { + } + + /// Construct an overlapped_handle on an existing native handle. + /** + * This constructor creates a handle object to hold an existing native handle. + * + * @param io_context The io_context object that the handle will use to + * dispatch handlers for any asynchronous operations performed on the handle. + * + * @param handle A native handle. + * + * @throws boost::system::system_error Thrown on failure. + */ + overlapped_handle(boost::asio::io_context& io_context, + const native_handle_type& handle) + : basic_io_object<BOOST_ASIO_SVC_T>(io_context) + { + boost::system::error_code ec; + this->get_service().assign(this->get_implementation(), handle, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct an overlapped_handle from another. + /** + * This constructor moves a handle from one object to another. + * + * @param other The other overlapped_handle object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c overlapped_handle(io_context&) constructor. + */ + overlapped_handle(overlapped_handle&& other) + : basic_io_object<BOOST_ASIO_SVC_T>(std::move(other)) + { + } + + /// Move-assign an overlapped_handle from another. + /** + * This assignment operator moves a handle from one object to another. + * + * @param other The other overlapped_handle object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c overlapped_handle(io_context&) constructor. + */ + overlapped_handle& operator=(overlapped_handle&& other) + { + basic_io_object<BOOST_ASIO_SVC_T>::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_context() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_service() + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_io_service(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return basic_io_object<BOOST_ASIO_SVC_T>::get_executor(); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since an overlapped_handle cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since an overlapped_handle cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + + /// Assign an existing native handle to the handle. + /* + * This function opens the handle to hold an existing native handle. + * + * @param handle A native handle. + * + * @throws boost::system::system_error Thrown on failure. + */ + void assign(const native_handle_type& handle) + { + boost::system::error_code ec; + this->get_service().assign(this->get_implementation(), handle, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native handle to the handle. + /* + * This function opens the handle to hold an existing native handle. + * + * @param handle A native handle. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& handle, + boost::system::error_code& ec) + { + this->get_service().assign(this->get_implementation(), handle, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the handle is open. + bool is_open() const + { + return this->get_service().is_open(this->get_implementation()); + } + + /// Close the handle. + /** + * This function is used to close the handle. Any asynchronous read or write + * operations will be cancelled immediately, and will complete with the + * boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. + */ + void close() + { + boost::system::error_code ec; + this->get_service().close(this->get_implementation(), ec); + boost::asio::detail::throw_error(ec, "close"); + } + + /// Close the handle. + /** + * This function is used to close the handle. Any asynchronous read or write + * operations will be cancelled immediately, and will complete with the + * boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) + { + this->get_service().close(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get the native handle representation. + /** + * This function may be used to obtain the underlying representation of the + * handle. This is intended to allow access to native handle functionality + * that is not otherwise provided. + */ + native_handle_type native_handle() + { + return this->get_service().native_handle(this->get_implementation()); + } + + /// Cancel all asynchronous operations associated with the handle. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. + */ + void cancel() + { + boost::system::error_code ec; + this->get_service().cancel(this->get_implementation(), ec); + boost::asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the handle. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) + { + this->get_service().cancel(this->get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + +protected: + /// Protected destructor to prevent deletion through this type. + /** + * This function destroys the handle, cancelling any outstanding asynchronous + * wait operations associated with the handle as if by calling @c cancel. + */ + ~overlapped_handle() + { + } +}; + +} // namespace windows +} // namespace asio +} // namespace boost + +#include <boost/asio/detail/pop_options.hpp> + +#undef BOOST_ASIO_SVC_T + +#endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + // || defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // !defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + +#endif // BOOST_ASIO_WINDOWS_OVERLAPPED_HANDLE_HPP diff --git a/boost/asio/windows/overlapped_ptr.hpp b/boost/asio/windows/overlapped_ptr.hpp index fa9fb3d200..5c6ce3a541 100644 --- a/boost/asio/windows/overlapped_ptr.hpp +++ b/boost/asio/windows/overlapped_ptr.hpp @@ -22,7 +22,7 @@ #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/win_iocp_overlapped_ptr.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -51,9 +51,9 @@ public: /// Construct an overlapped_ptr to contain the specified handler. template <typename Handler> - explicit overlapped_ptr(boost::asio::io_service& io_service, + explicit overlapped_ptr(boost::asio::io_context& io_context, BOOST_ASIO_MOVE_ARG(Handler) handler) - : impl_(io_service, BOOST_ASIO_MOVE_CAST(Handler)(handler)) + : impl_(io_context, BOOST_ASIO_MOVE_CAST(Handler)(handler)) { } @@ -71,10 +71,10 @@ public: /// Reset to contain the specified handler, freeing any current OVERLAPPED /// object. template <typename Handler> - void reset(boost::asio::io_service& io_service, + void reset(boost::asio::io_context& io_context, BOOST_ASIO_MOVE_ARG(Handler) handler) { - impl_.reset(io_service, BOOST_ASIO_MOVE_CAST(Handler)(handler)); + impl_.reset(io_context, BOOST_ASIO_MOVE_CAST(Handler)(handler)); } /// Get the contained OVERLAPPED object. diff --git a/boost/asio/windows/random_access_handle.hpp b/boost/asio/windows/random_access_handle.hpp index 993e193278..76d2bd7010 100644 --- a/boost/asio/windows/random_access_handle.hpp +++ b/boost/asio/windows/random_access_handle.hpp @@ -16,23 +16,364 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> +#include <boost/asio/windows/overlapped_handle.hpp> #if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) -#include <boost/asio/windows/basic_random_access_handle.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/windows/basic_random_access_handle.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + +#include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace windows { -/// Typedef for the typical usage of a random-access handle. +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +// Typedef for the typical usage of a random-access handle. typedef basic_random_access_handle<> random_access_handle; +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +/// Provides random-access handle functionality. +/** + * The windows::random_access_handle class provides asynchronous and + * blocking random-access handle functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +class random_access_handle + : public overlapped_handle +{ +public: + /// Construct a random_access_handle without opening it. + /** + * This constructor creates a random-access handle without opening it. The + * handle needs to be opened before data can be written to or read from it. + * + * @param io_context The io_context object that the random-access handle will + * use to dispatch handlers for any asynchronous operations performed on the + * handle. + */ + explicit random_access_handle(boost::asio::io_context& io_context) + : overlapped_handle(io_context) + { + } + + /// Construct a random_access_handle on an existing native handle. + /** + * This constructor creates a random-access handle object to hold an existing + * native handle. + * + * @param io_context The io_context object that the random-access handle will + * use to dispatch handlers for any asynchronous operations performed on the + * handle. + * + * @param handle The new underlying handle implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + random_access_handle(boost::asio::io_context& io_context, + const native_handle_type& handle) + : overlapped_handle(io_context, handle) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a random_access_handle from another. + /** + * This constructor moves a random-access handle from one object to another. + * + * @param other The other random_access_handle object from which the + * move will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c random_access_handle(io_context&) + * constructor. + */ + random_access_handle(random_access_handle&& other) + : overlapped_handle(std::move(other)) + { + } + + /// Move-assign a random_access_handle from another. + /** + * This assignment operator moves a random-access handle from one object to + * another. + * + * @param other The other random_access_handle object from which the + * move will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c random_access_handle(io_context&) + * constructor. + */ + random_access_handle& operator=(random_access_handle&& other) + { + overlapped_handle::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Write some data to the handle at the specified offset. + /** + * This function is used to write data to the random-access handle. The + * function call will block until one or more bytes of the data has been + * written successfully, or until an error occurs. + * + * @param offset The offset at which the data will be written. + * + * @param buffers One or more data buffers to be written to the handle. + * + * @returns The number of bytes written. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The write_some_at operation may not write all of the data. Consider + * using the @ref write_at function if you need to ensure that all data is + * written before the blocking operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * handle.write_some_at(42, boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename ConstBufferSequence> + std::size_t write_some_at(uint64_t offset, + const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->get_service().write_some_at( + this->get_implementation(), offset, buffers, ec); + boost::asio::detail::throw_error(ec, "write_some_at"); + return s; + } + + /// Write some data to the handle at the specified offset. + /** + * This function is used to write data to the random-access handle. The + * function call will block until one or more bytes of the data has been + * written successfully, or until an error occurs. + * + * @param offset The offset at which the data will be written. + * + * @param buffers One or more data buffers to be written to the handle. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write_at function if you need to ensure that + * all data is written before the blocking operation completes. + */ + template <typename ConstBufferSequence> + std::size_t write_some_at(uint64_t offset, + const ConstBufferSequence& buffers, boost::system::error_code& ec) + { + return this->get_service().write_some_at( + this->get_implementation(), offset, buffers, ec); + } + + /// Start an asynchronous write at the specified offset. + /** + * This function is used to asynchronously write data to the random-access + * handle. The function call always returns immediately. + * + * @param offset The offset at which the data will be written. + * + * @param buffers One or more data buffers to be written to the handle. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @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 + * boost::asio::io_context::post(). + * + * @note The write operation may not transmit all of the data to the peer. + * Consider using the @ref async_write_at function if you need to ensure that + * all data is written before the asynchronous operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * handle.async_write_some_at(42, boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename ConstBufferSequence, typename WriteHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_write_some_at(uint64_t offset, + const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + boost::asio::async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_write_some_at(this->get_implementation(), + offset, buffers, init.completion_handler); + + return init.result.get(); + } + + /// Read some data from the handle at the specified offset. + /** + * This function is used to read data from the random-access handle. The + * function call will block until one or more bytes of data has been read + * successfully, or until an error occurs. + * + * @param offset The offset at which the data will be read. + * + * @param buffers One or more buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read_at function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * handle.read_some_at(42, boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename MutableBufferSequence> + std::size_t read_some_at(uint64_t offset, + const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->get_service().read_some_at( + this->get_implementation(), offset, buffers, ec); + boost::asio::detail::throw_error(ec, "read_some_at"); + return s; + } + + /// Read some data from the handle at the specified offset. + /** + * This function is used to read data from the random-access handle. The + * function call will block until one or more bytes of data has been read + * successfully, or until an error occurs. + * + * @param offset The offset at which the data will be read. + * + * @param buffers One or more buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read_at function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + */ + template <typename MutableBufferSequence> + std::size_t read_some_at(uint64_t offset, + const MutableBufferSequence& buffers, boost::system::error_code& ec) + { + return this->get_service().read_some_at( + this->get_implementation(), offset, buffers, ec); + } + + /// Start an asynchronous read at the specified offset. + /** + * This function is used to asynchronously read data from the random-access + * handle. The function call always returns immediately. + * + * @param offset The offset at which the data will be read. + * + * @param buffers One or more buffers into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @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 + * boost::asio::io_context::post(). + * + * @note The read operation may not read all of the requested number of bytes. + * Consider using the @ref async_read_at function if you need to ensure that + * the requested amount of data is read before the asynchronous operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * handle.async_read_some_at(42, boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename MutableBufferSequence, typename ReadHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_read_some_at(uint64_t offset, + const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + boost::asio::async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_read_some_at(this->get_implementation(), + offset, buffers, init.completion_handler); + + return init.result.get(); + } +}; +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } // namespace windows } // namespace asio } // namespace boost +#include <boost/asio/detail/pop_options.hpp> + #endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) diff --git a/boost/asio/windows/random_access_handle_service.hpp b/boost/asio/windows/random_access_handle_service.hpp index 15a808f69a..a49a3955bd 100644 --- a/boost/asio/windows/random_access_handle_service.hpp +++ b/boost/asio/windows/random_access_handle_service.hpp @@ -17,6 +17,8 @@ #include <boost/asio/detail/config.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) @@ -25,7 +27,7 @@ #include <boost/asio/detail/cstdint.hpp> #include <boost/asio/detail/win_iocp_handle_service.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -36,7 +38,7 @@ namespace windows { /// Default service implementation for a random-access handle. class random_access_handle_service #if defined(GENERATING_DOCUMENTATION) - : public boost::asio::io_service::service + : public boost::asio::io_context::service #else : public boost::asio::detail::service_base<random_access_handle_service> #endif @@ -44,7 +46,7 @@ class random_access_handle_service public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. - static boost::asio::io_service::id id; + static boost::asio::io_context::id id; #endif private: @@ -59,13 +61,6 @@ public: typedef service_impl_type::implementation_type implementation_type; #endif - /// (Deprecated: Use native_handle_type.) The native handle type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_type; -#else - typedef service_impl_type::native_handle_type native_type; -#endif - /// The native handle type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; @@ -73,11 +68,11 @@ public: typedef service_impl_type::native_handle_type native_handle_type; #endif - /// Construct a new random-access handle service for the specified io_service. - explicit random_access_handle_service(boost::asio::io_service& io_service) + /// Construct a new random-access handle service for the specified io_context. + explicit random_access_handle_service(boost::asio::io_context& io_context) : boost::asio::detail::service_base< - random_access_handle_service>(io_service), - service_impl_(io_service) + random_access_handle_service>(io_context), + service_impl_(io_context) { } @@ -111,10 +106,11 @@ public: } /// Assign an existing native handle to a random-access handle. - boost::system::error_code assign(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID assign(implementation_type& impl, const native_handle_type& handle, boost::system::error_code& ec) { - return service_impl_.assign(impl, handle, ec); + service_impl_.assign(impl, handle, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the handle is open. @@ -124,16 +120,11 @@ public: } /// Close a random-access handle implementation. - boost::system::error_code close(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID close(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.close(impl, ec); - } - - /// (Deprecated: Use native_handle().) Get the native handle implementation. - native_type native(implementation_type& impl) - { - return service_impl_.native_handle(impl); + service_impl_.close(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get the native handle implementation. @@ -143,10 +134,11 @@ public: } /// Cancel all asynchronous operations associated with the handle. - boost::system::error_code cancel(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID cancel(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.cancel(impl, ec); + service_impl_.cancel(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Write the given data at the specified offset. @@ -165,11 +157,11 @@ public: uint64_t offset, const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - boost::asio::detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + boost::asio::async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); - service_impl_.async_write_some_at(impl, offset, buffers, init.handler); + service_impl_.async_write_some_at(impl, + offset, buffers, init.completion_handler); return init.result.get(); } @@ -190,20 +182,20 @@ public: uint64_t offset, const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - boost::asio::detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + boost::asio::async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); - service_impl_.async_read_some_at(impl, offset, buffers, init.handler); + service_impl_.async_read_some_at(impl, + offset, buffers, init.completion_handler); return init.result.get(); } private: // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { - service_impl_.shutdown_service(); + service_impl_.shutdown(); } // The platform-specific implementation. @@ -219,4 +211,6 @@ private: #endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_SERVICE_HPP diff --git a/boost/asio/windows/stream_handle.hpp b/boost/asio/windows/stream_handle.hpp index e52b8a16a6..1c7646a266 100644 --- a/boost/asio/windows/stream_handle.hpp +++ b/boost/asio/windows/stream_handle.hpp @@ -16,23 +16,348 @@ #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> +#include <boost/asio/windows/overlapped_handle.hpp> #if defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) -#include <boost/asio/windows/basic_stream_handle.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +# include <boost/asio/windows/basic_stream_handle.hpp> +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + +#include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace windows { -/// Typedef for the typical usage of a stream-oriented handle. +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +// Typedef for the typical usage of a stream-oriented handle. typedef basic_stream_handle<> stream_handle; +#else // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) +/// Provides stream-oriented handle functionality. +/** + * The windows::stream_handle class provides asynchronous and blocking + * stream-oriented handle functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +class stream_handle + : public overlapped_handle +{ +public: + /// Construct a stream_handle without opening it. + /** + * This constructor creates a stream handle without opening it. The handle + * needs to be opened and then connected or accepted before data can be sent + * or received on it. + * + * @param io_context The io_context object that the stream handle will use to + * dispatch handlers for any asynchronous operations performed on the handle. + */ + explicit stream_handle(boost::asio::io_context& io_context) + : overlapped_handle(io_context) + { + } + + /// Construct a stream_handle on an existing native handle. + /** + * This constructor creates a stream handle object to hold an existing native + * handle. + * + * @param io_context The io_context object that the stream handle will use to + * dispatch handlers for any asynchronous operations performed on the handle. + * + * @param handle The new underlying handle implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + stream_handle(boost::asio::io_context& io_context, + const native_handle_type& handle) + : overlapped_handle(io_context, handle) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a stream_handle from another. + /** + * This constructor moves a stream handle from one object to another. + * + * @param other The other stream_handle object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c stream_handle(io_context&) constructor. + */ + stream_handle(stream_handle&& other) + : overlapped_handle(std::move(other)) + { + } + + /// Move-assign a stream_handle from another. + /** + * This assignment operator moves a stream handle from one object to + * another. + * + * @param other The other stream_handle object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c stream_handle(io_context&) constructor. + */ + stream_handle& operator=(stream_handle&& other) + { + overlapped_handle::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Write some data to the handle. + /** + * This function is used to write data to the stream handle. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the handle. + * + * @returns The number of bytes written. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * handle.write_some(boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename ConstBufferSequence> + std::size_t write_some(const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->get_service().write_some( + this->get_implementation(), buffers, ec); + boost::asio::detail::throw_error(ec, "write_some"); + return s; + } + + /// Write some data to the handle. + /** + * This function is used to write data to the stream handle. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the handle. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + */ + template <typename ConstBufferSequence> + std::size_t write_some(const ConstBufferSequence& buffers, + boost::system::error_code& ec) + { + return this->get_service().write_some( + this->get_implementation(), buffers, ec); + } + + /// Start an asynchronous write. + /** + * This function is used to asynchronously write data to the stream handle. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be written to the handle. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @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 + * boost::asio::io_context::post(). + * + * @note The write operation may not transmit all of the data to the peer. + * Consider using the @ref async_write function if you need to ensure that all + * data is written before the asynchronous operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * handle.async_write_some(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename ConstBufferSequence, typename WriteHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + boost::asio::async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_write_some( + this->get_implementation(), buffers, init.completion_handler); + + return init.result.get(); + } + + /// Read some data from the handle. + /** + * This function is used to read data from the stream handle. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * handle.read_some(boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename MutableBufferSequence> + std::size_t read_some(const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->get_service().read_some( + this->get_implementation(), buffers, ec); + boost::asio::detail::throw_error(ec, "read_some"); + return s; + } + + /// Read some data from the handle. + /** + * This function is used to read data from the stream handle. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + */ + template <typename MutableBufferSequence> + std::size_t read_some(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + { + return this->get_service().read_some( + this->get_implementation(), buffers, ec); + } + + /// Start an asynchronous read. + /** + * This function is used to asynchronously read data from the stream handle. + * The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @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 + * boost::asio::io_context::post(). + * + * @note The read operation may not read all of the requested number of bytes. + * Consider using the @ref async_read function if you need to ensure that the + * requested amount of data is read before the asynchronous operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * handle.async_read_some(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template <typename MutableBufferSequence, typename ReadHandler> + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + boost::asio::async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); + + this->get_service().async_read_some( + this->get_implementation(), buffers, init.completion_handler); + + return init.result.get(); + } +}; +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) } // namespace windows } // namespace asio } // namespace boost +#include <boost/asio/detail/pop_options.hpp> + #endif // defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) diff --git a/boost/asio/windows/stream_handle_service.hpp b/boost/asio/windows/stream_handle_service.hpp index 5adcfaed1b..438954723c 100644 --- a/boost/asio/windows/stream_handle_service.hpp +++ b/boost/asio/windows/stream_handle_service.hpp @@ -17,6 +17,8 @@ #include <boost/asio/detail/config.hpp> +#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #if defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) @@ -24,7 +26,7 @@ #include <boost/asio/async_result.hpp> #include <boost/asio/detail/win_iocp_handle_service.hpp> #include <boost/asio/error.hpp> -#include <boost/asio/io_service.hpp> +#include <boost/asio/io_context.hpp> #include <boost/asio/detail/push_options.hpp> @@ -35,7 +37,7 @@ namespace windows { /// Default service implementation for a stream handle. class stream_handle_service #if defined(GENERATING_DOCUMENTATION) - : public boost::asio::io_service::service + : public boost::asio::io_context::service #else : public boost::asio::detail::service_base<stream_handle_service> #endif @@ -43,7 +45,7 @@ class stream_handle_service public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. - static boost::asio::io_service::id id; + static boost::asio::io_context::id id; #endif private: @@ -58,13 +60,6 @@ public: typedef service_impl_type::implementation_type implementation_type; #endif - /// (Deprecated: Use native_handle_type.) The native handle type. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined native_type; -#else - typedef service_impl_type::native_handle_type native_type; -#endif - /// The native handle type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; @@ -72,10 +67,10 @@ public: typedef service_impl_type::native_handle_type native_handle_type; #endif - /// Construct a new stream handle service for the specified io_service. - explicit stream_handle_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base<stream_handle_service>(io_service), - service_impl_(io_service) + /// Construct a new stream handle service for the specified io_context. + explicit stream_handle_service(boost::asio::io_context& io_context) + : boost::asio::detail::service_base<stream_handle_service>(io_context), + service_impl_(io_context) { } @@ -109,10 +104,11 @@ public: } /// Assign an existing native handle to a stream handle. - boost::system::error_code assign(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID assign(implementation_type& impl, const native_handle_type& handle, boost::system::error_code& ec) { - return service_impl_.assign(impl, handle, ec); + service_impl_.assign(impl, handle, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Determine whether the handle is open. @@ -122,16 +118,11 @@ public: } /// Close a stream handle implementation. - boost::system::error_code close(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID close(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.close(impl, ec); - } - - /// (Deprecated: Use native_handle().) Get the native handle implementation. - native_type native(implementation_type& impl) - { - return service_impl_.native_handle(impl); + service_impl_.close(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Get the native handle implementation. @@ -141,10 +132,11 @@ public: } /// Cancel all asynchronous operations associated with the handle. - boost::system::error_code cancel(implementation_type& impl, + BOOST_ASIO_SYNC_OP_VOID cancel(implementation_type& impl, boost::system::error_code& ec) { - return service_impl_.cancel(impl, ec); + service_impl_.cancel(impl, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Write the given data to the stream. @@ -163,11 +155,10 @@ public: const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { - boost::asio::detail::async_result_init< - WriteHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + boost::asio::async_completion<WriteHandler, + void (boost::system::error_code, std::size_t)> init(handler); - service_impl_.async_write_some(impl, buffers, init.handler); + service_impl_.async_write_some(impl, buffers, init.completion_handler); return init.result.get(); } @@ -188,20 +179,19 @@ public: const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { - boost::asio::detail::async_result_init< - ReadHandler, void (boost::system::error_code, std::size_t)> init( - BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + boost::asio::async_completion<ReadHandler, + void (boost::system::error_code, std::size_t)> init(handler); - service_impl_.async_read_some(impl, buffers, init.handler); + service_impl_.async_read_some(impl, buffers, init.completion_handler); return init.result.get(); } private: // Destroy all user-defined handler objects owned by the service. - void shutdown_service() + void shutdown() { - service_impl_.shutdown_service(); + service_impl_.shutdown(); } // The platform-specific implementation. @@ -217,4 +207,6 @@ private: #endif // defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_ENABLE_OLD_SERVICES) + #endif // BOOST_ASIO_WINDOWS_STREAM_HANDLE_SERVICE_HPP diff --git a/boost/asio/write.hpp b/boost/asio/write.hpp index b70e6f5bf5..87187c3d06 100644 --- a/boost/asio/write.hpp +++ b/boost/asio/write.hpp @@ -18,9 +18,13 @@ #include <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/async_result.hpp> -#include <boost/asio/basic_streambuf_fwd.hpp> +#include <boost/asio/buffer.hpp> #include <boost/asio/error.hpp> +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +# include <boost/asio/basic_streambuf_fwd.hpp> +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + #include <boost/asio/detail/push_options.hpp> namespace boost { @@ -70,7 +74,10 @@ namespace asio { * boost::asio::transfer_all()); @endcode */ template <typename SyncWriteStream, typename ConstBufferSequence> -std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers); +std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type* = 0); /// Write all of the supplied data to a stream before returning. /** @@ -110,7 +117,10 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers); */ template <typename SyncWriteStream, typename ConstBufferSequence> std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, - boost::system::error_code& ec); + boost::system::error_code& ec, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type* = 0); /// Write a certain amount of data to a stream before returning. /** @@ -161,7 +171,10 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, template <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition> std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, - CompletionCondition completion_condition); + CompletionCondition completion_condition, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type* = 0); /// Write a certain amount of data to a stream before returning. /** @@ -205,8 +218,172 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, template <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition> std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, - CompletionCondition completion_condition, boost::system::error_code& ec); + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type* = 0); + +/// Write all of the supplied data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This overload is equivalent to calling: + * @code boost::asio::write( + * s, buffers, + * boost::asio::transfer_all()); @endcode + */ +template <typename SyncWriteStream, typename DynamicBuffer> +std::size_t write(SyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type* = 0); + +/// Write all of the supplied data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @note This overload is equivalent to calling: + * @code boost::asio::write( + * s, buffers, + * boost::asio::transfer_all(), ec); @endcode + */ +template <typename SyncWriteStream, typename DynamicBuffer> +std::size_t write(SyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type* = 0); + +/// Write a certain amount of data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + */ +template <typename SyncWriteStream, typename DynamicBuffer, + typename CompletionCondition> +std::size_t write(SyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type* = 0); + +/// Write a certain amount of data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template <typename SyncWriteStream, typename DynamicBuffer, + typename CompletionCondition> +std::size_t write(SyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type* = 0); +#if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) /// Write all of the supplied data to a stream before returning. @@ -350,6 +527,7 @@ std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b, CompletionCondition completion_condition, boost::system::error_code& ec); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) /*@}*/ /** @@ -401,7 +579,7 @@ std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * To write a single data buffer use the @ref buffer function as follows: @@ -417,7 +595,10 @@ template <typename AsyncWriteStream, typename ConstBufferSequence, BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler); + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type* = 0); /// Start an asynchronous operation to write a certain amount of data to a /// stream. @@ -474,7 +655,7 @@ async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * To write a single data buffer use the @ref buffer function as follows: @@ -492,8 +673,135 @@ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler); + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_const_buffer_sequence<ConstBufferSequence>::value + >::type* = 0); + +/// Start an asynchronous operation to write all of the supplied data to a +/// stream. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_write_some function, and is known as a <em>composed operation</em>. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. + * + * @param s The stream to which the data is to be written. The type must support + * the AsyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. Successfully written + * data is automatically consumed from the buffers. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes written from the + * // buffers. If an error occurred, + * // this will be less than the sum + * // of the buffer sizes. + * ); @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 + * boost::asio::io_context::post(). + */ +template <typename AsyncWriteStream, + typename DynamicBuffer, typename WriteHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type* = 0); + +/// Start an asynchronous operation to write a certain amount of data to a +/// stream. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_write_some function, and is known as a <em>composed operation</em>. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. + * + * @param s The stream to which the data is to be written. The type must support + * the AsyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. Successfully written + * data is automatically consumed from the buffers. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_write_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's async_write_some function. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes written from the + * // buffers. If an error occurred, + * // this will be less than the sum + * // of the buffer sizes. + * ); @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 + * boost::asio::io_context::post(). + */ +template <typename AsyncWriteStream, typename DynamicBuffer, + typename CompletionCondition, typename WriteHandler> +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer) buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer<DynamicBuffer>::value + >::type* = 0); +#if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) /// Start an asynchronous operation to write all of the supplied data to a @@ -535,7 +843,7 @@ async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). */ template <typename AsyncWriteStream, typename Allocator, typename WriteHandler> BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, @@ -596,7 +904,7 @@ async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). */ template <typename AsyncWriteStream, typename Allocator, typename CompletionCondition, typename WriteHandler> @@ -607,6 +915,7 @@ async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b, BOOST_ASIO_MOVE_ARG(WriteHandler) handler); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) /*@}*/ diff --git a/boost/asio/write_at.hpp b/boost/asio/write_at.hpp index 266fc5bcaf..91eb52ef34 100644 --- a/boost/asio/write_at.hpp +++ b/boost/asio/write_at.hpp @@ -18,10 +18,13 @@ #include <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/async_result.hpp> -#include <boost/asio/basic_streambuf_fwd.hpp> #include <boost/asio/detail/cstdint.hpp> #include <boost/asio/error.hpp> +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +# include <boost/asio/basic_streambuf_fwd.hpp> +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + #include <boost/asio/detail/push_options.hpp> namespace boost { @@ -225,6 +228,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition, boost::system::error_code& ec); +#if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) /// Write all of the supplied data at the specified offset before returning. @@ -383,6 +387,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, boost::system::error_code& ec); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) /*@}*/ /** @@ -438,7 +443,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * To write a single data buffer use the @ref buffer function as follows: @@ -516,7 +521,7 @@ async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). * * @par Example * To write a single data buffer use the @ref buffer function as follows: @@ -537,6 +542,7 @@ async_write_at(AsyncRandomAccessWriteDevice& d, CompletionCondition completion_condition, BOOST_ASIO_MOVE_ARG(WriteHandler) handler); +#if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) /// Start an asynchronous operation to write all of the supplied data at the @@ -582,7 +588,7 @@ async_write_at(AsyncRandomAccessWriteDevice& d, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). */ template <typename AsyncRandomAccessWriteDevice, typename Allocator, typename WriteHandler> @@ -648,7 +654,7 @@ async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, * 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 - * boost::asio::io_service::post(). + * boost::asio::io_context::post(). */ template <typename AsyncRandomAccessWriteDevice, typename Allocator, typename CompletionCondition, typename WriteHandler> @@ -659,6 +665,7 @@ async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, BOOST_ASIO_MOVE_ARG(WriteHandler) handler); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) /*@}*/ |