From a7710aa4ec15ef88467af7f1a3d668d665068bf1 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Sun, 17 Jan 2010 21:42:36 +0000 Subject: [PATCH 01/38] Add coroutine::is_complete() and support for "yield break;". [SVN r59103] --- example/http/server4/coroutine.hpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/example/http/server4/coroutine.hpp b/example/http/server4/coroutine.hpp index f46c089e..369cbb74 100644 --- a/example/http/server4/coroutine.hpp +++ b/example/http/server4/coroutine.hpp @@ -17,6 +17,7 @@ public: coroutine() : value_(0) {} bool is_child() const { return value_ < 0; } bool is_parent() const { return !is_child(); } + bool is_complete() const { return value_ == -1; } private: friend class coroutine_ref; int value_; @@ -25,19 +26,24 @@ private: class coroutine_ref { public: - coroutine_ref(coroutine& c) : value_(c.value_) {} - coroutine_ref(coroutine* c) : value_(c->value_) {} + coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {} + coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {} + ~coroutine_ref() { if (!modified_) value_ = -1; } operator int() const { return value_; } - int& operator=(int v) { return value_ = v; } + int& operator=(int v) { modified_ = true; return value_ = v; } private: void operator=(const coroutine_ref&); int& value_; + bool modified_; }; #define CORO_REENTER(c) \ switch (coroutine_ref _coro_value = c) \ case -1: if (_coro_value) \ { \ + goto terminate_coroutine; \ + terminate_coroutine: \ + _coro_value = -1; \ goto bail_out_of_coroutine; \ bail_out_of_coroutine: \ break; \ @@ -54,9 +60,12 @@ private: else \ switch (_coro_value ? 0 : 1) \ for (;;) \ - case 1: if (_coro_value) \ - goto bail_out_of_coroutine; \ - else case 0: + case -1: if (_coro_value) \ + goto terminate_coroutine; \ + else for (;;) \ + case 1: if (_coro_value) \ + goto bail_out_of_coroutine; \ + else case 0: #define CORO_FORK \ for (_coro_value = -__LINE__;; _coro_value = __LINE__) \ From eecd73a23a123014d27f51700522b07d52fbab3a Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Sun, 17 Jan 2010 21:48:17 +0000 Subject: [PATCH 02/38] Document ordering of handlers in strands. Fix error in streambuf snippet. [SVN r59104] --- doc/reference.qbk | 92 +++++++++++++++++++++++++- include/boost/asio/basic_streambuf.hpp | 2 +- include/boost/asio/strand.hpp | 40 +++++++++++ 3 files changed, 131 insertions(+), 3 deletions(-) diff --git a/doc/reference.qbk b/doc/reference.qbk index d1b943c8..59fce702 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -30284,7 +30284,7 @@ Reading from a socket directly into a streambuf: boost::asio::streambuf b; // reserve 512 bytes in output sequence - boost::asio::streambuf::const_buffers_type bufs = b.prepare(512); + boost::asio::streambuf::mutable_buffers_type bufs = b.prepare(512); size_t n = sock.receive(bufs); @@ -37994,6 +37994,50 @@ Provides serialised handler execution. The [link boost_asio.reference.io_service__strand `io_service::strand`] class provides the ability to post and dispatch handlers with the guarantee that none of those handlers will execute concurrently. +[heading Order of handler invocation] + +Given: + + +* a strand object s + + +* an object a meeting completion handler requirements + + +* an object a1 which is an arbitrary copy of a made by the implementation + + +* an object b meeting completion handler requirements + + +* an object b1 which is an arbitrary copy of b made by the implementation + +if any of the following conditions are true: + + +* s.post(a) happens-before s.post(b) + + +* s.post(a) happens-before s.dispatch(b), where the latter is performed outside the strand + + +* s.dispatch(a) happens-before s.post(b), where the former is performed outside the strand + + +* s.dispatch(a) happens-before s.dispatch(b), where both are performed outside the strand + +then `asio_handler_invoke(a1, &a1)` happens-before `asio_handler_invoke(b1, &b1)`. + +Note that in the following case: + + async_op_1(..., s.wrap(a)); + async_op_2(..., s.wrap(b)); + + +the completion of the first async operation will perform `s.dispatch(a)`, and the second will perform `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. + + [heading Thread Safety] [*Distinct] [*objects:] Safe. @@ -64243,6 +64287,50 @@ Typedef for backwards compatibility. The [link boost_asio.reference.io_service__strand `io_service::strand`] class provides the ability to post and dispatch handlers with the guarantee that none of those handlers will execute concurrently. +[heading Order of handler invocation] + +Given: + + +* a strand object s + + +* an object a meeting completion handler requirements + + +* an object a1 which is an arbitrary copy of a made by the implementation + + +* an object b meeting completion handler requirements + + +* an object b1 which is an arbitrary copy of b made by the implementation + +if any of the following conditions are true: + + +* s.post(a) happens-before s.post(b) + + +* s.post(a) happens-before s.dispatch(b), where the latter is performed outside the strand + + +* s.dispatch(a) happens-before s.post(b), where the former is performed outside the strand + + +* s.dispatch(a) happens-before s.dispatch(b), where both are performed outside the strand + +then `asio_handler_invoke(a1, &a1)` happens-before `asio_handler_invoke(b1, &b1)`. + +Note that in the following case: + + async_op_1(..., s.wrap(a)); + async_op_2(..., s.wrap(b)); + + +the completion of the first async operation will perform `s.dispatch(a)`, and the second will perform `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. + + [heading Thread Safety] [*Distinct] [*objects:] Safe. @@ -65167,7 +65255,7 @@ Reading from a socket directly into a streambuf: boost::asio::streambuf b; // reserve 512 bytes in output sequence - boost::asio::streambuf::const_buffers_type bufs = b.prepare(512); + boost::asio::streambuf::mutable_buffers_type bufs = b.prepare(512); size_t n = sock.receive(bufs); diff --git a/include/boost/asio/basic_streambuf.hpp b/include/boost/asio/basic_streambuf.hpp index cf890d3f..e5f8a8dc 100644 --- a/include/boost/asio/basic_streambuf.hpp +++ b/include/boost/asio/basic_streambuf.hpp @@ -96,7 +96,7 @@ namespace asio { * boost::asio::streambuf b; * * // reserve 512 bytes in output sequence - * boost::asio::streambuf::const_buffers_type bufs = b.prepare(512); + * boost::asio::streambuf::mutable_buffers_type bufs = b.prepare(512); * * size_t n = sock.receive(bufs); * diff --git a/include/boost/asio/strand.hpp b/include/boost/asio/strand.hpp index c7c64a5e..a64d4867 100644 --- a/include/boost/asio/strand.hpp +++ b/include/boost/asio/strand.hpp @@ -30,6 +30,46 @@ namespace asio { * 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. + * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Safe. From c5a643df6b376817d3c2c64168c2817d20fbc979 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Sun, 17 Jan 2010 22:21:21 +0000 Subject: [PATCH 03/38] Update revision history. [SVN r59106] --- doc/history.qbk | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/doc/history.qbk b/doc/history.qbk index 392f2bbb..6721ada4 100644 --- a/doc/history.qbk +++ b/doc/history.qbk @@ -7,6 +7,39 @@ [section:history Revision History] +[heading Asio 1.4.4 / Boost 1.42] + +* Added a new HTTP Server 4 example illustrating the use of stackless coroutines + with Asio. +* Changed handler allocation and invocation to use `boost::addressof` to get the + address of handler objects, rather than applying `operator&` directly + ([@https://svn.boost.org/trac/boost/ticket/2977 #2977]). +* Restricted MSVC buffer debugging workaround to 2008, as it causes a crash with + 2010 beta 2 ([@https://svn.boost.org/trac/boost/ticket/3796 #3796], + [@https://svn.boost.org/trac/boost/ticket/3822 #3822]). +* Fixed a problem with the lifetime of handler memory, where Windows needs the + `OVERLAPPED` structure to be valid until both the initiating function call + has returned and the completion packet has been delivered. +* Don't block signals while performing system calls, but instead restart the + calls if they are interrupted. +* Documented the guarantee made by strand objects with respect to order of + handler invocation. +* Changed strands to use a pool of implementations, to make copying of strands + cheaper. +* Ensured that kqueue support is enabled for BSD platforms + ([@https://svn.boost.org/trac/boost/ticket/3626 #3626]). +* Added a `boost_` prefix to the `extern "C"` thread entry point function + ([@https://svn.boost.org/trac/boost/ticket/3809 #3809]). +* In `getaddrinfo` emulation, only check the socket type (`SOCK_STREAM` or + `SOCK_DGRAM`) if a service name has been specified. This should allow the + emulation to work with raw sockets. +* Added a workaround for some broken Windows firewalls that make a socket + appear bound to 0.0.0.0 when it is in fact bound to 127.0.0.1. +* Applied a fix for reported excessive CPU usage under Solaris + ([@https://svn.boost.org/trac/boost/ticket/3670 #3670]). +* Added some support for platforms that use older compilers such as g++ 2.95 + ([@https://svn.boost.org/trac/boost/ticket/3743 #3743]). + [heading Asio 1.4.3 / Boost 1.40] * Added a new ping example to illustrate the use of ICMP sockets. From 96ce1bea3fa4ba1d6f6b446c21aac10c99a104f6 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Tue, 9 Mar 2010 12:50:07 +0000 Subject: [PATCH 04/38] Reworked implementation. [SVN r60380] --- include/boost/asio/buffers_iterator.hpp | 138 +- .../boost/asio/datagram_socket_service.hpp | 29 +- include/boost/asio/deadline_timer_service.hpp | 36 +- .../asio/detail/base_from_completion_cond.hpp | 67 + .../asio/detail/buffer_sequence_adapter.hpp | 254 +++ .../boost/asio/detail/completion_handler.hpp | 73 + .../asio/detail/const_buffers_iterator.hpp | 153 -- .../boost/asio/detail/consuming_buffers.hpp | 54 +- .../asio/detail/deadline_timer_service.hpp | 63 +- .../boost/asio/detail/dev_poll_reactor.hpp | 410 +--- .../asio/detail/dev_poll_reactor_fwd.hpp | 1 - include/boost/asio/detail/epoll_reactor.hpp | 759 +++---- .../boost/asio/detail/epoll_reactor_fwd.hpp | 1 - include/boost/asio/detail/fenced_block.hpp | 68 + .../boost/asio/detail/gcc_fenced_block.hpp | 61 + .../asio/detail/gcc_x86_fenced_block.hpp | 63 + .../asio/detail/handler_base_from_member.hpp | 78 - include/boost/asio/detail/handler_queue.hpp | 231 --- include/boost/asio/detail/hash_map.hpp | 93 +- .../asio/detail/indirect_handler_queue.hpp | 293 --- include/boost/asio/detail/kqueue_reactor.hpp | 472 ++--- .../boost/asio/detail/kqueue_reactor_fwd.hpp | 1 - .../boost/asio/detail/macos_fenced_block.hpp | 59 + include/boost/asio/detail/null_buffers_op.hpp | 79 + include/boost/asio/detail/null_event.hpp | 6 + .../boost/asio/detail/null_fenced_block.hpp | 45 + include/boost/asio/detail/op_queue.hpp | 158 ++ include/boost/asio/detail/operation.hpp | 45 + include/boost/asio/detail/posix_event.hpp | 10 + include/boost/asio/detail/posix_mutex.hpp | 22 +- .../detail/reactive_descriptor_service.hpp | 492 ++--- .../detail/reactive_serial_port_service.hpp | 23 +- .../asio/detail/reactive_socket_service.hpp | 1182 ++++++----- include/boost/asio/detail/reactor.hpp | 34 + include/boost/asio/detail/reactor_fwd.hpp | 48 + include/boost/asio/detail/reactor_op.hpp | 62 + .../boost/asio/detail/reactor_op_queue.hpp | 383 +--- .../boost/asio/detail/resolver_service.hpp | 243 ++- include/boost/asio/detail/select_reactor.hpp | 455 ++--- .../boost/asio/detail/service_registry.hpp | 239 ++- .../asio/detail/solaris_fenced_block.hpp | 59 + include/boost/asio/detail/strand_service.hpp | 447 ++--- include/boost/asio/detail/task_io_service.hpp | 319 +-- .../asio/detail/task_io_service_2lock.hpp | 475 ----- .../asio/detail/task_io_service_operation.hpp | 71 + include/boost/asio/detail/timer_op.hpp | 46 + include/boost/asio/detail/timer_queue.hpp | 336 +--- .../boost/asio/detail/timer_queue_base.hpp | 32 +- include/boost/asio/detail/timer_queue_fwd.hpp | 33 + include/boost/asio/detail/timer_queue_set.hpp | 117 ++ include/boost/asio/detail/timer_scheduler.hpp | 36 + .../boost/asio/detail/timer_scheduler_fwd.hpp | 48 + include/boost/asio/detail/win_event.hpp | 9 + .../boost/asio/detail/win_fenced_block.hpp | 57 + .../asio/detail/win_iocp_handle_service.hpp | 427 ++-- .../boost/asio/detail/win_iocp_io_service.hpp | 549 +++--- .../boost/asio/detail/win_iocp_operation.hpp | 91 + .../asio/detail/win_iocp_overlapped_ptr.hpp | 130 +- .../detail/win_iocp_serial_port_service.hpp | 10 +- .../asio/detail/win_iocp_socket_service.hpp | 1739 +++++++---------- include/boost/asio/detail/win_mutex.hpp | 42 +- include/boost/asio/impl/io_service.ipp | 12 +- include/boost/asio/impl/read.ipp | 206 +- include/boost/asio/impl/read_at.ipp | 8 +- include/boost/asio/impl/write.ipp | 184 +- include/boost/asio/impl/write_at.ipp | 8 +- include/boost/asio/io_service.hpp | 31 +- .../boost/asio/ip/basic_resolver_iterator.hpp | 76 +- .../asio/posix/stream_descriptor_service.hpp | 35 +- include/boost/asio/raw_socket_service.hpp | 29 +- include/boost/asio/serial_port_service.hpp | 19 +- .../boost/asio/socket_acceptor_service.hpp | 29 +- .../asio/ssl/detail/openssl_operation.hpp | 3 +- .../ssl/detail/openssl_stream_service.hpp | 59 +- include/boost/asio/stream_socket_service.hpp | 29 +- .../windows/random_access_handle_service.hpp | 7 +- .../asio/windows/stream_handle_service.hpp | 7 +- 77 files changed, 5712 insertions(+), 7086 deletions(-) create mode 100644 include/boost/asio/detail/base_from_completion_cond.hpp create mode 100644 include/boost/asio/detail/buffer_sequence_adapter.hpp create mode 100644 include/boost/asio/detail/completion_handler.hpp delete mode 100644 include/boost/asio/detail/const_buffers_iterator.hpp create mode 100644 include/boost/asio/detail/fenced_block.hpp create mode 100644 include/boost/asio/detail/gcc_fenced_block.hpp create mode 100644 include/boost/asio/detail/gcc_x86_fenced_block.hpp delete mode 100644 include/boost/asio/detail/handler_base_from_member.hpp delete mode 100644 include/boost/asio/detail/handler_queue.hpp delete mode 100644 include/boost/asio/detail/indirect_handler_queue.hpp create mode 100644 include/boost/asio/detail/macos_fenced_block.hpp create mode 100644 include/boost/asio/detail/null_buffers_op.hpp create mode 100644 include/boost/asio/detail/null_fenced_block.hpp create mode 100644 include/boost/asio/detail/op_queue.hpp create mode 100644 include/boost/asio/detail/operation.hpp create mode 100644 include/boost/asio/detail/reactor.hpp create mode 100644 include/boost/asio/detail/reactor_fwd.hpp create mode 100644 include/boost/asio/detail/reactor_op.hpp create mode 100644 include/boost/asio/detail/solaris_fenced_block.hpp delete mode 100644 include/boost/asio/detail/task_io_service_2lock.hpp create mode 100644 include/boost/asio/detail/task_io_service_operation.hpp create mode 100644 include/boost/asio/detail/timer_op.hpp create mode 100644 include/boost/asio/detail/timer_queue_fwd.hpp create mode 100644 include/boost/asio/detail/timer_queue_set.hpp create mode 100644 include/boost/asio/detail/timer_scheduler.hpp create mode 100644 include/boost/asio/detail/timer_scheduler_fwd.hpp create mode 100644 include/boost/asio/detail/win_fenced_block.hpp create mode 100644 include/boost/asio/detail/win_iocp_operation.hpp diff --git a/include/boost/asio/buffers_iterator.hpp b/include/boost/asio/buffers_iterator.hpp index 0d292131..0b654b8c 100644 --- a/include/boost/asio/buffers_iterator.hpp +++ b/include/boost/asio/buffers_iterator.hpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -76,11 +76,10 @@ namespace detail /// A random access iterator over the bytes in a buffer sequence. template class buffers_iterator - : public boost::iterator_facade< - buffers_iterator, - typename detail::buffers_iterator_types< - BufferSequence, ByteType>::byte_type, - boost::random_access_traversal_tag> + : public boost::iterator< + std::random_access_iterator_tag, + typename detail::buffers_iterator_types< + BufferSequence, ByteType>::byte_type> { private: typedef typename detail::buffers_iterator_types< @@ -139,9 +138,132 @@ public: return new_iter; } -private: - friend class boost::iterator_core_access; + /// Dereference an iterator. + byte_type& operator*() const + { + return dereference(); + } + /// Dereference an iterator. + byte_type* operator->() const + { + return &dereference(); + } + + /// Access an individual element. + byte_type& operator[](std::ptrdiff_t difference) const + { + buffers_iterator tmp(*this); + tmp.advance(difference); + return *tmp; + } + + /// Increment operator (prefix). + buffers_iterator& operator++() + { + increment(); + return *this; + } + + /// Increment operator (postfix). + buffers_iterator operator++(int) + { + buffers_iterator tmp(*this); + ++*this; + return tmp; + } + + /// Decrement operator (prefix). + buffers_iterator& operator--() + { + decrement(); + return *this; + } + + /// Decrement operator (postfix). + buffers_iterator operator--(int) + { + buffers_iterator tmp(*this); + --*this; + return tmp; + } + + /// Addition operator. + buffers_iterator& operator+=(std::ptrdiff_t difference) + { + advance(difference); + return *this; + } + + /// Subtraction operator. + buffers_iterator& operator-=(std::ptrdiff_t difference) + { + advance(-difference); + return *this; + } + + /// Addition operator. + friend buffers_iterator operator+(const buffers_iterator& iter, + std::ptrdiff_t difference) + { + buffers_iterator tmp(iter); + tmp.advance(difference); + return tmp; + } + + /// Subtraction operator. + friend buffers_iterator operator-(const buffers_iterator& iter, + std::ptrdiff_t difference) + { + buffers_iterator tmp(iter); + tmp.advance(-difference); + return tmp; + } + + /// Subtraction operator. + friend std::ptrdiff_t operator-(const buffers_iterator& a, + const buffers_iterator& b) + { + return b.distance_to(a); + } + + /// Test two iterators for equality. + friend bool operator==(const buffers_iterator& a, const buffers_iterator& b) + { + return a.equal(b); + } + + /// Test two iterators for inequality. + friend bool operator!=(const buffers_iterator& a, const buffers_iterator& b) + { + return !a.equal(b); + } + + /// Compare two iterators. + friend bool operator<(const buffers_iterator& a, const buffers_iterator& b) + { + return a.distance_to(b) > 0; + } + + /// Compare two iterators. + friend bool operator<=(const buffers_iterator& a, const buffers_iterator& b) + { + return !(b < a); + } + + /// Compare two iterators. + friend bool operator>(const buffers_iterator& a, const buffers_iterator& b) + { + return b < a; + } + + /// Compare two iterators. + friend bool operator>=(const buffers_iterator& a, const buffers_iterator& b) + { + return !(a < b); + } + +private: // Dereference the iterator. byte_type& dereference() const { diff --git a/include/boost/asio/datagram_socket_service.hpp b/include/boost/asio/datagram_socket_service.hpp index 93deddc1..74bf7033 100644 --- a/include/boost/asio/datagram_socket_service.hpp +++ b/include/boost/asio/datagram_socket_service.hpp @@ -28,17 +28,7 @@ #if defined(BOOST_ASIO_HAS_IOCP) # include -#elif defined(BOOST_ASIO_HAS_EPOLL) -# include -# include -#elif defined(BOOST_ASIO_HAS_KQUEUE) -# include -# include -#elif defined(BOOST_ASIO_HAS_DEV_POLL) -# include -# include #else -# include # include #endif @@ -70,18 +60,8 @@ private: // The type of the platform-specific implementation. #if defined(BOOST_ASIO_HAS_IOCP) typedef detail::win_iocp_socket_service service_impl_type; -#elif defined(BOOST_ASIO_HAS_EPOLL) - typedef detail::reactive_socket_service< - Protocol, detail::epoll_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_KQUEUE) - typedef detail::reactive_socket_service< - Protocol, detail::kqueue_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_DEV_POLL) - typedef detail::reactive_socket_service< - Protocol, detail::dev_poll_reactor > service_impl_type; #else - typedef detail::reactive_socket_service< - Protocol, detail::select_reactor > service_impl_type; + typedef detail::reactive_socket_service service_impl_type; #endif public: @@ -103,13 +83,14 @@ public: explicit datagram_socket_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base< datagram_socket_service >(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new datagram socket implementation. @@ -324,8 +305,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace asio diff --git a/include/boost/asio/deadline_timer_service.hpp b/include/boost/asio/deadline_timer_service.hpp index 90e74828..624791db 100644 --- a/include/boost/asio/deadline_timer_service.hpp +++ b/include/boost/asio/deadline_timer_service.hpp @@ -27,18 +27,6 @@ #include #include -#if defined(BOOST_ASIO_HAS_IOCP) -# include -#elif defined(BOOST_ASIO_HAS_EPOLL) -# include -#elif defined(BOOST_ASIO_HAS_KQUEUE) -# include -#elif defined(BOOST_ASIO_HAS_DEV_POLL) -# include -#else -# include -#endif - namespace boost { namespace asio { @@ -70,22 +58,7 @@ public: private: // The type of the platform-specific implementation. -#if defined(BOOST_ASIO_HAS_IOCP) - typedef detail::deadline_timer_service< - traits_type, detail::win_iocp_io_service> service_impl_type; -#elif defined(BOOST_ASIO_HAS_EPOLL) - typedef detail::deadline_timer_service< - traits_type, detail::epoll_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_KQUEUE) - typedef detail::deadline_timer_service< - traits_type, detail::kqueue_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_DEV_POLL) - typedef detail::deadline_timer_service< - traits_type, detail::dev_poll_reactor > service_impl_type; -#else - typedef detail::deadline_timer_service< - traits_type, detail::select_reactor > service_impl_type; -#endif + typedef detail::deadline_timer_service service_impl_type; public: /// The implementation type of the deadline timer. @@ -99,13 +72,14 @@ public: explicit deadline_timer_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base< deadline_timer_service >(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new timer implementation. @@ -166,8 +140,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace asio diff --git a/include/boost/asio/detail/base_from_completion_cond.hpp b/include/boost/asio/detail/base_from_completion_cond.hpp new file mode 100644 index 00000000..1b1f1422 --- /dev/null +++ b/include/boost/asio/detail/base_from_completion_cond.hpp @@ -0,0 +1,67 @@ +// +// base_from_completion_cond.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_BASE_FROM_COMPLETION_COND_HPP +#define BOOST_ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class base_from_completion_cond +{ +protected: + explicit base_from_completion_cond(CompletionCondition completion_condition) + : completion_condition_(completion_condition) + { + } + + std::size_t check(const boost::system::error_code& ec, + std::size_t total_transferred) + { + return detail::adapt_completion_condition_result( + completion_condition_(ec, total_transferred)); + } + +private: + CompletionCondition completion_condition_; +}; + +template <> +class base_from_completion_cond +{ +protected: + explicit base_from_completion_cond(transfer_all_t) + { + } + + static std::size_t check(const boost::system::error_code& ec, + std::size_t total_transferred) + { + return transfer_all_t()(ec, total_transferred); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP diff --git a/include/boost/asio/detail/buffer_sequence_adapter.hpp b/include/boost/asio/detail/buffer_sequence_adapter.hpp new file mode 100644 index 00000000..ce9652ef --- /dev/null +++ b/include/boost/asio/detail/buffer_sequence_adapter.hpp @@ -0,0 +1,254 @@ +// +// buffer_sequence_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_BUFFER_SEQUENCE_ADAPTER_HPP +#define BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class buffer_sequence_adapter_base +{ +protected: +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + typedef WSABUF native_buffer_type; + + static void init_native_buffer(WSABUF& buf, + const boost::asio::mutable_buffer& buffer) + { + buf.buf = boost::asio::buffer_cast(buffer); + buf.len = boost::asio::buffer_size(buffer); + } + + static void init_native_buffer(WSABUF& buf, + const boost::asio::const_buffer& buffer) + { + buf.buf = const_cast(boost::asio::buffer_cast(buffer)); + buf.len = boost::asio::buffer_size(buffer); + } +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + typedef iovec native_buffer_type; + + static void init_iov_base(void*& base, void* addr) + { + base = addr; + } + + template + static void init_iov_base(T& base, void* addr) + { + base = static_cast(addr); + } + + static void init_native_buffer(iovec& iov, + const boost::asio::mutable_buffer& buffer) + { + init_iov_base(iov.iov_base, boost::asio::buffer_cast(buffer)); + iov.iov_len = boost::asio::buffer_size(buffer); + } + + static void init_native_buffer(iovec& iov, + const boost::asio::const_buffer& buffer) + { + init_iov_base(iov.iov_base, const_cast( + boost::asio::buffer_cast(buffer))); + iov.iov_len = boost::asio::buffer_size(buffer); + } +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +}; + +// Helper class to translate buffers into the native buffer representation. +template +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter(const Buffers& buffers) + : count_(0), total_buffer_size_(0) + { + typename Buffers::const_iterator iter = buffers.begin(); + typename Buffers::const_iterator end = buffers.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); + } + } + + native_buffer_type* buffers() + { + return buffers_; + } + + std::size_t count() const + { + return count_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const Buffers& buffers) + { + typename Buffers::const_iterator iter = buffers.begin(); + typename Buffers::const_iterator end = buffers.end(); + std::size_t i = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + if (boost::asio::buffer_size(Buffer(*iter)) > 0) + return false; + return true; + } + + static void validate(const Buffers& buffers) + { + typename Buffers::const_iterator iter = buffers.begin(); + typename Buffers::const_iterator end = buffers.end(); + for (; iter != end; ++iter) + { + Buffer buffer(*iter); + boost::asio::buffer_cast(buffer); + } + } + + static Buffer first(const Buffers& buffers) + { + typename Buffers::const_iterator iter = buffers.begin(); + typename Buffers::const_iterator end = buffers.end(); + for (; iter != end; ++iter) + { + Buffer buffer(*iter); + if (boost::asio::buffer_size(buffer) != 0) + return buffer; + } + return Buffer(); + } + +private: + // The maximum number of buffers to support in a single operation. + enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; + + native_buffer_type buffers_[max_buffers]; + std::size_t count_; + std::size_t total_buffer_size_; +}; + +template +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const boost::asio::mutable_buffers_1& buffers) + { + init_native_buffer(buffer_, buffers); + total_buffer_size_ = boost::asio::buffer_size(buffers); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const boost::asio::mutable_buffers_1& buffers) + { + return boost::asio::buffer_size(buffers) == 0; + } + + static void validate(const boost::asio::mutable_buffers_1& buffers) + { + boost::asio::buffer_cast(buffers); + } + + static Buffer first(const boost::asio::mutable_buffers_1& buffers) + { + return Buffer(buffers); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +template +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const boost::asio::const_buffers_1& buffers) + { + init_native_buffer(buffer_, buffers); + total_buffer_size_ = boost::asio::buffer_size(buffers); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const boost::asio::const_buffers_1& buffers) + { + return boost::asio::buffer_size(buffers) == 0; + } + + static void validate(const boost::asio::const_buffers_1& buffers) + { + boost::asio::buffer_cast(buffers); + } + + static Buffer first(const boost::asio::const_buffers_1& buffers) + { + return Buffer(buffers); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP diff --git a/include/boost/asio/detail/completion_handler.hpp b/include/boost/asio/detail/completion_handler.hpp new file mode 100644 index 00000000..d78e6c89 --- /dev/null +++ b/include/boost/asio/detail/completion_handler.hpp @@ -0,0 +1,73 @@ +// +// completion_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_COMPLETION_HANDLER_HPP +#define BOOST_ASIO_DETAIL_COMPLETION_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class completion_handler : public operation +{ +public: + completion_handler(Handler h) + : operation(&completion_handler::do_complete), + handler_(h) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + completion_handler* h(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(h->handler_, h); + + // Make the upcall if required. + if (owner) + { + // 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(h->handler_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_COMPLETION_HANDLER_HPP diff --git a/include/boost/asio/detail/const_buffers_iterator.hpp b/include/boost/asio/detail/const_buffers_iterator.hpp deleted file mode 100644 index 2ce636be..00000000 --- a/include/boost/asio/detail/const_buffers_iterator.hpp +++ /dev/null @@ -1,153 +0,0 @@ -// -// const_buffers_iterator.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2010 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_CONST_BUFFERS_ITERATOR_HPP -#define BOOST_ASIO_DETAIL_CONST_BUFFERS_ITERATOR_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#include -#include -#include -#include -#include - -#include - -namespace boost { -namespace asio { -namespace detail { - -// A proxy iterator for a sub-range in a list of buffers. -template -class const_buffers_iterator - : public boost::iterator_facade, - const char, boost::bidirectional_traversal_tag> -{ -public: - // Default constructor creates an iterator in an undefined state. - const_buffers_iterator() - { - } - - // Create an iterator for the specified position. - const_buffers_iterator(const ConstBufferSequence& buffers, - std::size_t position) - : begin_(buffers.begin()), - current_(buffers.begin()), - end_(buffers.end()), - position_(0) - { - while (current_ != end_) - { - current_buffer_ = *current_; - std::size_t buffer_size = boost::asio::buffer_size(current_buffer_); - if (position - position_ < buffer_size) - { - current_buffer_position_ = position - position_; - position_ = position; - return; - } - position_ += buffer_size; - ++current_; - } - current_buffer_ = boost::asio::const_buffer(); - current_buffer_position_ = 0; - } - - std::size_t position() const - { - return position_; - } - -private: - friend class boost::iterator_core_access; - - void increment() - { - if (current_ == end_) - return; - - ++position_; - - ++current_buffer_position_; - if (current_buffer_position_ != boost::asio::buffer_size(current_buffer_)) - return; - - ++current_; - current_buffer_position_ = 0; - while (current_ != end_) - { - current_buffer_ = *current_; - if (boost::asio::buffer_size(current_buffer_) > 0) - return; - ++current_; - } - } - - void decrement() - { - if (position_ == 0) - return; - - --position_; - - if (current_buffer_position_ != 0) - { - --current_buffer_position_; - return; - } - - typename ConstBufferSequence::const_iterator iter = current_; - while (iter != begin_) - { - --iter; - boost::asio::const_buffer buffer = *iter; - std::size_t buffer_size = boost::asio::buffer_size(buffer); - if (buffer_size > 0) - { - current_ = iter; - current_buffer_ = buffer; - current_buffer_position_ = buffer_size - 1; - return; - } - } - } - - bool equal(const const_buffers_iterator& other) const - { - return position_ == other.position_; - } - - const char& dereference() const - { - return boost::asio::buffer_cast( - current_buffer_)[current_buffer_position_]; - } - - boost::asio::const_buffer current_buffer_; - std::size_t current_buffer_position_; - typename ConstBufferSequence::const_iterator begin_; - typename ConstBufferSequence::const_iterator current_; - typename ConstBufferSequence::const_iterator end_; - std::size_t position_; -}; - -} // namespace detail -} // namespace asio -} // namespace boost - -#include - -#endif // BOOST_ASIO_DETAIL_CONST_BUFFERS_ITERATOR_HPP diff --git a/include/boost/asio/detail/consuming_buffers.hpp b/include/boost/asio/detail/consuming_buffers.hpp index bf04b1b4..3604cbaa 100644 --- a/include/boost/asio/detail/consuming_buffers.hpp +++ b/include/boost/asio/detail/consuming_buffers.hpp @@ -21,12 +21,11 @@ #include #include #include -#include +#include #include #include #include -#include namespace boost { namespace asio { @@ -35,9 +34,7 @@ namespace detail { // A proxy iterator for a sub-range in a list of buffers. template class consuming_buffers_iterator - : public boost::iterator_facade< - consuming_buffers_iterator, - const Buffer, boost::forward_traversal_tag> + : public boost::iterator { public: // Default constructor creates an end iterator. @@ -60,9 +57,48 @@ public: { } -private: - friend class boost::iterator_core_access; + // Dereference an iterator. + const Buffer& operator*() const + { + return dereference(); + } + // Dereference an iterator. + const Buffer* operator->() const + { + return &dereference(); + } + + // Increment operator (prefix). + consuming_buffers_iterator& operator++() + { + increment(); + return *this; + } + + // Increment operator (postfix). + consuming_buffers_iterator operator++(int) + { + consuming_buffers_iterator tmp(*this); + ++*this; + return tmp; + } + + // Test two iterators for equality. + friend bool operator==(const consuming_buffers_iterator& a, + const consuming_buffers_iterator& b) + { + return a.equal(b); + } + + // Test two iterators for inequality. + friend bool operator!=(const consuming_buffers_iterator& a, + const consuming_buffers_iterator& b) + { + return !a.equal(b); + } + +private: void increment() { if (!at_end_) @@ -170,7 +206,7 @@ public: } // Set the maximum size for a single transfer. - void set_max_size(std::size_t max_size) + void prepare(std::size_t max_size) { max_size_ = max_size; } @@ -226,7 +262,7 @@ public: // No-op. } - void set_max_size(std::size_t) + void prepare(std::size_t) { // No-op. } diff --git a/include/boost/asio/detail/deadline_timer_service.hpp b/include/boost/asio/detail/deadline_timer_service.hpp index 7885c9a6..5ba21b15 100644 --- a/include/boost/asio/detail/deadline_timer_service.hpp +++ b/include/boost/asio/detail/deadline_timer_service.hpp @@ -26,21 +26,20 @@ #include #include #include -#include +#include #include -#include #include #include +#include #include +#include namespace boost { namespace asio { namespace detail { -template +template class deadline_timer_service - : public boost::asio::detail::service_base< - deadline_timer_service > { public: // The time type. @@ -60,9 +59,7 @@ public: // Constructor. deadline_timer_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - deadline_timer_service >(io_service), - scheduler_(boost::asio::use_service(io_service)) + : scheduler_(boost::asio::use_service(io_service)) { scheduler_.init_task(); scheduler_.add_timer_queue(timer_queue_); @@ -156,34 +153,58 @@ public: } template - class wait_handler : - public handler_base_from_member + class wait_handler : public timer_op { public: - wait_handler(boost::asio::io_service& io_service, Handler handler) - : handler_base_from_member(handler), - io_service_(io_service), - work_(io_service) + wait_handler(Handler handler) + : timer_op(&wait_handler::do_complete), + handler_(handler) { } - void operator()(const boost::system::error_code& result) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) { - io_service_.post(detail::bind_handler(this->handler_, result)); + // Take ownership of the handler object. + wait_handler* h(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(h->handler_, h); + + // Make the upcall if required. + if (owner) + { + // 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(h->handler_, h->ec_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } private: - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; + Handler handler_; }; // Start an asynchronous wait on the timer. template void async_wait(implementation_type& impl, Handler handler) { + // Allocate and construct an operation to wrap the handler. + typedef wait_handler value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); + impl.might_have_pending_waits = true; - scheduler_.schedule_timer(timer_queue_, impl.expiry, - wait_handler(this->get_io_service(), handler), &impl); + + scheduler_.schedule_timer(timer_queue_, impl.expiry, ptr.get(), &impl); + ptr.release(); } private: @@ -191,7 +212,7 @@ private: timer_queue timer_queue_; // The object that schedules and executes timers. Usually a reactor. - Timer_Scheduler& scheduler_; + timer_scheduler& scheduler_; }; } // namespace detail diff --git a/include/boost/asio/detail/dev_poll_reactor.hpp b/include/boost/asio/detail/dev_poll_reactor.hpp index 73153845..873e4359 100644 --- a/include/boost/asio/detail/dev_poll_reactor.hpp +++ b/include/boost/asio/detail/dev_poll_reactor.hpp @@ -33,27 +33,30 @@ #include #include -#include #include #include -#include -#include +#include +#include #include #include #include -#include #include -#include +#include +#include +#include +#include namespace boost { namespace asio { namespace detail { -template class dev_poll_reactor - : public boost::asio::detail::service_base > + : public boost::asio::detail::service_base { public: + enum { read_op = 0, write_op = 1, + connect_op = 1, except_op = 2, max_ops = 3 }; + // Per-descriptor data. struct per_descriptor_data { @@ -61,28 +64,13 @@ public: // Constructor. dev_poll_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - dev_poll_reactor >(io_service), + : boost::asio::detail::service_base(io_service), + io_service_(use_service(io_service)), mutex_(), dev_poll_fd_(do_dev_poll_create()), - wait_in_progress_(false), interrupter_(), - read_op_queue_(), - write_op_queue_(), - except_op_queue_(), - pending_cancellations_(), - stop_thread_(false), - thread_(0), shutdown_(false) { - // Start the reactor's internal thread only if needed. - if (Own_Thread) - { - boost::asio::detail::signal_blocker sb; - thread_ = new boost::asio::detail::thread( - bind_handler(&dev_poll_reactor::call_run_thread, this)); - } - // Add the interrupter's descriptor to /dev/poll. ::pollfd ev = { 0 }; ev.fd = interrupter_.read_descriptor(); @@ -103,35 +91,20 @@ public: { boost::asio::detail::mutex::scoped_lock lock(mutex_); shutdown_ = true; - stop_thread_ = true; lock.unlock(); - if (thread_) - { - interrupter_.interrupt(); - thread_->join(); - delete thread_; - thread_ = 0; - } + op_queue ops; - read_op_queue_.destroy_operations(); - write_op_queue_.destroy_operations(); - except_op_queue_.destroy_operations(); + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->destroy_timers(); - timer_queues_.clear(); + timer_queues_.get_all_timers(ops); } - // Initialise the task, but only if the reactor is not in its own thread. + // Initialise the task. void init_task() { - if (!Own_Thread) - { - typedef task_io_service > - task_io_service_type; - use_service(this->get_io_service()).init_task(); - } + io_service_.init_task(); } // Register a socket with the reactor. Returns 0 on success, system error @@ -141,121 +114,44 @@ public: return 0; } - // Start a new read operation. The handler object will be invoked when the - // given descriptor is ready to be read, or an error has occurred. - template - void start_read_op(socket_type descriptor, per_descriptor_data&, - Handler handler, bool allow_speculative_read = true) + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + void start_op(int op_type, socket_type descriptor, + per_descriptor_data&, reactor_op* op, bool allow_speculative) { boost::asio::detail::mutex::scoped_lock lock(mutex_); if (shutdown_) return; - if (allow_speculative_read) + if (allow_speculative) { - if (!read_op_queue_.has_operation(descriptor)) + if (!op_queue_[op_type].has_operation(descriptor)) { - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) + if (op->perform()) { - handler.complete(ec, bytes_transferred); + lock.unlock(); + io_service_.post_immediate_completion(op); return; } } } - if (read_op_queue_.enqueue_operation(descriptor, handler)) + + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + io_service_.work_started(); + if (first) { ::pollfd& ev = add_pending_event_change(descriptor); - ev.events = POLLIN | POLLERR | POLLHUP; - if (write_op_queue_.has_operation(descriptor)) + ev.events = POLLERR | POLLHUP; + if (op_type == read_op + || op_queue_[read_op].has_operation(descriptor)) + ev.events |= POLLIN; + if (op_type == write_op + || op_queue_[write_op].has_operation(descriptor)) ev.events |= POLLOUT; - if (except_op_queue_.has_operation(descriptor)) - ev.events |= POLLPRI; - interrupter_.interrupt(); - } - } - - // Start a new write operation. The handler object will be invoked when the - // given descriptor is ready to be written, or an error has occurred. - template - void start_write_op(socket_type descriptor, per_descriptor_data&, - Handler handler, bool allow_speculative_write = true) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - - if (allow_speculative_write) - { - if (!write_op_queue_.has_operation(descriptor)) - { - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) - { - handler.complete(ec, bytes_transferred); - return; - } - } - } - - if (write_op_queue_.enqueue_operation(descriptor, handler)) - { - ::pollfd& ev = add_pending_event_change(descriptor); - ev.events = POLLOUT | POLLERR | POLLHUP; - if (read_op_queue_.has_operation(descriptor)) - ev.events |= POLLIN; - if (except_op_queue_.has_operation(descriptor)) - ev.events |= POLLPRI; - interrupter_.interrupt(); - } - } - - // Start a new exception operation. The handler object will be invoked when - // the given descriptor has exception information, or an error has occurred. - template - void start_except_op(socket_type descriptor, - per_descriptor_data&, Handler handler) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - - if (except_op_queue_.enqueue_operation(descriptor, handler)) - { - ::pollfd& ev = add_pending_event_change(descriptor); - ev.events = POLLPRI | POLLERR | POLLHUP; - if (read_op_queue_.has_operation(descriptor)) - ev.events |= POLLIN; - if (write_op_queue_.has_operation(descriptor)) - ev.events |= POLLOUT; - interrupter_.interrupt(); - } - } - - // Start a new write operation. The handler object will be invoked when the - // information available, or an error has occurred. - template - void start_connect_op(socket_type descriptor, - per_descriptor_data&, Handler handler) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - - if (write_op_queue_.enqueue_operation(descriptor, handler)) - { - ::pollfd& ev = add_pending_event_change(descriptor); - ev.events = POLLOUT | POLLERR | POLLHUP; - if (read_op_queue_.has_operation(descriptor)) - ev.events |= POLLIN; - if (except_op_queue_.has_operation(descriptor)) + if (op_type == except_op + || op_queue_[except_op].has_operation(descriptor)) ev.events |= POLLPRI; interrupter_.interrupt(); } @@ -267,7 +163,7 @@ public: void cancel_ops(socket_type descriptor, per_descriptor_data&) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); } // Cancel any operations that are running against the descriptor and remove @@ -282,7 +178,7 @@ public: interrupter_.interrupt(); // Cancel any outstanding operations associated with the descriptor. - cancel_ops_unlocked(descriptor); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); } // Add a new timer queue to the reactor. @@ -290,7 +186,7 @@ public: void add_timer_queue(timer_queue& timer_queue) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.push_back(&timer_queue); + timer_queues_.insert(&timer_queue); } // Remove a timer queue from the reactor. @@ -298,71 +194,48 @@ public: void remove_timer_queue(timer_queue& timer_queue) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - if (timer_queues_[i] == &timer_queue) - { - timer_queues_.erase(timer_queues_.begin() + i); - return; - } - } + timer_queues_.erase(&timer_queue); } - // Schedule a timer in the given timer queue to expire at the specified - // absolute time. The handler object will be invoked when the timer expires. - template + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, Handler handler, void* token) + const typename Time_Traits::time_type& time, timer_op* op, void* token) { boost::asio::detail::mutex::scoped_lock lock(mutex_); if (!shutdown_) - if (timer_queue.enqueue_timer(time, handler, token)) + { + bool earliest = timer_queue.enqueue_timer(time, op, token); + io_service_.work_started(); + if (earliest) interrupter_.interrupt(); + } } - // Cancel the timer associated with the given token. Returns the number of - // handlers that have been posted or dispatched. + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. template std::size_t cancel_timer(timer_queue& timer_queue, void* token) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - std::size_t n = timer_queue.cancel_timer(token); - if (n > 0) - interrupter_.interrupt(); + op_queue ops; + std::size_t n = timer_queue.cancel_timer(token, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); return n; } -private: - friend class task_io_service >; - // Run /dev/poll once until interrupted or events are ready to be dispatched. - void run(bool block) + void run(bool block, op_queue& ops) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - // Dispatch any operation cancellations that were made while the select - // loop was not running. - read_op_queue_.perform_cancellations(); - write_op_queue_.perform_cancellations(); - except_op_queue_.perform_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->dispatch_cancellations(); - - // Check if the thread is supposed to stop. - if (stop_thread_) - { - complete_operations_and_timers(lock); - return; - } - // We can return immediately if there's no work to do and the reactor is // not supposed to block. - if (!block && read_op_queue_.empty() && write_op_queue_.empty() - && except_op_queue_.empty() && all_timer_queues_are_empty()) - { - complete_operations_and_timers(lock); + if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty() + && op_queue_[except_op].empty() && timer_queues_.all_empty()) return; - } // Write the pending event registration changes to the /dev/poll descriptor. std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size(); @@ -373,14 +246,13 @@ private: &pending_event_changes_[0], events_size); if (result != static_cast(events_size)) { + boost::system::error_code ec = boost::system::error_code( + errno, boost::asio::error::get_system_category()); for (std::size_t i = 0; i < pending_event_changes_.size(); ++i) { int descriptor = pending_event_changes_[i].fd; - boost::system::error_code ec = boost::system::error_code( - errno, boost::asio::error::get_system_category()); - read_op_queue_.perform_all_operations(descriptor, ec); - write_op_queue_.perform_all_operations(descriptor, ec); - except_op_queue_.perform_all_operations(descriptor, ec); + for (int j = 0; j < max_ops; ++j) + op_queue_[j].cancel_operations(descriptor, ops, ec); } } pending_event_changes_.clear(); @@ -388,7 +260,6 @@ private: } int timeout = block ? get_timeout() : 0; - wait_in_progress_ = true; lock.unlock(); // Block on the /dev/poll descriptor. @@ -400,7 +271,6 @@ private: int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp); lock.lock(); - wait_in_progress_ = false; // Dispatch the waiting events. for (int i = 0; i < num_events; ++i) @@ -415,24 +285,24 @@ private: bool more_reads = false; bool more_writes = false; bool more_except = false; - boost::system::error_code ec; // Exception operations must be processed first to ensure that any // out-of-band data is read before normal data. if (events[i].events & (POLLPRI | POLLERR | POLLHUP)) - more_except = except_op_queue_.perform_operation(descriptor, ec); + more_except = + op_queue_[except_op].perform_operations(descriptor, ops); else - more_except = except_op_queue_.has_operation(descriptor); + more_except = op_queue_[except_op].has_operation(descriptor); if (events[i].events & (POLLIN | POLLERR | POLLHUP)) - more_reads = read_op_queue_.perform_operation(descriptor, ec); + more_reads = op_queue_[read_op].perform_operations(descriptor, ops); else - more_reads = read_op_queue_.has_operation(descriptor); + more_reads = op_queue_[read_op].has_operation(descriptor); if (events[i].events & (POLLOUT | POLLERR | POLLHUP)) - more_writes = write_op_queue_.perform_operation(descriptor, ec); + more_writes = op_queue_[write_op].perform_operations(descriptor, ops); else - more_writes = write_op_queue_.has_operation(descriptor); + more_writes = op_queue_[write_op].has_operation(descriptor); if ((events[i].events & (POLLERR | POLLHUP)) != 0 && !more_except && !more_reads && !more_writes) @@ -463,48 +333,15 @@ private: int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); if (result != sizeof(ev)) { - ec = boost::system::error_code(errno, + boost::system::error_code ec(errno, boost::asio::error::get_system_category()); - read_op_queue_.perform_all_operations(descriptor, ec); - write_op_queue_.perform_all_operations(descriptor, ec); - except_op_queue_.perform_all_operations(descriptor, ec); + for (int j = 0; j < max_ops; ++j) + op_queue_[j].cancel_operations(descriptor, ops, ec); } } } } - read_op_queue_.perform_cancellations(); - write_op_queue_.perform_cancellations(); - except_op_queue_.perform_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - timer_queues_[i]->dispatch_timers(); - timer_queues_[i]->dispatch_cancellations(); - } - - // Issue any pending cancellations. - for (size_t i = 0; i < pending_cancellations_.size(); ++i) - cancel_ops_unlocked(pending_cancellations_[i]); - pending_cancellations_.clear(); - - complete_operations_and_timers(lock); - } - - // Run the select loop in the thread. - void run_thread() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - while (!stop_thread_) - { - lock.unlock(); - run(true); - lock.lock(); - } - } - - // Entry point for the select loop thread. - static void call_run_thread(dev_poll_reactor* reactor) - { - reactor->run_thread(); + timer_queues_.get_ready_timers(ops); } // Interrupt the select loop. @@ -513,6 +350,7 @@ private: interrupter_.interrupt(); } +private: // Create the /dev/poll file descriptor. Throws an exception if the descriptor // cannot be created. static int do_dev_poll_create() @@ -529,75 +367,32 @@ private: return fd; } - // Check if all timer queues are empty. - bool all_timer_queues_are_empty() const - { - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - if (!timer_queues_[i]->empty()) - return false; - return true; - } - // 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. int get_timeout() { - if (all_timer_queues_are_empty()) - return -1; - // 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. - boost::posix_time::time_duration minimum_wait_duration - = boost::posix_time::minutes(5); - - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - boost::posix_time::time_duration wait_duration - = timer_queues_[i]->wait_duration(); - if (wait_duration < minimum_wait_duration) - minimum_wait_duration = wait_duration; - } - - if (minimum_wait_duration > boost::posix_time::time_duration()) - { - int milliseconds = minimum_wait_duration.total_milliseconds(); - return milliseconds > 0 ? milliseconds : 1; - } - else - { - return 0; - } + return timer_queues_.wait_duration_msec(5 * 60 * 1000); } // Cancel all operations associated with the given descriptor. The do_cancel // function of the handler objects will be invoked. This function does not // acquire the dev_poll_reactor's mutex. - void cancel_ops_unlocked(socket_type descriptor) + void cancel_ops_unlocked(socket_type descriptor, + const boost::system::error_code& ec) { - bool interrupt = read_op_queue_.cancel_operations(descriptor); - interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt; - interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt; - if (interrupt) + bool need_interrupt = false; + op_queue ops; + 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); + if (need_interrupt) interrupter_.interrupt(); } - // Clean up operations and timers. We must not hold the lock since the - // destructors may make calls back into this reactor. We make a copy of the - // vector of timer queues since the original may be modified while the lock - // is not held. - void complete_operations_and_timers( - boost::asio::detail::mutex::scoped_lock& lock) - { - timer_queues_for_cleanup_ = timer_queues_; - lock.unlock(); - read_op_queue_.complete_operations(); - write_op_queue_.complete_operations(); - except_op_queue_.complete_operations(); - for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i) - timer_queues_for_cleanup_[i]->complete_timers(); - } - // Add a pending event entry for the given descriptor. ::pollfd& add_pending_event_change(int descriptor) { @@ -619,6 +414,9 @@ private: } } + // The io_service implementation used to post completions. + io_service_impl& io_service_; + // Mutex to protect access to internal data. boost::asio::detail::mutex mutex_; @@ -631,36 +429,14 @@ private: // Hash map to associate a descriptor with a pending event change index. hash_map pending_event_change_index_; - // Whether the DP_POLL operation is currently in progress - bool wait_in_progress_; - // The interrupter is used to break a blocking DP_POLL operation. select_interrupter interrupter_; - // The queue of read operations. - reactor_op_queue read_op_queue_; - - // The queue of write operations. - reactor_op_queue write_op_queue_; - - // The queue of except operations. - reactor_op_queue except_op_queue_; + // The queues of read, write and except operations. + reactor_op_queue op_queue_[max_ops]; // The timer queues. - std::vector timer_queues_; - - // A copy of the timer queues, used when cleaning up timers. The copy is - // stored as a class data member to avoid unnecessary memory allocation. - std::vector timer_queues_for_cleanup_; - - // The descriptors that are pending cancellation. - std::vector pending_cancellations_; - - // Does the reactor loop thread need to stop. - bool stop_thread_; - - // The thread that is running the reactor loop. - boost::asio::detail::thread* thread_; + timer_queue_set timer_queues_; // Whether the service has been shut down. bool shutdown_; diff --git a/include/boost/asio/detail/dev_poll_reactor_fwd.hpp b/include/boost/asio/detail/dev_poll_reactor_fwd.hpp index d890fa8e..238cee52 100644 --- a/include/boost/asio/detail/dev_poll_reactor_fwd.hpp +++ b/include/boost/asio/detail/dev_poll_reactor_fwd.hpp @@ -27,7 +27,6 @@ namespace boost { namespace asio { namespace detail { -template class dev_poll_reactor; } // namespace detail diff --git a/include/boost/asio/detail/epoll_reactor.hpp b/include/boost/asio/detail/epoll_reactor.hpp index 6c6bfe32..c4c2dea7 100644 --- a/include/boost/asio/detail/epoll_reactor.hpp +++ b/include/boost/asio/detail/epoll_reactor.hpp @@ -23,115 +23,126 @@ #include #include -#include #include #include -#include #include #include #include #include #include -#include #include #include -#include -#include -#include +#include +#include #include #include -#include #include -#include +#include +#include +#include +#include + +#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# define BOOST_ASIO_HAS_TIMERFD 1 +#endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) + +#if defined(BOOST_ASIO_HAS_TIMERFD) +# include +# include +# include +#endif // defined(BOOST_ASIO_HAS_TIMERFD) namespace boost { namespace asio { namespace detail { -template class epoll_reactor - : public boost::asio::detail::service_base > + : public boost::asio::detail::service_base { public: - // Per-descriptor data. - struct per_descriptor_data + enum { read_op = 0, write_op = 1, + connect_op = 1, except_op = 2, max_ops = 3 }; + + // Per-descriptor queues. + struct descriptor_state { - bool allow_speculative_read; - bool allow_speculative_write; + descriptor_state() {} + descriptor_state(const descriptor_state&) {} + void operator=(const descriptor_state&) {} + + mutex mutex_; + op_queue op_queue_[max_ops]; + bool shutdown_; }; + // Per-descriptor data. + typedef descriptor_state* per_descriptor_data; + // Constructor. epoll_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base >(io_service), + : boost::asio::detail::service_base(io_service), + io_service_(use_service(io_service)), mutex_(), epoll_fd_(do_epoll_create()), - wait_in_progress_(false), +#if defined(BOOST_ASIO_HAS_TIMERFD) + timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)), +#else // defined(BOOST_ASIO_HAS_TIMERFD) + timer_fd_(-1), +#endif // defined(BOOST_ASIO_HAS_TIMERFD) interrupter_(), - read_op_queue_(), - write_op_queue_(), - except_op_queue_(), - pending_cancellations_(), - stop_thread_(false), - thread_(0), - shutdown_(false), - need_epoll_wait_(true) + shutdown_(false) { - // Start the reactor's internal thread only if needed. - if (Own_Thread) - { - boost::asio::detail::signal_blocker sb; - thread_ = new boost::asio::detail::thread( - bind_handler(&epoll_reactor::call_run_thread, this)); - } - // Add the interrupter's descriptor to epoll. epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLIN | EPOLLERR; - ev.data.fd = interrupter_.read_descriptor(); + ev.events = EPOLLIN | EPOLLERR | EPOLLET; + ev.data.ptr = &interrupter_; epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); + interrupter_.interrupt(); + + // Add the timer descriptor to epoll. + if (timer_fd_ != -1) + { + ev.events = EPOLLIN | EPOLLERR; + ev.data.ptr = &timer_fd_; + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); + } } // Destructor. ~epoll_reactor() { - shutdown_service(); close(epoll_fd_); + if (timer_fd_ != -1) + close(timer_fd_); } // Destroy all user-defined handler objects owned by the service. void shutdown_service() { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock lock(mutex_); shutdown_ = true; - stop_thread_ = true; lock.unlock(); - if (thread_) + op_queue ops; + + descriptor_map::iterator iter = registered_descriptors_.begin(); + descriptor_map::iterator end = registered_descriptors_.end(); + while (iter != end) { - interrupter_.interrupt(); - thread_->join(); - delete thread_; - thread_ = 0; + for (int i = 0; i < max_ops; ++i) + ops.push(iter->second.op_queue_[i]); + iter->second.shutdown_ = true; + ++iter; } - read_op_queue_.destroy_operations(); - write_op_queue_.destroy_operations(); - except_op_queue_.destroy_operations(); - - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->destroy_timers(); - timer_queues_.clear(); + timer_queues_.get_all_timers(ops); } - // Initialise the task, but only if the reactor is not in its own thread. + // Initialise the task. void init_task() { - if (!Own_Thread) - { - typedef task_io_service > task_io_service_type; - use_service(this->get_io_service()).init_task(); - } + io_service_.init_task(); } // Register a socket with the reactor. Returns 0 on success, system error @@ -139,454 +150,258 @@ public: int register_descriptor(socket_type descriptor, per_descriptor_data& descriptor_data) { - // No need to lock according to epoll documentation. + mutex::scoped_lock lock(registered_descriptors_mutex_); - descriptor_data.allow_speculative_read = true; - descriptor_data.allow_speculative_write = true; + descriptor_map::iterator new_entry = registered_descriptors_.insert( + std::make_pair(descriptor, descriptor_state())).first; + descriptor_data = &new_entry->second; epoll_event ev = { 0, { 0 } }; - ev.events = 0; - ev.data.fd = descriptor; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET; + ev.data.ptr = descriptor_data; int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); if (result != 0) return errno; + + descriptor_data->shutdown_ = false; + return 0; } - // Start a new read operation. The handler object will be invoked when the - // given descriptor is ready to be read, or an error has occurred. - template - void start_read_op(socket_type descriptor, + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + void start_op(int op_type, socket_type descriptor, per_descriptor_data& descriptor_data, - Handler handler, bool allow_speculative_read = true) + reactor_op* op, bool allow_speculative) { - if (allow_speculative_read && descriptor_data.allow_speculative_read) - { - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) - { - handler.complete(ec, bytes_transferred); - return; - } - - // We only get one shot at a speculative read in this function. - allow_speculative_read = false; - } - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + if (descriptor_data->shutdown_) return; - if (!allow_speculative_read) - need_epoll_wait_ = true; - else if (!read_op_queue_.has_operation(descriptor)) + if (descriptor_data->op_queue_[op_type].empty()) { - // Speculative reads are ok as there are no queued read operations. - descriptor_data.allow_speculative_read = true; - - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) + if (allow_speculative) { - handler.complete(ec, bytes_transferred); - return; + if (op->perform()) + { + descriptor_lock.unlock(); + io_service_.post_immediate_completion(op); + return; + } + } + else + { + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP + | EPOLLOUT | EPOLLPRI | EPOLLET; + ev.data.ptr = descriptor_data; + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); } } - // Speculative reads are not ok as there will be queued read operations. - descriptor_data.allow_speculative_read = false; - - if (read_op_queue_.enqueue_operation(descriptor, handler)) - { - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLIN | EPOLLERR | EPOLLHUP; - if (write_op_queue_.has_operation(descriptor)) - ev.events |= EPOLLOUT; - if (except_op_queue_.has_operation(descriptor)) - ev.events |= EPOLLPRI; - ev.data.fd = descriptor; - - int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); - if (result != 0 && errno == ENOENT) - result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); - if (result != 0) - { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - read_op_queue_.perform_all_operations(descriptor, ec); - } - } - } - - // Start a new write operation. The handler object will be invoked when the - // given descriptor is ready to be written, or an error has occurred. - template - void start_write_op(socket_type descriptor, - per_descriptor_data& descriptor_data, - Handler handler, bool allow_speculative_write = true) - { - if (allow_speculative_write && descriptor_data.allow_speculative_write) - { - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) - { - handler.complete(ec, bytes_transferred); - return; - } - - // We only get one shot at a speculative write in this function. - allow_speculative_write = false; - } - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - - if (!allow_speculative_write) - need_epoll_wait_ = true; - else if (!write_op_queue_.has_operation(descriptor)) - { - // Speculative writes are ok as there are no queued write operations. - descriptor_data.allow_speculative_write = true; - - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) - { - handler.complete(ec, bytes_transferred); - return; - } - } - - // Speculative writes are not ok as there will be queued write operations. - descriptor_data.allow_speculative_write = false; - - if (write_op_queue_.enqueue_operation(descriptor, handler)) - { - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLOUT | EPOLLERR | EPOLLHUP; - if (read_op_queue_.has_operation(descriptor)) - ev.events |= EPOLLIN; - if (except_op_queue_.has_operation(descriptor)) - ev.events |= EPOLLPRI; - ev.data.fd = descriptor; - - int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); - if (result != 0 && errno == ENOENT) - result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); - if (result != 0) - { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - write_op_queue_.perform_all_operations(descriptor, ec); - } - } - } - - // Start a new exception operation. The handler object will be invoked when - // the given descriptor has exception information, or an error has occurred. - template - void start_except_op(socket_type descriptor, - per_descriptor_data&, Handler handler) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - - if (except_op_queue_.enqueue_operation(descriptor, handler)) - { - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLPRI | EPOLLERR | EPOLLHUP; - if (read_op_queue_.has_operation(descriptor)) - ev.events |= EPOLLIN; - if (write_op_queue_.has_operation(descriptor)) - ev.events |= EPOLLOUT; - ev.data.fd = descriptor; - - int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); - if (result != 0 && errno == ENOENT) - result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); - if (result != 0) - { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - except_op_queue_.perform_all_operations(descriptor, ec); - } - } - } - - // Start a new write operation. The handler object will be invoked when the - // given descriptor is ready for writing or an error has occurred. Speculative - // writes are not allowed. - template - void start_connect_op(socket_type descriptor, - per_descriptor_data& descriptor_data, Handler handler) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - - // Speculative writes are not ok as there will be queued write operations. - descriptor_data.allow_speculative_write = false; - - if (write_op_queue_.enqueue_operation(descriptor, handler)) - { - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLOUT | EPOLLERR | EPOLLHUP; - if (read_op_queue_.has_operation(descriptor)) - ev.events |= EPOLLIN; - if (except_op_queue_.has_operation(descriptor)) - ev.events |= EPOLLPRI; - ev.data.fd = descriptor; - - int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); - if (result != 0 && errno == ENOENT) - result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); - if (result != 0) - { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - write_op_queue_.perform_all_operations(descriptor, ec); - } - } + descriptor_data->op_queue_[op_type].push(op); + io_service_.work_started(); } // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the // operation_aborted error. - void cancel_ops(socket_type descriptor, per_descriptor_data&) + void cancel_ops(socket_type descriptor, per_descriptor_data& descriptor_data) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + ops.push(descriptor_data->op_queue_[i]); + + descriptor_lock.unlock(); + + io_service_.post_deferred_completions(ops); } // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. - void close_descriptor(socket_type descriptor, per_descriptor_data&) + void close_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); - // Remove the descriptor from epoll. - epoll_event ev = { 0, { 0 } }; - epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); + // Remove the descriptor from the set of known descriptors. The descriptor + // will be automatically removed from the epoll set when it is closed. + descriptor_data->shutdown_ = true; - // Cancel any outstanding operations associated with the descriptor. - cancel_ops_unlocked(descriptor); + op_queue ops; + for (int i = 0; i < max_ops; ++i) + ops.push(descriptor_data->op_queue_[i]); + + descriptor_lock.unlock(); + + registered_descriptors_.erase(descriptor); + + descriptors_lock.unlock(); + + io_service_.post_deferred_completions(ops); } // Add a new timer queue to the reactor. template void add_timer_queue(timer_queue& timer_queue) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.push_back(&timer_queue); + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&timer_queue); } // Remove a timer queue from the reactor. template void remove_timer_queue(timer_queue& timer_queue) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&timer_queue); + } + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template + void schedule_timer(timer_queue& timer_queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token) + { + mutex::scoped_lock lock(mutex_); + if (!shutdown_) { - if (timer_queues_[i] == &timer_queue) + bool earliest = timer_queue.enqueue_timer(time, op, token); + io_service_.work_started(); + if (earliest) { - timer_queues_.erase(timer_queues_.begin() + i); - return; +#if defined(BOOST_ASIO_HAS_TIMERFD) + if (timer_fd_ != -1) + { + itimerspec new_timeout; + itimerspec old_timeout; + int flags = get_timeout(new_timeout); + timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); + return; + } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + interrupter_.interrupt(); } } } - // Schedule a timer in the given timer queue to expire at the specified - // absolute time. The handler object will be invoked when the timer expires. - template - void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, Handler handler, void* token) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_) - if (timer_queue.enqueue_timer(time, handler, token)) - interrupter_.interrupt(); - } - - // Cancel the timer associated with the given token. Returns the number of - // handlers that have been posted or dispatched. + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. template std::size_t cancel_timer(timer_queue& timer_queue, void* token) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - std::size_t n = timer_queue.cancel_timer(token); - if (n > 0) - interrupter_.interrupt(); + mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = timer_queue.cancel_timer(token, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); return n; } -private: - friend class task_io_service >; - // Run epoll once until interrupted or events are ready to be dispatched. - void run(bool block) + void run(bool block, op_queue& ops) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - // Dispatch any operation cancellations that were made while the select - // loop was not running. - read_op_queue_.perform_cancellations(); - write_op_queue_.perform_cancellations(); - except_op_queue_.perform_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->dispatch_cancellations(); - - // Check if the thread is supposed to stop. - if (stop_thread_) + // Calculate a timeout only if timerfd is not used. + int timeout; + if (timer_fd_ != -1) + timeout = block ? -1 : 0; + else { - complete_operations_and_timers(lock); - return; + mutex::scoped_lock lock(mutex_); + timeout = block ? get_timeout() : 0; } - // We can return immediately if there's no work to do and the reactor is - // not supposed to block. - if (!block && read_op_queue_.empty() && write_op_queue_.empty() - && except_op_queue_.empty() && all_timer_queues_are_empty()) - { - complete_operations_and_timers(lock); - return; - } - - int timeout = block ? get_timeout() : 0; - wait_in_progress_ = true; - lock.unlock(); - // Block on the epoll descriptor. epoll_event events[128]; - int num_events = (block || need_epoll_wait_) - ? epoll_wait(epoll_fd_, events, 128, timeout) - : 0; + int num_events = epoll_wait(epoll_fd_, events, 128, timeout); - lock.lock(); - wait_in_progress_ = false; +#if defined(BOOST_ASIO_HAS_TIMERFD) + bool check_timers = (timer_fd_ == -1); +#else // defined(BOOST_ASIO_HAS_TIMERFD) + bool check_timers = true; +#endif // defined(BOOST_ASIO_HAS_TIMERFD) // Dispatch the waiting events. for (int i = 0; i < num_events; ++i) { - int descriptor = events[i].data.fd; - if (descriptor == interrupter_.read_descriptor()) + void* ptr = events[i].data.ptr; + if (ptr == &interrupter_) { - interrupter_.reset(); + // No need to reset the interrupter since we're leaving the descriptor + // in a ready-to-read state and relying on edge-triggered notifications + // to make it so that we only get woken up when the descriptor's epoll + // registration is updated. + +#if defined(BOOST_ASIO_HAS_TIMERFD) + if (timer_fd_ == -1) + check_timers = true; +#else // defined(BOOST_ASIO_HAS_TIMERFD) + check_timers = true; +#endif // defined(BOOST_ASIO_HAS_TIMERFD) } +#if defined(BOOST_ASIO_HAS_TIMERFD) + else if (ptr == &timer_fd_) + { + check_timers = true; + } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) else { - bool more_reads = false; - bool more_writes = false; - bool more_except = false; - boost::system::error_code ec; + descriptor_state* descriptor_data = static_cast(ptr); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); // Exception operations must be processed first to ensure that any // out-of-band data is read before normal data. - if (events[i].events & (EPOLLPRI | EPOLLERR | EPOLLHUP)) - more_except = except_op_queue_.perform_operation(descriptor, ec); - else - more_except = except_op_queue_.has_operation(descriptor); - - if (events[i].events & (EPOLLIN | EPOLLERR | EPOLLHUP)) - more_reads = read_op_queue_.perform_operation(descriptor, ec); - else - more_reads = read_op_queue_.has_operation(descriptor); - - if (events[i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) - more_writes = write_op_queue_.perform_operation(descriptor, ec); - else - more_writes = write_op_queue_.has_operation(descriptor); - - if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0 - && (events[i].events & ~(EPOLLERR | EPOLLHUP)) == 0 - && !more_except && !more_reads && !more_writes) + static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI }; + for (int j = max_ops - 1; j >= 0; --j) { - // If we have an event and no operations associated with the - // descriptor then we need to delete the descriptor from epoll. The - // epoll_wait system call can produce EPOLLHUP or EPOLLERR events - // when there is no operation pending, so if we do not remove the - // descriptor we can end up in a tight loop of repeated - // calls to epoll_wait. - epoll_event ev = { 0, { 0 } }; - epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); - } - else - { - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLERR | EPOLLHUP; - if (more_reads) - ev.events |= EPOLLIN; - if (more_writes) - ev.events |= EPOLLOUT; - if (more_except) - ev.events |= EPOLLPRI; - ev.data.fd = descriptor; - int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); - if (result != 0 && errno == ENOENT) - result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); - if (result != 0) + if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP)) { - ec = boost::system::error_code(errno, - boost::asio::error::get_system_category()); - read_op_queue_.perform_all_operations(descriptor, ec); - write_op_queue_.perform_all_operations(descriptor, ec); - except_op_queue_.perform_all_operations(descriptor, ec); + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + if (op->perform()) + { + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + else + break; + } } } } } - read_op_queue_.perform_cancellations(); - write_op_queue_.perform_cancellations(); - except_op_queue_.perform_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) + + if (check_timers) { - timer_queues_[i]->dispatch_timers(); - timer_queues_[i]->dispatch_cancellations(); + mutex::scoped_lock common_lock(mutex_); + timer_queues_.get_ready_timers(ops); + +#if defined(BOOST_ASIO_HAS_TIMERFD) + if (timer_fd_ != -1) + { + itimerspec new_timeout; + itimerspec old_timeout; + int flags = get_timeout(new_timeout); + timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); + } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) } - - // Issue any pending cancellations. - for (size_t i = 0; i < pending_cancellations_.size(); ++i) - cancel_ops_unlocked(pending_cancellations_[i]); - pending_cancellations_.clear(); - - // Determine whether epoll_wait should be called when the reactor next runs. - need_epoll_wait_ = !read_op_queue_.empty() - || !write_op_queue_.empty() || !except_op_queue_.empty(); - - complete_operations_and_timers(lock); - } - - // Run the select loop in the thread. - void run_thread() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - while (!stop_thread_) - { - lock.unlock(); - run(true); - lock.lock(); - } - } - - // Entry point for the select loop thread. - static void call_run_thread(epoll_reactor* reactor) - { - reactor->run_thread(); } // Interrupt the select loop. void interrupt() { - interrupter_.interrupt(); + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLET; + ev.data.ptr = &interrupter_; + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev); } +private: // The hint to pass to epoll_create to size its data structures. enum { epoll_size = 20000 }; @@ -606,117 +421,65 @@ private: return fd; } - // Check if all timer queues are empty. - bool all_timer_queues_are_empty() const - { - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - if (!timer_queues_[i]->empty()) - return false; - return true; - } - // 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. int get_timeout() { - if (all_timer_queues_are_empty()) - return -1; - // 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. - boost::posix_time::time_duration minimum_wait_duration - = boost::posix_time::minutes(5); - - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - boost::posix_time::time_duration wait_duration - = timer_queues_[i]->wait_duration(); - if (wait_duration < minimum_wait_duration) - minimum_wait_duration = wait_duration; - } - - if (minimum_wait_duration > boost::posix_time::time_duration()) - { - int milliseconds = minimum_wait_duration.total_milliseconds(); - return milliseconds > 0 ? milliseconds : 1; - } - else - { - return 0; - } + return timer_queues_.wait_duration_msec(5 * 60 * 1000); } - // Cancel all operations associated with the given descriptor. The do_cancel - // function of the handler objects will be invoked. This function does not - // acquire the epoll_reactor's mutex. - void cancel_ops_unlocked(socket_type descriptor) +#if defined(BOOST_ASIO_HAS_TIMERFD) + // Get the timeout value for the timer descriptor. The return value is the + // flag argument to be used when calling timerfd_settime. + int get_timeout(itimerspec& ts) { - bool interrupt = read_op_queue_.cancel_operations(descriptor); - interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt; - interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt; - if (interrupt) - interrupter_.interrupt(); - } + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; - // Clean up operations and timers. We must not hold the lock since the - // destructors may make calls back into this reactor. We make a copy of the - // vector of timer queues since the original may be modified while the lock - // is not held. - void complete_operations_and_timers( - boost::asio::detail::mutex::scoped_lock& lock) - { - timer_queues_for_cleanup_ = timer_queues_; - lock.unlock(); - read_op_queue_.complete_operations(); - write_op_queue_.complete_operations(); - except_op_queue_.complete_operations(); - for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i) - timer_queues_for_cleanup_[i]->complete_timers(); + long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + ts.it_value.tv_sec = usec / 1000000; + ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1; + + return usec ? 0 : TFD_TIMER_ABSTIME; } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + + // The io_service implementation used to post completions. + io_service_impl& io_service_; // Mutex to protect access to internal data. - boost::asio::detail::mutex mutex_; + mutex mutex_; // The epoll file descriptor. int epoll_fd_; - // Whether the epoll_wait call is currently in progress - bool wait_in_progress_; + // The timer file descriptor. + int timer_fd_; // The interrupter is used to break a blocking epoll_wait call. select_interrupter interrupter_; - // The queue of read operations. - reactor_op_queue read_op_queue_; - - // The queue of write operations. - reactor_op_queue write_op_queue_; - - // The queue of except operations. - reactor_op_queue except_op_queue_; - // The timer queues. - std::vector timer_queues_; - - // A copy of the timer queues, used when cleaning up timers. The copy is - // stored as a class data member to avoid unnecessary memory allocation. - std::vector timer_queues_for_cleanup_; - - // The descriptors that are pending cancellation. - std::vector pending_cancellations_; - - // Does the reactor loop thread need to stop. - bool stop_thread_; - - // The thread that is running the reactor loop. - boost::asio::detail::thread* thread_; + timer_queue_set timer_queues_; // Whether the service has been shut down. bool shutdown_; - // Whether we need to call epoll_wait the next time the reactor is run. - bool need_epoll_wait_; + // Mutex to protect access to the registered descriptors. + mutex registered_descriptors_mutex_; + + // Keep track of all registered descriptors. This code relies on the fact that + // the hash_map implementation pools deleted nodes, meaning that we can assume + // our descriptor_state pointer remains valid even after the entry is removed. + // Technically this is not true for C++98, as that standard says that spliced + // elements in a list are invalidated. However, C++0x fixes this shortcoming + // so we'll just assume that C++98 std::list implementations will do the right + // thing anyway. + typedef detail::hash_map descriptor_map; + descriptor_map registered_descriptors_; }; } // namespace detail diff --git a/include/boost/asio/detail/epoll_reactor_fwd.hpp b/include/boost/asio/detail/epoll_reactor_fwd.hpp index 9659dd41..214cee54 100644 --- a/include/boost/asio/detail/epoll_reactor_fwd.hpp +++ b/include/boost/asio/detail/epoll_reactor_fwd.hpp @@ -33,7 +33,6 @@ namespace boost { namespace asio { namespace detail { -template class epoll_reactor; } // namespace detail diff --git a/include/boost/asio/detail/fenced_block.hpp b/include/boost/asio/detail/fenced_block.hpp new file mode 100644 index 00000000..f43097c4 --- /dev/null +++ b/include/boost/asio/detail/fenced_block.hpp @@ -0,0 +1,68 @@ +// +// fenced_block.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if 1//!defined(BOOST_HAS_THREADS) +# include +#elif defined(__MACH__) && defined(__APPLE__) +# include +#elif defined(__sun) +# include +#elif defined(__GNUC__) \ + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) +# include +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# include +#elif defined(BOOST_WINDOWS) +# include +#else +# include +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if 1//!defined(BOOST_HAS_THREADS) +typedef null_fenced_block fenced_block; +#elif defined(__MACH__) && defined(__APPLE__) +typedef macos_fenced_block fenced_block; +#elif defined(__sun) +typedef solaris_fenced_block fenced_block; +#elif defined(__GNUC__) \ + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) +typedef gcc_fenced_block fenced_block; +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +typedef gcc_x86_fenced_block fenced_block; +#elif defined(BOOST_WINDOWS) +typedef win_fenced_block fenced_block; +#else +typedef null_fenced_block fenced_block; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/gcc_fenced_block.hpp b/include/boost/asio/detail/gcc_fenced_block.hpp new file mode 100644 index 00000000..6b58ee89 --- /dev/null +++ b/include/boost/asio/detail/gcc_fenced_block.hpp @@ -0,0 +1,61 @@ +// +// gcc_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_GCC_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_GCC_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if defined(__GNUC__) \ + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) + +namespace boost { +namespace asio { +namespace detail { + +class gcc_fenced_block + : private noncopyable +{ +public: + // Constructor. + gcc_fenced_block() + : value_(0) + { + __sync_lock_test_and_set(&value_, 1); + } + + // Destructor. + ~gcc_fenced_block() + { + __sync_lock_release(&value_); + } + +private: + int value_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(__GNUC__) + // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) + +#include + +#endif // BOOST_ASIO_DETAIL_GCC_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/gcc_x86_fenced_block.hpp b/include/boost/asio/detail/gcc_x86_fenced_block.hpp new file mode 100644 index 00000000..fc23d662 --- /dev/null +++ b/include/boost/asio/detail/gcc_x86_fenced_block.hpp @@ -0,0 +1,63 @@ +// +// gcc_x86_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_GCC_X86_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +namespace boost { +namespace asio { +namespace detail { + +class gcc_x86_fenced_block + : private noncopyable +{ +public: + // Constructor. + gcc_x86_fenced_block() + { + barrier(); + } + + // Destructor. + ~gcc_x86_fenced_block() + { + barrier(); + } + +private: + static int barrier() + { + int r = 0; + __asm__ __volatile__ ("xchgl %%eax, %0" : "=m" (r) : : "memory", "cc"); + return r; + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +#include + +#endif // BOOST_ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/handler_base_from_member.hpp b/include/boost/asio/detail/handler_base_from_member.hpp deleted file mode 100644 index 4e471e33..00000000 --- a/include/boost/asio/detail/handler_base_from_member.hpp +++ /dev/null @@ -1,78 +0,0 @@ -// -// handler_base_from_member.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2010 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_BASE_FROM_MEMBER_HPP -#define BOOST_ASIO_DETAIL_HANDLER_BASE_FROM_MEMBER_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#include -#include - -namespace boost { -namespace asio { -namespace detail { - -// Base class for classes that need a handler data member. Forwards the custom -// allocation and invocation hooks to the contained handler. -template -class handler_base_from_member -{ -public: - handler_base_from_member(Handler handler) - : handler_(handler) - { - } - -//protected: - Handler handler_; - -protected: - // Protected destructor to prevent deletion through this type. - ~handler_base_from_member() - { - } -}; - -template -inline void* asio_handler_allocate(std::size_t size, - handler_base_from_member* this_handler) -{ - return boost_asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); -} - -template -inline void asio_handler_deallocate(void* pointer, std::size_t size, - handler_base_from_member* this_handler) -{ - boost_asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); -} - -template -inline void asio_handler_invoke(const Function& function, - handler_base_from_member* this_handler) -{ - boost_asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); -} - -} // namespace detail -} // namespace asio -} // namespace boost - -#include - -#endif // BOOST_ASIO_DETAIL_HANDLER_BASE_FROM_MEMBER_HPP diff --git a/include/boost/asio/detail/handler_queue.hpp b/include/boost/asio/detail/handler_queue.hpp deleted file mode 100644 index c1fb9887..00000000 --- a/include/boost/asio/detail/handler_queue.hpp +++ /dev/null @@ -1,231 +0,0 @@ -// -// handler_queue.hpp -// ~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2010 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_QUEUE_HPP -#define BOOST_ASIO_DETAIL_HANDLER_QUEUE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#include -#include -#include - -namespace boost { -namespace asio { -namespace detail { - -class handler_queue - : private noncopyable -{ -public: - // Base class for handlers in the queue. - class handler - : private noncopyable - { - public: - void invoke() - { - invoke_func_(this); - } - - void destroy() - { - destroy_func_(this); - } - - protected: - typedef void (*invoke_func_type)(handler*); - typedef void (*destroy_func_type)(handler*); - - handler(invoke_func_type invoke_func, - destroy_func_type destroy_func) - : next_(0), - invoke_func_(invoke_func), - destroy_func_(destroy_func) - { - } - - ~handler() - { - } - - private: - friend class handler_queue; - handler* next_; - invoke_func_type invoke_func_; - destroy_func_type destroy_func_; - }; - - // Smart point to manager handler lifetimes. - class scoped_ptr - : private noncopyable - { - public: - explicit scoped_ptr(handler* h) - : handler_(h) - { - } - - ~scoped_ptr() - { - if (handler_) - handler_->destroy(); - } - - handler* get() const - { - return handler_; - } - - handler* release() - { - handler* tmp = handler_; - handler_ = 0; - return tmp; - } - - private: - handler* handler_; - }; - - // Constructor. - handler_queue() - : front_(0), - back_(0) - { - } - - // Wrap a handler to be pushed into the queue. - template - static handler* wrap(Handler h) - { - // Allocate and construct an object to wrap the handler. - typedef handler_wrapper value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(h); - handler_ptr ptr(raw_ptr, h); - return ptr.release(); - } - - // Get the handler at the front of the queue. - handler* front() - { - return front_; - } - - // Pop a handler from the front of the queue. - void pop() - { - if (front_) - { - handler* tmp = front_; - front_ = front_->next_; - if (front_ == 0) - back_ = 0; - tmp->next_= 0; - } - } - - // Push a handler on to the back of the queue. - void push(handler* h) - { - h->next_ = 0; - if (back_) - { - back_->next_ = h; - back_ = h; - } - else - { - front_ = back_ = h; - } - } - - // Whether the queue is empty. - bool empty() const - { - return front_ == 0; - } - -private: - // Template wrapper for handlers. - template - class handler_wrapper - : public handler - { - public: - handler_wrapper(Handler h) - : handler( - &handler_wrapper::do_call, - &handler_wrapper::do_destroy), - handler_(h) - { - } - - static void do_call(handler* base) - { - // Take ownership of the handler object. - typedef handler_wrapper this_type; - this_type* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(h->handler_, h); - - // Make a copy of the handler so that the memory can be deallocated before - // the upcall is made. - Handler handler(h->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Make the upcall. - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - - static void do_destroy(handler* base) - { - // Take ownership of the handler object. - typedef handler_wrapper this_type; - this_type* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(h->handler_, h); - - // 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(h->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); - } - - private: - Handler handler_; - }; - - // The front of the queue. - handler* front_; - - // The back of the queue. - handler* back_; -}; - -} // namespace detail -} // namespace asio -} // namespace boost - -#include - -#endif // BOOST_ASIO_DETAIL_HANDLER_QUEUE_HPP diff --git a/include/boost/asio/detail/hash_map.hpp b/include/boost/asio/detail/hash_map.hpp index c620da78..36c9a99b 100644 --- a/include/boost/asio/detail/hash_map.hpp +++ b/include/boost/asio/detail/hash_map.hpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -62,9 +61,16 @@ public: // Constructor. hash_map() - : size_(0) + : size_(0), + buckets_(0), + num_buckets_(0) { - rehash(hash_size(0)); + } + + // Destructor. + ~hash_map() + { + delete[] buckets_; } // Get an iterator for the beginning of the map. @@ -100,17 +106,20 @@ public: // Find an entry in the map. iterator find(const K& k) { - size_t bucket = calculate_hash_value(k) % buckets_.size(); - iterator it = buckets_[bucket].first; - if (it == values_.end()) - return values_.end(); - iterator end = buckets_[bucket].last; - ++end; - while (it != end) + if (num_buckets_) { - if (it->first == k) - return it; - ++it; + size_t bucket = calculate_hash_value(k) % num_buckets_; + iterator it = buckets_[bucket].first; + if (it == values_.end()) + return values_.end(); + iterator end = buckets_[bucket].last; + ++end; + while (it != end) + { + if (it->first == k) + return it; + ++it; + } } return values_.end(); } @@ -118,17 +127,20 @@ public: // Find an entry in the map. const_iterator find(const K& k) const { - size_t bucket = calculate_hash_value(k) % buckets_.size(); - const_iterator it = buckets_[bucket].first; - if (it == values_.end()) - return it; - const_iterator end = buckets_[bucket].last; - ++end; - while (it != end) + if (num_buckets_) { - if (it->first == k) + size_t bucket = calculate_hash_value(k) % num_buckets_; + const_iterator it = buckets_[bucket].first; + if (it == values_.end()) return it; - ++it; + const_iterator end = buckets_[bucket].last; + ++end; + while (it != end) + { + if (it->first == k) + return it; + ++it; + } } return values_.end(); } @@ -136,9 +148,9 @@ public: // Insert a new entry into the map. std::pair insert(const value_type& v) { - if (size_ + 1 >= buckets_.size()) + if (size_ + 1 >= num_buckets_) rehash(hash_size(size_ + 1)); - size_t bucket = calculate_hash_value(v.first) % buckets_.size(); + size_t bucket = calculate_hash_value(v.first) % num_buckets_; iterator it = buckets_[bucket].first; if (it == values_.end()) { @@ -165,7 +177,7 @@ public: { assert(it != values_.end()); - size_t bucket = calculate_hash_value(it->first) % buckets_.size(); + size_t bucket = calculate_hash_value(it->first) % num_buckets_; bool is_first = (it == buckets_[bucket].first); bool is_last = (it == buckets_[bucket].last); if (is_first && is_last) @@ -179,6 +191,14 @@ public: --size_; } + // Erase a key from the map. + void erase(const K& k) + { + iterator it = find(k); + if (it != values_.end()) + erase(it); + } + // Remove all entries from the map. void clear() { @@ -187,8 +207,9 @@ public: size_ = 0; // Initialise all buckets to empty. - for (size_t i = 0; i < buckets_.size(); ++i) - buckets_[i].first = buckets_[i].last = values_.end(); + iterator end = values_.end(); + for (size_t i = 0; i < num_buckets_; ++i) + buckets_[i].first = buckets_[i].last = end; } private: @@ -215,21 +236,24 @@ private: // Re-initialise the hash from the values already contained in the list. void rehash(std::size_t num_buckets) { - if (num_buckets == buckets_.size()) + if (num_buckets == num_buckets_) return; + num_buckets_ = num_buckets; iterator end = values_.end(); // Update number of buckets and initialise all buckets to empty. - buckets_.resize(num_buckets); - for (std::size_t i = 0; i < buckets_.size(); ++i) + bucket_type* tmp = new bucket_type[num_buckets_]; + delete[] buckets_; + buckets_ = tmp; + for (std::size_t i = 0; i < num_buckets_; ++i) buckets_[i].first = buckets_[i].last = end; // Put all values back into the hash. iterator iter = values_.begin(); while (iter != end) { - std::size_t bucket = calculate_hash_value(iter->first) % buckets_.size(); + std::size_t bucket = calculate_hash_value(iter->first) % num_buckets_; if (buckets_[bucket].last == end) { buckets_[bucket].first = buckets_[bucket].last = iter++; @@ -282,14 +306,15 @@ private: // The type for a bucket in the hash table. struct bucket_type { - bucket_type() {} - bucket_type(const bucket_type&) { /* noop */ } iterator first; iterator last; }; // The buckets in the hash. - std::vector buckets_; + bucket_type* buckets_; + + // The number of buckets in the hash. + std::size_t num_buckets_; }; } // namespace detail diff --git a/include/boost/asio/detail/indirect_handler_queue.hpp b/include/boost/asio/detail/indirect_handler_queue.hpp deleted file mode 100644 index 72b10308..00000000 --- a/include/boost/asio/detail/indirect_handler_queue.hpp +++ /dev/null @@ -1,293 +0,0 @@ -// -// indirect_handler_queue.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2010 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_INDIRECT_HANDLER_QUEUE_HPP -#define BOOST_ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#include -#include -#include - -#if defined(_MSC_VER) && (_MSC_VER >= 1310) -extern "C" void _ReadWriteBarrier(); -# pragma intrinsic(_ReadWriteBarrier) -#endif // defined(_MSC_VER) && (_MSC_VER >= 1310) - -namespace boost { -namespace asio { -namespace detail { - -class indirect_handler_queue - : private noncopyable -{ -public: - class handler; - - // Element for a node in the queue. - class node - { - public: - node() - : version_(0), - handler_(0), - next_(0) - { - } - - private: - friend class indirect_handler_queue; - unsigned long version_; - handler* handler_; - node* next_; - }; - - // Base class for handlers in the queue. - class handler - : private noncopyable - { - public: - void invoke() - { - invoke_func_(this); - } - - void destroy() - { - destroy_func_(this); - } - - protected: - typedef void (*invoke_func_type)(handler*); - typedef void (*destroy_func_type)(handler*); - - handler(invoke_func_type invoke_func, - destroy_func_type destroy_func) - : node_(new node), - invoke_func_(invoke_func), - destroy_func_(destroy_func) - { - } - - ~handler() - { - if (node_) - delete node_; - } - - private: - friend class indirect_handler_queue; - node* node_; - invoke_func_type invoke_func_; - destroy_func_type destroy_func_; - }; - - // Smart point to manager handler lifetimes. - class scoped_ptr - : private noncopyable - { - public: - explicit scoped_ptr(handler* h) - : handler_(h) - { - } - - ~scoped_ptr() - { - if (handler_) - handler_->destroy(); - } - - handler* get() const - { - return handler_; - } - - handler* release() - { - handler* tmp = handler_; - handler_ = 0; - return tmp; - } - - private: - handler* handler_; - }; - - // Constructor. - indirect_handler_queue() - : front_(new node), - back_(front_), - next_version_(1) - { - } - - // Destructor. - ~indirect_handler_queue() - { - while (front_) - { - node* tmp = front_; - front_ = front_->next_; - delete tmp; - } - } - - // Wrap a handler to be pushed into the queue. - template - static handler* wrap(Handler h) - { - // Allocate and construct an object to wrap the handler. - typedef handler_wrapper value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(h); - handler_ptr ptr(raw_ptr, h); - return ptr.release(); - } - - // Determine whether the queue has something ready to pop. - bool poppable() - { - return front_->next_ != 0; - } - - // The version number at the front of the queue. - unsigned long front_version() - { - return front_->version_; - } - - // The version number at the back of the queue. - unsigned long back_version() - { - return back_->version_; - } - - // Pop a handler from the front of the queue. - handler* pop() - { - node* n = front_; - node* new_front = n->next_; - if (new_front) - { - handler* h = new_front->handler_; - h->node_ = n; - new_front->handler_ = 0; - front_ = new_front; - return h; - } - return 0; - } - - // Push a handler on to the back of the queue. - void push(handler* h) - { - node* n = h->node_; - h->node_ = 0; - n->version_ = next_version_; - next_version_ += 2; - n->handler_ = h; - n->next_ = 0; - memory_barrier(); - back_->next_ = n; - back_ = n; - } - -private: - // Template wrapper for handlers. - template - class handler_wrapper - : public handler - { - public: - handler_wrapper(Handler h) - : handler( - &handler_wrapper::do_call, - &handler_wrapper::do_destroy), - handler_(h) - { - } - - static void do_call(handler* base) - { - // Take ownership of the handler object. - typedef handler_wrapper this_type; - this_type* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(h->handler_, h); - - // Make a copy of the handler so that the memory can be deallocated before - // the upcall is made. - Handler handler(h->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Make the upcall. - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - - static void do_destroy(handler* base) - { - // Take ownership of the handler object. - typedef handler_wrapper this_type; - this_type* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(h->handler_, h); - - // 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(h->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); - } - - private: - Handler handler_; - }; - - // Helper function to create a memory barrier. - static void memory_barrier() - { -#if defined(_GLIBCXX_WRITE_MEM_BARRIER) - _GLIBCXX_WRITE_MEM_BARRIER; -#elif defined(_MSC_VER) && (_MSC_VER >= 1310) - _ReadWriteBarrier(); -#else -# error memory barrier required -#endif - } - - // The front of the queue. - node* front_; - - // The back of the queue. - node* back_; - - // The next version counter to be assigned to a node. - unsigned long next_version_; -}; - -} // namespace detail -} // namespace asio -} // namespace boost - -#include - -#endif // BOOST_ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP diff --git a/include/boost/asio/detail/kqueue_reactor.hpp b/include/boost/asio/detail/kqueue_reactor.hpp index ea8e2850..9b8599ba 100644 --- a/include/boost/asio/detail/kqueue_reactor.hpp +++ b/include/boost/asio/detail/kqueue_reactor.hpp @@ -24,28 +24,27 @@ #include #include -#include #include #include #include #include -#include #include #include #include #include #include -#include #include -#include -#include +#include +#include #include #include #include -#include #include -#include +#include +#include +#include +#include // Older versions of Mac OS X may not define EV_OOBAND. #if !defined(EV_OOBAND) @@ -56,43 +55,29 @@ namespace boost { namespace asio { namespace detail { -template class kqueue_reactor - : public boost::asio::detail::service_base > + : public boost::asio::detail::service_base { public: + enum { read_op = 0, write_op = 1, + connect_op = 1, except_op = 2, max_ops = 3 }; + // Per-descriptor data. struct per_descriptor_data { - bool allow_speculative_read; - bool allow_speculative_write; + bool allow_speculative[max_ops]; }; // Constructor. kqueue_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - kqueue_reactor >(io_service), + : boost::asio::detail::service_base(io_service), + io_service_(use_service(io_service)), mutex_(), kqueue_fd_(do_kqueue_create()), - wait_in_progress_(false), interrupter_(), - read_op_queue_(), - write_op_queue_(), - except_op_queue_(), - pending_cancellations_(), - stop_thread_(false), - thread_(0), shutdown_(false), need_kqueue_wait_(true) { - // Start the reactor's internal thread only if needed. - if (Own_Thread) - { - boost::asio::detail::signal_blocker sb; - thread_ = new boost::asio::detail::thread( - bind_handler(&kqueue_reactor::call_run_thread, this)); - } - // Add the interrupter's descriptor to the kqueue. struct kevent event; EV_SET(&event, interrupter_.read_descriptor(), @@ -112,65 +97,49 @@ public: { boost::asio::detail::mutex::scoped_lock lock(mutex_); shutdown_ = true; - stop_thread_ = true; lock.unlock(); - if (thread_) - { - interrupter_.interrupt(); - thread_->join(); - delete thread_; - thread_ = 0; - } + op_queue ops; - read_op_queue_.destroy_operations(); - write_op_queue_.destroy_operations(); - except_op_queue_.destroy_operations(); + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->destroy_timers(); - timer_queues_.clear(); + timer_queues_.get_all_timers(ops); } - // Initialise the task, but only if the reactor is not in its own thread. + // Initialise the task. void init_task() { - if (!Own_Thread) - { - typedef task_io_service > task_io_service_type; - use_service(this->get_io_service()).init_task(); - } + io_service_.init_task(); } // Register a socket with the reactor. Returns 0 on success, system error // code on failure. int register_descriptor(socket_type, per_descriptor_data& descriptor_data) { - descriptor_data.allow_speculative_read = true; - descriptor_data.allow_speculative_write = true; + descriptor_data.allow_speculative[read_op] = true; + descriptor_data.allow_speculative[write_op] = true; + descriptor_data.allow_speculative[except_op] = true; return 0; } - // Start a new read operation. The handler object will be invoked when the - // given descriptor is ready to be read, or an error has occurred. - template - void start_read_op(socket_type descriptor, - per_descriptor_data& descriptor_data, Handler handler, - bool allow_speculative_read = true) + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + void start_op(int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, + reactor_op* op, bool allow_speculative) { - if (allow_speculative_read && descriptor_data.allow_speculative_read) + if (allow_speculative && descriptor_data.allow_speculative[op_type]) { - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) + if (op->perform()) { - handler.complete(ec, bytes_transferred); + io_service_.post_immediate_completion(op); return; } // We only get one shot at a speculative read in this function. - allow_speculative_read = false; + allow_speculative = false; } boost::asio::detail::mutex::scoped_lock lock(mutex_); @@ -178,146 +147,49 @@ public: if (shutdown_) return; - if (!allow_speculative_read) + if (!allow_speculative) need_kqueue_wait_ = true; - else if (!read_op_queue_.has_operation(descriptor)) + else if (!op_queue_[op_type].has_operation(descriptor)) { // Speculative reads are ok as there are no queued read operations. - descriptor_data.allow_speculative_read = true; + descriptor_data.allow_speculative[op_type] = true; - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) + if (op->perform()) { - handler.complete(ec, bytes_transferred); + lock.unlock(); + io_service_.post_immediate_completion(op); return; } } // Speculative reads are not ok as there will be queued read operations. - descriptor_data.allow_speculative_read = false; + descriptor_data.allow_speculative[op_type] = false; - if (read_op_queue_.enqueue_operation(descriptor, handler)) + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + io_service_.work_started(); + if (first) { struct kevent event; - EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0); - if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) + switch (op_type) { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - read_op_queue_.perform_all_operations(descriptor, ec); - } - } - } - - // Start a new write operation. The handler object will be invoked when the - // given descriptor is ready to be written, or an error has occurred. - template - void start_write_op(socket_type descriptor, - per_descriptor_data& descriptor_data, Handler handler, - bool allow_speculative_write = true) - { - if (allow_speculative_write && descriptor_data.allow_speculative_write) - { - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) - { - handler.complete(ec, bytes_transferred); - return; - } - - // We only get one shot at a speculative write in this function. - allow_speculative_write = false; - } - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - - if (!allow_speculative_write) - need_kqueue_wait_ = true; - else if (!write_op_queue_.has_operation(descriptor)) - { - // Speculative writes are ok as there are no queued write operations. - descriptor_data.allow_speculative_write = true; - - boost::system::error_code ec; - std::size_t bytes_transferred = 0; - if (handler.perform(ec, bytes_transferred)) - { - handler.complete(ec, bytes_transferred); - return; - } - } - - // Speculative writes are not ok as there will be queued write operations. - descriptor_data.allow_speculative_write = false; - - if (write_op_queue_.enqueue_operation(descriptor, handler)) - { - struct kevent event; - EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0); - if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) - { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - write_op_queue_.perform_all_operations(descriptor, ec); - } - } - } - - // Start a new exception operation. The handler object will be invoked when - // the given descriptor has exception information, or an error has occurred. - template - void start_except_op(socket_type descriptor, - per_descriptor_data&, Handler handler) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - - if (except_op_queue_.enqueue_operation(descriptor, handler)) - { - struct kevent event; - if (read_op_queue_.has_operation(descriptor)) + case read_op: EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0); - else - EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0); - if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) - { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - except_op_queue_.perform_all_operations(descriptor, ec); + break; + case write_op: + EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0); + break; + case except_op: + if (op_queue_[read_op].has_operation(descriptor)) + EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0); + else + EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, EV_OOBAND, 0, 0); + break; } - } - } - - // Start a new write operation. The handler object will be invoked when the - // given descriptor is ready to be written, or an error has occurred. - template - void start_connect_op(socket_type descriptor, - per_descriptor_data& descriptor_data, Handler handler) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - - // Speculative writes are not ok as there will be queued write operations. - descriptor_data.allow_speculative_write = false; - - if (write_op_queue_.enqueue_operation(descriptor, handler)) - { - struct kevent event; - EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { boost::system::error_code ec(errno, boost::asio::error::get_system_category()); - write_op_queue_.perform_all_operations(descriptor, ec); + cancel_ops_unlocked(descriptor, ec); } } } @@ -328,7 +200,7 @@ public: void cancel_ops(socket_type descriptor, per_descriptor_data&) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); } // Cancel any operations that are running against the descriptor and remove @@ -344,7 +216,7 @@ public: ::kevent(kqueue_fd_, event, 2, 0, 0, 0); // Cancel any outstanding operations associated with the descriptor. - cancel_ops_unlocked(descriptor); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); } // Add a new timer queue to the reactor. @@ -352,7 +224,7 @@ public: void add_timer_queue(timer_queue& timer_queue) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.push_back(&timer_queue); + timer_queues_.insert(&timer_queue); } // Remove a timer queue from the reactor. @@ -360,77 +232,53 @@ public: void remove_timer_queue(timer_queue& timer_queue) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - if (timer_queues_[i] == &timer_queue) - { - timer_queues_.erase(timer_queues_.begin() + i); - return; - } - } + timer_queues_.erase(&timer_queue); } - // Schedule a timer in the given timer queue to expire at the specified - // absolute time. The handler object will be invoked when the timer expires. - template + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, Handler handler, void* token) + const typename Time_Traits::time_type& time, timer_op* op, void* token) { boost::asio::detail::mutex::scoped_lock lock(mutex_); if (!shutdown_) - if (timer_queue.enqueue_timer(time, handler, token)) + { + bool earliest = timer_queue.enqueue_timer(time, op, token); + io_service_.work_started(); + if (earliest) interrupter_.interrupt(); + } } - // Cancel the timer associated with the given token. Returns the number of - // handlers that have been posted or dispatched. + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. template std::size_t cancel_timer(timer_queue& timer_queue, void* token) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - std::size_t n = timer_queue.cancel_timer(token); - if (n > 0) - interrupter_.interrupt(); + op_queue ops; + std::size_t n = timer_queue.cancel_timer(token, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); return n; } -private: - friend class task_io_service >; - // Run the kqueue loop. - void run(bool block) + void run(bool block, op_queue& ops) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - // Dispatch any operation cancellations that were made while the select - // loop was not running. - read_op_queue_.perform_cancellations(); - write_op_queue_.perform_cancellations(); - except_op_queue_.perform_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->dispatch_cancellations(); - - // Check if the thread is supposed to stop. - if (stop_thread_) - { - complete_operations_and_timers(lock); - return; - } - // We can return immediately if there's no work to do and the reactor is // not supposed to block. - if (!block && read_op_queue_.empty() && write_op_queue_.empty() - && except_op_queue_.empty() && all_timer_queues_are_empty()) - { - complete_operations_and_timers(lock); + if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty() + && op_queue_[except_op].empty() && timer_queues_.all_empty()) return; - } // Determine how long to block while waiting for events. timespec timeout_buf = { 0, 0 }; timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf; - wait_in_progress_ = true; lock.unlock(); // Block on the kqueue descriptor. @@ -440,7 +288,6 @@ private: : 0; lock.lock(); - wait_in_progress_ = false; // Dispatch the waiting events. for (int i = 0; i < num_events; ++i) @@ -459,23 +306,22 @@ private: { boost::system::error_code error( events[i].data, boost::asio::error::get_system_category()); - except_op_queue_.perform_all_operations(descriptor, error); - read_op_queue_.perform_all_operations(descriptor, error); + op_queue_[except_op].perform_operations(descriptor, ops); + op_queue_[read_op].perform_operations(descriptor, ops); } else if (events[i].flags & EV_OOBAND) { - boost::system::error_code error; - more_except = except_op_queue_.perform_operation(descriptor, error); + more_except + = op_queue_[except_op].perform_operations(descriptor, ops); if (events[i].data > 0) - more_reads = read_op_queue_.perform_operation(descriptor, error); + more_reads = op_queue_[read_op].perform_operations(descriptor, ops); else - more_reads = read_op_queue_.has_operation(descriptor); + more_reads = op_queue_[read_op].has_operation(descriptor); } else { - boost::system::error_code error; - more_reads = read_op_queue_.perform_operation(descriptor, error); - more_except = except_op_queue_.has_operation(descriptor); + more_reads = op_queue_[read_op].perform_operations(descriptor, ops); + more_except = op_queue_[except_op].has_operation(descriptor); } // Update the descriptor in the kqueue. @@ -490,8 +336,8 @@ private: { boost::system::error_code error(errno, boost::asio::error::get_system_category()); - except_op_queue_.perform_all_operations(descriptor, error); - read_op_queue_.perform_all_operations(descriptor, error); + op_queue_[except_op].cancel_operations(descriptor, ops, error); + op_queue_[read_op].cancel_operations(descriptor, ops, error); } } else if (events[i].filter == EVFILT_WRITE) @@ -502,12 +348,11 @@ private: { boost::system::error_code error( events[i].data, boost::asio::error::get_system_category()); - write_op_queue_.perform_all_operations(descriptor, error); + op_queue_[write_op].cancel_operations(descriptor, ops, error); } else { - boost::system::error_code error; - more_writes = write_op_queue_.perform_operation(descriptor, error); + more_writes = op_queue_[write_op].perform_operations(descriptor, ops); } // Update the descriptor in the kqueue. @@ -520,48 +365,15 @@ private: { boost::system::error_code error(errno, boost::asio::error::get_system_category()); - write_op_queue_.perform_all_operations(descriptor, error); + op_queue_[write_op].cancel_operations(descriptor, ops, error); } } } - - read_op_queue_.perform_cancellations(); - write_op_queue_.perform_cancellations(); - except_op_queue_.perform_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - timer_queues_[i]->dispatch_timers(); - timer_queues_[i]->dispatch_cancellations(); - } - - // Issue any pending cancellations. - for (std::size_t i = 0; i < pending_cancellations_.size(); ++i) - cancel_ops_unlocked(pending_cancellations_[i]); - pending_cancellations_.clear(); + timer_queues_.get_ready_timers(ops); // Determine whether kqueue needs to be called next time the reactor is run. - need_kqueue_wait_ = !read_op_queue_.empty() - || !write_op_queue_.empty() || !except_op_queue_.empty(); - - complete_operations_and_timers(lock); - } - - // Run the select loop in the thread. - void run_thread() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - while (!stop_thread_) - { - lock.unlock(); - run(true); - lock.lock(); - } - } - - // Entry point for the select loop thread. - static void call_run_thread(kqueue_reactor* reactor) - { - reactor->run_thread(); + need_kqueue_wait_ = !op_queue_[read_op].empty() + || !op_queue_[write_op].empty() || !op_queue_[except_op].empty(); } // Interrupt the select loop. @@ -570,6 +382,7 @@ private: interrupter_.interrupt(); } +private: // Create the kqueue file descriptor. Throws an exception if the descriptor // cannot be created. static int do_kqueue_create() @@ -586,75 +399,30 @@ private: return fd; } - // Check if all timer queues are empty. - bool all_timer_queues_are_empty() const - { - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - if (!timer_queues_[i]->empty()) - return false; - return true; - } - // Get the timeout value for the kevent call. timespec* get_timeout(timespec& ts) { - if (all_timer_queues_are_empty()) - return 0; - // 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. - boost::posix_time::time_duration minimum_wait_duration - = boost::posix_time::minutes(5); - - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - boost::posix_time::time_duration wait_duration - = timer_queues_[i]->wait_duration(); - if (wait_duration < minimum_wait_duration) - minimum_wait_duration = wait_duration; - } - - if (minimum_wait_duration > boost::posix_time::time_duration()) - { - ts.tv_sec = minimum_wait_duration.total_seconds(); - ts.tv_nsec = minimum_wait_duration.total_nanoseconds() % 1000000000; - } - else - { - ts.tv_sec = 0; - ts.tv_nsec = 0; - } - + long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; return &ts; } - // Cancel all operations associated with the given descriptor. The do_cancel - // function of the handler objects will be invoked. This function does not - // acquire the kqueue_reactor's mutex. - void cancel_ops_unlocked(socket_type descriptor) + // Cancel all operations associated with the given descriptor. This function + // does not acquire the kqueue_reactor's mutex. + void cancel_ops_unlocked(socket_type descriptor, + const boost::system::error_code& ec) { - bool interrupt = read_op_queue_.cancel_operations(descriptor); - interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt; - interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt; - if (interrupt) - interrupter_.interrupt(); + op_queue ops; + for (int i = 0; i < max_ops; ++i) + op_queue_[i].cancel_operations(descriptor, ops, ec); + io_service_.post_deferred_completions(ops); } - // Clean up operations and timers. We must not hold the lock since the - // destructors may make calls back into this reactor. We make a copy of the - // vector of timer queues since the original may be modified while the lock - // is not held. - void complete_operations_and_timers( - boost::asio::detail::mutex::scoped_lock& lock) - { - timer_queues_for_cleanup_ = timer_queues_; - lock.unlock(); - read_op_queue_.complete_operations(); - write_op_queue_.complete_operations(); - except_op_queue_.complete_operations(); - for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i) - timer_queues_for_cleanup_[i]->complete_timers(); - } + // The io_service implementation used to post completions. + io_service_impl& io_service_; // Mutex to protect access to internal data. boost::asio::detail::mutex mutex_; @@ -662,36 +430,14 @@ private: // The kqueue file descriptor. int kqueue_fd_; - // Whether the kqueue wait call is currently in progress - bool wait_in_progress_; - // The interrupter is used to break a blocking kevent call. select_interrupter interrupter_; - // The queue of read operations. - reactor_op_queue read_op_queue_; - - // The queue of write operations. - reactor_op_queue write_op_queue_; - - // The queue of except operations. - reactor_op_queue except_op_queue_; + // The queues of read, write and except operations. + reactor_op_queue op_queue_[max_ops]; // The timer queues. - std::vector timer_queues_; - - // A copy of the timer queues, used when cleaning up timers. The copy is - // stored as a class data member to avoid unnecessary memory allocation. - std::vector timer_queues_for_cleanup_; - - // The descriptors that are pending cancellation. - std::vector pending_cancellations_; - - // Does the reactor loop thread need to stop. - bool stop_thread_; - - // The thread that is running the reactor loop. - boost::asio::detail::thread* thread_; + timer_queue_set timer_queues_; // Whether the service has been shut down. bool shutdown_; diff --git a/include/boost/asio/detail/kqueue_reactor_fwd.hpp b/include/boost/asio/detail/kqueue_reactor_fwd.hpp index b2751bfa..0471c391 100644 --- a/include/boost/asio/detail/kqueue_reactor_fwd.hpp +++ b/include/boost/asio/detail/kqueue_reactor_fwd.hpp @@ -30,7 +30,6 @@ namespace boost { namespace asio { namespace detail { -template class kqueue_reactor; } // namespace detail diff --git a/include/boost/asio/detail/macos_fenced_block.hpp b/include/boost/asio/detail/macos_fenced_block.hpp new file mode 100644 index 00000000..496d7f0c --- /dev/null +++ b/include/boost/asio/detail/macos_fenced_block.hpp @@ -0,0 +1,59 @@ +// +// macos_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_MACOS_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if defined(__MACH__) && defined(__APPLE__) + +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class macos_fenced_block + : private noncopyable +{ +public: + // Constructor. + macos_fenced_block() + { + OSMemoryBarrier(); + } + + // Destructor. + ~macos_fenced_block() + { + OSMemoryBarrier(); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(__MACH__) && defined(__APPLE__) + +#include + +#endif // BOOST_ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/null_buffers_op.hpp b/include/boost/asio/detail/null_buffers_op.hpp new file mode 100644 index 00000000..02160af5 --- /dev/null +++ b/include/boost/asio/detail/null_buffers_op.hpp @@ -0,0 +1,79 @@ +// +// null_buffers_op.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_BUFFERS_OP_HPP +#define BOOST_ASIO_DETAIL_NULL_BUFFERS_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class null_buffers_op : public reactor_op +{ +public: + null_buffers_op(Handler handler) + : reactor_op(&null_buffers_op::do_perform, &null_buffers_op::do_complete), + handler_(handler) + { + } + + static bool do_perform(reactor_op*) + { + return true; + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + null_buffers_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) + { + // 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(o->handler_, o->ec_, o->bytes_transferred_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_NULL_BUFFERS_OP_HPP diff --git a/include/boost/asio/detail/null_event.hpp b/include/boost/asio/detail/null_event.hpp index 184f753a..e926d4e3 100644 --- a/include/boost/asio/detail/null_event.hpp +++ b/include/boost/asio/detail/null_event.hpp @@ -49,6 +49,12 @@ public: { } + // Signal the event and unlock the mutex. + template + void signal_and_unlock(Lock&) + { + } + // Reset the event. template void clear(Lock&) diff --git a/include/boost/asio/detail/null_fenced_block.hpp b/include/boost/asio/detail/null_fenced_block.hpp new file mode 100644 index 00000000..ea8e0fce --- /dev/null +++ b/include/boost/asio/detail/null_fenced_block.hpp @@ -0,0 +1,45 @@ +// +// null_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_NULL_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class null_fenced_block + : private noncopyable +{ +public: + // Constructor. + null_fenced_block() + { + } + + // Destructor. + ~null_fenced_block() + { + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_NULL_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/op_queue.hpp b/include/boost/asio/detail/op_queue.hpp new file mode 100644 index 00000000..ddf3e187 --- /dev/null +++ b/include/boost/asio/detail/op_queue.hpp @@ -0,0 +1,158 @@ +// +// op_queue.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_OP_QUEUE_HPP +#define BOOST_ASIO_DETAIL_OP_QUEUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class op_queue; + +class op_queue_access +{ +public: + template + static Operation* next(Operation* o) + { + return static_cast(o->next_); + } + + template + static void next(Operation1*& o1, Operation2* o2) + { + o1->next_ = o2; + } + + template + static void destroy(Operation* o) + { + o->destroy(); + } + + template + static Operation*& front(op_queue& q) + { + return q.front_; + } + + template + static Operation*& back(op_queue& q) + { + return q.back_; + } +}; + +template +class op_queue + : private noncopyable +{ +public: + // Constructor. + op_queue() + : front_(0), + back_(0) + { + } + + // Destructor destroys all operations. + ~op_queue() + { + while (Operation* op = front_) + { + pop(); + op_queue_access::destroy(op); + } + } + + // Get the operation at the front of the queue. + Operation* front() + { + return front_; + } + + // Pop an operation from the front of the queue. + void pop() + { + if (front_) + { + Operation* tmp = front_; + front_ = op_queue_access::next(front_); + if (front_ == 0) + back_ = 0; + op_queue_access::next(tmp, static_cast(0)); + } + } + + // Push an operation on to the back of the queue. + void push(Operation* h) + { + op_queue_access::next(h, static_cast(0)); + if (back_) + { + op_queue_access::next(back_, h); + back_ = h; + } + else + { + front_ = back_ = h; + } + } + + // Push all operations from another queue on to the back of the queue. The + // source queue may contain operations of a derived type. + template + void push(op_queue& q) + { + if (Operation* other_front = op_queue_access::front(q)) + { + if (back_) + op_queue_access::next(back_, other_front); + else + front_ = other_front; + back_ = op_queue_access::back(q); + op_queue_access::front(q) = 0; + op_queue_access::back(q) = 0; + } + } + + // Whether the queue is empty. + bool empty() const + { + return front_ == 0; + } + +private: + friend class op_queue_access; + + // The front of the queue. + Operation* front_; + + // The back of the queue. + Operation* back_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_OP_QUEUE_HPP diff --git a/include/boost/asio/detail/operation.hpp b/include/boost/asio/detail/operation.hpp new file mode 100644 index 00000000..579b6b5a --- /dev/null +++ b/include/boost/asio/detail/operation.hpp @@ -0,0 +1,45 @@ +// +// operation.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_OPERATION_HPP +#define BOOST_ASIO_DETAIL_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else +# include +# include +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_HAS_IOCP) +typedef win_iocp_operation operation; +#else +typedef task_io_service_operation operation; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_OPERATION_HPP diff --git a/include/boost/asio/detail/posix_event.hpp b/include/boost/asio/detail/posix_event.hpp index 20c0fe30..b2938cfa 100644 --- a/include/boost/asio/detail/posix_event.hpp +++ b/include/boost/asio/detail/posix_event.hpp @@ -72,6 +72,16 @@ public: ::pthread_cond_signal(&cond_); // Ignore EINVAL. } + // Signal the event and unlock the mutex. + template + void signal_and_unlock(Lock& lock) + { + BOOST_ASSERT(lock.locked()); + signalled_ = true; + lock.unlock(); + ::pthread_cond_signal(&cond_); // Ignore EINVAL. + } + // Reset the event. template void clear(Lock& lock) diff --git a/include/boost/asio/detail/posix_mutex.hpp b/include/boost/asio/detail/posix_mutex.hpp index e7209c1c..6d9a44f5 100644 --- a/include/boost/asio/detail/posix_mutex.hpp +++ b/include/boost/asio/detail/posix_mutex.hpp @@ -62,35 +62,19 @@ public: // Destructor. ~posix_mutex() { - ::pthread_mutex_destroy(&mutex_); + ::pthread_mutex_destroy(&mutex_); // Ignore EBUSY. } // Lock the mutex. void lock() { - int error = ::pthread_mutex_lock(&mutex_); - if (error != 0) - { - boost::system::system_error e( - boost::system::error_code(error, - boost::asio::error::get_system_category()), - "mutex"); - boost::throw_exception(e); - } + (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL. } // Unlock the mutex. void unlock() { - int error = ::pthread_mutex_unlock(&mutex_); - if (error != 0) - { - boost::system::system_error e( - boost::system::error_code(error, - boost::asio::error::get_system_category()), - "mutex"); - boost::throw_exception(e); - } + (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL. } private: diff --git a/include/boost/asio/detail/reactive_descriptor_service.hpp b/include/boost/asio/detail/reactive_descriptor_service.hpp index 61f676b7..a3a087d6 100644 --- a/include/boost/asio/detail/reactive_descriptor_service.hpp +++ b/include/boost/asio/detail/reactive_descriptor_service.hpp @@ -21,10 +21,13 @@ #include #include #include -#include -#include -#include +#include #include +#include +#include +#include +#include +#include #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) @@ -32,10 +35,7 @@ namespace boost { namespace asio { namespace detail { -template class reactive_descriptor_service - : public boost::asio::detail::service_base< - reactive_descriptor_service > { public: // The native type of a descriptor. @@ -55,22 +55,28 @@ public: private: // Only this service will have access to the internal values. - friend class reactive_descriptor_service; + friend class reactive_descriptor_service; // The native descriptor representation. int descriptor_; enum { - user_set_non_blocking = 1, // The user wants a non-blocking descriptor. - internal_non_blocking = 2 // The descriptor has been set non-blocking. + // The user wants a non-blocking descriptor. + user_set_non_blocking = 1, + + // The descriptor has been set non-blocking. + internal_non_blocking = 2, + + // Helper "flag" used to determine whether the socket is non-blocking. + non_blocking = user_set_non_blocking | internal_non_blocking }; // Flags indicating the current state of the descriptor. unsigned char flags_; // Per-descriptor data used by the reactor. - typename Reactor::per_descriptor_data reactor_data_; + reactor::per_descriptor_data reactor_data_; }; // The maximum number of buffers to support in a single operation. @@ -78,9 +84,8 @@ public: // Constructor. reactive_descriptor_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - reactive_descriptor_service >(io_service), - reactor_(boost::asio::use_service(io_service)) + : io_service_impl_(boost::asio::use_service(io_service)), + reactor_(boost::asio::use_service(io_service)) { reactor_.init_task(); } @@ -236,47 +241,22 @@ public: return 0; } - // Copy buffers into array. - descriptor_ops::buf bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - descriptor_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - total_buffer_size += boost::asio::buffer_size(buffer); - } + buffer_sequence_adapter bufs(buffers); // A request to read_some 0 bytes on a stream is a no-op. - if (total_buffer_size == 0) + if (bufs.all_empty()) { ec = boost::system::error_code(); return 0; } - // Make descriptor non-blocking if user wants non-blocking. - if (impl.flags_ & implementation_type::user_set_non_blocking) - { - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - ioctl_arg_type non_blocking = 1; - if (descriptor_ops::ioctl(impl.descriptor_, - FIONBIO, &non_blocking, ec)) - return 0; - impl.flags_ |= implementation_type::internal_non_blocking; - } - } - // Send the data. for (;;) { // Try to complete the operation without blocking. int bytes_sent = descriptor_ops::gather_write( - impl.descriptor_, bufs, i, ec); + impl.descriptor_, bufs.buffers(), bufs.count(), ec); // Check if operation succeeded. if (bytes_sent >= 0) @@ -310,48 +290,31 @@ public: return 0; } - template - class write_operation : - public handler_base_from_member + template + class write_op_base : public reactor_op { public: - write_operation(int descriptor, boost::asio::io_service& io_service, - const ConstBufferSequence& buffers, Handler handler) - : handler_base_from_member(handler), + write_op_base(int descriptor, + const ConstBufferSequence& buffers, func_type complete_func) + : reactor_op(&write_op_base::do_perform, complete_func), descriptor_(descriptor), - io_service_(io_service), - work_(io_service), buffers_(buffers) { } - bool perform(boost::system::error_code& ec, - std::size_t& bytes_transferred) + static bool do_perform(reactor_op* base) { - // Check whether the operation was successful. - if (ec) - { - bytes_transferred = 0; - return true; - } + write_op_base* o(static_cast(base)); - // Copy buffers into array. - descriptor_ops::buf bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers_.begin(); - typename ConstBufferSequence::const_iterator end = buffers_.end(); - size_t i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - descriptor_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - } + buffer_sequence_adapter bufs(o->buffers_); for (;;) { // Write the data. - int bytes = descriptor_ops::gather_write(descriptor_, bufs, i, ec); + boost::system::error_code ec; + int bytes = descriptor_ops::gather_write( + o->descriptor_, bufs.buffers(), bufs.count(), ec); // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) @@ -362,22 +325,56 @@ public: || ec == boost::asio::error::try_again) return false; - bytes_transferred = (bytes < 0 ? 0 : bytes); + o->ec_ = ec; + o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); return true; } } - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) + private: + int descriptor_; + ConstBufferSequence buffers_; + }; + + template + class write_op : public write_op_base + { + public: + write_op(int descriptor, + const ConstBufferSequence& buffers, Handler handler) + : write_op_base( + descriptor, buffers, &write_op::do_complete), + handler_(handler) { - io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + write_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) + { + // 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(o->handler_, o->ec_, o->bytes_transferred_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } private: - int descriptor_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; - ConstBufferSequence buffers_; + Handler handler_; }; // Start an asynchronous write. The data being sent must be valid for the @@ -386,96 +383,31 @@ public: void async_write_some(implementation_type& impl, const ConstBufferSequence& buffers, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - // Determine total size of buffers. - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - total_buffer_size += boost::asio::buffer_size(buffer); - } + // Allocate and construct an operation to wrap the handler. + typedef write_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, impl.descriptor_, buffers, handler); - // A request to read_some 0 bytes on a stream is a no-op. - if (total_buffer_size == 0) - { - this->get_io_service().post(bind_handler(handler, - boost::system::error_code(), 0)); - return; - } - - // Make descriptor non-blocking. - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) - { - this->get_io_service().post(bind_handler(handler, ec, 0)); - return; - } - impl.flags_ |= implementation_type::internal_non_blocking; - } - - reactor_.start_write_op(impl.descriptor_, impl.reactor_data_, - write_operation( - impl.descriptor_, this->get_io_service(), buffers, handler)); - } + start_op(impl, reactor::write_op, ptr.get(), true, + buffer_sequence_adapter::all_empty(buffers)); + ptr.release(); } - template - class null_buffers_operation : - public handler_base_from_member - { - public: - null_buffers_operation(boost::asio::io_service& io_service, Handler handler) - : handler_base_from_member(handler), - work_(io_service) - { - } - - bool perform(boost::system::error_code&, - std::size_t& bytes_transferred) - { - bytes_transferred = 0; - return true; - } - - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - work_.get_io_service().post(bind_handler( - this->handler_, ec, bytes_transferred)); - } - - private: - boost::asio::io_service::work work_; - }; - // Start an asynchronous wait until data can be written without blocking. template void async_write_some(implementation_type& impl, const null_buffers&, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - reactor_.start_write_op(impl.descriptor_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); + + start_op(impl, reactor::write_op, ptr.get(), false, false); + ptr.release(); } // Read some data from the stream. Returns the number of bytes read. @@ -489,46 +421,22 @@ public: return 0; } - // Copy buffers into array. - descriptor_ops::buf bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - descriptor_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - total_buffer_size += boost::asio::buffer_size(buffer); - } + buffer_sequence_adapter bufs(buffers); // A request to read_some 0 bytes on a stream is a no-op. - if (total_buffer_size == 0) + if (bufs.all_empty()) { ec = boost::system::error_code(); return 0; } - // Make descriptor non-blocking if user wants non-blocking. - if (impl.flags_ & implementation_type::user_set_non_blocking) - { - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - ioctl_arg_type non_blocking = 1; - if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) - return 0; - impl.flags_ |= implementation_type::internal_non_blocking; - } - } - // Read some data. for (;;) { // Try to complete the operation without blocking. int bytes_read = descriptor_ops::scatter_read( - impl.descriptor_, bufs, i, ec); + impl.descriptor_, bufs.buffers(), bufs.count(), ec); // Check if operation succeeded. if (bytes_read > 0) @@ -569,48 +477,31 @@ public: return 0; } - template - class read_operation : - public handler_base_from_member + template + class read_op_base : public reactor_op { public: - read_operation(int descriptor, boost::asio::io_service& io_service, - const MutableBufferSequence& buffers, Handler handler) - : handler_base_from_member(handler), + read_op_base(int descriptor, + const MutableBufferSequence& buffers, func_type complete_func) + : reactor_op(&read_op_base::do_perform, complete_func), descriptor_(descriptor), - io_service_(io_service), - work_(io_service), buffers_(buffers) { } - bool perform(boost::system::error_code& ec, - std::size_t& bytes_transferred) + static bool do_perform(reactor_op* base) { - // Check whether the operation was successful. - if (ec) - { - bytes_transferred = 0; - return true; - } + read_op_base* o(static_cast(base)); - // Copy buffers into array. - descriptor_ops::buf bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers_.begin(); - typename MutableBufferSequence::const_iterator end = buffers_.end(); - size_t i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - descriptor_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - } + buffer_sequence_adapter bufs(o->buffers_); for (;;) { // Read some data. - int bytes = descriptor_ops::scatter_read(descriptor_, bufs, i, ec); + boost::system::error_code ec; + int bytes = descriptor_ops::scatter_read( + o->descriptor_, bufs.buffers(), bufs.count(), ec); if (bytes == 0) ec = boost::asio::error::eof; @@ -623,22 +514,56 @@ public: || ec == boost::asio::error::try_again) return false; - bytes_transferred = (bytes < 0 ? 0 : bytes); + o->ec_ = ec; + o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); return true; } } - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) + private: + int descriptor_; + MutableBufferSequence buffers_; + }; + + template + class read_op : public read_op_base + { + public: + read_op(int descriptor, + const MutableBufferSequence& buffers, Handler handler) + : read_op_base( + descriptor, buffers, &read_op::do_complete), + handler_(handler) { - io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + read_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) + { + // 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(o->handler_, o->ec_, o->bytes_transferred_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } private: - int descriptor_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; - MutableBufferSequence buffers_; + Handler handler_; }; // Start an asynchronous read. The buffer for the data being read must be @@ -647,49 +572,17 @@ public: void async_read_some(implementation_type& impl, const MutableBufferSequence& buffers, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - // Determine total size of buffers. - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - total_buffer_size += boost::asio::buffer_size(buffer); - } + // Allocate and construct an operation to wrap the handler. + typedef read_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, + impl.descriptor_, buffers, handler); - // A request to read_some 0 bytes on a stream is a no-op. - if (total_buffer_size == 0) - { - this->get_io_service().post(bind_handler(handler, - boost::system::error_code(), 0)); - return; - } - - // Make descriptor non-blocking. - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) - { - this->get_io_service().post(bind_handler(handler, ec, 0)); - return; - } - impl.flags_ |= implementation_type::internal_non_blocking; - } - - reactor_.start_read_op(impl.descriptor_, impl.reactor_data_, - read_operation( - impl.descriptor_, this->get_io_service(), buffers, handler)); - } + start_op(impl, reactor::read_op, ptr.get(), true, + buffer_sequence_adapter::all_empty(buffers)); + ptr.release(); } // Wait until data can be read without blocking. @@ -697,22 +590,61 @@ public: void async_read_some(implementation_type& impl, const null_buffers&, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - reactor_.start_read_op(impl.descriptor_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); + + start_op(impl, reactor::read_op, ptr.get(), false, false); + ptr.release(); } private: + // Start the asynchronous operation. + void start_op(implementation_type& impl, int op_type, + reactor_op* op, bool non_blocking, bool noop) + { + if (!noop) + { + if (is_open(impl)) + { + if (is_non_blocking(impl) || set_non_blocking(impl, op->ec_)) + { + reactor_.start_op(op_type, impl.descriptor_, + impl.reactor_data_, op, non_blocking); + return; + } + } + else + op->ec_ = boost::asio::error::bad_descriptor; + } + + io_service_impl_.post_immediate_completion(op); + } + + // Determine whether the descriptor has been set non-blocking. + bool is_non_blocking(implementation_type& impl) const + { + return (impl.flags_ & implementation_type::non_blocking); + } + + // Set the internal non-blocking flag. + bool set_non_blocking(implementation_type& impl, + boost::system::error_code& ec) + { + ioctl_arg_type non_blocking = 1; + if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) + return false; + impl.flags_ |= implementation_type::internal_non_blocking; + return true; + } + + // The io_service implementation used to post completions. + io_service_impl& io_service_impl_; + // The selector that performs event demultiplexing for the service. - Reactor& reactor_; + reactor& reactor_; }; } // namespace detail diff --git a/include/boost/asio/detail/reactive_serial_port_service.hpp b/include/boost/asio/detail/reactive_serial_port_service.hpp index cd163e9c..faa2149e 100644 --- a/include/boost/asio/detail/reactive_serial_port_service.hpp +++ b/include/boost/asio/detail/reactive_serial_port_service.hpp @@ -38,31 +38,24 @@ namespace asio { namespace detail { // Extend reactive_descriptor_service to provide serial port support. -template class reactive_serial_port_service - : public boost::asio::detail::service_base< - reactive_serial_port_service > { public: - // The native type of a stream handle. - typedef typename reactive_descriptor_service::native_type - native_type; + // The native type of a serial port. + typedef reactive_descriptor_service::native_type native_type; - // The implementation type of the stream handle. - typedef typename reactive_descriptor_service::implementation_type - implementation_type; + // The implementation type of the serial port. + typedef reactive_descriptor_service::implementation_type implementation_type; reactive_serial_port_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - reactive_serial_port_service>(io_service), - descriptor_service_(boost::asio::use_service< - reactive_descriptor_service >(io_service)) + : descriptor_service_(io_service) { } // Destroy all user-defined handler objects owned by the service. void shutdown_service() { + descriptor_service_.shutdown_service(); } // Construct a new handle implementation. @@ -254,8 +247,8 @@ public: } private: - // The handle service used for initiating asynchronous operations. - reactive_descriptor_service& descriptor_service_; + // The implementation used for initiating asynchronous operations. + reactive_descriptor_service descriptor_service_; }; } // namespace detail diff --git a/include/boost/asio/detail/reactive_socket_service.hpp b/include/boost/asio/detail/reactive_socket_service.hpp index 95d39dda..1b81f242 100644 --- a/include/boost/asio/detail/reactive_socket_service.hpp +++ b/include/boost/asio/detail/reactive_socket_service.hpp @@ -17,18 +17,17 @@ #include -#include -#include -#include - #include #include #include #include #include -#include +#include +#include #include -#include +#include +#include +#include #include #include #include @@ -37,10 +36,8 @@ namespace boost { namespace asio { namespace detail { -template +template class reactive_socket_service - : public boost::asio::detail::service_base< - reactive_socket_service > { public: // The protocol type. @@ -67,7 +64,7 @@ public: private: // Only this service will have access to the internal values. - friend class reactive_socket_service; + friend class reactive_socket_service; // The native socket representation. socket_type socket_; @@ -87,7 +84,7 @@ public: // User wants connection_aborted errors, which are disabled by default. enable_connection_aborted = 4, - // The user set the linger option. Needs to be checked when closing. + // The user set the linger option. Needs to be checked when closing. user_set_linger = 8 }; @@ -98,17 +95,13 @@ public: protocol_type protocol_; // Per-descriptor data used by the reactor. - typename Reactor::per_descriptor_data reactor_data_; + reactor::per_descriptor_data reactor_data_; }; - // The maximum number of buffers to support in a single operation. - enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; - // Constructor. reactive_socket_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - reactive_socket_service >(io_service), - reactor_(boost::asio::use_service(io_service)) + : io_service_impl_(use_service(io_service)), + reactor_(use_service(io_service)) { reactor_.init_task(); } @@ -553,23 +546,11 @@ public: return 0; } - // Copy buffers into array. - socket_ops::buf bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - socket_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - total_buffer_size += boost::asio::buffer_size(buffer); - } + buffer_sequence_adapter bufs(buffers); // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) + if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) { ec = boost::system::error_code(); return 0; @@ -579,7 +560,8 @@ public: for (;;) { // Try to complete the operation without blocking. - int bytes_sent = socket_ops::send(impl.socket_, bufs, i, flags, ec); + int bytes_sent = socket_ops::send(impl.socket_, + bufs.buffers(), bufs.count(), flags, ec); // Check if operation succeeded. if (bytes_sent >= 0) @@ -613,50 +595,32 @@ public: return 0; } - template - class send_operation : - public handler_base_from_member + template + class send_op_base : public reactor_op { public: - send_operation(socket_type socket, boost::asio::io_service& io_service, - const ConstBufferSequence& buffers, socket_base::message_flags flags, - Handler handler) - : handler_base_from_member(handler), + send_op_base(socket_type socket, const ConstBufferSequence& buffers, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&send_op_base::do_perform, complete_func), socket_(socket), - io_service_(io_service), - work_(io_service), buffers_(buffers), flags_(flags) { } - bool perform(boost::system::error_code& ec, - std::size_t& bytes_transferred) + static bool do_perform(reactor_op* base) { - // Check whether the operation was successful. - if (ec) - { - bytes_transferred = 0; - return true; - } + send_op_base* o(static_cast(base)); - // Copy buffers into array. - socket_ops::buf bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers_.begin(); - typename ConstBufferSequence::const_iterator end = buffers_.end(); - size_t i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - socket_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - } + buffer_sequence_adapter bufs(o->buffers_); for (;;) { // Send the data. - int bytes = socket_ops::send(socket_, bufs, i, flags_, ec); + boost::system::error_code ec; + int bytes = socket_ops::send(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, ec); // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) @@ -667,23 +631,57 @@ public: || ec == boost::asio::error::try_again) return false; - bytes_transferred = (bytes < 0 ? 0 : bytes); + o->ec_ = ec; + o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); return true; } } - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) + private: + socket_type socket_; + ConstBufferSequence buffers_; + socket_base::message_flags flags_; + }; + + template + class send_op : public send_op_base + { + public: + send_op(socket_type socket, const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + : send_op_base(socket, + buffers, flags, &send_op::do_complete), + handler_(handler) { - io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + send_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) + { + // 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(o->handler_, o->ec_, o->bytes_transferred_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } private: - socket_type socket_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; - ConstBufferSequence buffers_; - socket_base::message_flags flags_; + Handler handler_; }; // Start an asynchronous send. The data being sent must be valid for the @@ -692,102 +690,33 @@ public: void async_send(implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - if (impl.protocol_.type() == SOCK_STREAM) - { - // Determine total size of buffers. - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - total_buffer_size += boost::asio::buffer_size(buffer); - } + // Allocate and construct an operation to wrap the handler. + typedef send_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, + impl.socket_, buffers, flags, handler); - // A request to receive 0 bytes on a stream socket is a no-op. - if (total_buffer_size == 0) - { - this->get_io_service().post(bind_handler(handler, - boost::system::error_code(), 0)); - return; - } - } - - // Make socket non-blocking. - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - if (!(impl.flags_ & implementation_type::non_blocking)) - { - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - { - this->get_io_service().post(bind_handler(handler, ec, 0)); - return; - } - } - impl.flags_ |= implementation_type::internal_non_blocking; - } - - reactor_.start_write_op(impl.socket_, impl.reactor_data_, - send_operation( - impl.socket_, this->get_io_service(), buffers, flags, handler)); - } + start_op(impl, reactor::write_op, ptr.get(), true, + (impl.protocol_.type() == SOCK_STREAM + && buffer_sequence_adapter::all_empty(buffers))); + ptr.release(); } - template - class null_buffers_operation : - public handler_base_from_member - { - public: - null_buffers_operation(boost::asio::io_service& io_service, Handler handler) - : handler_base_from_member(handler), - work_(io_service) - { - } - - bool perform(boost::system::error_code&, - std::size_t& bytes_transferred) - { - bytes_transferred = 0; - return true; - } - - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - work_.get_io_service().post(bind_handler( - this->handler_, ec, bytes_transferred)); - } - - private: - boost::asio::io_service::work work_; - }; - // Start an asynchronous wait until data can be sent without blocking. template void async_send(implementation_type& impl, const null_buffers&, socket_base::message_flags, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - reactor_.start_write_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); + + start_op(impl, reactor::write_op, ptr.get(), false, false); + ptr.release(); } // Send a datagram to the specified endpoint. Returns the number of bytes @@ -803,25 +732,15 @@ public: return 0; } - // Copy buffers into array. - socket_ops::buf bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - socket_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - } + buffer_sequence_adapter bufs(buffers); // Send the data. for (;;) { // Try to complete the operation without blocking. - int bytes_sent = socket_ops::sendto(impl.socket_, bufs, i, flags, - destination.data(), destination.size(), ec); + int bytes_sent = socket_ops::sendto(impl.socket_, bufs.buffers(), + bufs.count(), flags, destination.data(), destination.size(), ec); // Check if operation succeeded. if (bytes_sent >= 0) @@ -856,52 +775,34 @@ public: return 0; } - template - class send_to_operation : - public handler_base_from_member + template + class send_to_op_base : public reactor_op { public: - send_to_operation(socket_type socket, boost::asio::io_service& io_service, - const ConstBufferSequence& buffers, const endpoint_type& endpoint, - socket_base::message_flags flags, Handler handler) - : handler_base_from_member(handler), + send_to_op_base(socket_type socket, const ConstBufferSequence& buffers, + const endpoint_type& endpoint, socket_base::message_flags flags, + func_type complete_func) + : reactor_op(&send_to_op_base::do_perform, complete_func), socket_(socket), - io_service_(io_service), - work_(io_service), buffers_(buffers), destination_(endpoint), flags_(flags) { } - bool perform(boost::system::error_code& ec, - std::size_t& bytes_transferred) + static bool do_perform(reactor_op* base) { - // Check whether the operation was successful. - if (ec) - { - bytes_transferred = 0; - return true; - } + send_to_op_base* o(static_cast(base)); - // Copy buffers into array. - socket_ops::buf bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers_.begin(); - typename ConstBufferSequence::const_iterator end = buffers_.end(); - size_t i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - socket_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - } + buffer_sequence_adapter bufs(o->buffers_); for (;;) { // Send the data. - int bytes = socket_ops::sendto(socket_, bufs, i, flags_, - destination_.data(), destination_.size(), ec); + boost::system::error_code ec; + int bytes = socket_ops::sendto(o->socket_, bufs.buffers(), bufs.count(), + o->flags_, o->destination_.data(), o->destination_.size(), ec); // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) @@ -912,26 +813,61 @@ public: || ec == boost::asio::error::try_again) return false; - bytes_transferred = (bytes < 0 ? 0 : bytes); + o->ec_ = ec; + o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); return true; } } - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); - } - private: socket_type socket_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; ConstBufferSequence buffers_; endpoint_type destination_; socket_base::message_flags flags_; }; + template + class send_to_op : public send_to_op_base + { + public: + send_to_op(socket_type socket, const ConstBufferSequence& buffers, + const endpoint_type& endpoint, socket_base::message_flags flags, + Handler handler) + : send_to_op_base(socket, + buffers, endpoint, flags, &send_to_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + send_to_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) + { + // 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(o->handler_, o->ec_, o->bytes_transferred_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } + } + + private: + Handler handler_; + }; + // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. template @@ -940,34 +876,15 @@ public: const endpoint_type& destination, socket_base::message_flags flags, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - // Make socket non-blocking. - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - if (!(impl.flags_ & implementation_type::non_blocking)) - { - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - { - this->get_io_service().post(bind_handler(handler, ec, 0)); - return; - } - } - impl.flags_ |= implementation_type::internal_non_blocking; - } + // Allocate and construct an operation to wrap the handler. + typedef send_to_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, impl.socket_, + buffers, destination, flags, handler); - reactor_.start_write_op(impl.socket_, impl.reactor_data_, - send_to_operation( - impl.socket_, this->get_io_service(), buffers, - destination, flags, handler)); - } + start_op(impl, reactor::write_op, ptr.get(), true, false); + ptr.release(); } // Start an asynchronous wait until data can be sent without blocking. @@ -975,17 +892,14 @@ public: void async_send_to(implementation_type& impl, const null_buffers&, socket_base::message_flags, const endpoint_type&, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - reactor_.start_write_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); + + start_op(impl, reactor::write_op, ptr.get(), false, false); + ptr.release(); } // Receive some data from the peer. Returns the number of bytes received. @@ -1000,23 +914,11 @@ public: return 0; } - // Copy buffers into array. - socket_ops::buf bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - socket_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - total_buffer_size += boost::asio::buffer_size(buffer); - } + buffer_sequence_adapter bufs(buffers); // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) + if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) { ec = boost::system::error_code(); return 0; @@ -1026,7 +928,8 @@ public: for (;;) { // Try to complete the operation without blocking. - int bytes_recvd = socket_ops::recv(impl.socket_, bufs, i, flags, ec); + int bytes_recvd = socket_ops::recv(impl.socket_, + bufs.buffers(), bufs.count(), flags, ec); // Check if operation succeeded. if (bytes_recvd > 0) @@ -1067,53 +970,35 @@ public: return 0; } - template - class receive_operation : - public handler_base_from_member + template + class receive_op_base : public reactor_op { public: - receive_operation(socket_type socket, int protocol_type, - boost::asio::io_service& io_service, + receive_op_base(socket_type socket, int protocol_type, const MutableBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - : handler_base_from_member(handler), + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&receive_op_base::do_perform, complete_func), socket_(socket), protocol_type_(protocol_type), - io_service_(io_service), - work_(io_service), buffers_(buffers), flags_(flags) { } - bool perform(boost::system::error_code& ec, - std::size_t& bytes_transferred) + static bool do_perform(reactor_op* base) { - // Check whether the operation was successful. - if (ec) - { - bytes_transferred = 0; - return true; - } + receive_op_base* o(static_cast(base)); - // Copy buffers into array. - socket_ops::buf bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers_.begin(); - typename MutableBufferSequence::const_iterator end = buffers_.end(); - size_t i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - socket_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - } + buffer_sequence_adapter bufs(o->buffers_); for (;;) { // Receive some data. - int bytes = socket_ops::recv(socket_, bufs, i, flags_, ec); - if (bytes == 0 && protocol_type_ == SOCK_STREAM) + boost::system::error_code ec; + int bytes = socket_ops::recv(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, ec); + if (bytes == 0 && o->protocol_type_ == SOCK_STREAM) ec = boost::asio::error::eof; // Retry operation if interrupted by signal. @@ -1125,26 +1010,61 @@ public: || ec == boost::asio::error::try_again) return false; - bytes_transferred = (bytes < 0 ? 0 : bytes); + o->ec_ = ec; + o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); return true; } } - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); - } - private: socket_type socket_; int protocol_type_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; MutableBufferSequence buffers_; socket_base::message_flags flags_; }; + template + class receive_op : public receive_op_base + { + public: + receive_op(socket_type socket, int protocol_type, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + : receive_op_base(socket, + protocol_type, buffers, flags, &receive_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + receive_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) + { + // 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(o->handler_, o->ec_, o->bytes_transferred_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } + } + + private: + Handler handler_; + }; + // Start an asynchronous receive. The buffer for the data being received // must be valid for the lifetime of the asynchronous operation. template @@ -1152,66 +1072,22 @@ public: const MutableBufferSequence& buffers, socket_base::message_flags flags, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - if (impl.protocol_.type() == SOCK_STREAM) - { - // Determine total size of buffers. - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - total_buffer_size += boost::asio::buffer_size(buffer); - } + // Allocate and construct an operation to wrap the handler. + typedef receive_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + int protocol_type = impl.protocol_.type(); + handler_ptr ptr(raw_ptr, impl.socket_, + protocol_type, buffers, flags, handler); - // A request to receive 0 bytes on a stream socket is a no-op. - if (total_buffer_size == 0) - { - this->get_io_service().post(bind_handler(handler, - boost::system::error_code(), 0)); - return; - } - } - - // Make socket non-blocking. - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - if (!(impl.flags_ & implementation_type::non_blocking)) - { - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - { - this->get_io_service().post(bind_handler(handler, ec, 0)); - return; - } - } - impl.flags_ |= implementation_type::internal_non_blocking; - } - - if (flags & socket_base::message_out_of_band) - { - reactor_.start_except_op(impl.socket_, impl.reactor_data_, - receive_operation( - impl.socket_, impl.protocol_.type(), - this->get_io_service(), buffers, flags, handler)); - } - else - { - reactor_.start_read_op(impl.socket_, impl.reactor_data_, - receive_operation( - impl.socket_, impl.protocol_.type(), - this->get_io_service(), buffers, flags, handler)); - } - } + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + ptr.get(), true, + (impl.protocol_.type() == SOCK_STREAM + && buffer_sequence_adapter::all_empty(buffers))); + ptr.release(); } // Wait until data can be received without blocking. @@ -1219,22 +1095,17 @@ public: void async_receive(implementation_type& impl, const null_buffers&, socket_base::message_flags flags, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else if (flags & socket_base::message_out_of_band) - { - reactor_.start_except_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler)); - } - else - { - reactor_.start_read_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + ptr.get(), false, false); + ptr.release(); } // Receive a datagram with the endpoint of the sender. Returns the number of @@ -1251,26 +1122,16 @@ public: return 0; } - // Copy buffers into array. - socket_ops::buf bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - size_t i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - socket_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - } + buffer_sequence_adapter bufs(buffers); // Receive some data. for (;;) { // Try to complete the operation without blocking. std::size_t addr_len = sender_endpoint.capacity(); - int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs, i, flags, - sender_endpoint.data(), &addr_len, ec); + int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs.buffers(), + bufs.count(), flags, sender_endpoint.data(), &addr_len, ec); // Check if operation succeeded. if (bytes_recvd > 0) @@ -1318,56 +1179,37 @@ public: return 0; } - template - class receive_from_operation : - public handler_base_from_member + template + class receive_from_op_base : public reactor_op { public: - receive_from_operation(socket_type socket, int protocol_type, - boost::asio::io_service& io_service, + receive_from_op_base(socket_type socket, int protocol_type, const MutableBufferSequence& buffers, endpoint_type& endpoint, - socket_base::message_flags flags, Handler handler) - : handler_base_from_member(handler), + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&receive_from_op_base::do_perform, complete_func), socket_(socket), protocol_type_(protocol_type), - io_service_(io_service), - work_(io_service), buffers_(buffers), sender_endpoint_(endpoint), flags_(flags) { } - bool perform(boost::system::error_code& ec, - std::size_t& bytes_transferred) + static bool do_perform(reactor_op* base) { - // Check whether the operation was successful. - if (ec) - { - bytes_transferred = 0; - return true; - } + receive_from_op_base* o(static_cast(base)); - // Copy buffers into array. - socket_ops::buf bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers_.begin(); - typename MutableBufferSequence::const_iterator end = buffers_.end(); - size_t i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - socket_ops::init_buf(bufs[i], - boost::asio::buffer_cast(buffer), - boost::asio::buffer_size(buffer)); - } + buffer_sequence_adapter bufs(o->buffers_); for (;;) { // Receive some data. - std::size_t addr_len = sender_endpoint_.capacity(); - int bytes = socket_ops::recvfrom(socket_, bufs, i, flags_, - sender_endpoint_.data(), &addr_len, ec); - if (bytes == 0 && protocol_type_ == SOCK_STREAM) + boost::system::error_code ec; + std::size_t addr_len = o->sender_endpoint_.capacity(); + int bytes = socket_ops::recvfrom(o->socket_, bufs.buffers(), + bufs.count(), o->flags_, o->sender_endpoint_.data(), &addr_len, ec); + if (bytes == 0 && o->protocol_type_ == SOCK_STREAM) ec = boost::asio::error::eof; // Retry operation if interrupted by signal. @@ -1379,28 +1221,63 @@ public: || ec == boost::asio::error::try_again) return false; - sender_endpoint_.resize(addr_len); - bytes_transferred = (bytes < 0 ? 0 : bytes); + o->sender_endpoint_.resize(addr_len); + o->ec_ = ec; + o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); return true; } } - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); - } - private: socket_type socket_; int protocol_type_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; MutableBufferSequence buffers_; endpoint_type& sender_endpoint_; socket_base::message_flags flags_; }; + template + class receive_from_op : public receive_from_op_base + { + public: + receive_from_op(socket_type socket, int protocol_type, + const MutableBufferSequence& buffers, endpoint_type& endpoint, + socket_base::message_flags flags, Handler handler) + : receive_from_op_base(socket, protocol_type, + buffers, endpoint, flags, &receive_from_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + receive_from_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) + { + // 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(o->handler_, o->ec_, o->bytes_transferred_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } + } + + private: + Handler handler_; + }; + // Start an asynchronous receive. The buffer for the data being received and // the sender_endpoint object must both be valid for the lifetime of the // asynchronous operation. @@ -1409,34 +1286,19 @@ public: const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - // Make socket non-blocking. - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - if (!(impl.flags_ & implementation_type::non_blocking)) - { - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - { - this->get_io_service().post(bind_handler(handler, ec, 0)); - return; - } - } - impl.flags_ |= implementation_type::internal_non_blocking; - } + // Allocate and construct an operation to wrap the handler. + typedef receive_from_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + int protocol_type = impl.protocol_.type(); + handler_ptr ptr(raw_ptr, impl.socket_, + protocol_type, buffers, sender_endpoint, flags, handler); - reactor_.start_read_op(impl.socket_, impl.reactor_data_, - receive_from_operation( - impl.socket_, impl.protocol_.type(), this->get_io_service(), - buffers, sender_endpoint, flags, handler)); - } + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + ptr.get(), true, false); + ptr.release(); } // Wait until data can be received without blocking. @@ -1445,28 +1307,20 @@ public: const null_buffers&, endpoint_type& sender_endpoint, socket_base::message_flags flags, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - // Reset endpoint since it can be given no sensible value at this time. - sender_endpoint = endpoint_type(); + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); - if (flags & socket_base::message_out_of_band) - { - reactor_.start_except_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler)); - } - else - { - reactor_.start_read_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } - } + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + ptr.get(), false, false); + ptr.release(); } // Accept a new connection. @@ -1546,19 +1400,15 @@ public: } } - template - class accept_operation : - public handler_base_from_member + template + class accept_op_base : public reactor_op { public: - accept_operation(socket_type socket, boost::asio::io_service& io_service, - Socket& peer, const protocol_type& protocol, - endpoint_type* peer_endpoint, bool enable_connection_aborted, - Handler handler) - : handler_base_from_member(handler), + accept_op_base(socket_type socket, Socket& peer, + const protocol_type& protocol, endpoint_type* peer_endpoint, + bool enable_connection_aborted, func_type complete_func) + : reactor_op(&accept_op_base::do_perform, complete_func), socket_(socket), - io_service_(io_service), - work_(io_service), peer_(peer), protocol_(protocol), peer_endpoint_(peer_endpoint), @@ -1566,27 +1416,25 @@ public: { } - bool perform(boost::system::error_code& ec, std::size_t&) + static bool do_perform(reactor_op* base) { - // Check whether the operation was successful. - if (ec) - return true; + accept_op_base* o(static_cast(base)); for (;;) { // Accept the waiting connection. + boost::system::error_code ec; socket_holder new_socket; std::size_t addr_len = 0; - if (peer_endpoint_) + std::size_t* addr_len_p = 0; + socket_addr_type* addr = 0; + if (o->peer_endpoint_) { - addr_len = peer_endpoint_->capacity(); - new_socket.reset(socket_ops::accept(socket_, - peer_endpoint_->data(), &addr_len, ec)); - } - else - { - new_socket.reset(socket_ops::accept(socket_, 0, 0, ec)); + addr_len = o->peer_endpoint_->capacity(); + addr_len_p = &addr_len; + addr = o->peer_endpoint_->data(); } + new_socket.reset(socket_ops::accept(o->socket_, addr, addr_len_p, ec)); // Retry operation if interrupted by signal. if (ec == boost::asio::error::interrupted) @@ -1597,83 +1445,95 @@ public: || ec == boost::asio::error::try_again) return false; if (ec == boost::asio::error::connection_aborted - && !enable_connection_aborted_) + && !o->enable_connection_aborted_) return false; #if defined(EPROTO) - if (ec.value() == EPROTO && !enable_connection_aborted_) + if (ec.value() == EPROTO && !o->enable_connection_aborted_) return false; #endif // defined(EPROTO) // Transfer ownership of the new socket to the peer object. if (!ec) { - if (peer_endpoint_) - peer_endpoint_->resize(addr_len); - peer_.assign(protocol_, new_socket.get(), ec); + if (o->peer_endpoint_) + o->peer_endpoint_->resize(addr_len); + o->peer_.assign(o->protocol_, new_socket.get(), ec); if (!ec) new_socket.release(); } + o->ec_ = ec; return true; } } - void complete(const boost::system::error_code& ec, std::size_t) - { - io_service_.post(bind_handler(this->handler_, ec)); - } - private: socket_type socket_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; Socket& peer_; protocol_type protocol_; endpoint_type* peer_endpoint_; bool enable_connection_aborted_; }; + template + class accept_op : public accept_op_base + { + public: + accept_op(socket_type socket, Socket& peer, const protocol_type& protocol, + endpoint_type* peer_endpoint, bool enable_connection_aborted, + Handler handler) + : accept_op_base(socket, peer, protocol, peer_endpoint, + enable_connection_aborted, &accept_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + accept_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) + { + // 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(o->handler_, o->ec_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } + } + + private: + Handler handler_; + }; + // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. template void async_accept(implementation_type& impl, Socket& peer, endpoint_type* peer_endpoint, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor)); - } - else if (peer.is_open()) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::already_open)); - } - else - { - // Make socket non-blocking. - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - if (!(impl.flags_ & implementation_type::non_blocking)) - { - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - { - this->get_io_service().post(bind_handler(handler, ec)); - return; - } - } - impl.flags_ |= implementation_type::internal_non_blocking; - } + // Allocate and construct an operation to wrap the handler. + typedef accept_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + bool enable_connection_aborted = + (impl.flags_ & implementation_type::enable_connection_aborted) != 0; + handler_ptr ptr(raw_ptr, impl.socket_, peer, + impl.protocol_, peer_endpoint, enable_connection_aborted, handler); - reactor_.start_read_op(impl.socket_, impl.reactor_data_, - accept_operation( - impl.socket_, this->get_io_service(), - peer, impl.protocol_, peer_endpoint, - (impl.flags_ & implementation_type::enable_connection_aborted) != 0, - handler)); - } + start_accept_op(impl, ptr.get(), peer.is_open()); + ptr.release(); } // Connect the socket to the specified endpoint. @@ -1713,53 +1573,77 @@ public: return ec; } - template - class connect_operation : - public handler_base_from_member + class connect_op_base : public reactor_op { public: - connect_operation(socket_type socket, - boost::asio::io_service& io_service, Handler handler) - : handler_base_from_member(handler), - socket_(socket), - io_service_(io_service), - work_(io_service) + connect_op_base(socket_type socket, func_type complete_func) + : reactor_op(&connect_op_base::do_perform, complete_func), + socket_(socket) { } - bool perform(boost::system::error_code& ec, std::size_t&) + static bool do_perform(reactor_op* base) { - // Check whether the operation was successful. - if (ec) - return true; + connect_op_base* o(static_cast(base)); // Get the error code from the connect operation. int connect_error = 0; size_t connect_error_len = sizeof(connect_error); - if (socket_ops::getsockopt(socket_, SOL_SOCKET, SO_ERROR, - &connect_error, &connect_error_len, ec) == socket_error_retval) + if (socket_ops::getsockopt(o->socket_, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, o->ec_) == socket_error_retval) return true; // The connection failed so the handler will be posted with an error code. if (connect_error) { - ec = boost::system::error_code(connect_error, + o->ec_ = boost::system::error_code(connect_error, boost::asio::error::get_system_category()); - return true; } return true; } - void complete(const boost::system::error_code& ec, std::size_t) + private: + socket_type socket_; + }; + + template + class connect_op : public connect_op_base + { + public: + connect_op(socket_type socket, Handler handler) + : connect_op_base(socket, &connect_op::do_complete), + handler_(handler) { - io_service_.post(bind_handler(this->handler_, ec)); + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + connect_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) + { + // 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(o->handler_, o->ec_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } private: - socket_type socket_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; + Handler handler_; }; // Start an asynchronous connect. @@ -1767,59 +1651,103 @@ public: void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor)); - return; - } + // Allocate and construct an operation to wrap the handler. + typedef connect_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, impl.socket_, handler); - // Make socket non-blocking. - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - if (!(impl.flags_ & implementation_type::non_blocking)) - { - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - { - this->get_io_service().post(bind_handler(handler, ec)); - return; - } - } - impl.flags_ |= implementation_type::internal_non_blocking; - } - - // Start the connect operation. The socket is already marked as non-blocking - // so the connection will take place asynchronously. - boost::system::error_code ec; - if (socket_ops::connect(impl.socket_, peer_endpoint.data(), - peer_endpoint.size(), ec) == 0) - { - // The connect operation has finished successfully so we need to post the - // handler immediately. - this->get_io_service().post(bind_handler(handler, - boost::system::error_code())); - } - else if (ec == boost::asio::error::in_progress - || ec == boost::asio::error::would_block) - { - // The connection is happening in the background, and we need to wait - // until the socket becomes writeable. - reactor_.start_connect_op(impl.socket_, impl.reactor_data_, - connect_operation(impl.socket_, - this->get_io_service(), handler)); - } - else - { - // The connect operation has failed, so post the handler immediately. - this->get_io_service().post(bind_handler(handler, ec)); - } + start_connect_op(impl, ptr.get(), peer_endpoint); + ptr.release(); } private: + // Start the asynchronous read or write operation. + void start_op(implementation_type& impl, int op_type, + reactor_op* op, bool non_blocking, bool noop) + { + if (!noop) + { + if (is_open(impl)) + { + if (!non_blocking || is_non_blocking(impl) + || set_non_blocking(impl, op->ec_)) + { + reactor_.start_op(op_type, impl.socket_, + impl.reactor_data_, op, non_blocking); + return; + } + } + else + op->ec_ = boost::asio::error::bad_descriptor; + } + + io_service_impl_.post_immediate_completion(op); + } + + // Start the asynchronous accept operation. + void start_accept_op(implementation_type& impl, + reactor_op* op, bool peer_is_open) + { + if (!peer_is_open) + start_op(impl, reactor::read_op, op, true, false); + else + { + op->ec_ = boost::asio::error::already_open; + io_service_impl_.post_immediate_completion(op); + } + } + + // Start the asynchronous connect operation. + void start_connect_op(implementation_type& impl, + reactor_op* op, const endpoint_type& peer_endpoint) + { + if (is_open(impl)) + { + if (is_non_blocking(impl) || set_non_blocking(impl, op->ec_)) + { + if (socket_ops::connect(impl.socket_, peer_endpoint.data(), + peer_endpoint.size(), op->ec_) != 0) + { + if (op->ec_ == boost::asio::error::in_progress + || op->ec_ == boost::asio::error::would_block) + { + op->ec_ = boost::system::error_code(); + reactor_.start_op(reactor::connect_op, + impl.socket_, impl.reactor_data_, op, true); + return; + } + } + } + } + else + op->ec_ = boost::asio::error::bad_descriptor; + + io_service_impl_.post_immediate_completion(op); + } + + // Determine whether the socket has been set non-blocking. + bool is_non_blocking(implementation_type& impl) const + { + return (impl.flags_ & implementation_type::non_blocking); + } + + // Set the internal non-blocking flag. + bool set_non_blocking(implementation_type& impl, + boost::system::error_code& ec) + { + ioctl_arg_type non_blocking = 1; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + return false; + impl.flags_ |= implementation_type::internal_non_blocking; + return true; + } + + // The io_service implementation used to post completions. + io_service_impl& io_service_impl_; + // The selector that performs event demultiplexing for the service. - Reactor& reactor_; + reactor& reactor_; }; } // namespace detail diff --git a/include/boost/asio/detail/reactor.hpp b/include/boost/asio/detail/reactor.hpp new file mode 100644 index 00000000..43e432b8 --- /dev/null +++ b/include/boost/asio/detail/reactor.hpp @@ -0,0 +1,34 @@ +// +// reactor.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_REACTOR_HPP +#define BOOST_ASIO_DETAIL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +#if defined(BOOST_ASIO_HAS_EPOLL) +# include +#elif defined(BOOST_ASIO_HAS_KQUEUE) +# include +#elif defined(BOOST_ASIO_HAS_DEV_POLL) +# include +#else +# include +#endif + +#include + +#endif // BOOST_ASIO_DETAIL_REACTOR_HPP diff --git a/include/boost/asio/detail/reactor_fwd.hpp b/include/boost/asio/detail/reactor_fwd.hpp new file mode 100644 index 00000000..9ff05eb5 --- /dev/null +++ b/include/boost/asio/detail/reactor_fwd.hpp @@ -0,0 +1,48 @@ +// +// reactor_fwd.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_REACTOR_FWD_HPP +#define BOOST_ASIO_DETAIL_REACTOR_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_HAS_IOCP) +typedef select_reactor reactor; +#elif defined(BOOST_ASIO_HAS_EPOLL) +typedef epoll_reactor reactor; +#elif defined(BOOST_ASIO_HAS_KQUEUE) +typedef kqueue_reactor reactor; +#elif defined(BOOST_ASIO_HAS_DEV_POLL) +typedef dev_poll_reactor reactor; +#else +typedef select_reactor reactor; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTOR_FWD_HPP diff --git a/include/boost/asio/detail/reactor_op.hpp b/include/boost/asio/detail/reactor_op.hpp new file mode 100644 index 00000000..40647ec8 --- /dev/null +++ b/include/boost/asio/detail/reactor_op.hpp @@ -0,0 +1,62 @@ +// +// reactor_op.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_REACTOR_OP_HPP +#define BOOST_ASIO_DETAIL_REACTOR_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class reactor_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + boost::system::error_code ec_; + + // The number of bytes transferred, to be passed to the completion handler. + std::size_t bytes_transferred_; + + // Perform the operation. Returns true if it is finished. + bool perform() + { + return perform_func_(this); + } + +protected: + typedef bool (*perform_func_type)(reactor_op*); + + reactor_op(perform_func_type perform_func, func_type complete_func) + : operation(complete_func), + bytes_transferred_(0), + perform_func_(perform_func) + { + } + +private: + perform_func_type perform_func_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTOR_OP_HPP diff --git a/include/boost/asio/detail/reactor_op_queue.hpp b/include/boost/asio/detail/reactor_op_queue.hpp index 46f0c104..0dd56540 100644 --- a/include/boost/asio/detail/reactor_op_queue.hpp +++ b/include/boost/asio/detail/reactor_op_queue.hpp @@ -17,14 +17,11 @@ #include -#include -#include -#include - #include -#include #include #include +#include +#include namespace boost { namespace asio { @@ -37,39 +34,21 @@ class reactor_op_queue public: // Constructor. reactor_op_queue() - : operations_(), - cancelled_operations_(0), - complete_operations_(0) + : operations_() { } // Add a new operation to the queue. Returns true if this is the only // operation for the given descriptor, in which case the reactor's event // demultiplexing function call may need to be interrupted and restarted. - template - bool enqueue_operation(Descriptor descriptor, Operation operation) + bool enqueue_operation(Descriptor descriptor, reactor_op* op) { - // Allocate and construct an object to wrap the handler. - typedef handler_alloc_traits > alloc_traits; - raw_handler_ptr raw_ptr(operation); - handler_ptr ptr(raw_ptr, descriptor, operation); - - typedef typename operation_map::iterator iterator; - typedef typename operation_map::value_type value_type; + typedef typename operations_map::iterator iterator; + typedef typename operations_map::value_type value_type; std::pair entry = - operations_.insert(value_type(descriptor, ptr.get())); - if (entry.second) - { - ptr.release(); - return true; - } - - op_base* current_op = entry.first->second; - while (current_op->next_) - current_op = current_op->next_; - current_op->next_ = ptr.release(); - - return false; + operations_.insert(value_type(descriptor, operations())); + entry.first->second.op_queue_.push(op); + return entry.second; } // Cancel all operations associated with the descriptor. Any operations @@ -77,16 +56,19 @@ public: // next time perform_cancellations is called. Returns true if any operations // were cancelled, in which case the reactor's event demultiplexing function // may need to be interrupted and restarted. - bool cancel_operations(Descriptor descriptor) + bool cancel_operations(Descriptor descriptor, op_queue& ops, + const boost::system::error_code& ec = + boost::asio::error::operation_aborted) { - typename operation_map::iterator i = operations_.find(descriptor); + typename operations_map::iterator i = operations_.find(descriptor); if (i != operations_.end()) { - op_base* last_op = i->second; - while (last_op->next_) - last_op = last_op->next_; - last_op->next_ = cancelled_operations_; - cancelled_operations_ = i->second; + while (reactor_op* op = i->second.op_queue_.front()) + { + op->ec_ = ec; + i->second.op_queue_.pop(); + ops.push(op); + } operations_.erase(i); return true; } @@ -106,79 +88,37 @@ public: return operations_.find(descriptor) != operations_.end(); } - // Perform the first operation corresponding to the descriptor. Returns true - // if there are more operations queued for the descriptor. - bool perform_operation(Descriptor descriptor, - const boost::system::error_code& result) + // Perform the operations corresponding to the descriptor. Returns true if + // there are still unfinished operations queued for the descriptor. + bool perform_operations(Descriptor descriptor, op_queue& ops) { - typename operation_map::iterator i = operations_.find(descriptor); + typename operations_map::iterator i = operations_.find(descriptor); if (i != operations_.end()) { - op_base* this_op = i->second; - i->second = this_op->next_; - this_op->next_ = complete_operations_; - complete_operations_ = this_op; - bool done = this_op->perform(result); - if (done) + while (reactor_op* op = i->second.op_queue_.front()) { - // Operation has finished. - if (i->second) + if (op->perform()) { - return true; + i->second.op_queue_.pop(); + ops.push(op); } else { - operations_.erase(i); - return false; - } - } - else - { - // Operation wants to be called again. Leave it at the front of the - // queue for this descriptor, and remove from the completed list. - complete_operations_ = this_op->next_; - this_op->next_ = i->second; - i->second = this_op; - return true; - } - } - return false; - } - - // Perform all operations corresponding to the descriptor. - void perform_all_operations(Descriptor descriptor, - const boost::system::error_code& result) - { - typename operation_map::iterator i = operations_.find(descriptor); - if (i != operations_.end()) - { - while (i->second) - { - op_base* this_op = i->second; - i->second = this_op->next_; - this_op->next_ = complete_operations_; - complete_operations_ = this_op; - bool done = this_op->perform(result); - if (!done) - { - // Operation has not finished yet, so leave at front of queue, and - // remove from the completed list. - complete_operations_ = this_op->next_; - this_op->next_ = i->second; - i->second = this_op; - return; + return true; } } operations_.erase(i); } + return false; } // Fill a descriptor set with the descriptors corresponding to each active - // operation. + // operation. The op_queue is used only when descriptors fail to be added to + // the descriptor set. template - void get_descriptors(Descriptor_Set& descriptors) + void get_descriptors(Descriptor_Set& descriptors, op_queue& ops) { - typename operation_map::iterator i = operations_.begin(); + typename operations_map::iterator i = operations_.begin(); while (i != operations_.end()) { Descriptor descriptor = i->first; @@ -186,7 +126,7 @@ public: if (!descriptors.set(descriptor)) { boost::system::error_code ec(error::fd_set_failure); - perform_all_operations(descriptor, ec); + cancel_operations(descriptor, ops, ec); } } } @@ -194,257 +134,62 @@ public: // Perform the operations corresponding to the ready file descriptors // contained in the given descriptor set. template - void perform_operations_for_descriptors(const Descriptor_Set& descriptors, - const boost::system::error_code& result) + void perform_operations_for_descriptors( + const Descriptor_Set& descriptors, op_queue& ops) { - typename operation_map::iterator i = operations_.begin(); + typename operations_map::iterator i = operations_.begin(); while (i != operations_.end()) { - typename operation_map::iterator op_iter = i++; + typename operations_map::iterator op_iter = i++; if (descriptors.is_set(op_iter->first)) { - op_base* this_op = op_iter->second; - op_iter->second = this_op->next_; - this_op->next_ = complete_operations_; - complete_operations_ = this_op; - bool done = this_op->perform(result); - if (done) + while (reactor_op* op = op_iter->second.op_queue_.front()) { - if (!op_iter->second) - operations_.erase(op_iter); - } - else - { - // Operation has not finished yet, so leave at front of queue, and - // remove from the completed list. - complete_operations_ = this_op->next_; - this_op->next_ = op_iter->second; - op_iter->second = this_op; + if (op->perform()) + { + op_iter->second.op_queue_.pop(); + ops.push(op); + } + else + { + break; + } } + + if (op_iter->second.op_queue_.empty()) + operations_.erase(op_iter); } } } - // Perform any pending cancels for operations. - void perform_cancellations() + // Get all operations owned by the queue. + void get_all_operations(op_queue& ops) { - while (cancelled_operations_) - { - op_base* this_op = cancelled_operations_; - cancelled_operations_ = this_op->next_; - this_op->next_ = complete_operations_; - complete_operations_ = this_op; - this_op->perform(boost::asio::error::operation_aborted); - } - } - - // Complete all operations that are waiting to be completed. - void complete_operations() - { - while (complete_operations_) - { - op_base* next_op = complete_operations_->next_; - complete_operations_->next_ = 0; - complete_operations_->complete(); - complete_operations_ = next_op; - } - } - - // Destroy all operations owned by the queue. - void destroy_operations() - { - while (cancelled_operations_) - { - op_base* next_op = cancelled_operations_->next_; - cancelled_operations_->next_ = 0; - cancelled_operations_->destroy(); - cancelled_operations_ = next_op; - } - - while (complete_operations_) - { - op_base* next_op = complete_operations_->next_; - complete_operations_->next_ = 0; - complete_operations_->destroy(); - complete_operations_ = next_op; - } - - typename operation_map::iterator i = operations_.begin(); + typename operations_map::iterator i = operations_.begin(); while (i != operations_.end()) { - typename operation_map::iterator op_iter = i++; - op_base* curr_op = op_iter->second; + typename operations_map::iterator op_iter = i++; + ops.push(op_iter->second.op_queue_); operations_.erase(op_iter); - while (curr_op) - { - op_base* next_op = curr_op->next_; - curr_op->next_ = 0; - curr_op->destroy(); - curr_op = next_op; - } } } private: - // Base class for reactor operations. A function pointer is used instead of - // virtual functions to avoid the associated overhead. - class op_base + struct operations { - public: - // Get the descriptor associated with the operation. - Descriptor descriptor() const - { - return descriptor_; - } + operations() {} + operations(const operations&) {} + void operator=(const operations&) {} - // Perform the operation. - bool perform(const boost::system::error_code& result) - { - result_ = result; - return perform_func_(this, result_, bytes_transferred_); - } - - // Destroy the operation and post the handler. - void complete() - { - complete_func_(this, result_, bytes_transferred_); - } - - // Destroy the operation. - void destroy() - { - destroy_func_(this); - } - - protected: - typedef bool (*perform_func_type)(op_base*, - boost::system::error_code&, std::size_t&); - typedef void (*complete_func_type)(op_base*, - const boost::system::error_code&, std::size_t); - typedef void (*destroy_func_type)(op_base*); - - // Construct an operation for the given descriptor. - op_base(perform_func_type perform_func, complete_func_type complete_func, - destroy_func_type destroy_func, Descriptor descriptor) - : perform_func_(perform_func), - complete_func_(complete_func), - destroy_func_(destroy_func), - descriptor_(descriptor), - result_(), - bytes_transferred_(0), - next_(0) - { - } - - // Prevent deletion through this type. - ~op_base() - { - } - - private: - friend class reactor_op_queue; - - // The function to be called to perform the operation. - perform_func_type perform_func_; - - // The function to be called to delete the operation and post the handler. - complete_func_type complete_func_; - - // The function to be called to delete the operation. - destroy_func_type destroy_func_; - - // The descriptor associated with the operation. - Descriptor descriptor_; - - // The result of the operation. - boost::system::error_code result_; - - // The number of bytes transferred in the operation. - std::size_t bytes_transferred_; - - // The next operation for the same file descriptor. - op_base* next_; - }; - - // Adaptor class template for operations. - template - class op - : public op_base - { - public: - // Constructor. - op(Descriptor descriptor, Operation operation) - : op_base(&op::do_perform, &op::do_complete, - &op::do_destroy, descriptor), - operation_(operation) - { - } - - // Perform the operation. - static bool do_perform(op_base* base, - boost::system::error_code& result, std::size_t& bytes_transferred) - { - return static_cast*>(base)->operation_.perform( - result, bytes_transferred); - } - - // Destroy the operation and post the handler. - static void do_complete(op_base* base, - const boost::system::error_code& result, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - typedef op this_type; - this_type* this_op(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(this_op->operation_, this_op); - - // Make a copy of the error_code and the operation so that the memory can - // be deallocated before the upcall is made. - boost::system::error_code ec(result); - Operation operation(this_op->operation_); - - // Free the memory associated with the operation. - ptr.reset(); - - // Make the upcall. - operation.complete(ec, bytes_transferred); - } - - // Destroy the operation. - static void do_destroy(op_base* base) - { - // Take ownership of the operation object. - typedef op this_type; - this_type* this_op(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(this_op->operation_, this_op); - - // A sub-object of the operation may be the true owner of the memory - // associated with the operation. Consequently, a local copy of the - // operation is required to ensure that any owning sub-object remains - // valid until after we have deallocated the memory here. - Operation operation(this_op->operation_); - (void)operation; - - // Free the memory associated with the operation. - ptr.reset(); - } - - private: - Operation operation_; + // The operations waiting on the desccriptor. + op_queue op_queue_; }; // The type for a map of operations. - typedef hash_map operation_map; + typedef hash_map operations_map; // The operations that are currently executing asynchronously. - operation_map operations_; - - // The list of operations that have been cancelled. - op_base* cancelled_operations_; - - // The list of operations waiting to be completed. - op_base* complete_operations_; + operations_map operations_; }; } // namespace detail diff --git a/include/boost/asio/detail/resolver_service.hpp b/include/boost/asio/detail/resolver_service.hpp index 3270cd67..22f98601 100644 --- a/include/boost/asio/detail/resolver_service.hpp +++ b/include/boost/asio/detail/resolver_service.hpp @@ -27,8 +27,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -89,7 +91,10 @@ public: : boost::asio::detail::service_base< resolver_service >(io_service), mutex_(), + io_service_impl_(boost::asio::use_service(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_)), work_thread_(0) { @@ -143,7 +148,7 @@ public: std::string service_name = query.service_name(); boost::asio::detail::addrinfo_type hints = query.hints(); - socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0, + socket_ops::getaddrinfo(!host_name.empty() ? host_name.c_str() : 0, service_name.c_str(), &hints, &address_info, ec); auto_addrinfo auto_address_info(address_info); @@ -154,54 +159,84 @@ public: } template - class resolve_query_handler + class resolve_op + : public operation { public: - resolve_query_handler(implementation_type impl, const query_type& query, - boost::asio::io_service& io_service, Handler handler) - : impl_(impl), + resolve_op(implementation_type impl, const query_type& query, + io_service_impl& io_service_impl, Handler handler) + : operation(&resolve_op::do_complete), + impl_(impl), query_(query), - io_service_(io_service), - work_(io_service), + io_service_impl_(io_service_impl), handler_(handler) { } - void operator()() + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) { - // Check if the operation has been cancelled. - if (impl_.expired()) + // Take ownership of the operation object. + resolve_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + if (owner) { - iterator_type iterator; - io_service_.post(boost::asio::detail::bind_handler(handler_, - boost::asio::error::operation_aborted, iterator)); - return; + if (owner != &o->io_service_impl_) + { + // The operation is being run on the worker io_service. Time to + // perform the resolver operation. + + if (o->impl_.expired()) + { + // THe operation has been cancelled. + o->ec_ = boost::asio::error::operation_aborted; + } + else + { + // Perform the blocking host resolution operation. + boost::asio::detail::addrinfo_type* address_info = 0; + std::string host_name = o->query_.host_name(); + std::string service_name = o->query_.service_name(); + boost::asio::detail::addrinfo_type hints = o->query_.hints(); + socket_ops::getaddrinfo(!host_name.empty() ? host_name.c_str() : 0, + service_name.c_str(), &hints, &address_info, o->ec_); + auto_addrinfo auto_address_info(address_info); + o->iter_ = iterator_type::create( + address_info, host_name, service_name); + } + + o->io_service_impl_.post_deferred_completion(o); + ptr.release(); + } + else + { + // The operation has been returned to the main io_serice. The + // completion handler is ready to be delivered. + + // 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(o->handler_, o->ec_, o->iter_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } - - // Perform the blocking host resolution operation. - boost::asio::detail::addrinfo_type* address_info = 0; - std::string host_name = query_.host_name(); - std::string service_name = query_.service_name(); - boost::asio::detail::addrinfo_type hints = query_.hints(); - boost::system::error_code ec; - socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0, - service_name.c_str(), &hints, &address_info, ec); - auto_addrinfo auto_address_info(address_info); - - // Invoke the handler and pass the result. - iterator_type iterator; - if (!ec) - iterator = iterator_type::create(address_info, host_name, service_name); - io_service_.post(boost::asio::detail::bind_handler( - handler_, ec, iterator)); } private: boost::weak_ptr impl_; query_type query_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; + io_service_impl& io_service_impl_; Handler handler_; + boost::system::error_code ec_; + iterator_type iter_; }; // Asynchronously resolve a query to a list of entries. @@ -209,12 +244,19 @@ public: void async_resolve(implementation_type& impl, const query_type& query, Handler handler) { + // Allocate and construct an operation to wrap the handler. + typedef resolve_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, + impl, query, io_service_impl_, handler); + if (work_io_service_) { start_work_thread(); - work_io_service_->post( - resolve_query_handler( - impl, query, this->get_io_service(), handler)); + io_service_impl_.work_started(); + work_io_service_impl_.post_immediate_completion(ptr.get()); + ptr.release(); } } @@ -243,61 +285,89 @@ public: } template - class resolve_endpoint_handler + class resolve_endpoint_op + : public operation { public: - resolve_endpoint_handler(implementation_type impl, - const endpoint_type& endpoint, boost::asio::io_service& io_service, - Handler handler) - : impl_(impl), - endpoint_(endpoint), - io_service_(io_service), - work_(io_service), + resolve_endpoint_op(implementation_type impl, const endpoint_type& ep, + io_service_impl& io_service_impl, Handler handler) + : operation(&resolve_endpoint_op::do_complete), + impl_(impl), + ep_(ep), + io_service_impl_(io_service_impl), handler_(handler) { } - void operator()() + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) { - // Check if the operation has been cancelled. - if (impl_.expired()) + // Take ownership of the operation object. + resolve_endpoint_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + if (owner) { - iterator_type iterator; - io_service_.post(boost::asio::detail::bind_handler(handler_, - boost::asio::error::operation_aborted, iterator)); - return; + if (owner != &o->io_service_impl_) + { + // The operation is being run on the worker io_service. Time to + // perform the resolver operation. + + if (o->impl_.expired()) + { + // THe operation has been cancelled. + o->ec_ = boost::asio::error::operation_aborted; + } + else + { + // Perform the blocking endoint resolution operation. + char host_name[NI_MAXHOST]; + char service_name[NI_MAXSERV]; + int flags = o->ep_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0; + socket_ops::getnameinfo(o->ep_.data(), o->ep_.size(), + host_name, NI_MAXHOST, service_name, + NI_MAXSERV, flags, o->ec_); + if (o->ec_) + { + flags |= NI_NUMERICSERV; + socket_ops::getnameinfo(o->ep_.data(), o->ep_.size(), + host_name, NI_MAXHOST, service_name, + NI_MAXSERV, flags, o->ec_); + } + o->iter_ = iterator_type::create(o->ep_, host_name, service_name); + } + + o->io_service_impl_.post_deferred_completion(o); + ptr.release(); + } + else + { + // The operation has been returned to the main io_serice. The + // completion handler is ready to be delivered. + + // 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(o->handler_, o->ec_, o->iter_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } - - - // First try resolving with the service name. If that fails try resolving - // but allow the service to be returned as a number. - char host_name[NI_MAXHOST]; - char service_name[NI_MAXSERV]; - int flags = endpoint_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0; - boost::system::error_code ec; - socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(), - host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); - if (ec) - { - flags |= NI_NUMERICSERV; - socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(), - host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); - } - - // Invoke the handler and pass the result. - iterator_type iterator; - if (!ec) - iterator = iterator_type::create(endpoint_, host_name, service_name); - io_service_.post(boost::asio::detail::bind_handler( - handler_, ec, iterator)); } private: boost::weak_ptr impl_; - endpoint_type endpoint_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; + endpoint_type ep_; + io_service_impl& io_service_impl_; Handler handler_; + boost::system::error_code ec_; + iterator_type iter_; }; // Asynchronously resolve an endpoint to a list of entries. @@ -305,12 +375,19 @@ public: void async_resolve(implementation_type& impl, const endpoint_type& endpoint, Handler handler) { + // Allocate and construct an operation to wrap the handler. + typedef resolve_endpoint_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, + impl, endpoint, io_service_impl_, handler); + if (work_io_service_) { start_work_thread(); - work_io_service_->post( - resolve_endpoint_handler( - impl, endpoint, this->get_io_service(), handler)); + io_service_impl_.work_started(); + work_io_service_impl_.post_immediate_completion(ptr.get()); + ptr.release(); } } @@ -340,9 +417,15 @@ private: // Mutex to protect access to internal data. boost::asio::detail::mutex mutex_; + // The io_service implementation used to post completions. + io_service_impl& io_service_impl_; + // Private io_service used for performing asynchronous host resolution. boost::scoped_ptr work_io_service_; + // The work io_service implementation used to post completions. + io_service_impl& work_io_service_impl_; + // Work for the private io_service to perform. boost::scoped_ptr work_; diff --git a/include/boost/asio/detail/select_reactor.hpp b/include/boost/asio/detail/select_reactor.hpp index ba8b5d3b..91030e91 100644 --- a/include/boost/asio/detail/select_reactor.hpp +++ b/include/boost/asio/detail/select_reactor.hpp @@ -22,9 +22,6 @@ #include #include #include -#include -#include -#include #include #include @@ -32,6 +29,8 @@ #include #include #include +#include +#include #include #include #include @@ -39,9 +38,11 @@ #include #include #include -#include #include -#include +#include +#include +#include +#include namespace boost { namespace asio { @@ -52,6 +53,14 @@ class select_reactor : public boost::asio::detail::service_base > { public: +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + enum { read_op = 0, write_op = 1, except_op = 2, + max_select_ops = 3, connect_op = 3, max_ops = 4 }; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + enum { read_op = 0, write_op = 1, except_op = 2, + max_select_ops = 3, connect_op = 1, max_ops = 3 }; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Per-descriptor data. struct per_descriptor_data { @@ -61,13 +70,9 @@ public: select_reactor(boost::asio::io_service& io_service) : boost::asio::detail::service_base< select_reactor >(io_service), + io_service_(use_service(io_service)), mutex_(), - select_in_progress_(false), interrupter_(), - read_op_queue_(), - write_op_queue_(), - except_op_queue_(), - pending_cancellations_(), stop_thread_(false), thread_(0), shutdown_(false) @@ -94,31 +99,29 @@ public: stop_thread_ = true; lock.unlock(); - if (thread_) + if (Own_Thread) { - interrupter_.interrupt(); - thread_->join(); - delete thread_; - thread_ = 0; + if (thread_) + { + interrupter_.interrupt(); + thread_->join(); + delete thread_; + thread_ = 0; + } } - read_op_queue_.destroy_operations(); - write_op_queue_.destroy_operations(); - except_op_queue_.destroy_operations(); + op_queue ops; - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->destroy_timers(); - timer_queues_.clear(); + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); + + timer_queues_.get_all_timers(ops); } // Initialise the task, but only if the reactor is not in its own thread. void init_task() { - if (!Own_Thread) - { - typedef task_io_service > task_io_service_type; - use_service(this->get_io_service()).init_task(); - } + io_service_.init_task(); } // Register a socket with the reactor. Returns 0 on success, system error @@ -128,111 +131,17 @@ public: return 0; } - // Start a new read operation. The handler object will be invoked when the - // given descriptor is ready to be read, or an error has occurred. - template - void start_read_op(socket_type descriptor, per_descriptor_data&, - Handler handler, bool /*allow_speculative_read*/ = true) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_) - if (read_op_queue_.enqueue_operation(descriptor, handler)) - interrupter_.interrupt(); - } - - // Start a new write operation. The handler object will be invoked when the - // given descriptor is ready to be written, or an error has occurred. - template - void start_write_op(socket_type descriptor, per_descriptor_data&, - Handler handler, bool /*allow_speculative_write*/ = true) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_) - if (write_op_queue_.enqueue_operation(descriptor, handler)) - interrupter_.interrupt(); - } - - // Start a new exception operation. The handler object will be invoked when - // the given descriptor has exception information, or an error has occurred. - template - void start_except_op(socket_type descriptor, - per_descriptor_data&, Handler handler) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_) - if (except_op_queue_.enqueue_operation(descriptor, handler)) - interrupter_.interrupt(); - } - - // Wrapper for connect handlers to enable the handler object to be placed - // in both the write and the except operation queues, but ensure that only - // one of the handlers is called. - template - class connect_handler_wrapper - { - public: - connect_handler_wrapper(socket_type descriptor, - boost::shared_ptr completed, - select_reactor& reactor, Handler handler) - : descriptor_(descriptor), - completed_(completed), - reactor_(reactor), - handler_(handler) - { - } - - bool perform(boost::system::error_code& ec, - std::size_t& bytes_transferred) - { - // Check whether one of the handlers has already been called. If it has, - // then we don't want to do anything in this handler. - if (*completed_) - { - completed_.reset(); // Indicate that this handler should not complete. - return true; - } - - // Cancel the other reactor operation for the connection. - *completed_ = true; - reactor_.enqueue_cancel_ops_unlocked(descriptor_); - - // Call the contained handler. - return handler_.perform(ec, bytes_transferred); - } - - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - if (completed_.get()) - handler_.complete(ec, bytes_transferred); - } - - private: - socket_type descriptor_; - boost::shared_ptr completed_; - select_reactor& reactor_; - Handler handler_; - }; - - // Start new write and exception operations. The handler object will be - // invoked when the given descriptor is ready for writing or has exception - // information available, or an error has occurred. The handler will be called - // only once. - template - void start_connect_op(socket_type descriptor, - per_descriptor_data&, Handler handler) + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + void start_op(int op_type, socket_type descriptor, + per_descriptor_data&, reactor_op* op, bool) { boost::asio::detail::mutex::scoped_lock lock(mutex_); if (!shutdown_) { - boost::shared_ptr completed(new bool(false)); - connect_handler_wrapper wrapped_handler( - descriptor, completed, *this, handler); - bool interrupt = write_op_queue_.enqueue_operation( - descriptor, wrapped_handler); - interrupt = except_op_queue_.enqueue_operation( - descriptor, wrapped_handler) || interrupt; - if (interrupt) + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + io_service_.work_started(); + if (first) interrupter_.interrupt(); } } @@ -243,17 +152,7 @@ public: void cancel_ops(socket_type descriptor, per_descriptor_data&) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor); - } - - // Enqueue cancellation of all operations associated with the given - // descriptor. The handlers associated with the descriptor will be invoked - // with the operation_aborted error. This function does not acquire the - // select_reactor's mutex, and so should only be used when the reactor lock is - // already held. - void enqueue_cancel_ops_unlocked(socket_type descriptor) - { - pending_cancellations_.push_back(descriptor); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); } // Cancel any operations that are running against the descriptor and remove @@ -261,7 +160,7 @@ public: void close_descriptor(socket_type descriptor, per_descriptor_data&) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); } // Add a new timer queue to the reactor. @@ -269,7 +168,7 @@ public: void add_timer_queue(timer_queue& timer_queue) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.push_back(&timer_queue); + timer_queues_.insert(&timer_queue); } // Remove a timer queue from the reactor. @@ -277,147 +176,111 @@ public: void remove_timer_queue(timer_queue& timer_queue) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - if (timer_queues_[i] == &timer_queue) - { - timer_queues_.erase(timer_queues_.begin() + i); - return; - } - } + timer_queues_.erase(&timer_queue); } - // Schedule a timer in the given timer queue to expire at the specified - // absolute time. The handler object will be invoked when the timer expires. - template + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, Handler handler, void* token) + const typename Time_Traits::time_type& time, timer_op* op, void* token) { boost::asio::detail::mutex::scoped_lock lock(mutex_); if (!shutdown_) - if (timer_queue.enqueue_timer(time, handler, token)) + { + bool earliest = timer_queue.enqueue_timer(time, op, token); + io_service_.work_started(); + if (earliest) interrupter_.interrupt(); + } } - // Cancel the timer associated with the given token. Returns the number of - // handlers that have been posted or dispatched. + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. template std::size_t cancel_timer(timer_queue& timer_queue, void* token) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - std::size_t n = timer_queue.cancel_timer(token); - if (n > 0) - interrupter_.interrupt(); + op_queue ops; + std::size_t n = timer_queue.cancel_timer(token, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); return n; } -private: - friend class task_io_service >; - // Run select once until interrupted or events are ready to be dispatched. - void run(bool block) + void run(bool block, op_queue& ops) { boost::asio::detail::mutex::scoped_lock lock(mutex_); - // Dispatch any operation cancellations that were made while the select - // loop was not running. - read_op_queue_.perform_cancellations(); - write_op_queue_.perform_cancellations(); - except_op_queue_.perform_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->dispatch_cancellations(); - // Check if the thread is supposed to stop. - if (stop_thread_) + if (Own_Thread) + if (stop_thread_) + return; + + // Set up the descriptor sets. + fd_set_adapter fds[max_select_ops]; + fds[read_op].set(interrupter_.read_descriptor()); + socket_type max_fd = 0; + bool have_work_to_do = !timer_queues_.all_empty(); + for (int i = 0; i < max_select_ops; ++i) { - complete_operations_and_timers(lock); - return; + have_work_to_do = have_work_to_do || !op_queue_[i].empty(); + op_queue_[i].get_descriptors(fds[i], ops); + if (fds[i].max_descriptor() > max_fd) + max_fd = fds[i].max_descriptor(); } +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Connection operations on Windows use both except and write fd_sets. + have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty(); + op_queue_[connect_op].get_descriptors(fds[write_op], ops); + if (fds[write_op].max_descriptor() > max_fd) + max_fd = fds[write_op].max_descriptor(); + op_queue_[connect_op].get_descriptors(fds[except_op], ops); + if (fds[except_op].max_descriptor() > max_fd) + max_fd = fds[except_op].max_descriptor(); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // We can return immediately if there's no work to do and the reactor is // not supposed to block. - if (!block && read_op_queue_.empty() && write_op_queue_.empty() - && except_op_queue_.empty() && all_timer_queues_are_empty()) - { - complete_operations_and_timers(lock); + if (!block && !have_work_to_do) return; - } - // Set up the descriptor sets. - fd_set_adapter read_fds; - read_fds.set(interrupter_.read_descriptor()); - read_op_queue_.get_descriptors(read_fds); - fd_set_adapter write_fds; - write_op_queue_.get_descriptors(write_fds); - fd_set_adapter except_fds; - except_op_queue_.get_descriptors(except_fds); - socket_type max_fd = read_fds.max_descriptor(); - if (write_fds.max_descriptor() > max_fd) - max_fd = write_fds.max_descriptor(); - if (except_fds.max_descriptor() > max_fd) - max_fd = except_fds.max_descriptor(); - - // Block on the select call without holding the lock so that new - // operations can be started while the call is executing. + // Determine how long to block while waiting for events. timeval tv_buf = { 0, 0 }; timeval* tv = block ? get_timeout(tv_buf) : &tv_buf; - select_in_progress_ = true; + lock.unlock(); + + // Block on the select call until descriptors become ready. boost::system::error_code ec; int retval = socket_ops::select(static_cast(max_fd + 1), - read_fds, write_fds, except_fds, tv, ec); - lock.lock(); - select_in_progress_ = false; + fds[read_op], fds[write_op], fds[except_op], tv, ec); // Reset the interrupter. - if (retval > 0 && read_fds.is_set(interrupter_.read_descriptor())) + if (retval > 0 && fds[read_op].is_set(interrupter_.read_descriptor())) interrupter_.reset(); + lock.lock(); + // Dispatch all ready operations. if (retval > 0) { +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Connection operations on Windows use both except and write fd_sets. + op_queue_[connect_op].perform_operations_for_descriptors( + fds[except_op], ops); + op_queue_[connect_op].perform_operations_for_descriptors( + fds[write_op], ops); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Exception operations must be processed first to ensure that any // out-of-band data is read before normal data. - except_op_queue_.perform_operations_for_descriptors( - except_fds, boost::system::error_code()); - read_op_queue_.perform_operations_for_descriptors( - read_fds, boost::system::error_code()); - write_op_queue_.perform_operations_for_descriptors( - write_fds, boost::system::error_code()); - except_op_queue_.perform_cancellations(); - read_op_queue_.perform_cancellations(); - write_op_queue_.perform_cancellations(); + for (int i = max_select_ops - 1; i >= 0; --i) + op_queue_[i].perform_operations_for_descriptors(fds[i], ops); } - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - timer_queues_[i]->dispatch_timers(); - timer_queues_[i]->dispatch_cancellations(); - } - - // Issue any pending cancellations. - for (size_t i = 0; i < pending_cancellations_.size(); ++i) - cancel_ops_unlocked(pending_cancellations_[i]); - pending_cancellations_.clear(); - - complete_operations_and_timers(lock); - } - - // Run the select loop in the thread. - void run_thread() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - while (!stop_thread_) - { - lock.unlock(); - run(true); - lock.lock(); - } - } - - // Entry point for the select loop thread. - static void call_run_thread(select_reactor* reactor) - { - reactor->run_thread(); + timer_queues_.get_ready_timers(ops); } // Interrupt the select loop. @@ -426,103 +289,73 @@ private: interrupter_.interrupt(); } - // Check if all timer queues are empty. - bool all_timer_queues_are_empty() const +private: + // Run the select loop in the thread. + void run_thread() { - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - if (!timer_queues_[i]->empty()) - return false; - return true; + if (Own_Thread) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + while (!stop_thread_) + { + lock.unlock(); + op_queue ops; + run(true, ops); + io_service_.post_deferred_completions(ops); + lock.lock(); + } + } + } + + // Entry point for the select loop thread. + static void call_run_thread(select_reactor* reactor) + { + if (Own_Thread) + { + reactor->run_thread(); + } } // Get the timeout value for the select call. timeval* get_timeout(timeval& tv) { - if (all_timer_queues_are_empty()) - return 0; - // 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. - boost::posix_time::time_duration minimum_wait_duration - = boost::posix_time::minutes(5); - - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - boost::posix_time::time_duration wait_duration - = timer_queues_[i]->wait_duration(); - if (wait_duration < minimum_wait_duration) - minimum_wait_duration = wait_duration; - } - - if (minimum_wait_duration > boost::posix_time::time_duration()) - { - tv.tv_sec = minimum_wait_duration.total_seconds(); - tv.tv_usec = minimum_wait_duration.total_microseconds() % 1000000; - } - else - { - tv.tv_sec = 0; - tv.tv_usec = 0; - } - + long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; return &tv; } - // Cancel all operations associated with the given descriptor. The do_cancel - // function of the handler objects will be invoked. This function does not - // acquire the select_reactor's mutex. - void cancel_ops_unlocked(socket_type descriptor) + // Cancel all operations associated with the given descriptor. This function + // does not acquire the select_reactor's mutex. + void cancel_ops_unlocked(socket_type descriptor, + const boost::system::error_code& ec) { - bool interrupt = read_op_queue_.cancel_operations(descriptor); - interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt; - interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt; - if (interrupt) + bool need_interrupt = false; + op_queue ops; + 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); + if (need_interrupt) interrupter_.interrupt(); } - // Clean up operations and timers. We must not hold the lock since the - // destructors may make calls back into this reactor. We make a copy of the - // vector of timer queues since the original may be modified while the lock - // is not held. - void complete_operations_and_timers( - boost::asio::detail::mutex::scoped_lock& lock) - { - timer_queues_for_cleanup_ = timer_queues_; - lock.unlock(); - read_op_queue_.complete_operations(); - write_op_queue_.complete_operations(); - except_op_queue_.complete_operations(); - for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i) - timer_queues_for_cleanup_[i]->complete_timers(); - } + // The io_service implementation used to post completions. + io_service_impl& io_service_; // Mutex to protect access to internal data. boost::asio::detail::mutex mutex_; - // Whether the select loop is currently running or not. - bool select_in_progress_; - // The interrupter is used to break a blocking select call. select_interrupter interrupter_; - // The queue of read operations. - reactor_op_queue read_op_queue_; - - // The queue of write operations. - reactor_op_queue write_op_queue_; - - // The queue of exception operations. - reactor_op_queue except_op_queue_; + // The queues of read, write and except operations. + reactor_op_queue op_queue_[max_ops]; // The timer queues. - std::vector timer_queues_; - - // A copy of the timer queues, used when cleaning up timers. The copy is - // stored as a class data member to avoid unnecessary memory allocation. - std::vector timer_queues_for_cleanup_; - - // The descriptors that are pending cancellation. - std::vector pending_cancellations_; + timer_queue_set timer_queues_; // Does the reactor loop thread need to stop. bool stop_thread_; diff --git a/include/boost/asio/detail/service_registry.hpp b/include/boost/asio/detail/service_registry.hpp index b648939f..e640ec86 100644 --- a/include/boost/asio/detail/service_registry.hpp +++ b/include/boost/asio/detail/service_registry.hpp @@ -18,7 +18,6 @@ #include #include -#include #include #include @@ -80,7 +79,7 @@ public: while (first_service_) { boost::asio::io_service::service* next_service = first_service_->next_; - delete first_service_; + destroy(first_service_); first_service_ = next_service; } } @@ -91,41 +90,10 @@ public: template Service& use_service() { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - // First see if there is an existing service object for the given type. - boost::asio::io_service::service* service = first_service_; - while (service) - { - if (service_id_matches(*service, Service::id)) - return *static_cast(service); - service = service->next_; - } - - // Create a new service object. The service registry's mutex is not locked - // at this time to allow for nested calls into this function from the new - // service's constructor. - lock.unlock(); - std::auto_ptr new_service(new Service(owner_)); - init_service_id(*new_service, Service::id); - Service& new_service_ref = *new_service; - lock.lock(); - - // Check that nobody else created another service object of the same type - // while the lock was released. - service = first_service_; - while (service) - { - if (service_id_matches(*service, Service::id)) - return *static_cast(service); - service = service->next_; - } - - // Service was successfully initialised, pass ownership to registry. - new_service->next_ = first_service_; - first_service_ = new_service.release(); - - return new_service_ref; + boost::asio::io_service::service::key key; + init_key(key, Service::id); + factory_type factory = &service_registry::create; + return *static_cast(do_use_service(key, factory)); } // Add a service object. Returns false on error, in which case ownership of @@ -133,35 +101,156 @@ public: template bool add_service(Service* new_service) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - // Check if there is an existing service object for the given type. - boost::asio::io_service::service* service = first_service_; - while (service) - { - if (service_id_matches(*service, Service::id)) - return false; - service = service->next_; - } - - // Take ownership of the service object. - init_service_id(*new_service, Service::id); - new_service->next_ = first_service_; - first_service_ = new_service; - - return true; + boost::asio::io_service::service::key key; + init_key(key, Service::id); + return do_add_service(key, new_service); } // Check whether a service object of the specified type already exists. template bool has_service() const + { + boost::asio::io_service::service::key key; + init_key(key, Service::id); + return do_has_service(key); + } + +private: + // Initialise a service's key based on its id. + void init_key(boost::asio::io_service::service::key& key, + const boost::asio::io_service::id& id) + { + key.type_info_ = 0; + key.id_ = &id; + } + +#if !defined(BOOST_ASIO_NO_TYPEID) + // Initialise a service's key based on its id. + template + void init_key(boost::asio::io_service::service::key& key, + const boost::asio::detail::service_id& /*id*/) + { + key.type_info_ = &typeid(typeid_wrapper); + key.id_ = 0; + } +#endif // !defined(BOOST_ASIO_NO_TYPEID) + + // Check if a service matches the given id. + static bool keys_match( + const boost::asio::io_service::service::key& key1, + const boost::asio::io_service::service::key& key2) + { + if (key1.id_ && key2.id_) + if (key1.id_ == key2.id_) + return true; + if (key1.type_info_ && key2.type_info_) + if (*key1.type_info_ == *key2.type_info_) + return true; + return false; + } + + // The type of a factory function used for creating a service instance. + typedef boost::asio::io_service::service* + (*factory_type)(boost::asio::io_service&); + + // Factory function for creating a service instance. + template + static boost::asio::io_service::service* create( + boost::asio::io_service& owner) + { + return new Service(owner); + } + + // Destroy a service instance. + static void destroy(boost::asio::io_service::service* service) + { + delete service; + } + + // Helper class to manage service pointers. + struct auto_service_ptr + { + boost::asio::io_service::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::io_service::service* do_use_service( + const boost::asio::io_service::service::key& key, + factory_type factory) + { + 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_; + while (service) + { + if (keys_match(service->key_, key)) + return service; + service = service->next_; + } + + // Create a new service object. The service registry's mutex is not locked + // 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_) }; + new_service.ptr_->key_ = key; + lock.lock(); + + // Check that nobody else created another service object of the same type + // while the lock was released. + service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return service; + service = service->next_; + } + + // Service was successfully initialised, pass ownership to registry. + new_service.ptr_->next_ = first_service_; + first_service_ = new_service.ptr_; + new_service.ptr_ = 0; + return first_service_; + } + + // Add a service object. Returns false on error, in which case ownership of + // the object is retained by the caller. + bool do_add_service( + const boost::asio::io_service::service::key& key, + boost::asio::io_service::service* new_service) + { + 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_; + while (service) + { + if (keys_match(service->key_, key)) + return false; + service = service->next_; + } + + // Take ownership of the service object. + new_service->key_ = key; + new_service->next_ = first_service_; + first_service_ = new_service; + + return true; + } + + // Check whether a service object with the specified key already exists. + bool do_has_service(const boost::asio::io_service::service::key& key) const { boost::asio::detail::mutex::scoped_lock lock(mutex_); boost::asio::io_service::service* service = first_service_; while (service) { - if (service_id_matches(*service, Service::id)) + if (keys_match(service->key_, key)) return true; service = service->next_; } @@ -169,46 +258,6 @@ public: return false; } -private: - // Set a service's id. - void init_service_id(boost::asio::io_service::service& service, - const boost::asio::io_service::id& id) - { - service.type_info_ = 0; - service.id_ = &id; - } - -#if !defined(BOOST_ASIO_NO_TYPEID) - // Set a service's id. - template - void init_service_id(boost::asio::io_service::service& service, - const boost::asio::detail::service_id& /*id*/) - { - service.type_info_ = &typeid(typeid_wrapper); - service.id_ = 0; - } -#endif // !defined(BOOST_ASIO_NO_TYPEID) - - // Check if a service matches the given id. - static bool service_id_matches( - const boost::asio::io_service::service& service, - const boost::asio::io_service::id& id) - { - return service.id_ == &id; - } - -#if !defined(BOOST_ASIO_NO_TYPEID) - // Check if a service matches the given id. - template - static bool service_id_matches( - const boost::asio::io_service::service& service, - const boost::asio::detail::service_id& /*id*/) - { - return service.type_info_ != 0 - && *service.type_info_ == typeid(typeid_wrapper); - } -#endif // !defined(BOOST_ASIO_NO_TYPEID) - // Mutex to protect access to internal data. mutable boost::asio::detail::mutex mutex_; diff --git a/include/boost/asio/detail/solaris_fenced_block.hpp b/include/boost/asio/detail/solaris_fenced_block.hpp new file mode 100644 index 00000000..be9803e7 --- /dev/null +++ b/include/boost/asio/detail/solaris_fenced_block.hpp @@ -0,0 +1,59 @@ +// +// solaris_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SOLARIS_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if defined(__sun) + +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class solaris_fenced_block + : private noncopyable +{ +public: + // Constructor. + solaris_fenced_block() + { + membar_consumer(); + } + + // Destructor. + ~solaris_fenced_block() + { + membar_producer(); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(__sun) + +#include + +#endif // BOOST_ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/strand_service.hpp b/include/boost/asio/detail/strand_service.hpp index b228cec3..d6b45b1a 100644 --- a/include/boost/asio/detail/strand_service.hpp +++ b/include/boost/asio/detail/strand_service.hpp @@ -18,19 +18,19 @@ #include #include -#include -#include #include #include #include #include -#include #include +#include +#include #include #include #include -#include +#include +#include #include namespace boost { @@ -41,252 +41,45 @@ namespace detail { class strand_service : public boost::asio::detail::service_base { +private: + struct on_do_complete_exit; + struct on_dispatch_exit; + public: - class handler_base; - class invoke_current_handler; - class post_next_waiter_on_exit; // The underlying implementation of a strand. class strand_impl + : public operation { public: strand_impl() - : current_handler_(0), - first_waiter_(0), - last_waiter_(0) + : operation(&strand_service::do_complete), + count_(0) { } private: // Only this service will have access to the internal values. friend class strand_service; - friend class post_next_waiter_on_exit; - friend class invoke_current_handler; + friend struct on_do_complete_exit; + friend struct on_dispatch_exit; // Mutex to protect access to internal data. boost::asio::detail::mutex mutex_; - // The handler that is ready to execute. If this pointer is non-null then it - // indicates that a handler holds the lock. - handler_base* current_handler_; + // The count of handlers in the strand, including the upcall (if any). + std::size_t count_; - // The start of the list of waiting handlers for the strand. - handler_base* first_waiter_; - - // The end of the list of waiting handlers for the strand. - handler_base* last_waiter_; - - // Storage for posted handlers. - typedef boost::aligned_storage<128> handler_storage_type; -#if defined(__BORLANDC__) - boost::aligned_storage<128> handler_storage_; -#else - handler_storage_type handler_storage_; -#endif + // The handlers waiting on the strand. + op_queue queue_; }; - friend class strand_impl; - typedef strand_impl* implementation_type; - // Base class for all handler types. - class handler_base - { - public: - typedef void (*invoke_func_type)(handler_base*, - strand_service&, implementation_type&); - typedef void (*destroy_func_type)(handler_base*); - - handler_base(invoke_func_type invoke_func, destroy_func_type destroy_func) - : next_(0), - invoke_func_(invoke_func), - destroy_func_(destroy_func) - { - } - - void invoke(strand_service& service_impl, implementation_type& impl) - { - invoke_func_(this, service_impl, impl); - } - - void destroy() - { - destroy_func_(this); - } - - protected: - ~handler_base() - { - } - - private: - friend class strand_service; - friend class strand_impl; - friend class post_next_waiter_on_exit; - handler_base* next_; - invoke_func_type invoke_func_; - destroy_func_type destroy_func_; - }; - - // Helper class to allow handlers to be dispatched. - class invoke_current_handler - { - public: - invoke_current_handler(strand_service& service_impl, - const implementation_type& impl) - : service_impl_(service_impl), - impl_(impl) - { - } - - void operator()() - { - impl_->current_handler_->invoke(service_impl_, impl_); - } - - friend void* asio_handler_allocate(std::size_t size, - invoke_current_handler* this_handler) - { - return this_handler->do_handler_allocate(size); - } - - friend void asio_handler_deallocate(void*, std::size_t, - invoke_current_handler*) - { - } - - void* do_handler_allocate(std::size_t size) - { -#if defined(__BORLANDC__) - BOOST_ASSERT(size <= boost::aligned_storage<128>::size); -#else - BOOST_ASSERT(size <= strand_impl::handler_storage_type::size); -#endif - (void)size; - return impl_->handler_storage_.address(); - } - - // The asio_handler_invoke hook is not defined here since the default one - // provides the correct behaviour, and including it here breaks MSVC 7.1 - // in some situations. - - private: - strand_service& service_impl_; - implementation_type impl_; - }; - - // Helper class to automatically enqueue next waiter on block exit. - class post_next_waiter_on_exit - { - public: - post_next_waiter_on_exit(strand_service& service_impl, - implementation_type& impl) - : service_impl_(service_impl), - impl_(impl), - cancelled_(false) - { - } - - ~post_next_waiter_on_exit() - { - if (!cancelled_) - { - boost::asio::detail::mutex::scoped_lock lock(impl_->mutex_); - impl_->current_handler_ = impl_->first_waiter_; - if (impl_->current_handler_) - { - impl_->first_waiter_ = impl_->first_waiter_->next_; - if (impl_->first_waiter_ == 0) - impl_->last_waiter_ = 0; - lock.unlock(); - service_impl_.get_io_service().post( - invoke_current_handler(service_impl_, impl_)); - } - } - } - - void cancel() - { - cancelled_ = true; - } - - private: - strand_service& service_impl_; - implementation_type& impl_; - bool cancelled_; - }; - - // Class template for a waiter. - template - class handler_wrapper - : public handler_base - { - public: - handler_wrapper(Handler handler) - : handler_base(&handler_wrapper::do_invoke, - &handler_wrapper::do_destroy), - handler_(handler) - { - } - - static void do_invoke(handler_base* base, - strand_service& service_impl, implementation_type& impl) - { - // Take ownership of the handler object. - typedef handler_wrapper this_type; - this_type* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(h->handler_, h); - - post_next_waiter_on_exit p1(service_impl, impl); - - // Make a copy of the handler so that the memory can be deallocated before - // the upcall is made. - Handler handler(h->handler_); - - // A handler object must still be valid when the next waiter is posted - // since destroying the last handler might cause the strand object to be - // destroyed. Therefore we create a second post_next_waiter_on_exit object - // that will be destroyed before the handler object. - p1.cancel(); - post_next_waiter_on_exit p2(service_impl, impl); - - // Free the memory associated with the handler. - ptr.reset(); - - // Indicate that this strand is executing on the current thread. - call_stack::context ctx(impl); - - // Make the upcall. - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - - static void do_destroy(handler_base* base) - { - // Take ownership of the handler object. - typedef handler_wrapper this_type; - this_type* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(h->handler_, h); - - // 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(h->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); - } - - private: - Handler handler_; - }; - // Construct a new strand service for the specified io_service. explicit strand_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base(io_service), + io_service_(boost::asio::use_service(io_service)), mutex_(), salt_(0) { @@ -295,37 +88,13 @@ public: // Destroy all user-defined handler objects owned by the service. void shutdown_service() { - // Construct a list of all handlers to be destroyed. - boost::asio::detail::mutex::scoped_lock lock(mutex_); - handler_base* first_handler = 0; - for (std::size_t i = 0; i < num_implementations; ++i) - { - if (strand_impl* impl = implementations_[i].get()) - { - if (impl->current_handler_) - { - impl->current_handler_->next_ = first_handler; - first_handler = impl->current_handler_; - impl->current_handler_ = 0; - } - if (impl->first_waiter_) - { - impl->last_waiter_->next_ = first_handler; - first_handler = impl->first_waiter_; - impl->first_waiter_ = 0; - impl->last_waiter_ = 0; - } - } - } + op_queue ops; - // Destroy all handlers without holding the lock. - lock.unlock(); - while (first_handler) - { - handler_base* next = first_handler->next_; - first_handler->destroy(); - first_handler = next; - } + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + for (std::size_t i = 0; i < num_implementations; ++i) + if (strand_impl* impl = implementations_[i].get()) + ops.push(impl->queue_); } // Construct a new strand implementation. @@ -352,45 +121,54 @@ public: template void dispatch(implementation_type& impl, Handler handler) { + // If we are already in the strand then the handler can run immediately. if (call_stack::contains(impl)) { + boost::asio::detail::fenced_block b; boost_asio_handler_invoke_helpers::invoke(handler, handler); + return; } - else + + // Allocate and construct an object to wrap the handler. + typedef completion_handler value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); + + // If we are running inside the io_service, and no other handler is queued + // or running, then the handler can run immediately. + bool can_dispatch = call_stack::contains(&io_service_); + impl->mutex_.lock(); + bool first = (++impl->count_ == 1); + if (can_dispatch && first) { - // Allocate and construct an object to wrap the handler. - typedef handler_wrapper value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + // Immediate invocation is allowed. + impl->mutex_.unlock(); - boost::asio::detail::mutex::scoped_lock lock(impl->mutex_); + // Memory must be releaesed before any upcall is made. + ptr.reset(); - if (impl->current_handler_ == 0) - { - // This handler now has the lock, so can be dispatched immediately. - impl->current_handler_ = ptr.release(); - lock.unlock(); - this->get_io_service().dispatch(invoke_current_handler(*this, impl)); - } - else - { - // Another handler already holds the lock, so this handler must join - // the list of waiters. The handler will be posted automatically when - // its turn comes. - if (impl->last_waiter_) - { - impl->last_waiter_->next_ = ptr.get(); - impl->last_waiter_ = impl->last_waiter_->next_; - } - else - { - impl->first_waiter_ = ptr.get(); - impl->last_waiter_ = ptr.get(); - } - ptr.release(); - } + // Indicate that this strand is executing on the current thread. + call_stack::context ctx(impl); + + // Ensure the next handler, if any, is scheduled on block exit. + on_dispatch_exit on_exit = { &io_service_, impl }; + (void)on_exit; + + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + return; } + + // Immediate invocation is not allowed, so enqueue for later. + impl->queue_.push(ptr.get()); + impl->mutex_.unlock(); + ptr.release(); + + // The first handler to be enqueued is responsible for scheduling the + // strand. + if (first) + io_service_.post_immediate_completion(impl); } // Request the io_service to invoke the given handler and return immediately. @@ -398,40 +176,85 @@ public: void post(implementation_type& impl, Handler handler) { // Allocate and construct an object to wrap the handler. - typedef handler_wrapper value_type; + typedef completion_handler value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); handler_ptr ptr(raw_ptr, handler); - boost::asio::detail::mutex::scoped_lock lock(impl->mutex_); + // Add the handler to the queue. + impl->mutex_.lock(); + bool first = (++impl->count_ == 1); + impl->queue_.push(ptr.get()); + impl->mutex_.unlock(); + ptr.release(); - if (impl->current_handler_ == 0) - { - // This handler now has the lock, so can be dispatched immediately. - impl->current_handler_ = ptr.release(); - lock.unlock(); - this->get_io_service().post(invoke_current_handler(*this, impl)); - } - else - { - // Another handler already holds the lock, so this handler must join the - // list of waiters. The handler will be posted automatically when its turn - // comes. - if (impl->last_waiter_) - { - impl->last_waiter_->next_ = ptr.get(); - impl->last_waiter_ = impl->last_waiter_->next_; - } - else - { - impl->first_waiter_ = ptr.get(); - impl->last_waiter_ = ptr.get(); - } - ptr.release(); - } + // The first handler to be enqueue is responsible for scheduling the strand. + if (first) + io_service_.post_immediate_completion(impl); } private: + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + if (owner) + { + strand_impl* impl = static_cast(base); + + // Get the next handler to be executed. + impl->mutex_.lock(); + operation* o = impl->queue_.front(); + impl->queue_.pop(); + impl->mutex_.unlock(); + + // Indicate that this strand is executing on the current thread. + call_stack::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; + + o->complete(*owner); + } + } + + // Helper class to re-post the strand on exit. + struct on_do_complete_exit + { + io_service_impl* owner_; + strand_impl* impl_; + + ~on_do_complete_exit() + { + impl_->mutex_.lock(); + bool more_handlers = (--impl_->count_ > 0); + impl_->mutex_.unlock(); + + if (more_handlers) + owner_->post_immediate_completion(impl_); + } + }; + + // Helper class to re-post the strand on exit. + struct on_dispatch_exit + { + io_service_impl* io_service_; + strand_impl* impl_; + + ~on_dispatch_exit() + { + impl_->mutex_.lock(); + bool more_handlers = (--impl_->count_ > 0); + impl_->mutex_.unlock(); + + if (more_handlers) + io_service_->post_immediate_completion(impl_); + } + }; + + // The io_service implementation used to post completions. + io_service_impl& io_service_; + // Mutex to protect access to the array of implementations. boost::asio::detail::mutex mutex_; diff --git a/include/boost/asio/detail/task_io_service.hpp b/include/boost/asio/detail/task_io_service.hpp index ddfea72e..fe6af3ce 100644 --- a/include/boost/asio/detail/task_io_service.hpp +++ b/include/boost/asio/detail/task_io_service.hpp @@ -15,21 +15,25 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#if defined(BOOST_ASIO_ENABLE_TWO_LOCK_QUEUE) -#include -#else // defined(BOOST_ASIO_ENABLE_TWO_LOCK_QUEUE) - #include #include #include +#include #include +#include #include #include -#include #include +#include #include #include +#include + +#include +#include +#include +#include namespace boost { namespace asio { @@ -40,6 +44,8 @@ class task_io_service : public boost::asio::detail::service_base > { public: + typedef task_io_service_operation operation; + // Constructor. task_io_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base >(io_service), @@ -65,12 +71,12 @@ public: lock.unlock(); // Destroy handler objects. - while (!handler_queue_.empty()) + while (!op_queue_.empty()) { - handler_queue::handler* h = handler_queue_.front(); - handler_queue_.pop(); - if (h != &task_handler_) - h->destroy(); + operation* o = op_queue_.front(); + op_queue_.pop(); + if (o != &task_operation_) + o->destroy(); } // Reset to initial state. @@ -84,14 +90,21 @@ public: if (!shutdown_ && !task_) { task_ = &use_service(this->get_io_service()); - handler_queue_.push(&task_handler_); - interrupt_one_idle_thread(lock); + op_queue_.push(&task_operation_); + wake_one_thread_and_unlock(lock); } } // Run the event loop until interrupted or no more work. size_t run(boost::system::error_code& ec) { + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + typename call_stack::context ctx(this); idle_thread_info this_idle_thread; @@ -100,7 +113,7 @@ public: boost::asio::detail::mutex::scoped_lock lock(mutex_); size_t n = 0; - while (do_one(lock, &this_idle_thread, ec)) + for (; do_one(lock, &this_idle_thread); lock.lock()) if (n != (std::numeric_limits::max)()) ++n; return n; @@ -109,6 +122,13 @@ public: // Run until interrupted or one operation is performed. size_t run_one(boost::system::error_code& ec) { + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + typename call_stack::context ctx(this); idle_thread_info this_idle_thread; @@ -116,18 +136,25 @@ public: boost::asio::detail::mutex::scoped_lock lock(mutex_); - return do_one(lock, &this_idle_thread, ec); + return do_one(lock, &this_idle_thread); } // Poll for operations without blocking. size_t poll(boost::system::error_code& ec) { + if (outstanding_work_ == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + typename call_stack::context ctx(this); boost::asio::detail::mutex::scoped_lock lock(mutex_); size_t n = 0; - while (do_one(lock, 0, ec)) + for (; do_one(lock, 0); lock.lock()) if (n != (std::numeric_limits::max)()) ++n; return n; @@ -136,11 +163,18 @@ public: // Poll for one operation without blocking. size_t poll_one(boost::system::error_code& ec) { + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + typename call_stack::context ctx(this); boost::asio::detail::mutex::scoped_lock lock(mutex_); - return do_one(lock, 0, ec); + return do_one(lock, 0); } // Interrupt the event processing loop. @@ -160,16 +194,14 @@ public: // Notify that some work has started. void work_started() { - boost::asio::detail::mutex::scoped_lock lock(mutex_); ++outstanding_work_; } // Notify that some work has finished. void work_finished() { - boost::asio::detail::mutex::scoped_lock lock(mutex_); if (--outstanding_work_ == 0) - stop_all_threads(lock); + stop(); } // Request invocation of the given handler. @@ -177,7 +209,10 @@ public: void dispatch(Handler handler) { if (call_stack::contains(this)) + { + boost::asio::detail::fenced_block b; boost_asio_handler_invoke_helpers::invoke(handler, handler); + } else post(handler); } @@ -187,29 +222,41 @@ public: void post(Handler handler) { // Allocate and construct an operation to wrap the handler. - handler_queue::scoped_ptr ptr(handler_queue::wrap(handler)); + typedef completion_handler value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - // If the service has been shut down we silently discard the handler. - if (shutdown_) - return; - - // Add the handler to the end of the queue. - handler_queue_.push(ptr.get()); + post_immediate_completion(ptr.get()); ptr.release(); + } - // An undelivered handler is treated as unfinished work. - ++outstanding_work_; + // 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(operation* op) + { + work_started(); + post_deferred_completion(op); + } - // Wake up a thread to execute the handler. - if (!interrupt_one_idle_thread(lock)) + // Request invocation of the given operation and return immediately. Assumes + // that work_started() was previously called for the operation. + void post_deferred_completion(operation* op) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue_.push(op); + wake_one_thread_and_unlock(lock); + } + + // Request invocation of the given operations and return immediately. Assumes + // that work_started() was previously called for each operation. + void post_deferred_completions(op_queue& ops) + { + if (!ops.empty()) { - if (!task_interrupted_ && task_) - { - task_interrupted_ = true; - task_->interrupt(); - } + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue_.push(ops); + wake_one_thread_and_unlock(lock); } } @@ -217,57 +264,60 @@ private: struct idle_thread_info; size_t do_one(boost::asio::detail::mutex::scoped_lock& lock, - idle_thread_info* this_idle_thread, boost::system::error_code& ec) + idle_thread_info* this_idle_thread) { - if (outstanding_work_ == 0 && !stopped_) - { - stop_all_threads(lock); - ec = boost::system::error_code(); - return 0; - } - bool polling = !this_idle_thread; bool task_has_run = false; while (!stopped_) { - if (!handler_queue_.empty()) + if (!op_queue_.empty()) { // Prepare to execute first handler from queue. - handler_queue::handler* h = handler_queue_.front(); - handler_queue_.pop(); + operation* o = op_queue_.front(); + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); - if (h == &task_handler_) + if (o == &task_operation_) { - bool more_handlers = (!handler_queue_.empty()); task_interrupted_ = more_handlers || polling; // If the task has already run and we're polling then we're done. if (task_has_run && polling) { task_interrupted_ = true; - handler_queue_.push(&task_handler_); - ec = boost::system::error_code(); + op_queue_.push(&task_operation_); return 0; } task_has_run = true; - lock.unlock(); - task_cleanup c(lock, *this); + if (more_handlers) + wake_one_idle_thread_and_unlock(lock); + else + lock.unlock(); - // Run the task. May throw an exception. Only block if the handler - // queue is empty and we have an idle_thread_info object, otherwise - // we want to return as soon as possible. - task_->run(!more_handlers && !polling); + op_queue completed_ops; + task_cleanup c = { this, &lock, &completed_ops }; + (void)c; + + // 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 && !polling, completed_ops); } else { - lock.unlock(); - handler_cleanup c(lock, *this); + if (more_handlers) + wake_one_thread_and_unlock(lock); + else + lock.unlock(); - // Invoke the handler. May throw an exception. - h->invoke(); // invoke() deletes the handler object + // Ensure the count of outstanding work is decremented on block exit. + work_finished_on_block_exit on_exit = { this }; + (void)on_exit; + + // Complete the operation. May throw an exception. + o->complete(*this); // deletes the operation object - ec = boost::system::error_code(); return 1; } } @@ -281,12 +331,10 @@ private: } else { - ec = boost::system::error_code(); return 0; } } - ec = boost::system::error_code(); return 0; } @@ -295,34 +343,7 @@ private: boost::asio::detail::mutex::scoped_lock& lock) { stopped_ = true; - interrupt_all_idle_threads(lock); - if (!task_interrupted_ && task_) - { - task_interrupted_ = true; - task_->interrupt(); - } - } - // Interrupt a single idle thread. Returns true if a thread was interrupted, - // false if no running thread could be found to interrupt. - bool interrupt_one_idle_thread( - boost::asio::detail::mutex::scoped_lock& lock) - { - if (first_idle_thread_) - { - idle_thread_info* idle_thread = first_idle_thread_; - first_idle_thread_ = idle_thread->next; - idle_thread->next = 0; - idle_thread->wakeup_event.signal(lock); - return true; - } - return false; - } - - // Interrupt all idle threads. - void interrupt_all_idle_threads( - boost::asio::detail::mutex::scoped_lock& lock) - { while (first_idle_thread_) { idle_thread_info* idle_thread = first_idle_thread_; @@ -330,57 +351,75 @@ private: idle_thread->next = 0; idle_thread->wakeup_event.signal(lock); } + + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } + } + + // Wakes a single idle thread and unlocks the mutex. Returns true if an idle + // thread was found. If there is no idle thread, returns false and leaves the + // mutex locked. + bool wake_one_idle_thread_and_unlock( + boost::asio::detail::mutex::scoped_lock& lock) + { + if (first_idle_thread_) + { + idle_thread_info* idle_thread = first_idle_thread_; + first_idle_thread_ = idle_thread->next; + idle_thread->next = 0; + idle_thread->wakeup_event.signal_and_unlock(lock); + return true; + } + return false; + } + + // Wake a single idle thread, or the task, and always unlock the mutex. + void wake_one_thread_and_unlock( + boost::asio::detail::mutex::scoped_lock& lock) + { + if (!wake_one_idle_thread_and_unlock(lock)) + { + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } + lock.unlock(); + } } // Helper class to perform task-related operations on block exit. - class task_cleanup; - friend class task_cleanup; - class task_cleanup + struct task_cleanup; + friend struct task_cleanup; + struct task_cleanup { - public: - task_cleanup(boost::asio::detail::mutex::scoped_lock& lock, - task_io_service& task_io_svc) - : lock_(lock), - task_io_service_(task_io_svc) - { - } - ~task_cleanup() { - // Reinsert the task at the end of the handler queue. - lock_.lock(); - task_io_service_.task_interrupted_ = true; - task_io_service_.handler_queue_.push(&task_io_service_.task_handler_); + // 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(*ops_); + task_io_service_->op_queue_.push(&task_io_service_->task_operation_); } - private: - boost::asio::detail::mutex::scoped_lock& lock_; - task_io_service& task_io_service_; + task_io_service* task_io_service_; + boost::asio::detail::mutex::scoped_lock* lock_; + op_queue* ops_; }; - // Helper class to perform handler-related operations on block exit. - class handler_cleanup; - friend class handler_cleanup; - class handler_cleanup + // Helper class to call work_finished() on block exit. + struct work_finished_on_block_exit { - public: - handler_cleanup(boost::asio::detail::mutex::scoped_lock& lock, - task_io_service& task_io_svc) - : lock_(lock), - task_io_service_(task_io_svc) + ~work_finished_on_block_exit() { + task_io_service_->work_finished(); } - ~handler_cleanup() - { - lock_.lock(); - if (--task_io_service_.outstanding_work_ == 0) - task_io_service_.stop_all_threads(lock_); - } - - private: - boost::asio::detail::mutex::scoped_lock& lock_; - task_io_service& task_io_service_; + task_io_service* task_io_service_; }; // Mutex to protect access to internal data. @@ -389,25 +428,20 @@ private: // The task to be run by this service. Task* task_; - // Handler object to represent the position of the task in the queue. - class task_handler - : public handler_queue::handler + // Operation object to represent the position of the task in the queue. + struct task_operation : public operation { - public: - task_handler() - : handler_queue::handler(0, 0) - { - } - } task_handler_; + task_operation() : operation(0) {} + } task_operation_; // Whether the task has been interrupted. bool task_interrupted_; // The count of unfinished work. - int outstanding_work_; + boost::detail::atomic_count outstanding_work_; // The queue of handlers that are ready to be delivered. - handler_queue handler_queue_; + op_queue op_queue_; // Flag to indicate that the dispatcher has been stopped. bool stopped_; @@ -422,7 +456,7 @@ private: idle_thread_info* next; }; - // The number of threads that are currently idle. + // The threads that are currently idle. idle_thread_info* first_idle_thread_; }; @@ -430,9 +464,6 @@ private: } // namespace asio } // namespace boost -#include #include -#endif // defined(BOOST_ASIO_ENABLE_TWO_LOCK_QUEUE) - #endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP diff --git a/include/boost/asio/detail/task_io_service_2lock.hpp b/include/boost/asio/detail/task_io_service_2lock.hpp deleted file mode 100644 index 71bceefb..00000000 --- a/include/boost/asio/detail/task_io_service_2lock.hpp +++ /dev/null @@ -1,475 +0,0 @@ -// -// task_io_service_2lock.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2010 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_TASK_IO_SERVICE_2LOCK_HPP -#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_2LOCK_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace boost { -namespace asio { -namespace detail { - -// An alternative task_io_service implementation based on a two-lock queue. - -template -class task_io_service - : public boost::asio::detail::service_base > -{ -public: - typedef indirect_handler_queue handler_queue; - - // Constructor. - task_io_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base >(io_service), - front_mutex_(), - back_mutex_(), - task_(0), - outstanding_work_(0), - front_stopped_(false), - back_stopped_(false), - back_shutdown_(false), - back_first_idle_thread_(0), - back_task_thread_(0) - { - } - - void init(size_t /*concurrency_hint*/) - { - } - - // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); - back_shutdown_ = true; - back_lock.unlock(); - - // Destroy handler objects. - while (handler_queue::handler* h = handler_queue_.pop()) - if (h != &task_handler_) - h->destroy(); - - // Reset to initial state. - task_ = 0; - } - - // Initialise the task, if required. - void init_task() - { - boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); - if (!back_shutdown_ && !task_) - { - task_ = &use_service(this->get_io_service()); - handler_queue_.push(&task_handler_); - interrupt_one_idle_thread(back_lock); - } - } - - // Run the event loop until interrupted or no more work. - size_t run(boost::system::error_code& ec) - { - if (outstanding_work_ == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - typename call_stack::context ctx(this); - - idle_thread_info this_idle_thread; - this_idle_thread.next = 0; - - size_t n = 0; - while (do_one(&this_idle_thread, ec)) - if (n != (std::numeric_limits::max)()) - ++n; - return n; - } - - // Run until interrupted or one operation is performed. - size_t run_one(boost::system::error_code& ec) - { - if (outstanding_work_ == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - typename call_stack::context ctx(this); - - idle_thread_info this_idle_thread; - this_idle_thread.next = 0; - - return do_one(&this_idle_thread, ec); - } - - // Poll for operations without blocking. - size_t poll(boost::system::error_code& ec) - { - if (outstanding_work_ == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - typename call_stack::context ctx(this); - - size_t n = 0; - while (do_one(0, ec)) - if (n != (std::numeric_limits::max)()) - ++n; - return n; - } - - // Poll for one operation without blocking. - size_t poll_one(boost::system::error_code& ec) - { - if (outstanding_work_ == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - typename call_stack::context ctx(this); - - return do_one(0, ec); - } - - // Interrupt the event processing loop. - void stop() - { - boost::asio::detail::mutex::scoped_lock front_lock(front_mutex_); - front_stopped_ = true; - front_lock.unlock(); - - boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); - back_stopped_ = true; - interrupt_all_idle_threads(back_lock); - } - - // Reset in preparation for a subsequent run invocation. - void reset() - { - boost::asio::detail::mutex::scoped_lock front_lock(front_mutex_); - front_stopped_ = false; - front_lock.unlock(); - - boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); - back_stopped_ = false; - } - - // Notify that some work has started. - void work_started() - { - ++outstanding_work_; - } - - // Notify that some work has finished. - void work_finished() - { - if (--outstanding_work_ == 0) - stop(); - } - - // Request invocation of the given handler. - template - void dispatch(Handler handler) - { - if (call_stack::contains(this)) - boost_asio_handler_invoke_helpers::invoke(handler, handler); - else - post(handler); - } - - // Request invocation of the given handler and return immediately. - template - void post(Handler handler) - { - // Allocate and construct an operation to wrap the handler. - handler_queue::scoped_ptr ptr(handler_queue::wrap(handler)); - - boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); - - // If the service has been shut down we silently discard the handler. - if (back_shutdown_) - return; - - // Add the handler to the end of the queue. - handler_queue_.push(ptr.get()); - ptr.release(); - - // An undelivered handler is treated as unfinished work. - ++outstanding_work_; - - // Wake up a thread to execute the handler. - interrupt_one_idle_thread(back_lock); - } - -private: - struct idle_thread_info; - - size_t do_one(idle_thread_info* this_idle_thread, - boost::system::error_code& ec) - { - bool task_has_run = false; - for (;;) - { - // The front lock must be held before we can pop items from the queue. - boost::asio::detail::mutex::scoped_lock front_lock(front_mutex_); - if (front_stopped_) - { - ec = boost::system::error_code(); - return 0; - } - - if (handler_queue::handler* h = handler_queue_.pop()) - { - if (h == &task_handler_) - { - bool more_handlers = handler_queue_.poppable(); - unsigned long front_version = handler_queue_.front_version(); - front_lock.unlock(); - - // The task is always added to the back of the queue when we exit - // this block. - task_cleanup c(*this); - - // If we're polling and the task has already run then we're done. - bool polling = !this_idle_thread; - if (task_has_run && polling) - { - ec = boost::system::error_code(); - return 0; - } - - // If we're considering going idle we need to check whether the queue - // is still empty. If it is, add the thread to the list of idle - // threads. - if (!more_handlers && !polling) - { - boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); - if (back_stopped_) - { - ec = boost::system::error_code(); - return 0; - } - else if (front_version == handler_queue_.back_version()) - { - back_task_thread_ = this_idle_thread; - } - else - { - more_handlers = true; - } - } - - // Run the task. May throw an exception. Only block if the handler - // queue is empty and we're not polling, otherwise we want to return - // as soon as possible. - task_has_run = true; - task_->run(!more_handlers && !polling); - } - else - { - front_lock.unlock(); - handler_cleanup c(*this); - - // Invoke the handler. May throw an exception. - h->invoke(); // invoke() deletes the handler object - - ec = boost::system::error_code(); - return 1; - } - } - else if (this_idle_thread) - { - unsigned long front_version = handler_queue_.front_version(); - front_lock.unlock(); - - // If we're considering going idle we need to check whether the queue - // is still empty. If it is, add the thread to the list of idle - // threads. - boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); - if (back_stopped_) - { - ec = boost::system::error_code(); - return 0; - } - else if (front_version == handler_queue_.back_version()) - { - this_idle_thread->next = back_first_idle_thread_; - back_first_idle_thread_ = this_idle_thread; - this_idle_thread->wakeup_event.clear(back_lock); - this_idle_thread->wakeup_event.wait(back_lock); - } - } - else - { - ec = boost::system::error_code(); - return 0; - } - } - } - - // Interrupt a single idle thread. - void interrupt_one_idle_thread( - boost::asio::detail::mutex::scoped_lock& back_lock) - { - if (back_first_idle_thread_) - { - idle_thread_info* idle_thread = back_first_idle_thread_; - back_first_idle_thread_ = idle_thread->next; - idle_thread->next = 0; - idle_thread->wakeup_event.signal(back_lock); - } - else if (back_task_thread_ && task_) - { - back_task_thread_ = 0; - task_->interrupt(); - } - } - - // Interrupt all idle threads. - void interrupt_all_idle_threads( - boost::asio::detail::mutex::scoped_lock& back_lock) - { - while (back_first_idle_thread_) - { - idle_thread_info* idle_thread = back_first_idle_thread_; - back_first_idle_thread_ = idle_thread->next; - idle_thread->next = 0; - idle_thread->wakeup_event.signal(back_lock); - } - - if (back_task_thread_ && task_) - { - back_task_thread_ = 0; - task_->interrupt(); - } - } - - // Helper class to perform task-related operations on block exit. - class task_cleanup; - friend class task_cleanup; - class task_cleanup - { - public: - task_cleanup(task_io_service& task_io_svc) - : task_io_service_(task_io_svc) - { - } - - ~task_cleanup() - { - // Reinsert the task at the end of the handler queue. - boost::asio::detail::mutex::scoped_lock back_lock( - task_io_service_.back_mutex_); - task_io_service_.back_task_thread_ = 0; - task_io_service_.handler_queue_.push(&task_io_service_.task_handler_); - } - - private: - task_io_service& task_io_service_; - }; - - // Helper class to perform handler-related operations on block exit. - class handler_cleanup - { - public: - handler_cleanup(task_io_service& task_io_svc) - : task_io_service_(task_io_svc) - { - } - - ~handler_cleanup() - { - task_io_service_.work_finished(); - } - - private: - task_io_service& task_io_service_; - }; - - // Mutexes to protect access to internal data. - boost::asio::detail::mutex front_mutex_; - boost::asio::detail::mutex back_mutex_; - - // The task to be run by this service. - Task* task_; - - // Handler object to represent the position of the task in the queue. - class task_handler - : public handler_queue::handler - { - public: - task_handler() - : handler_queue::handler(0, 0) - { - } - } task_handler_; - - // The count of unfinished work. - boost::detail::atomic_count outstanding_work_; - - // The queue of handlers that are ready to be delivered. - handler_queue handler_queue_; - - // Flag to indicate that the dispatcher has been stopped. - bool front_stopped_; - bool back_stopped_; - - // Flag to indicate that the dispatcher has been shut down. - bool back_shutdown_; - - // Structure containing information about an idle thread. - struct idle_thread_info - { - event wakeup_event; - idle_thread_info* next; - }; - - // The number of threads that are currently idle. - idle_thread_info* back_first_idle_thread_; - - // The thread that is currently blocked on the task. - idle_thread_info* back_task_thread_; -}; - -} // namespace detail -} // namespace asio -} // namespace boost - -#include - -#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_2LOCK_HPP diff --git a/include/boost/asio/detail/task_io_service_operation.hpp b/include/boost/asio/detail/task_io_service_operation.hpp new file mode 100644 index 00000000..557f6732 --- /dev/null +++ b/include/boost/asio/detail/task_io_service_operation.hpp @@ -0,0 +1,71 @@ +// +// task_io_service_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_TASK_IO_SERVICE_OPERATION_HPP +#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +// Base class for all operations. A function pointer is used instead of virtual +// functions to avoid the associated overhead. +template +class task_io_service_operation +{ +public: + void complete(task_io_service& owner) + { + func_(&owner, this, boost::system::error_code(), 0); + } + + void destroy() + { + func_(0, this, boost::system::error_code(), 0); + } + +protected: + typedef void (*func_type)(task_io_service*, + task_io_service_operation*, boost::system::error_code, std::size_t); + + task_io_service_operation(func_type func) + : next_(0), + func_(func) + { + } + + // Prevents deletion through this type. + ~task_io_service_operation() + { + } + +private: + friend class op_queue_access; + task_io_service_operation* next_; + func_type func_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include +#include + +#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP diff --git a/include/boost/asio/detail/timer_op.hpp b/include/boost/asio/detail/timer_op.hpp new file mode 100644 index 00000000..9973d893 --- /dev/null +++ b/include/boost/asio/detail/timer_op.hpp @@ -0,0 +1,46 @@ +// +// timer_op.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_TIMER_OP_HPP +#define BOOST_ASIO_DETAIL_TIMER_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class timer_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + boost::system::error_code ec_; + +protected: + timer_op(func_type func) + : operation(func) + { + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_TIMER_OP_HPP diff --git a/include/boost/asio/detail/timer_queue.hpp b/include/boost/asio/detail/timer_queue.hpp index 35c8a77c..164b3420 100644 --- a/include/boost/asio/detail/timer_queue.hpp +++ b/include/boost/asio/detail/timer_queue.hpp @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -27,9 +26,9 @@ #include #include -#include #include -#include +#include +#include #include namespace boost { @@ -50,50 +49,36 @@ public: // Constructor. timer_queue() : timers_(), - heap_(), - cancelled_timers_(0), - complete_timers_(0) + heap_() { } // Add a new timer to the queue. Returns true if this is the timer that is // earliest in the queue, in which case the reactor's event demultiplexing // function call may need to be interrupted and restarted. - template - bool enqueue_timer(const time_type& time, Handler handler, void* token) + bool enqueue_timer(const time_type& time, timer_op* op, void* token) { // Ensure that there is space for the timer in the heap. We reserve here so // that the push_back below will not throw due to a reallocation failure. heap_.reserve(heap_.size() + 1); - // Create a new timer object. - typedef timer timer_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr new_timer(raw_ptr, time, handler, token); - // Insert the new timer into the hash. - typedef typename hash_map::iterator iterator; - typedef typename hash_map::value_type value_type; + typedef typename hash_map::iterator iterator; + typedef typename hash_map::value_type value_type; std::pair result = - timers_.insert(value_type(token, new_timer.get())); - if (!result.second) + timers_.insert(value_type(token, timer())); + result.first->second.op_queue_.push(op); + if (result.second) { - result.first->second->prev_ = new_timer.get(); - new_timer.get()->next_ = result.first->second; - result.first->second = new_timer.get(); + // Put the new timer at the correct position in the heap. + result.first->second.time_ = time; + result.first->second.heap_index_ = heap_.size(); + result.first->second.token_ = token; + heap_.push_back(&result.first->second); + up_heap(heap_.size() - 1); } - // Put the timer at the correct position in the heap. - new_timer.get()->heap_index_ = heap_.size(); - heap_.push_back(new_timer.get()); - up_heap(heap_.size() - 1); - bool is_first = (heap_[0] == new_timer.get()); - - // Ownership of the timer is transferred to the timer queue. - new_timer.release(); - - return is_first; + return (heap_[0] == &result.first->second); } // Whether there are no timers in the queue. @@ -103,226 +88,106 @@ public: } // Get the time for the timer that is earliest in the queue. - virtual boost::posix_time::time_duration wait_duration() const + virtual long wait_duration_msec(long max_duration) const { if (heap_.empty()) - return boost::posix_time::pos_infin; - return Time_Traits::to_posix_duration( + return max_duration; + + boost::posix_time::time_duration duration = Time_Traits::to_posix_duration( Time_Traits::subtract(heap_[0]->time_, Time_Traits::now())); + + if (duration > boost::posix_time::milliseconds(max_duration)) + duration = boost::posix_time::milliseconds(max_duration); + else if (duration < boost::posix_time::milliseconds(0)) + duration = boost::posix_time::milliseconds(0); + + return duration.total_milliseconds(); } - // Dispatch the timers that are earlier than the specified time. - virtual void dispatch_timers() + // Get the time for the timer that is earliest in the queue. + virtual long wait_duration_usec(long max_duration) const + { + if (heap_.empty()) + return max_duration; + + boost::posix_time::time_duration duration = Time_Traits::to_posix_duration( + Time_Traits::subtract(heap_[0]->time_, Time_Traits::now())); + + if (duration > boost::posix_time::microseconds(max_duration)) + duration = boost::posix_time::microseconds(max_duration); + else if (duration < boost::posix_time::microseconds(0)) + duration = boost::posix_time::microseconds(0); + + return duration.total_microseconds(); + } + + // Dequeue all timers not later than the current time. + virtual void get_ready_timers(op_queue& ops) { const time_type now = Time_Traits::now(); while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_)) { - timer_base* t = heap_[0]; + timer* t = heap_[0]; + ops.push(t->op_queue_); remove_timer(t); - t->result_ = boost::system::error_code(); - t->prev_ = 0; - t->next_ = complete_timers_; - complete_timers_ = t; } } - // Cancel the timers with the given token. Any timers pending for the token - // will be notified that they have been cancelled next time - // dispatch_cancellations is called. Returns the number of timers that were - // cancelled. - std::size_t cancel_timer(void* timer_token) + // Dequeue all timers. + virtual void get_all_timers(op_queue& ops) + { + typename hash_map::iterator i = timers_.begin(); + typename hash_map::iterator end = timers_.end(); + while (i != end) + { + ops.push(i->second.op_queue_); + typename hash_map::iterator old_i = i++; + timers_.erase(old_i); + } + + heap_.clear(); + timers_.clear(); + } + + // Cancel and dequeue the timers with the given token. + std::size_t cancel_timer(void* timer_token, op_queue& ops) { std::size_t num_cancelled = 0; - typedef typename hash_map::iterator iterator; + typedef typename hash_map::iterator iterator; iterator it = timers_.find(timer_token); if (it != timers_.end()) { - timer_base* t = it->second; - while (t) + while (timer_op* op = it->second.op_queue_.front()) { - timer_base* next = t->next_; - remove_timer(t); - t->prev_ = 0; - t->next_ = cancelled_timers_; - cancelled_timers_ = t; - t = next; + op->ec_ = boost::asio::error::operation_aborted; + it->second.op_queue_.pop(); + ops.push(op); ++num_cancelled; } + remove_timer(&it->second); } return num_cancelled; } - // Dispatch any pending cancels for timers. - virtual void dispatch_cancellations() - { - while (cancelled_timers_) - { - timer_base* this_timer = cancelled_timers_; - this_timer->result_ = boost::asio::error::operation_aborted; - cancelled_timers_ = this_timer->next_; - this_timer->next_ = complete_timers_; - complete_timers_ = this_timer; - } - } - - // Complete any timers that are waiting to be completed. - virtual void complete_timers() - { - while (complete_timers_) - { - timer_base* this_timer = complete_timers_; - complete_timers_ = this_timer->next_; - this_timer->next_ = 0; - this_timer->complete(); - } - } - - // Destroy all timers. - virtual void destroy_timers() - { - typename hash_map::iterator i = timers_.begin(); - typename hash_map::iterator end = timers_.end(); - while (i != end) - { - timer_base* t = i->second; - typename hash_map::iterator old_i = i++; - timers_.erase(old_i); - destroy_timer_list(t); - } - heap_.clear(); - timers_.clear(); - destroy_timer_list(cancelled_timers_); - destroy_timer_list(complete_timers_); - } - private: - // Base class for timer operations. Function pointers are used instead of - // virtual functions to avoid the associated overhead. - class timer_base + // Structure representing a single outstanding timer. + struct timer { - public: - // Delete the timer and post the handler. - void complete() - { - complete_func_(this, result_); - } - - // Delete the timer. - void destroy() - { - destroy_func_(this); - } - - protected: - typedef void (*complete_func_type)(timer_base*, - const boost::system::error_code&); - typedef void (*destroy_func_type)(timer_base*); - - // Constructor. - timer_base(complete_func_type complete_func, destroy_func_type destroy_func, - const time_type& time, void* token) - : complete_func_(complete_func), - destroy_func_(destroy_func), - time_(time), - token_(token), - next_(0), - prev_(0), - heap_index_( - std::numeric_limits::max BOOST_PREVENT_MACRO_SUBSTITUTION()) - { - } - - // Prevent deletion through this type. - ~timer_base() - { - } - - private: - friend class timer_queue; - - // The function to be called to delete the timer and post the handler. - complete_func_type complete_func_; - - // The function to be called to delete the timer. - destroy_func_type destroy_func_; - - // The result of the timer operation. - boost::system::error_code result_; + timer() {} + timer(const timer&) {} + void operator=(const timer&) {} // The time when the timer should fire. time_type time_; - // The token associated with the timer. - void* token_; - - // The next timer known to the queue. - timer_base* next_; - - // The previous timer known to the queue. - timer_base* prev_; + // The operations waiting on the timer. + op_queue op_queue_; // The index of the timer in the heap. size_t heap_index_; - }; - // Adaptor class template for using handlers in timers. - template - class timer - : public timer_base - { - public: - // Constructor. - timer(const time_type& time, Handler handler, void* token) - : timer_base(&timer::complete_handler, - &timer::destroy_handler, time, token), - handler_(handler) - { - } - - // Delete the timer and post the handler. - static void complete_handler(timer_base* base, - const boost::system::error_code& result) - { - // Take ownership of the timer object. - typedef timer this_type; - this_type* this_timer(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(this_timer->handler_, this_timer); - - // Make a copy of the error_code and the handler so that the memory can - // be deallocated before the upcall is made. - boost::system::error_code ec(result); - Handler handler(this_timer->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Make the upcall. - handler(ec); - } - - // Delete the timer. - static void destroy_handler(timer_base* base) - { - // Take ownership of the timer object. - typedef timer this_type; - this_type* this_timer(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(this_timer->handler_, this_timer); - - // 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(this_timer->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); - } - - private: - Handler handler_; + // The token associated with the timer. + void* token_; }; // Move the item at the given index up the heap to its correct position. @@ -359,7 +224,7 @@ private: // Swap two entries in the heap. void swap_heap(size_t index1, size_t index2) { - timer_base* tmp = heap_[index1]; + timer* tmp = heap_[index1]; heap_[index1] = heap_[index2]; heap_[index2] = tmp; heap_[index1]->heap_index_ = index1; @@ -367,7 +232,7 @@ private: } // Remove a timer from the heap and list of timers. - void remove_timer(timer_base* t) + void remove_timer(timer* t) { // Remove the timer from the heap. size_t index = t->heap_index_; @@ -391,44 +256,17 @@ private: } // Remove the timer from the hash. - typedef typename hash_map::iterator iterator; + typedef typename hash_map::iterator iterator; iterator it = timers_.find(t->token_); if (it != timers_.end()) - { - if (it->second == t) - it->second = t->next_; - if (t->prev_) - t->prev_->next_ = t->next_; - if (t->next_) - t->next_->prev_ = t->prev_; - if (it->second == 0) - timers_.erase(it); - } - } - - // Destroy all timers in a linked list. - void destroy_timer_list(timer_base*& t) - { - while (t) - { - timer_base* next = t->next_; - t->next_ = 0; - t->destroy(); - t = next; - } + timers_.erase(it); } // A hash of timer token to linked lists of timers. - hash_map timers_; + hash_map timers_; // The heap of timers, with the earliest timer at the front. - std::vector heap_; - - // The list of timers to be cancelled. - timer_base* cancelled_timers_; - - // The list of timers waiting to be completed. - timer_base* complete_timers_; + std::vector heap_; }; } // namespace detail diff --git a/include/boost/asio/detail/timer_queue_base.hpp b/include/boost/asio/detail/timer_queue_base.hpp index cd6a0d37..074c2e15 100644 --- a/include/boost/asio/detail/timer_queue_base.hpp +++ b/include/boost/asio/detail/timer_queue_base.hpp @@ -17,13 +17,9 @@ #include -#include // Must come before posix_time. - -#include -#include -#include - #include +#include +#include namespace boost { namespace asio { @@ -33,6 +29,9 @@ class timer_queue_base : private noncopyable { public: + // Constructor. + timer_queue_base() : next_(0) {} + // Destructor. virtual ~timer_queue_base() {} @@ -40,19 +39,22 @@ public: virtual bool empty() const = 0; // Get the time to wait until the next timer. - virtual boost::posix_time::time_duration wait_duration() const = 0; + virtual long wait_duration_msec(long max_duration) const = 0; - // Dispatch all ready timers. - virtual void dispatch_timers() = 0; + // Get the time to wait until the next timer. + virtual long wait_duration_usec(long max_duration) const = 0; - // Dispatch any pending cancels for timers. - virtual void dispatch_cancellations() = 0; + // Dequeue all ready timers. + virtual void get_ready_timers(op_queue& ops) = 0; - // Complete all timers that are waiting to be completed. - virtual void complete_timers() = 0; + // Dequeue all timers. + virtual void get_all_timers(op_queue& ops) = 0; - // Destroy all timers. - virtual void destroy_timers() = 0; +private: + friend class timer_queue_set; + + // Next timer queue in the set. + timer_queue_base* next_; }; } // namespace detail diff --git a/include/boost/asio/detail/timer_queue_fwd.hpp b/include/boost/asio/detail/timer_queue_fwd.hpp new file mode 100644 index 00000000..b8bc5f2e --- /dev/null +++ b/include/boost/asio/detail/timer_queue_fwd.hpp @@ -0,0 +1,33 @@ +// +// timer_queue_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_TIMER_QUEUE_FWD_HPP +#define BOOST_ASIO_DETAIL_TIMER_QUEUE_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class timer_queue; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_FWD_HPP diff --git a/include/boost/asio/detail/timer_queue_set.hpp b/include/boost/asio/detail/timer_queue_set.hpp new file mode 100644 index 00000000..a92a6b90 --- /dev/null +++ b/include/boost/asio/detail/timer_queue_set.hpp @@ -0,0 +1,117 @@ +// +// timer_queue_set.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_TIMER_QUEUE_SET_HPP +#define BOOST_ASIO_DETAIL_TIMER_QUEUE_SET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class timer_queue_set +{ +public: + // Constructor. + timer_queue_set() + : first_(0) + { + } + + // Add a timer queue to the set. + void insert(timer_queue_base* q) + { + q->next_ = first_; + first_ = q; + } + + // Remove a timer queue from the set. + void erase(timer_queue_base* q) + { + if (first_) + { + if (q == first_) + { + first_ = q->next_; + q->next_ = 0; + return; + } + + for (timer_queue_base* p = first_; p->next_; p = p->next_) + { + if (p->next_ == q) + { + p->next_ = q->next_; + q->next_ = 0; + return; + } + } + } + } + + // Determine whether all queues are empty. + bool all_empty() const + { + for (timer_queue_base* p = first_; p; p = p->next_) + if (!p->empty()) + return false; + return true; + } + + // Get the wait duration in milliseconds. + long wait_duration_msec(long max_duration) const + { + long min_duration = max_duration; + for (timer_queue_base* p = first_; p; p = p->next_) + min_duration = p->wait_duration_msec(min_duration); + return min_duration; + } + + // Get the wait duration in microseconds. + long wait_duration_usec(long max_duration) const + { + long min_duration = max_duration; + for (timer_queue_base* p = first_; p; p = p->next_) + min_duration = p->wait_duration_usec(min_duration); + return min_duration; + } + + // Dequeue all ready timers. + void get_ready_timers(op_queue& ops) + { + for (timer_queue_base* p = first_; p; p = p->next_) + p->get_ready_timers(ops); + } + + // Dequeue all timers. + void get_all_timers(op_queue& ops) + { + for (timer_queue_base* p = first_; p; p = p->next_) + p->get_all_timers(ops); + } + +private: + timer_queue_base* first_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_SET_HPP diff --git a/include/boost/asio/detail/timer_scheduler.hpp b/include/boost/asio/detail/timer_scheduler.hpp new file mode 100644 index 00000000..bc837ee0 --- /dev/null +++ b/include/boost/asio/detail/timer_scheduler.hpp @@ -0,0 +1,36 @@ +// +// timer_scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_TIMER_SCHEDULER_HPP +#define BOOST_ASIO_DETAIL_TIMER_SCHEDULER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#elif defined(BOOST_ASIO_HAS_EPOLL) +# include +#elif defined(BOOST_ASIO_HAS_KQUEUE) +# include +#elif defined(BOOST_ASIO_HAS_DEV_POLL) +# include +#else +# include +#endif + +#include + +#endif // BOOST_ASIO_DETAIL_TIMER_SCHEDULER_HPP diff --git a/include/boost/asio/detail/timer_scheduler_fwd.hpp b/include/boost/asio/detail/timer_scheduler_fwd.hpp new file mode 100644 index 00000000..9d0b1e63 --- /dev/null +++ b/include/boost/asio/detail/timer_scheduler_fwd.hpp @@ -0,0 +1,48 @@ +// +// timer_scheduler_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_TIMER_SCHEDULER_FWD_HPP +#define BOOST_ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_HAS_IOCP) +typedef win_iocp_io_service timer_scheduler; +#elif defined(BOOST_ASIO_HAS_EPOLL) +typedef epoll_reactor timer_scheduler; +#elif defined(BOOST_ASIO_HAS_KQUEUE) +typedef kqueue_reactor timer_scheduler; +#elif defined(BOOST_ASIO_HAS_DEV_POLL) +typedef dev_poll_reactor timer_scheduler; +#else +typedef select_reactor timer_scheduler; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP diff --git a/include/boost/asio/detail/win_event.hpp b/include/boost/asio/detail/win_event.hpp index 637b580d..bddf09d6 100644 --- a/include/boost/asio/detail/win_event.hpp +++ b/include/boost/asio/detail/win_event.hpp @@ -71,6 +71,15 @@ public: ::SetEvent(event_); } + // Signal the event and unlock the mutex. + template + void signal_and_unlock(Lock& lock) + { + BOOST_ASSERT(lock.locked()); + lock.unlock(); + ::SetEvent(event_); + } + // Reset the event. template void clear(Lock& lock) diff --git a/include/boost/asio/detail/win_fenced_block.hpp b/include/boost/asio/detail/win_fenced_block.hpp new file mode 100644 index 00000000..443b50c9 --- /dev/null +++ b/include/boost/asio/detail/win_fenced_block.hpp @@ -0,0 +1,57 @@ +// +// win_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_WIN_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if defined(BOOST_WINDOWS) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_fenced_block + : private noncopyable +{ +public: + // Constructor. + win_fenced_block() + { + MemoryBarrier(); + } + + // Destructor. + ~win_fenced_block() + { + MemoryBarrier(); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_WINDOWS) + +#include + +#endif // BOOST_ASIO_DETAIL_WIN_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/win_iocp_handle_service.hpp b/include/boost/asio/detail/win_iocp_handle_service.hpp index 6998d573..3f90a6f2 100644 --- a/include/boost/asio/detail/win_iocp_handle_service.hpp +++ b/include/boost/asio/detail/win_iocp_handle_service.hpp @@ -26,13 +26,14 @@ #include #include -#include #include #include #include +#include #include #include #include +#include #include namespace boost { @@ -40,12 +41,8 @@ namespace asio { namespace detail { class win_iocp_handle_service - : public boost::asio::detail::service_base { public: - // Base class for all operations. - typedef win_iocp_io_service::operation operation; - // The native type of a stream handle. typedef HANDLE native_type; @@ -81,8 +78,7 @@ public: }; win_iocp_handle_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base(io_service), - iocp_service_(boost::asio::use_service(io_service)), + : iocp_service_(boost::asio::use_service(io_service)), mutex_(), impl_list_(0) { @@ -307,16 +303,9 @@ public: return 0; } - // Find first buffer of non-zero length. - boost::asio::const_buffer buffer; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - for (DWORD i = 0; iter != end; ++iter, ++i) - { - buffer = boost::asio::const_buffer(*iter); - if (boost::asio::buffer_size(buffer) != 0) - break; - } + boost::asio::const_buffer buffer = + buffer_sequence_adapter::first(buffers); // A request to write 0 bytes on a handle is a no-op. if (boost::asio::buffer_size(buffer) == 0) @@ -365,79 +354,48 @@ public: } template - class write_operation - : public operation + class write_op : public operation { public: - write_operation(win_iocp_io_service& io_service, - const ConstBufferSequence& buffers, Handler handler) - : operation(io_service, - &write_operation::do_completion_impl, - &write_operation::destroy_impl), - work_(io_service.get_io_service()), + write_op(const ConstBufferSequence& buffers, Handler handler) + : operation(&write_op::do_complete), buffers_(buffers), handler_(handler) { } - private: - static void do_completion_impl(operation* op, - DWORD last_error, size_t bytes_transferred) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. - typedef write_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); + write_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - typename ConstBufferSequence::const_iterator iter - = handler_op->buffers_.begin(); - typename ConstBufferSequence::const_iterator end - = handler_op->buffers_.end(); - while (iter != end) + // Make the upcall if required. + if (owner) { - boost::asio::const_buffer buffer(*iter); - boost::asio::buffer_cast(buffer); - ++iter; - } +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Make a copy of the handler so that the memory can be deallocated before - // the upcall is made. - Handler handler(handler_op->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Call the handler. - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - boost_asio_handler_invoke_helpers::invoke( - bind_handler(handler, ec, bytes_transferred), handler); + // 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(o->handler_, ec, bytes_transferred); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } } - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef write_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); - } - - boost::asio::io_service::work work_; + private: ConstBufferSequence buffers_; Handler handler_; }; @@ -457,65 +415,16 @@ public: void async_write_some_at(implementation_type& impl, boost::uint64_t offset, const ConstBufferSequence& buffers, Handler handler) { - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); - // Allocate and construct an operation to wrap the handler. - typedef write_operation value_type; + typedef write_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, iocp_service_, buffers, handler); + handler_ptr ptr(raw_ptr, buffers, handler); - if (!is_open(impl)) - { - ptr.get()->on_immediate_completion(WSAEBADF, 0); - ptr.release(); - return; - } - - // Find first buffer of non-zero length. - boost::asio::const_buffer buffer; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - for (DWORD i = 0; iter != end; ++iter, ++i) - { - buffer = boost::asio::const_buffer(*iter); - if (boost::asio::buffer_size(buffer) != 0) - break; - } - - // A request to write 0 bytes on a handle is a no-op. - if (boost::asio::buffer_size(buffer) == 0) - { - ptr.get()->on_immediate_completion(0, 0); - ptr.release(); - return; - } - - // Write the data. - DWORD bytes_transferred = 0; - ptr.get()->Offset = offset & 0xFFFFFFFF; - ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::WriteFile(impl.handle_, - boost::asio::buffer_cast(buffer), - static_cast(boost::asio::buffer_size(buffer)), - &bytes_transferred, ptr.get()); - DWORD last_error = ::GetLastError(); - - // Check if the operation completed immediately. - if (!ok && last_error != ERROR_IO_PENDING) - { - ptr.get()->on_immediate_completion(last_error, bytes_transferred); - ptr.release(); - } - else - { - ptr.get()->on_pending(); - ptr.release(); - } + start_write_op(impl, offset, + buffer_sequence_adapter::first(buffers), ptr.get()); + ptr.release(); } // Read some data. Returns the number of bytes received. @@ -537,16 +446,9 @@ public: return 0; } - // Find first buffer of non-zero length. - boost::asio::mutable_buffer buffer; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - for (DWORD i = 0; iter != end; ++iter, ++i) - { - buffer = boost::asio::mutable_buffer(*iter); - if (boost::asio::buffer_size(buffer) != 0) - break; - } + boost::asio::mutable_buffer buffer = + buffer_sequence_adapter::first(buffers); // A request to read 0 bytes on a stream handle is a no-op. if (boost::asio::buffer_size(buffer) == 0) @@ -609,89 +511,54 @@ public: } template - class read_operation - : public operation + class read_op : public operation { public: - read_operation(win_iocp_io_service& io_service, - const MutableBufferSequence& buffers, Handler handler) - : operation(io_service, - &read_operation< - MutableBufferSequence, Handler>::do_completion_impl, - &read_operation< - MutableBufferSequence, Handler>::destroy_impl), - work_(io_service.get_io_service()), + read_op(const MutableBufferSequence& buffers, Handler handler) + : operation(&read_op::do_complete), buffers_(buffers), handler_(handler) { } - private: - static void do_completion_impl(operation* op, - DWORD last_error, size_t bytes_transferred) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. - typedef read_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); + read_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - typename MutableBufferSequence::const_iterator iter - = handler_op->buffers_.begin(); - typename MutableBufferSequence::const_iterator end - = handler_op->buffers_.end(); - while (iter != end) + // Make the upcall if required. + if (owner) { - boost::asio::mutable_buffer buffer(*iter); - boost::asio::buffer_cast(buffer); - ++iter; - } +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check for the end-of-file condition. - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - if (!ec && bytes_transferred == 0 || last_error == ERROR_HANDLE_EOF) - { - ec = boost::asio::error::eof; + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_HANDLE_EOF) + { + ec = boost::asio::error::eof; + } + + // 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(o->handler_, ec, bytes_transferred); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); } - - // Make a copy of the handler so that the memory can be deallocated before - // the upcall is made. - Handler handler(handler_op->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Call the handler. - boost_asio_handler_invoke_helpers::invoke( - bind_handler(handler, ec, bytes_transferred), handler); } - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef read_operation op_type; - op_type* handler_op(static_cast(op)); - typedef boost::asio::detail::handler_alloc_traits< - Handler, op_type> alloc_traits; - boost::asio::detail::handler_ptr ptr( - handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); - } - - boost::asio::io_service::work work_; + private: MutableBufferSequence buffers_; Handler handler_; }; @@ -712,63 +579,16 @@ public: void async_read_some_at(implementation_type& impl, boost::uint64_t offset, const MutableBufferSequence& buffers, Handler handler) { - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); - // Allocate and construct an operation to wrap the handler. - typedef read_operation value_type; + typedef read_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, iocp_service_, buffers, handler); + handler_ptr ptr(raw_ptr, buffers, handler); - if (!is_open(impl)) - { - ptr.get()->on_immediate_completion(WSAEBADF, 0); - ptr.release(); - return; - } - - // Find first buffer of non-zero length. - boost::asio::mutable_buffer buffer; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - for (DWORD i = 0; iter != end; ++iter, ++i) - { - buffer = boost::asio::mutable_buffer(*iter); - if (boost::asio::buffer_size(buffer) != 0) - break; - } - - // A request to receive 0 bytes on a stream handle is a no-op. - if (boost::asio::buffer_size(buffer) == 0) - { - ptr.get()->on_immediate_completion(0, 0); - ptr.release(); - return; - } - - // Read some data. - DWORD bytes_transferred = 0; - ptr.get()->Offset = offset & 0xFFFFFFFF; - ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::ReadFile(impl.handle_, - boost::asio::buffer_cast(buffer), - static_cast(boost::asio::buffer_size(buffer)), - &bytes_transferred, ptr.get()); - DWORD last_error = ::GetLastError(); - if (!ok && last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA) - { - ptr.get()->on_immediate_completion(last_error, bytes_transferred); - ptr.release(); - } - else - { - ptr.get()->on_pending(); - ptr.release(); - } + start_read_op(impl, offset, + buffer_sequence_adapter::first(buffers), ptr.get()); + ptr.release(); } private: @@ -794,6 +614,93 @@ private: void async_read_some_at(implementation_type& impl, boost::uint64_t offset, const null_buffers& buffers, Handler handler); + // Helper function to start a write operation. + void start_write_op(implementation_type& impl, boost::uint64_t offset, + const boost::asio::const_buffer& buffer, operation* op) + { + update_cancellation_thread_id(); + iocp_service_.work_started(); + + if (!is_open(impl)) + { + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + } + else if (boost::asio::buffer_size(buffer) == 0) + { + // A request to write 0 bytes on a handle is a no-op. + iocp_service_.on_completion(op); + } + else + { + DWORD bytes_transferred = 0; + op->Offset = offset & 0xFFFFFFFF; + op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::WriteFile(impl.handle_, + boost::asio::buffer_cast(buffer), + static_cast(boost::asio::buffer_size(buffer)), + &bytes_transferred, op); + DWORD last_error = ::GetLastError(); + if (!ok && last_error != ERROR_IO_PENDING + && last_error != ERROR_MORE_DATA) + { + iocp_service_.on_completion(op, last_error, bytes_transferred); + } + else + { + iocp_service_.on_pending(op); + } + } + } + + // Helper function to start a read operation. + void start_read_op(implementation_type& impl, boost::uint64_t offset, + const boost::asio::mutable_buffer& buffer, operation* op) + { + update_cancellation_thread_id(); + iocp_service_.work_started(); + + if (!is_open(impl)) + { + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + } + else if (boost::asio::buffer_size(buffer) == 0) + { + // A request to read 0 bytes on a handle is a no-op. + iocp_service_.on_completion(op); + } + else + { + DWORD bytes_transferred = 0; + op->Offset = offset & 0xFFFFFFFF; + op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::ReadFile(impl.handle_, + boost::asio::buffer_cast(buffer), + static_cast(boost::asio::buffer_size(buffer)), + &bytes_transferred, op); + DWORD last_error = ::GetLastError(); + if (!ok && last_error != ERROR_IO_PENDING + && last_error != ERROR_MORE_DATA) + { + iocp_service_.on_completion(op, last_error, bytes_transferred); + } + else + { + iocp_service_.on_pending(op); + } + } + } + + // Update the ID of the thread from which cancellation is safe. + void update_cancellation_thread_id() + { +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + if (impl.safe_cancellation_thread_id_ == 0) + impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) + impl.safe_cancellation_thread_id_ = ~DWORD(0); +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + } + // Helper function to close a handle when the associated object is being // destroyed. void close_for_destruction(implementation_type& impl) diff --git a/include/boost/asio/detail/win_iocp_io_service.hpp b/include/boost/asio/detail/win_iocp_io_service.hpp index 1dfb9a19..83b16bf8 100644 --- a/include/boost/asio/detail/win_iocp_io_service.hpp +++ b/include/boost/asio/detail/win_iocp_io_service.hpp @@ -29,122 +29,37 @@ #include #include +#include +#include #include #include +#include +#include #include #include -#include -#include +#include +#include +#include +#include +#include namespace boost { namespace asio { namespace detail { +class timer_op; + class win_iocp_io_service : public boost::asio::detail::service_base { public: - // Base class for all operations. A function pointer is used instead of - // virtual functions to avoid the associated overhead. - // - // This class inherits from OVERLAPPED so that we can downcast to get back to - // the operation pointer from the LPOVERLAPPED out parameter of - // GetQueuedCompletionStatus. - class operation; - friend class operation; - class operation - : public OVERLAPPED - { - public: - typedef void (*invoke_func_type)(operation*, DWORD, size_t); - typedef void (*destroy_func_type)(operation*); - - operation(win_iocp_io_service& iocp_service, - invoke_func_type invoke_func, destroy_func_type destroy_func) - : iocp_service_(iocp_service), - ready_(0), - last_error_(~DWORD(0)), - bytes_transferred_(0), - invoke_func_(invoke_func), - destroy_func_(destroy_func) - { - Internal = 0; - InternalHigh = 0; - Offset = 0; - OffsetHigh = 0; - hEvent = 0; - - ::InterlockedIncrement(&iocp_service_.outstanding_operations_); - } - - void reset() - { - Internal = 0; - InternalHigh = 0; - Offset = 0; - OffsetHigh = 0; - hEvent = 0; - ready_ = 0; - last_error_ = ~DWORD(0); - bytes_transferred_ = 0; - } - - void on_pending() - { - if (::InterlockedCompareExchange(&ready_, 1, 0) == 1) - iocp_service_.post_completion(this, last_error_, bytes_transferred_); - } - - void on_immediate_completion(DWORD last_error, DWORD bytes_transferred) - { - ready_ = 1; - iocp_service_.post_completion(this, last_error, bytes_transferred); - } - - bool on_completion(DWORD last_error, DWORD bytes_transferred) - { - if (last_error_ == ~DWORD(0)) - { - last_error_ = last_error; - bytes_transferred_ = bytes_transferred; - } - - if (::InterlockedCompareExchange(&ready_, 1, 0) == 1) - { - invoke_func_(this, last_error_, bytes_transferred_); - return true; - } - - return false; - } - - void destroy() - { - destroy_func_(this); - } - - protected: - // Prevent deletion through this type. - ~operation() - { - ::InterlockedDecrement(&iocp_service_.outstanding_operations_); - } - - private: - win_iocp_io_service& iocp_service_; - long ready_; - DWORD last_error_; - DWORD bytes_transferred_; - invoke_func_type invoke_func_; - destroy_func_type destroy_func_; - }; + typedef win_iocp_operation operation; // Constructor. win_iocp_io_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base(io_service), iocp_(), outstanding_work_(0), - outstanding_operations_(0), stopped_(0), shutdown_(0), timer_thread_(0), @@ -172,24 +87,34 @@ public: { ::InterlockedExchange(&shutdown_, 1); - while (::InterlockedExchangeAdd(&outstanding_operations_, 0) > 0) + while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0) { - DWORD bytes_transferred = 0; -#if defined(WINVER) && (WINVER < 0x0500) - DWORD completion_key = 0; -#else - DWORD_PTR completion_key = 0; -#endif - LPOVERLAPPED overlapped = 0; - ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, - &completion_key, &overlapped, INFINITE); - if (overlapped) - static_cast(overlapped)->destroy(); + op_queue ops; + timer_queues_.get_all_timers(ops); + ops.push(completed_ops_); + if (!ops.empty()) + { + while (operation* op = ops.front()) + { + ops.pop(); + ::InterlockedDecrement(&outstanding_work_); + op->destroy(); + } + } + else + { + DWORD bytes_transferred = 0; + dword_ptr_t completion_key = 0; + LPOVERLAPPED overlapped = 0; + ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, + &completion_key, &overlapped, max_timeout); + if (overlapped) + { + ::InterlockedDecrement(&outstanding_work_); + static_cast(overlapped)->destroy(); + } + } } - - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->destroy_timers(); - timer_queues_.clear(); } // Initialise the task. Nothing to do here. @@ -219,6 +144,7 @@ public: { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) { + stop(); ec = boost::system::error_code(); return 0; } @@ -237,6 +163,7 @@ public: { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) { + stop(); ec = boost::system::error_code(); return 0; } @@ -251,6 +178,7 @@ public: { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) { + stop(); ec = boost::system::error_code(); return 0; } @@ -269,6 +197,7 @@ public: { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) { + stop(); ec = boost::system::error_code(); return 0; } @@ -319,7 +248,10 @@ public: void dispatch(Handler handler) { if (call_stack::contains(this)) + { + boost::asio::detail::fenced_block b; boost_asio_handler_invoke_helpers::invoke(handler, handler); + } else post(handler); } @@ -328,37 +260,128 @@ public: template void post(Handler handler) { - // If the service has been shut down we silently discard the handler. - if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) - return; - // Allocate and construct an operation to wrap the handler. - typedef handler_operation value_type; + typedef completion_handler value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, *this, handler); + handler_ptr ptr(raw_ptr, handler); - // Enqueue the operation on the I/O completion port. - ptr.get()->on_immediate_completion(0, 0); - - // Operation has been successfully posted. + post_immediate_completion(ptr.get()); ptr.release(); } - // Request invocation of the given OVERLAPPED-derived operation. - void post_completion(operation* op, DWORD op_last_error, - DWORD bytes_transferred) + // 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(operation* op) { + work_started(); + post_deferred_completion(op); + } + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() was previously called for the operation. + void post_deferred_completion(operation* op) + { + // Flag the operation as ready. + op->ready_ = 1; + // Enqueue the operation on the I/O completion port. if (!::PostQueuedCompletionStatus(iocp_.handle, - bytes_transferred, op_last_error, op)) + 0, overlapped_contains_result, op)) { - DWORD last_error = ::GetLastError(); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "pqcs"); - boost::throw_exception(e); + // Out of resources. Put on completed queue instead. + boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); + completed_ops_.push(op); + } + } + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() was previously called for the operations. + void post_deferred_completions(op_queue& ops) + { + while (operation* op = ops.front()) + { + ops.pop(); + + // Flag the operation as ready. + op->ready_ = 1; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); + completed_ops_.push(op); + completed_ops_.push(ops); + } + } + } + + // Called after starting an overlapped I/O operation that did not complete + // immediately. The caller must have already called work_started() prior to + // starting the operation. + void on_pending(operation* op) + { + if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) + { + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); + completed_ops_.push(op); + } + } + } + + // Called after starting an overlapped I/O operation that completed + // immediately. The caller must have already called work_started() prior to + // starting the operation. + void on_completion(operation* op, + DWORD last_error = 0, DWORD bytes_transferred = 0) + { + // Flag that the operation is ready for invocation. + op->ready_ = 1; + + // Store results in the OVERLAPPED structure. + op->Internal = reinterpret_cast( + &boost::asio::error::get_system_category()); + op->Offset = last_error; + op->OffsetHigh = bytes_transferred; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); + completed_ops_.push(op); + } + } + + // Called after starting an overlapped I/O operation that completed + // immediately. The caller must have already called work_started() prior to + // starting the operation. + void on_completion(operation* op, + const boost::system::error_code& ec, DWORD bytes_transferred = 0) + { + // Flag that the operation is ready for invocation. + op->ready_ = 1; + + // Store results in the OVERLAPPED structure. + op->Internal = reinterpret_cast(&ec.category()); + op->Offset = ec.value(); + op->OffsetHigh = bytes_transferred; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); + completed_ops_.push(op); } } @@ -367,7 +390,7 @@ public: void add_timer_queue(timer_queue& timer_queue) { boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - timer_queues_.push_back(&timer_queue); + timer_queues_.insert(&timer_queue); } // Remove a timer queue from the service. @@ -375,36 +398,28 @@ public: void remove_timer_queue(timer_queue& timer_queue) { boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - if (timer_queues_[i] == &timer_queue) - { - timer_queues_.erase(timer_queues_.begin() + i); - return; - } - } + timer_queues_.erase(&timer_queue); } - // Schedule a timer in the given timer queue to expire at the specified - // absolute time. The handler object will be invoked when the timer expires. - template + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, Handler handler, void* token) + const typename Time_Traits::time_type& time, timer_op* op, void* token) { // If the service has been shut down we silently discard the timer. if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) return; boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - if (timer_queue.enqueue_timer(time, handler, token)) + bool interrupt = timer_queue.enqueue_timer(time, op, token); + work_started(); + if (interrupt && !timer_interrupt_issued_) { - if (!timer_interrupt_issued_) - { - timer_interrupt_issued_ = true; - lock.unlock(); - ::PostQueuedCompletionStatus(iocp_.handle, - 0, steal_timer_dispatching, 0); - } + timer_interrupt_issued_ = true; + lock.unlock(); + ::PostQueuedCompletionStatus(iocp_.handle, + 0, steal_timer_dispatching, 0); } } @@ -418,7 +433,9 @@ public: return 0; boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - std::size_t n = timer_queue.cancel_timer(token); + op_queue ops; + std::size_t n = timer_queue.cancel_timer(token, ops); + post_deferred_completions(ops); if (n > 0 && !timer_interrupt_issued_) { timer_interrupt_issued_ = true; @@ -430,6 +447,14 @@ public: } private: +#if defined(WINVER) && (WINVER < 0x0500) + typedef DWORD dword_ptr_t; + typedef ULONG ulong_ptr_t; +#else // defined(WINVER) && (WINVER < 0x0500) + typedef DWORD_PTR dword_ptr_t; + typedef ULONG_PTR ulong_ptr_t; +#endif // defined(WINVER) && (WINVER < 0x0500) + // 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). @@ -454,11 +479,7 @@ private: // Get the next operation from the queue. DWORD bytes_transferred = 0; -#if defined(WINVER) && (WINVER < 0x0500) - DWORD completion_key = 0; -#else - DWORD_PTR completion_key = 0; -#endif + dword_ptr_t completion_key = 0; LPOVERLAPPED overlapped = 0; ::SetLastError(0); BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, @@ -468,32 +489,11 @@ private: // Dispatch any pending timers. if (dispatching_timers) { - try - { - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - if (!timer_queues_.empty()) - { - timer_queues_copy_ = timer_queues_; - for (std::size_t i = 0; i < timer_queues_copy_.size(); ++i) - { - timer_queues_copy_[i]->dispatch_timers(); - timer_queues_copy_[i]->dispatch_cancellations(); - timer_queues_copy_[i]->complete_timers(); - } - } - } - catch (...) - { - // Transfer responsibility for dispatching timers to another thread. - if (::InterlockedCompareExchange(&timer_thread_, - 0, this_thread_id) == this_thread_id) - { - ::PostQueuedCompletionStatus(iocp_.handle, - 0, transfer_timer_dispatching, 0); - } - - throw; - } + boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); + op_queue ops; + ops.push(completed_ops_); + timer_queues_.get_ready_timers(ops); + post_deferred_completions(ops); } if (!ok && overlapped == 0) @@ -522,11 +522,9 @@ private: } else if (overlapped) { - // We may have been passed a last_error value in the completion_key. - if (last_error == 0) - { - last_error = completion_key; - } + operation* op = static_cast(overlapped); + boost::system::error_code result_ec(last_error, + boost::asio::error::get_system_category()); // Transfer responsibility for dispatching timers to another thread. if (dispatching_timers && ::InterlockedCompareExchange( @@ -536,14 +534,35 @@ private: 0, transfer_timer_dispatching, 0); } - // Ensure that the io_service does not exit due to running out of work - // while we make the upcall. - auto_work work(*this); - - // Dispatch the operation. - operation* op = static_cast(overlapped); - if (op->on_completion(last_error, bytes_transferred)) + // We may have been passed the last_error and bytes_transferred in the + // OVERLAPPED structure itself. + if (completion_key == overlapped_contains_result) { + result_ec = boost::system::error_code(static_cast(op->Offset), + *reinterpret_cast(op->Internal)); + bytes_transferred = op->OffsetHigh; + } + + // Otherwise ensure any result has been saved into the OVERLAPPED + // structure. + else + { + op->Internal = reinterpret_cast(&result_ec.category()); + op->Offset = result_ec.value(); + op->OffsetHigh = bytes_transferred; + } + + // Dispatch the operation only if ready. The operation may not be ready + // if the initiating function (e.g. a call to WSARecv) has not yet + // returned. This is because the initiating function still wants access + // to the operation's OVERLAPPED structure. + if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) + { + // Ensure the count of outstanding work is decremented on block exit. + work_finished_on_block_exit on_exit = { this }; + (void)on_exit; + + op->complete(*this, result_ec, bytes_transferred); ec = boost::system::error_code(); return 1; } @@ -588,126 +607,23 @@ private: } } - // Check if all timer queues are empty. - bool all_timer_queues_are_empty() const - { - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - if (!timer_queues_[i]->empty()) - return false; - return true; - } - // Get the timeout value for the GetQueuedCompletionStatus call. The timeout // value is returned as a number of milliseconds. We will wait no longer than // 1000 milliseconds. DWORD get_timeout() { - if (all_timer_queues_are_empty()) - return max_timeout; - - boost::posix_time::time_duration minimum_wait_duration - = boost::posix_time::milliseconds(max_timeout); - - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { - boost::posix_time::time_duration wait_duration - = timer_queues_[i]->wait_duration(); - if (wait_duration < minimum_wait_duration) - minimum_wait_duration = wait_duration; - } - - if (minimum_wait_duration > boost::posix_time::time_duration()) - { - int milliseconds = minimum_wait_duration.total_milliseconds(); - return static_cast(milliseconds > 0 ? milliseconds : 1); - } - else - { - return 0; - } + return timer_queues_.wait_duration_msec(max_timeout); } - struct auto_work + // Helper class to call work_finished() on block exit. + struct work_finished_on_block_exit { - auto_work(win_iocp_io_service& io_service) - : io_service_(io_service) + ~work_finished_on_block_exit() { - io_service_.work_started(); + io_service_->work_finished(); } - ~auto_work() - { - io_service_.work_finished(); - } - - private: - win_iocp_io_service& io_service_; - }; - - template - struct handler_operation - : public operation - { - handler_operation(win_iocp_io_service& io_service, - Handler handler) - : operation(io_service, &handler_operation::do_completion_impl, - &handler_operation::destroy_impl), - io_service_(io_service), - handler_(handler) - { - io_service_.work_started(); - } - - ~handler_operation() - { - io_service_.work_finished(); - } - - private: - // Prevent copying and assignment. - handler_operation(const handler_operation&); - void operator=(const handler_operation&); - - static void do_completion_impl(operation* op, DWORD, size_t) - { - // Take ownership of the operation object. - typedef handler_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // Make a copy of the handler so that the memory can be deallocated before - // the upcall is made. - Handler handler(handler_op->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Make the upcall. - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef handler_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); - } - - win_iocp_io_service& io_service_; - Handler handler_; + win_iocp_io_service* io_service_; }; // The IO completion port used for queueing operations. @@ -721,10 +637,6 @@ private: // The count of unfinished work. long outstanding_work_; - // The count of unfinished operations. - long outstanding_operations_; - friend class operation; - // Flag to indicate whether the event loop has been stopped. long stopped_; @@ -742,7 +654,12 @@ private: // Completion key value to indicate that responsibility for dispatching // timers should be stolen from another thread. - steal_timer_dispatching = 2 + steal_timer_dispatching = 2, + + // Completion key value to indicate that an operation has posted with the + // original last_error and bytes_transferred values stored in the fields of + // the OVERLAPPED structure. + overlapped_contains_result = 3 }; // The thread that's currently in charge of dispatching timers. @@ -755,12 +672,10 @@ private: bool timer_interrupt_issued_; // The timer queues. - std::vector timer_queues_; + timer_queue_set timer_queues_; - // A copy of the timer queues, used when dispatching, cancelling and cleaning - // up timers. The copy is stored as a class data member to avoid unnecessary - // memory allocation. - std::vector timer_queues_copy_; + // The operations that are ready to dispatch. + op_queue completed_ops_; }; } // namespace detail diff --git a/include/boost/asio/detail/win_iocp_operation.hpp b/include/boost/asio/detail/win_iocp_operation.hpp new file mode 100644 index 00000000..d7d5723b --- /dev/null +++ b/include/boost/asio/detail/win_iocp_operation.hpp @@ -0,0 +1,91 @@ +// +// win_iocp_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_OPERATION_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Base class for all operations. A function pointer is used instead of virtual +// functions to avoid the associated overhead. +class win_iocp_operation + : public OVERLAPPED +{ +public: + void complete(win_iocp_io_service& owner, + const boost::system::error_code& ec = boost::system::error_code(), + std::size_t bytes_transferred = 0) + { + func_(&owner, this, ec, bytes_transferred); + } + + void destroy() + { + func_(0, this, boost::system::error_code(), 0); + } + +protected: + typedef void (*func_type)(win_iocp_io_service*, + win_iocp_operation*, boost::system::error_code, std::size_t); + + win_iocp_operation(func_type func) + : next_(0), + func_(func) + { + reset(); + } + + // Prevents deletion through this type. + ~win_iocp_operation() + { + } + + void reset() + { + Internal = 0; + InternalHigh = 0; + Offset = 0; + OffsetHigh = 0; + hEvent = 0; + ready_ = 0; + } + +private: + friend class op_queue_access; + friend class win_iocp_io_service; + win_iocp_operation* next_; + func_type func_; + long ready_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#include +#include + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_OPERATION_HPP diff --git a/include/boost/asio/detail/win_iocp_overlapped_ptr.hpp b/include/boost/asio/detail/win_iocp_overlapped_ptr.hpp index bb64014d..082a5b1b 100644 --- a/include/boost/asio/detail/win_iocp_overlapped_ptr.hpp +++ b/include/boost/asio/detail/win_iocp_overlapped_ptr.hpp @@ -21,8 +21,10 @@ #if defined(BOOST_ASIO_HAS_IOCP) +#include #include #include +#include namespace boost { namespace asio { @@ -35,7 +37,8 @@ class win_iocp_overlapped_ptr public: // Construct an empty win_iocp_overlapped_ptr. win_iocp_overlapped_ptr() - : ptr_(0) + : ptr_(0), + iocp_service_(0) { } @@ -43,7 +46,8 @@ public: template explicit win_iocp_overlapped_ptr( boost::asio::io_service& io_service, Handler handler) - : ptr_(0) + : ptr_(0), + iocp_service_(0) { this->reset(io_service, handler); } @@ -61,6 +65,8 @@ public: { ptr_->destroy(); ptr_ = 0; + iocp_service_->work_finished(); + iocp_service_ = 0; } } @@ -69,12 +75,14 @@ public: template void reset(boost::asio::io_service& io_service, Handler handler) { - typedef overlapped_operation value_type; + typedef overlapped_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, io_service.impl_, handler); + handler_ptr ptr(raw_ptr, handler); + io_service.impl_.work_started(); reset(); ptr_ = ptr.release(); + iocp_service_ = &io_service.impl_; } // Get the contained OVERLAPPED object. @@ -93,10 +101,11 @@ public: OVERLAPPED* release() { if (ptr_) - ptr_->on_pending(); + iocp_service_->on_pending(ptr_); OVERLAPPED* tmp = ptr_; ptr_ = 0; + iocp_service_ = 0; return tmp; } @@ -106,99 +115,54 @@ public: { if (ptr_) { - ptr_->ec_ = ec; - ptr_->on_immediate_completion(0, static_cast(bytes_transferred)); + iocp_service_->on_completion(ptr_, ec, + static_cast(bytes_transferred)); ptr_ = 0; + iocp_service_ = 0; } } private: - struct overlapped_operation_base - : public win_iocp_io_service::operation - { - overlapped_operation_base(win_iocp_io_service& io_service, - invoke_func_type invoke_func, destroy_func_type destroy_func) - : win_iocp_io_service::operation(io_service, invoke_func, destroy_func), - io_service_(io_service) - { - io_service_.work_started(); - } - - ~overlapped_operation_base() - { - io_service_.work_finished(); - } - - win_iocp_io_service& io_service_; - boost::system::error_code ec_; - }; - template - struct overlapped_operation - : public overlapped_operation_base + struct overlapped_op : public win_iocp_operation { - overlapped_operation(win_iocp_io_service& io_service, - Handler handler) - : overlapped_operation_base(io_service, - &overlapped_operation::do_completion_impl, - &overlapped_operation::destroy_impl), + overlapped_op(Handler handler) + : win_iocp_operation(&overlapped_op::do_complete), handler_(handler) { } + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + overlapped_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) + { + // 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(o->handler_, ec, bytes_transferred); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } + } + private: - // Prevent copying and assignment. - overlapped_operation(const overlapped_operation&); - void operator=(const overlapped_operation&); - - static void do_completion_impl(win_iocp_io_service::operation* op, - DWORD last_error, size_t bytes_transferred) - { - // Take ownership of the operation object. - typedef overlapped_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // Make a copy of the handler and error_code so that the memory can be - // deallocated before the upcall is made. - Handler handler(handler_op->handler_); - boost::system::error_code ec(handler_op->ec_); - if (last_error) - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - - // Free the memory associated with the handler. - ptr.reset(); - - // Make the upcall. - boost_asio_handler_invoke_helpers::invoke( - bind_handler(handler, ec, bytes_transferred), handler); - } - - static void destroy_impl(win_iocp_io_service::operation* op) - { - // Take ownership of the operation object. - typedef overlapped_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); - } - Handler handler_; }; - overlapped_operation_base* ptr_; + win_iocp_operation* ptr_; + win_iocp_io_service* iocp_service_; }; } // namespace detail diff --git a/include/boost/asio/detail/win_iocp_serial_port_service.hpp b/include/boost/asio/detail/win_iocp_serial_port_service.hpp index 4d6d2e94..288287c2 100644 --- a/include/boost/asio/detail/win_iocp_serial_port_service.hpp +++ b/include/boost/asio/detail/win_iocp_serial_port_service.hpp @@ -37,7 +37,6 @@ namespace detail { // Extend win_iocp_handle_service to provide serial port support. class win_iocp_serial_port_service - : public boost::asio::detail::service_base { public: // The native type of a stream handle. @@ -47,10 +46,7 @@ public: typedef win_iocp_handle_service::implementation_type implementation_type; win_iocp_serial_port_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - win_iocp_serial_port_service>(io_service), - handle_service_( - boost::asio::use_service(io_service)) + : handle_service_(io_service) { } @@ -279,8 +275,8 @@ public: } private: - // The handle service used for initiating asynchronous operations. - win_iocp_handle_service& handle_service_; + // The implementation used for initiating asynchronous operations. + win_iocp_handle_service handle_service_; }; } // namespace detail diff --git a/include/boost/asio/detail/win_iocp_socket_service.hpp b/include/boost/asio/detail/win_iocp_socket_service.hpp index e0c08063..7114f04f 100644 --- a/include/boost/asio/detail/win_iocp_socket_service.hpp +++ b/include/boost/asio/detail/win_iocp_socket_service.hpp @@ -28,15 +28,19 @@ #include #include -#include #include #include #include #include +#include +#include #include #include #include -#include +#include +#include +#include +#include #include #include #include @@ -48,7 +52,6 @@ namespace detail { template class win_iocp_socket_service - : public boost::asio::detail::service_base > { public: // The protocol type. @@ -57,9 +60,6 @@ public: // The endpoint type. typedef typename Protocol::endpoint endpoint_type; - // Base class for all operations. - typedef win_iocp_io_service::operation operation; - struct noop_deleter { void operator()(void*) {} }; typedef boost::shared_ptr shared_cancel_token_type; typedef boost::weak_ptr weak_cancel_token_type; @@ -114,9 +114,6 @@ public: endpoint_type remote_endpoint_; }; - // The type of the reactor used for connect operations. - typedef detail::select_reactor reactor_type; - // The implementation type of the socket. class implementation_type { @@ -161,7 +158,7 @@ public: protocol_type protocol_; // Per-descriptor data used by the reactor. - reactor_type::per_descriptor_data reactor_data_; + 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 @@ -176,14 +173,10 @@ public: implementation_type* prev_; }; - // The maximum number of buffers to support in a single operation. - enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; - // Constructor. win_iocp_socket_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - win_iocp_socket_service >(io_service), - iocp_service_(boost::asio::use_service(io_service)), + : io_service_(io_service), + iocp_service_(use_service(io_service)), reactor_(0), mutex_(), impl_list_(0) @@ -304,11 +297,11 @@ public: // 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_type* reactor = static_cast( + reactor* r = static_cast( interlocked_compare_exchange_pointer( reinterpret_cast(&reactor_), 0, 0)); - if (reactor) - reactor->close_descriptor(impl.socket_, impl.reactor_data_); + if (r) + r->close_descriptor(impl.socket_, impl.reactor_data_); if (socket_ops::close(impl.socket_, ec) == socket_error_retval) return ec; @@ -665,23 +658,11 @@ public: return 0; } - // Copy buffers into WSABUF array. - ::WSABUF bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - DWORD i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - bufs[i].len = static_cast(boost::asio::buffer_size(buffer)); - bufs[i].buf = const_cast( - boost::asio::buffer_cast(buffer)); - total_buffer_size += boost::asio::buffer_size(buffer); - } + buffer_sequence_adapter bufs(buffers); // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) + if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) { ec = boost::system::error_code(); return 0; @@ -689,8 +670,8 @@ public: // Send the data. DWORD bytes_transferred = 0; - int result = ::WSASend(impl.socket_, bufs, - i, &bytes_transferred, flags, 0, 0); + int result = ::WSASend(impl.socket_, bufs.buffers(), + bufs.count(), &bytes_transferred, flags, 0, 0); if (result != 0) { DWORD last_error = ::WSAGetLastError(); @@ -724,94 +705,63 @@ public: } template - class send_operation - : public operation + class send_op : public operation { public: - send_operation(win_iocp_io_service& io_service, - weak_cancel_token_type cancel_token, + send_op(weak_cancel_token_type cancel_token, const ConstBufferSequence& buffers, Handler handler) - : operation(io_service, - &send_operation::do_completion_impl, - &send_operation::destroy_impl), - work_(io_service.get_io_service()), + : operation(&send_op::do_complete), cancel_token_(cancel_token), buffers_(buffers), handler_(handler) { } - private: - static void do_completion_impl(operation* op, - DWORD last_error, size_t bytes_transferred) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. - typedef send_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); + send_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - typename ConstBufferSequence::const_iterator iter - = handler_op->buffers_.begin(); - typename ConstBufferSequence::const_iterator end - = handler_op->buffers_.end(); - while (iter != end) + // Make the upcall if required. + if (owner) { - boost::asio::const_buffer buffer(*iter); - boost::asio::buffer_cast(buffer); - ++iter; - } +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Map non-portable errors to their portable counterparts. - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - if (ec.value() == ERROR_NETNAME_DELETED) - { - if (handler_op->cancel_token_.expired()) - ec = boost::asio::error::operation_aborted; - else - ec = boost::asio::error::connection_reset; + // 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::binder2 + handler(o->handler_, ec, bytes_transferred); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); } - 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. - Handler handler(handler_op->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Call the handler. - boost_asio_handler_invoke_helpers::invoke( - detail::bind_handler(handler, ec, bytes_transferred), handler); } - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef send_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); - } - - boost::asio::io_service::work work_; + private: weak_cancel_token_type cancel_token_; ConstBufferSequence buffers_; Handler handler_; @@ -823,127 +773,34 @@ public: void async_send(implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, Handler handler) { -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - // Allocate and construct an operation to wrap the handler. - typedef send_operation value_type; + typedef send_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, iocp_service_, + handler_ptr ptr(raw_ptr, impl.cancel_token_, buffers, handler); - if (!is_open(impl)) - { - ptr.get()->on_immediate_completion(WSAEBADF, 0); - ptr.release(); - return; - } + buffer_sequence_adapter bufs(buffers); - // Copy buffers into WSABUF array. - ::WSABUF bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - DWORD i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - bufs[i].len = static_cast(boost::asio::buffer_size(buffer)); - bufs[i].buf = const_cast( - boost::asio::buffer_cast(buffer)); - total_buffer_size += boost::asio::buffer_size(buffer); - } - - // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) - { - ptr.get()->on_immediate_completion(0, 0); - ptr.release(); - return; - } - - // Send the data. - DWORD bytes_transferred = 0; - int result = ::WSASend(impl.socket_, bufs, i, - &bytes_transferred, flags, ptr.get(), 0); - DWORD last_error = ::WSAGetLastError(); - - // Check if the operation completed immediately. - if (result != 0 && last_error != WSA_IO_PENDING) - { - ptr.get()->on_immediate_completion(last_error, bytes_transferred); - ptr.release(); - } - else - { - ptr.get()->on_pending(); - ptr.release(); - } + start_send_op(impl, bufs.buffers(), bufs.count(), flags, + impl.protocol_.type() == SOCK_STREAM && bufs.all_empty(), ptr.get()); + ptr.release(); } - template - class null_buffers_operation - { - public: - null_buffers_operation(boost::asio::io_service& io_service, Handler handler) - : work_(io_service), - handler_(handler) - { - } - - bool perform(boost::system::error_code&, - std::size_t& bytes_transferred) - { - bytes_transferred = 0; - return true; - } - - void complete(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - work_.get_io_service().post(bind_handler( - handler_, ec, bytes_transferred)); - } - - private: - boost::asio::io_service::work work_; - Handler handler_; - }; - // Start an asynchronous wait until data can be sent without blocking. template void async_send(implementation_type& impl, const null_buffers&, socket_base::message_flags, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - // Check if the reactor was already obtained from the io_service. - reactor_type* reactor = static_cast( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (!reactor) - { - reactor = &(boost::asio::use_service( - this->get_io_service())); - interlocked_exchange_pointer( - reinterpret_cast(&reactor_), reactor); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); - reactor->start_write_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } + start_reactor_op(impl, reactor::write_op, ptr.get()); + ptr.release(); } // Send a datagram to the specified endpoint. Returns the number of bytes @@ -959,23 +816,14 @@ public: return 0; } - // Copy buffers into WSABUF array. - ::WSABUF bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - DWORD i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - bufs[i].len = static_cast(boost::asio::buffer_size(buffer)); - bufs[i].buf = const_cast( - boost::asio::buffer_cast(buffer)); - } + buffer_sequence_adapter bufs(buffers); // Send the data. DWORD bytes_transferred = 0; - int result = ::WSASendTo(impl.socket_, bufs, i, &bytes_transferred, - flags, destination.data(), static_cast(destination.size()), 0, 0); + int result = ::WSASendTo(impl.socket_, bufs.buffers(), bufs.count(), + &bytes_transferred, flags, destination.data(), + static_cast(destination.size()), 0, 0); if (result != 0) { DWORD last_error = ::WSAGetLastError(); @@ -1008,85 +856,57 @@ public: } template - class send_to_operation - : public operation + class send_to_op : public operation { public: - send_to_operation(win_iocp_io_service& io_service, + send_to_op(weak_cancel_token_type cancel_token, const ConstBufferSequence& buffers, Handler handler) - : operation(io_service, - &send_to_operation::do_completion_impl, - &send_to_operation::destroy_impl), - work_(io_service.get_io_service()), + : operation(&send_to_op::do_complete), + cancel_token_(cancel_token), buffers_(buffers), handler_(handler) { } - private: - static void do_completion_impl(operation* op, - DWORD last_error, size_t bytes_transferred) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. - typedef send_to_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); + send_to_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - typename ConstBufferSequence::const_iterator iter - = handler_op->buffers_.begin(); - typename ConstBufferSequence::const_iterator end - = handler_op->buffers_.end(); - while (iter != end) + // Make the upcall if required. + if (owner) { - boost::asio::const_buffer buffer(*iter); - boost::asio::buffer_cast(buffer); - ++iter; - } +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Map non-portable errors to their portable counterparts. - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - if (ec.value() == ERROR_PORT_UNREACHABLE) - { - ec = boost::asio::error::connection_refused; + // Map non-portable errors to their portable counterparts. + 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::binder2 + handler(o->handler_, ec, bytes_transferred); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); } - - // Make a copy of the handler so that the memory can be deallocated before - // the upcall is made. - Handler handler(handler_op->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Call the handler. - boost_asio_handler_invoke_helpers::invoke( - detail::bind_handler(handler, ec, bytes_transferred), handler); } - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef send_to_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); - } - - boost::asio::io_service::work work_; + private: + weak_cancel_token_type cancel_token_; ConstBufferSequence buffers_; Handler handler_; }; @@ -1098,57 +918,19 @@ public: const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, Handler handler) { -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - // Allocate and construct an operation to wrap the handler. - typedef send_to_operation value_type; + typedef send_to_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, iocp_service_, buffers, handler); + handler_ptr ptr(raw_ptr, + impl.cancel_token_, buffers, handler); - if (!is_open(impl)) - { - ptr.get()->on_immediate_completion(WSAEBADF, 0); - ptr.release(); - return; - } + buffer_sequence_adapter bufs(buffers); - // Copy buffers into WSABUF array. - ::WSABUF bufs[max_buffers]; - typename ConstBufferSequence::const_iterator iter = buffers.begin(); - typename ConstBufferSequence::const_iterator end = buffers.end(); - DWORD i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::const_buffer buffer(*iter); - bufs[i].len = static_cast(boost::asio::buffer_size(buffer)); - bufs[i].buf = const_cast( - boost::asio::buffer_cast(buffer)); - } - - // Send the data. - DWORD bytes_transferred = 0; - int result = ::WSASendTo(impl.socket_, bufs, i, &bytes_transferred, flags, - destination.data(), static_cast(destination.size()), ptr.get(), 0); - DWORD last_error = ::WSAGetLastError(); - - // Check if the operation completed immediately. - if (result != 0 && last_error != WSA_IO_PENDING) - { - ptr.get()->on_immediate_completion(last_error, bytes_transferred); - ptr.release(); - } - else - { - ptr.get()->on_pending(); - ptr.release(); - } + start_send_to_op(impl, bufs.buffers(), + bufs.count(), destination, flags, ptr.get()); + ptr.release(); } // Start an asynchronous wait until data can be sent without blocking. @@ -1156,29 +938,14 @@ public: void async_send_to(implementation_type& impl, const null_buffers&, socket_base::message_flags, const endpoint_type&, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - // Check if the reactor was already obtained from the io_service. - reactor_type* reactor = static_cast( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (!reactor) - { - reactor = &(boost::asio::use_service( - this->get_io_service())); - interlocked_exchange_pointer( - reinterpret_cast(&reactor_), reactor); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); - reactor->start_write_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } + start_reactor_op(impl, reactor::write_op, ptr.get()); + ptr.release(); } // Receive some data from the peer. Returns the number of bytes received. @@ -1193,22 +960,11 @@ public: return 0; } - // Copy buffers into WSABUF array. - ::WSABUF bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - DWORD i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - bufs[i].len = static_cast(boost::asio::buffer_size(buffer)); - bufs[i].buf = boost::asio::buffer_cast(buffer); - total_buffer_size += boost::asio::buffer_size(buffer); - } + buffer_sequence_adapter bufs(buffers); // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) + if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) { ec = boost::system::error_code(); return 0; @@ -1217,8 +973,8 @@ public: // Receive some data. DWORD bytes_transferred = 0; DWORD recv_flags = flags; - int result = ::WSARecv(impl.socket_, bufs, i, - &bytes_transferred, &recv_flags, 0, 0); + int result = ::WSARecv(impl.socket_, bufs.buffers(), + bufs.count(), &bytes_transferred, &recv_flags, 0, 0); if (result != 0) { DWORD last_error = ::WSAGetLastError(); @@ -1257,106 +1013,73 @@ public: } template - class receive_operation - : public operation + class receive_op : public operation { public: - receive_operation(int protocol_type, win_iocp_io_service& io_service, - weak_cancel_token_type cancel_token, + receive_op(int protocol_type, weak_cancel_token_type cancel_token, const MutableBufferSequence& buffers, Handler handler) - : operation(io_service, - &receive_operation< - MutableBufferSequence, Handler>::do_completion_impl, - &receive_operation< - MutableBufferSequence, Handler>::destroy_impl), + : operation(&receive_op::do_complete), protocol_type_(protocol_type), - work_(io_service.get_io_service()), cancel_token_(cancel_token), buffers_(buffers), handler_(handler) { } - private: - static void do_completion_impl(operation* op, - DWORD last_error, size_t bytes_transferred) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. - typedef receive_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); + receive_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - typename MutableBufferSequence::const_iterator iter - = handler_op->buffers_.begin(); - typename MutableBufferSequence::const_iterator end - = handler_op->buffers_.end(); - while (iter != end) + // Make the upcall if required. + if (owner) { - boost::asio::mutable_buffer buffer(*iter); - boost::asio::buffer_cast(buffer); - ++iter; - } +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Map non-portable errors to their portable counterparts. - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - if (ec.value() == ERROR_NETNAME_DELETED) - { - if (handler_op->cancel_token_.expired()) - ec = boost::asio::error::operation_aborted; - else - ec = boost::asio::error::connection_reset; + // 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; + } + + // Check for connection closed. + else if (!ec && bytes_transferred == 0 + && o->protocol_type_ == SOCK_STREAM + && !boost::is_same::value) + { + ec = boost::asio::error::eof; + } + + // 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(o->handler_, ec, bytes_transferred); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); } - else if (ec.value() == ERROR_PORT_UNREACHABLE) - { - ec = boost::asio::error::connection_refused; - } - - // Check for connection closed. - else if (!ec && bytes_transferred == 0 - && handler_op->protocol_type_ == SOCK_STREAM - && !boost::is_same::value) - { - ec = boost::asio::error::eof; - } - - // Make a copy of the handler so that the memory can be deallocated before - // the upcall is made. - Handler handler(handler_op->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Call the handler. - boost_asio_handler_invoke_helpers::invoke( - detail::bind_handler(handler, ec, bytes_transferred), handler); - } - - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef receive_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); } + private: int protocol_type_; - boost::asio::io_service::work work_; weak_cancel_token_type cancel_token_; MutableBufferSequence buffers_; Handler handler_; @@ -1369,67 +1092,20 @@ public: const MutableBufferSequence& buffers, socket_base::message_flags flags, Handler handler) { -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - // Allocate and construct an operation to wrap the handler. - typedef receive_operation value_type; + typedef receive_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); int protocol_type = impl.protocol_.type(); handler_ptr ptr(raw_ptr, protocol_type, - iocp_service_, impl.cancel_token_, buffers, handler); + impl.cancel_token_, buffers, handler); - if (!is_open(impl)) - { - ptr.get()->on_immediate_completion(WSAEBADF, 0); - ptr.release(); - return; - } + buffer_sequence_adapter bufs(buffers); - // Copy buffers into WSABUF array. - ::WSABUF bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - DWORD i = 0; - size_t total_buffer_size = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - bufs[i].len = static_cast(boost::asio::buffer_size(buffer)); - bufs[i].buf = boost::asio::buffer_cast(buffer); - total_buffer_size += boost::asio::buffer_size(buffer); - } - - // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) - { - ptr.get()->on_immediate_completion(0, 0); - ptr.release(); - return; - } - - // Receive some data. - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = ::WSARecv(impl.socket_, bufs, i, - &bytes_transferred, &recv_flags, ptr.get(), 0); - DWORD last_error = ::WSAGetLastError(); - if (result != 0 && last_error != WSA_IO_PENDING) - { - ptr.get()->on_immediate_completion(last_error, bytes_transferred); - ptr.release(); - } - else - { - ptr.get()->on_pending(); - ptr.release(); - } + start_receive_op(impl, bufs.buffers(), bufs.count(), flags, + protocol_type == SOCK_STREAM && bufs.all_empty(), ptr.get()); + ptr.release(); } // Wait until data can be received without blocking. @@ -1437,75 +1113,36 @@ public: void async_receive(implementation_type& impl, const null_buffers& buffers, socket_base::message_flags flags, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else if (impl.protocol_.type() == SOCK_STREAM) + if (impl.protocol_.type() == SOCK_STREAM) { // For stream sockets on Windows, we may issue a 0-byte overlapped // WSARecv to wait until there is data available on the socket. -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - // Allocate and construct an operation to wrap the handler. - typedef receive_operation value_type; + typedef receive_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); int protocol_type = impl.protocol_.type(); handler_ptr ptr(raw_ptr, protocol_type, - iocp_service_, impl.cancel_token_, buffers, handler); + impl.cancel_token_, buffers, handler); - // Issue a receive operation with an empty buffer. ::WSABUF buf = { 0, 0 }; - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = ::WSARecv(impl.socket_, &buf, 1, - &bytes_transferred, &recv_flags, ptr.get(), 0); - DWORD last_error = ::WSAGetLastError(); - if (result != 0 && last_error != WSA_IO_PENDING) - { - ptr.get()->on_immediate_completion(last_error, bytes_transferred); - ptr.release(); - } - else - { - ptr.get()->on_pending(); - ptr.release(); - } + start_receive_op(impl, &buf, 1, flags, false, ptr.get()); + ptr.release(); } else { - // Check if the reactor was already obtained from the io_service. - reactor_type* reactor = static_cast( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (!reactor) - { - reactor = &(boost::asio::use_service( - this->get_io_service())); - interlocked_exchange_pointer( - reinterpret_cast(&reactor_), reactor); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); - if (flags & socket_base::message_out_of_band) - { - reactor->start_except_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler)); - } - else - { - reactor->start_read_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } + start_reactor_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + ptr.get()); + ptr.release(); } } @@ -1523,24 +1160,16 @@ public: return 0; } - // Copy buffers into WSABUF array. - ::WSABUF bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - DWORD i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - bufs[i].len = static_cast(boost::asio::buffer_size(buffer)); - bufs[i].buf = boost::asio::buffer_cast(buffer); - } + buffer_sequence_adapter bufs(buffers); // Receive some data. DWORD bytes_transferred = 0; DWORD recv_flags = flags; int endpoint_size = static_cast(sender_endpoint.capacity()); - int result = ::WSARecvFrom(impl.socket_, bufs, i, &bytes_transferred, - &recv_flags, sender_endpoint.data(), &endpoint_size, 0, 0); + int result = ::WSARecvFrom(impl.socket_, bufs.buffers(), + bufs.count(), &bytes_transferred, &recv_flags, + sender_endpoint.data(), &endpoint_size, 0, 0); if (result != 0) { DWORD last_error = ::WSAGetLastError(); @@ -1583,22 +1212,15 @@ public: } template - class receive_from_operation - : public operation + class receive_from_op : public operation { public: - receive_from_operation(int protocol_type, win_iocp_io_service& io_service, - endpoint_type& endpoint, const MutableBufferSequence& buffers, - Handler handler) - : operation(io_service, - &receive_from_operation< - MutableBufferSequence, Handler>::do_completion_impl, - &receive_from_operation< - MutableBufferSequence, Handler>::destroy_impl), + receive_from_op(int protocol_type, endpoint_type& endpoint, + const MutableBufferSequence& buffers, Handler handler) + : operation(&receive_from_op::do_complete), protocol_type_(protocol_type), endpoint_(endpoint), endpoint_size_(static_cast(endpoint.capacity())), - work_(io_service.get_io_service()), buffers_(buffers), handler_(handler) { @@ -1609,83 +1231,51 @@ public: return endpoint_size_; } - private: - static void do_completion_impl(operation* op, - DWORD last_error, size_t bytes_transferred) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. - typedef receive_from_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); + receive_from_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - typename MutableBufferSequence::const_iterator iter - = handler_op->buffers_.begin(); - typename MutableBufferSequence::const_iterator end - = handler_op->buffers_.end(); - while (iter != end) + // Make the upcall if required. + if (owner) { - boost::asio::mutable_buffer buffer(*iter); - boost::asio::buffer_cast(buffer); - ++iter; - } +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Map non-portable errors to their portable counterparts. - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - if (ec.value() == ERROR_PORT_UNREACHABLE) - { - ec = boost::asio::error::connection_refused; + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = boost::asio::error::connection_refused; + } + + // Record the size of the endpoint returned by the operation. + o->endpoint_.resize(o->endpoint_size_); + + // 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(o->handler_, ec, bytes_transferred); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); } - - // Check for connection closed. - if (!ec && bytes_transferred == 0 - && handler_op->protocol_type_ == SOCK_STREAM) - { - ec = boost::asio::error::eof; - } - - // Record the size of the endpoint returned by the operation. - handler_op->endpoint_.resize(handler_op->endpoint_size_); - - // Make a copy of the handler so that the memory can be deallocated before - // the upcall is made. - Handler handler(handler_op->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Call the handler. - boost_asio_handler_invoke_helpers::invoke( - detail::bind_handler(handler, ec, bytes_transferred), handler); - } - - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef receive_from_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); } + private: int protocol_type_; endpoint_type& endpoint_; int endpoint_size_; - boost::asio::io_service::work work_; + weak_cancel_token_type cancel_token_; MutableBufferSequence buffers_; Handler handler_; }; @@ -1698,58 +1288,20 @@ public: const MutableBufferSequence& buffers, endpoint_type& sender_endp, socket_base::message_flags flags, Handler handler) { -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - // Allocate and construct an operation to wrap the handler. - typedef receive_from_operation value_type; + typedef receive_from_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); int protocol_type = impl.protocol_.type(); - handler_ptr ptr(raw_ptr, protocol_type, - iocp_service_, sender_endp, buffers, handler); + handler_ptr ptr(raw_ptr, + protocol_type, sender_endp, buffers, handler); - if (!is_open(impl)) - { - ptr.get()->on_immediate_completion(WSAEBADF, 0); - ptr.release(); - return; - } + buffer_sequence_adapter bufs(buffers); - // Copy buffers into WSABUF array. - ::WSABUF bufs[max_buffers]; - typename MutableBufferSequence::const_iterator iter = buffers.begin(); - typename MutableBufferSequence::const_iterator end = buffers.end(); - DWORD i = 0; - for (; iter != end && i < max_buffers; ++iter, ++i) - { - boost::asio::mutable_buffer buffer(*iter); - bufs[i].len = static_cast(boost::asio::buffer_size(buffer)); - bufs[i].buf = boost::asio::buffer_cast(buffer); - } - - // Receive some data. - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = ::WSARecvFrom(impl.socket_, bufs, i, &bytes_transferred, - &recv_flags, sender_endp.data(), &ptr.get()->endpoint_size(), - ptr.get(), 0); - DWORD last_error = ::WSAGetLastError(); - if (result != 0 && last_error != WSA_IO_PENDING) - { - ptr.get()->on_immediate_completion(last_error, bytes_transferred); - ptr.release(); - } - else - { - ptr.get()->on_pending(); - ptr.release(); - } + start_receive_from_op(impl, bufs.buffers(), bufs.count(), + sender_endp, flags, &ptr.get()->endpoint_size(), ptr.get()); + ptr.release(); } // Wait until data can be received without blocking. @@ -1758,40 +1310,20 @@ public: const null_buffers&, endpoint_type& sender_endpoint, socket_base::message_flags flags, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor, 0)); - } - else - { - // Check if the reactor was already obtained from the io_service. - reactor_type* reactor = static_cast( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (!reactor) - { - reactor = &(boost::asio::use_service( - this->get_io_service())); - interlocked_exchange_pointer( - reinterpret_cast(&reactor_), reactor); - } + // Allocate and construct an operation to wrap the handler. + typedef null_buffers_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); - // Reset endpoint since it can be given no sensible value at this time. - sender_endpoint = endpoint_type(); + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); - if (flags & socket_base::message_out_of_band) - { - reactor->start_except_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler)); - } - else - { - reactor->start_read_op(impl.socket_, impl.reactor_data_, - null_buffers_operation(this->get_io_service(), handler), - false); - } - } + start_reactor_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + ptr.get()); + ptr.release(); } // Accept a new connection. @@ -1852,32 +1384,27 @@ public: } template - class accept_operation - : public operation + class accept_op : public operation { public: - accept_operation(win_iocp_io_service& io_service, - socket_type socket, socket_type new_socket, Socket& peer, - const protocol_type& protocol, endpoint_type* peer_endpoint, - bool enable_connection_aborted, Handler handler) - : operation(io_service, - &accept_operation::do_completion_impl, - &accept_operation::destroy_impl), - io_service_(io_service), + accept_op(win_iocp_io_service& iocp_service, socket_type socket, + Socket& peer, const protocol_type& protocol, + endpoint_type* peer_endpoint, bool enable_connection_aborted, + Handler handler) + : operation(&accept_op::do_complete), + iocp_service_(iocp_service), socket_(socket), - new_socket_(new_socket), peer_(peer), protocol_(protocol), peer_endpoint_(peer_endpoint), - work_(io_service.get_io_service()), enable_connection_aborted_(enable_connection_aborted), handler_(handler) { } - socket_type new_socket() + socket_holder& new_socket() { - return new_socket_.get(); + return new_socket_; } void* output_buffer() @@ -1890,166 +1417,145 @@ public: return sizeof(sockaddr_storage_type) + 16; } - private: - static void do_completion_impl(operation* op, DWORD last_error, size_t) + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t /*bytes_transferred*/) { - // Take ownership of the operation object. - typedef accept_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); + // Take ownership of the handler object. + accept_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); - // Map Windows error ERROR_NETNAME_DELETED to connection_aborted. - if (last_error == ERROR_NETNAME_DELETED) + // Make the upcall if required. + if (owner) { - last_error = WSAECONNABORTED; - } - - // Restart the accept operation if we got the connection_aborted error - // and the enable_connection_aborted socket option is not set. - if (last_error == WSAECONNABORTED - && !ptr.get()->enable_connection_aborted_) - { - // Reset OVERLAPPED structure. - ptr.get()->reset(); - - // Create a new socket for the next connection, since the AcceptEx call - // fails with WSAEINVAL if we try to reuse the same socket. - boost::system::error_code ec; - ptr.get()->new_socket_.reset(); - ptr.get()->new_socket_.reset(socket_ops::socket( - ptr.get()->protocol_.family(), ptr.get()->protocol_.type(), - ptr.get()->protocol_.protocol(), ec)); - if (ptr.get()->new_socket() != invalid_socket) + // Map Windows error ERROR_NETNAME_DELETED to connection_aborted. + if (ec.value() == ERROR_NETNAME_DELETED) { - // Accept a connection. - DWORD bytes_read = 0; - BOOL result = ::AcceptEx(ptr.get()->socket_, ptr.get()->new_socket(), - ptr.get()->output_buffer(), 0, ptr.get()->address_length(), - ptr.get()->address_length(), &bytes_read, ptr.get()); - last_error = ::WSAGetLastError(); + ec = boost::asio::error::connection_aborted; + } - // Check if the operation completed immediately. - if (!result && last_error != WSA_IO_PENDING) + // 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_) + { + // Reset OVERLAPPED structure. + o->reset(); + + // Create a new socket for the next connection, since the AcceptEx + // call fails with WSAEINVAL if we try to reuse the same socket. + o->new_socket_.reset(); + o->new_socket_.reset(socket_ops::socket(o->protocol_.family(), + o->protocol_.type(), o->protocol_.protocol(), ec)); + if (o->new_socket_.get() != invalid_socket) { - if (last_error == ERROR_NETNAME_DELETED - || last_error == WSAECONNABORTED) + // Accept a connection. + DWORD bytes_read = 0; + BOOL result = ::AcceptEx(o->socket_, o->new_socket_.get(), + o->output_buffer(), 0, o->address_length(), + o->address_length(), &bytes_read, o); + DWORD last_error = ::WSAGetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + + // Check if the operation completed immediately. + if (!result && last_error != WSA_IO_PENDING) { - // Post this handler so that operation will be restarted again. - ptr.get()->on_immediate_completion(last_error, 0); - ptr.release(); - return; + if (last_error == ERROR_NETNAME_DELETED + || last_error == WSAECONNABORTED) + { + // Post this handler so that operation will be restarted again. + o->iocp_service_.work_started(); + o->iocp_service_.on_completion(o, ec); + ptr.release(); + return; + } + else + { + // Operation already complete. Continue with rest of this + // handler. + } } else { - // Operation already complete. Continue with rest of this handler. + // Asynchronous operation has been successfully restarted. + o->iocp_service_.work_started(); + o->iocp_service_.on_pending(o); + ptr.release(); + return; } } + } + + // Get the address of the peer. + endpoint_type peer_endpoint; + if (!ec) + { + LPSOCKADDR local_addr = 0; + int local_addr_length = 0; + LPSOCKADDR remote_addr = 0; + int remote_addr_length = 0; + GetAcceptExSockaddrs(o->output_buffer(), 0, o->address_length(), + o->address_length(), &local_addr, &local_addr_length, + &remote_addr, &remote_addr_length); + if (static_cast(remote_addr_length) + > peer_endpoint.capacity()) + { + ec = boost::asio::error::invalid_argument; + } else { - // Asynchronous operation has been successfully restarted. - ptr.get()->on_pending(); - ptr.release(); - return; + using namespace std; // For memcpy. + memcpy(peer_endpoint.data(), remote_addr, remote_addr_length); + peer_endpoint.resize(static_cast(remote_addr_length)); } } - } - // Get the address of the peer. - endpoint_type peer_endpoint; - if (last_error == 0) - { - LPSOCKADDR local_addr = 0; - int local_addr_length = 0; - LPSOCKADDR remote_addr = 0; - int remote_addr_length = 0; - GetAcceptExSockaddrs(handler_op->output_buffer(), 0, - handler_op->address_length(), handler_op->address_length(), - &local_addr, &local_addr_length, &remote_addr, &remote_addr_length); - if (static_cast(remote_addr_length) - > peer_endpoint.capacity()) + // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname + // and getpeername will work on the accepted socket. + if (!ec) { - last_error = WSAEINVAL; + SOCKET update_ctx_param = o->socket_; + socket_ops::setsockopt(o->new_socket_.get(), + SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, + &update_ctx_param, sizeof(SOCKET), ec); } - else + + // If the socket was successfully accepted, transfer ownership of the + // socket to the peer object. + if (!ec) { - using namespace std; // For memcpy. - memcpy(peer_endpoint.data(), remote_addr, remote_addr_length); - peer_endpoint.resize(static_cast(remote_addr_length)); + o->peer_.assign(o->protocol_, + native_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; + + // 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(o->handler_, ec); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); } - - // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname - // and getpeername will work on the accepted socket. - if (last_error == 0) - { - SOCKET update_ctx_param = handler_op->socket_; - boost::system::error_code ec; - if (socket_ops::setsockopt(handler_op->new_socket_.get(), - SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, - &update_ctx_param, sizeof(SOCKET), ec) != 0) - { - last_error = ec.value(); - } - } - - // If the socket was successfully accepted, transfer ownership of the - // socket to the peer object. - if (last_error == 0) - { - boost::system::error_code ec; - handler_op->peer_.assign(handler_op->protocol_, - native_type(handler_op->new_socket_.get(), peer_endpoint), ec); - if (ec) - last_error = ec.value(); - else - handler_op->new_socket_.release(); - } - - // Pass endpoint back to caller. - if (handler_op->peer_endpoint_) - *handler_op->peer_endpoint_ = peer_endpoint; - - // Make a copy of the handler so that the memory can be deallocated before - // the upcall is made. - Handler handler(handler_op->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Call the handler. - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - boost_asio_handler_invoke_helpers::invoke( - detail::bind_handler(handler, ec), handler); } - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef accept_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // 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(handler_op->handler_); - (void)handler; - - // Free the memory associated with the handler. - ptr.reset(); - } - - win_iocp_io_service& io_service_; + private: + win_iocp_io_service& iocp_service_; socket_type socket_; socket_holder new_socket_; Socket& peer_; protocol_type protocol_; endpoint_type* peer_endpoint_; - boost::asio::io_service::work work_; unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; bool enable_connection_aborted_; Handler handler_; @@ -2061,86 +1567,18 @@ public: void async_accept(implementation_type& impl, Socket& peer, endpoint_type* peer_endpoint, Handler handler) { - // Check whether acceptor has been initialised. - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor)); - return; - } - - // Check that peer socket has not already been opened. - if (peer.is_open()) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::already_open)); - return; - } - -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - - // Create a new socket for the connection. - boost::system::error_code ec; - socket_holder sock(socket_ops::socket(impl.protocol_.family(), - impl.protocol_.type(), impl.protocol_.protocol(), ec)); - if (sock.get() == invalid_socket) - { - this->get_io_service().post(bind_handler(handler, ec)); - return; - } - // Allocate and construct an operation to wrap the handler. - typedef accept_operation value_type; + typedef accept_op value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); - socket_type new_socket = sock.get(); bool enable_connection_aborted = (impl.flags_ & implementation_type::enable_connection_aborted); - handler_ptr ptr(raw_ptr, - iocp_service_, impl.socket_, new_socket, peer, impl.protocol_, - peer_endpoint, enable_connection_aborted, handler); - sock.release(); + handler_ptr ptr(raw_ptr, iocp_service_, impl.socket_, peer, + impl.protocol_, peer_endpoint, enable_connection_aborted, handler); - // Accept a connection. - DWORD bytes_read = 0; - BOOL result = ::AcceptEx(impl.socket_, ptr.get()->new_socket(), - ptr.get()->output_buffer(), 0, ptr.get()->address_length(), - ptr.get()->address_length(), &bytes_read, ptr.get()); - DWORD last_error = ::WSAGetLastError(); - - // Check if the operation completed immediately. - if (!result && last_error != WSA_IO_PENDING) - { - if (!enable_connection_aborted - && (last_error == ERROR_NETNAME_DELETED - || last_error == WSAECONNABORTED)) - { - // Post handler so that operation will be restarted again. We do not - // perform the AcceptEx again here to avoid the possibility of starving - // other handlers. - ptr.get()->on_immediate_completion(last_error, 0); - ptr.release(); - } - else - { - boost::asio::io_service::work work(this->get_io_service()); - ptr.reset(); - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - iocp_service_.post(bind_handler(handler, ec)); - } - } - else - { - ptr.get()->on_pending(); - ptr.release(); - } + start_accept_op(impl, peer.is_open(), ptr.get()->new_socket(), + ptr.get()->output_buffer(), ptr.get()->address_length(), ptr.get()); + ptr.release(); } // Connect the socket to the specified endpoint. @@ -2159,67 +1597,76 @@ public: return ec; } - template - class connect_operation + class connect_op_base : public reactor_op { public: - connect_operation(socket_type socket, bool user_set_non_blocking, - boost::asio::io_service& io_service, Handler handler) - : socket_(socket), - user_set_non_blocking_(user_set_non_blocking), - io_service_(io_service), - work_(io_service), - handler_(handler) + connect_op_base(socket_type socket, func_type complete_func) + : reactor_op(&connect_op_base::do_perform, complete_func), + socket_(socket) { } - bool perform(boost::system::error_code& ec, - std::size_t& bytes_transferred) + static bool do_perform(reactor_op* base) { - bytes_transferred = 0; - - // Check whether the operation was successful. - if (ec) - return true; + connect_op_base* o(static_cast(base)); // Get the error code from the connect operation. int connect_error = 0; size_t connect_error_len = sizeof(connect_error); - if (socket_ops::getsockopt(socket_, SOL_SOCKET, SO_ERROR, - &connect_error, &connect_error_len, ec) == socket_error_retval) + if (socket_ops::getsockopt(o->socket_, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, o->ec_) == socket_error_retval) return true; - // If connection failed then post the handler with the error code. + // The connection failed so the handler will be posted with an error code. if (connect_error) { - ec = boost::system::error_code(connect_error, + o->ec_ = boost::system::error_code(connect_error, boost::asio::error::get_system_category()); - return true; } - // Revert socket to blocking mode unless the user requested otherwise. - if (!user_set_non_blocking_) - { - ioctl_arg_type non_blocking = 0; - if (socket_ops::ioctl(socket_, FIONBIO, &non_blocking, ec)) - return true; - } - - // Post the result of the successful connection operation. - ec = boost::system::error_code(); return true; } - void complete(const boost::system::error_code& ec, std::size_t) - { - io_service_.post(bind_handler(handler_, ec)); - } - private: socket_type socket_; - bool user_set_non_blocking_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; + }; + + template + class connect_op : public connect_op_base + { + public: + connect_op(socket_type socket, Handler handler) + : connect_op_base(socket, &connect_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + connect_op* o(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(o->handler_, o); + + // Make the upcall if required. + if (owner) + { + // 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(o->handler_, o->ec_); + ptr.reset(); + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } + } + + private: Handler handler_; }; @@ -2228,86 +1675,216 @@ public: void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, Handler handler) { - if (!is_open(impl)) - { - this->get_io_service().post(bind_handler(handler, - boost::asio::error::bad_descriptor)); - return; - } + // Allocate and construct an operation to wrap the handler. + typedef connect_op value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, impl.socket_, handler); -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - - // Check if the reactor was already obtained from the io_service. - reactor_type* reactor = static_cast( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (!reactor) - { - reactor = &(boost::asio::use_service( - this->get_io_service())); - interlocked_exchange_pointer( - reinterpret_cast(&reactor_), reactor); - } - - // Mark the socket as non-blocking so that the connection will take place - // asynchronously. - ioctl_arg_type non_blocking = 1; - boost::system::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - { - this->get_io_service().post(bind_handler(handler, ec)); - return; - } - - // Start the connect operation. - if (socket_ops::connect(impl.socket_, peer_endpoint.data(), - peer_endpoint.size(), ec) == 0) - { - // Revert socket to blocking mode unless the user requested otherwise. - if (!(impl.flags_ & implementation_type::user_set_non_blocking)) - { - non_blocking = 0; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec); - } - - // The connect operation has finished successfully so we need to post the - // handler immediately. - this->get_io_service().post(bind_handler(handler, ec)); - } - else if (ec == boost::asio::error::in_progress - || ec == boost::asio::error::would_block) - { - // The connection is happening in the background, and we need to wait - // until the socket becomes writeable. - boost::shared_ptr completed(new bool(false)); - reactor->start_connect_op(impl.socket_, impl.reactor_data_, - connect_operation( - impl.socket_, - (impl.flags_ & implementation_type::user_set_non_blocking) != 0, - this->get_io_service(), handler)); - } - else - { - // Revert socket to blocking mode unless the user requested otherwise. - if (!(impl.flags_ & implementation_type::user_set_non_blocking)) - { - non_blocking = 0; - boost::system::error_code ignored_ec; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); - } - - // The connect operation has failed, so post the handler immediately. - this->get_io_service().post(bind_handler(handler, ec)); - } + start_connect_op(impl, ptr.get(), peer_endpoint); + ptr.release(); } private: + // Helper function to start an asynchronous send operation. + void start_send_op(implementation_type& impl, WSABUF* buffers, + std::size_t buffer_count, socket_base::message_flags flags, + bool noop, operation* op) + { + update_cancellation_thread_id(); + iocp_service_.work_started(); + + if (noop) + iocp_service_.on_completion(op); + else if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + int result = ::WSASend(impl.socket_, buffers, + buffer_count, &bytes_transferred, flags, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } + } + + // Helper function to start an asynchronous send_to operation. + void start_send_to_op(implementation_type& impl, WSABUF* buffers, + std::size_t buffer_count, const endpoint_type& destination, + socket_base::message_flags flags, operation* op) + { + update_cancellation_thread_id(); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + int result = ::WSASendTo(impl.socket_, buffers, buffer_count, + &bytes_transferred, flags, destination.data(), + static_cast(destination.size()), op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } + } + + // Helper function to start an asynchronous receive operation. + void start_receive_op(implementation_type& impl, WSABUF* buffers, + std::size_t buffer_count, socket_base::message_flags flags, + bool noop, operation* op) + { + update_cancellation_thread_id(); + iocp_service_.work_started(); + + if (noop) + iocp_service_.on_completion(op); + else if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecv(impl.socket_, buffers, buffer_count, + &bytes_transferred, &recv_flags, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_NETNAME_DELETED) + last_error = WSAECONNRESET; + else if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } + } + + // Helper function to start an asynchronous receive_from operation. + void start_receive_from_op(implementation_type& impl, WSABUF* buffers, + std::size_t buffer_count, endpoint_type& sender_endpoint, + socket_base::message_flags flags, int* endpoint_size, operation* op) + { + update_cancellation_thread_id(); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecvFrom(impl.socket_, buffers, + buffer_count, &bytes_transferred, &recv_flags, + sender_endpoint.data(), endpoint_size, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } + } + + // Helper function to start an asynchronous receive_from operation. + void start_accept_op(implementation_type& impl, + bool peer_is_open, socket_holder& new_socket, + void* output_buffer, DWORD address_length, operation* op) + { + update_cancellation_thread_id(); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else if (peer_is_open) + iocp_service_.on_completion(op, boost::asio::error::already_open); + else + { + boost::system::error_code ec; + new_socket.reset(socket_ops::socket(impl.protocol_.family(), + impl.protocol_.type(), impl.protocol_.protocol(), ec)); + if (new_socket.get() == invalid_socket) + iocp_service_.on_completion(op, ec); + else + { + DWORD bytes_read = 0; + BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer, + 0, address_length, address_length, &bytes_read, op); + DWORD last_error = ::WSAGetLastError(); + if (!result && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error); + else + iocp_service_.on_pending(op); + } + } + } + + // Start an asynchronous read or write operation using the the reactor. + void start_reactor_op(implementation_type& impl, int op_type, reactor_op* op) + { + reactor& r = get_reactor(); + update_cancellation_thread_id(); + + if (is_open(impl)) + { + r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false); + return; + } + else + op->ec_ = boost::asio::error::bad_descriptor; + + iocp_service_.post_immediate_completion(op); + } + + // Start the asynchronous connect operation using the reactor. + void start_connect_op(implementation_type& impl, + reactor_op* op, const endpoint_type& peer_endpoint) + { + reactor& r = get_reactor(); + update_cancellation_thread_id(); + + if (is_open(impl)) + { + ioctl_arg_type non_blocking = 1; + if (!socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, op->ec_)) + { + if (socket_ops::connect(impl.socket_, peer_endpoint.data(), + peer_endpoint.size(), op->ec_) != 0) + { + if (!op->ec_ + && !(impl.flags_ & implementation_type::user_set_non_blocking)) + { + non_blocking = 0; + socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, op->ec_); + } + + if (op->ec_ == boost::asio::error::in_progress + || op->ec_ == boost::asio::error::would_block) + { + op->ec_ = boost::system::error_code(); + r.start_op(reactor::connect_op, impl.socket_, + impl.reactor_data_, op, true); + return; + } + } + } + } + else + op->ec_ = boost::asio::error::bad_descriptor; + + iocp_service_.post_immediate_completion(op); + } + // Helper function to close a socket when the associated object is being // destroyed. void close_for_destruction(implementation_type& impl) @@ -2317,11 +1894,11 @@ private: // 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_type* reactor = static_cast( + reactor* r = static_cast( interlocked_compare_exchange_pointer( reinterpret_cast(&reactor_), 0, 0)); - if (reactor) - reactor->close_descriptor(impl.socket_, impl.reactor_data_); + if (r) + r->close_descriptor(impl.socket_, impl.reactor_data_); // The socket destructor must not block. If the user has changed the // linger option to block in the foreground, we will change it back to the @@ -2347,6 +1924,33 @@ private: } } + // Update the ID of the thread from which cancellation is safe. + void update_cancellation_thread_id() + { +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + if (impl.safe_cancellation_thread_id_ == 0) + impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) + impl.safe_cancellation_thread_id_ = ~DWORD(0); +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + } + + // 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 + // this service. + reactor& get_reactor() + { + reactor* r = static_cast( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (!r) + { + r = &(use_service(io_service_)); + interlocked_exchange_pointer(reinterpret_cast(&reactor_), r); + } + return *r; + } + // Helper function to emulate InterlockedCompareExchangePointer functionality // for: // - very old Platform SDKs; and @@ -2375,13 +1979,16 @@ private: #endif } + // The io_service used to obtain the reactor, if required. + boost::asio::io_service& io_service_; + // The IOCP service used for running asynchronous operations and dispatching // handlers. win_iocp_io_service& iocp_service_; // The reactor used for performing connect operations. This object is created // only if needed. - reactor_type* reactor_; + reactor* reactor_; // Mutex to protect access to the linked list of implementations. boost::asio::detail::mutex mutex_; diff --git a/include/boost/asio/detail/win_mutex.hpp b/include/boost/asio/detail/win_mutex.hpp index 107d7076..ff71fbeb 100644 --- a/include/boost/asio/detail/win_mutex.hpp +++ b/include/boost/asio/detail/win_mutex.hpp @@ -66,15 +66,7 @@ public: // Lock the mutex. void lock() { - int error = do_lock(); - if (error != 0) - { - boost::system::system_error e( - boost::system::error_code(error, - boost::asio::error::get_system_category()), - "mutex"); - boost::throw_exception(e); - } + ::EnterCriticalSection(&crit_section_); } // Unlock the mutex. @@ -92,12 +84,12 @@ private: #if defined(__MINGW32__) // Not sure if MinGW supports structured exception handling, so for now // we'll just call the Windows API and hope. - ::InitializeCriticalSection(&crit_section_); + ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000); return 0; #else __try { - ::InitializeCriticalSection(&crit_section_); + ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000); } __except(GetExceptionCode() == STATUS_NO_MEMORY ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) @@ -109,34 +101,6 @@ private: #endif } - // Locking must be performed in a separate function to lock() since the - // compiler does not support the use of structured exceptions and C++ - // exceptions in the same function. - int do_lock() - { -#if defined(__MINGW32__) - // Not sure if MinGW supports structured exception handling, so for now - // we'll just call the Windows API and hope. - ::EnterCriticalSection(&crit_section_); - return 0; -#else - __try - { - ::EnterCriticalSection(&crit_section_); - } - __except(GetExceptionCode() == STATUS_INVALID_HANDLE - || GetExceptionCode() == STATUS_NO_MEMORY - ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) - { - if (GetExceptionCode() == STATUS_NO_MEMORY) - return ERROR_OUTOFMEMORY; - return ERROR_INVALID_HANDLE; - } - - return 0; -#endif - } - ::CRITICAL_SECTION crit_section_; }; diff --git a/include/boost/asio/impl/io_service.ipp b/include/boost/asio/impl/io_service.ipp index 9234dc45..20f868d2 100644 --- a/include/boost/asio/impl/io_service.ipp +++ b/include/boost/asio/impl/io_service.ipp @@ -26,18 +26,9 @@ #if defined(BOOST_ASIO_HAS_IOCP) # include -#elif defined(BOOST_ASIO_HAS_EPOLL) -# include -# include -#elif defined(BOOST_ASIO_HAS_KQUEUE) -# include -# include -#elif defined(BOOST_ASIO_HAS_DEV_POLL) -# include -# include #else -# include # include +# include #endif namespace boost { @@ -176,7 +167,6 @@ inline boost::asio::io_service& io_service::work::get_io_service() inline io_service::service::service(boost::asio::io_service& owner) : owner_(owner), - type_info_(0), next_(0) { } diff --git a/include/boost/asio/impl/read.ipp b/include/boost/asio/impl/read.ipp index 05ea9608..772c06bc 100644 --- a/include/boost/asio/impl/read.ipp +++ b/include/boost/asio/impl/read.ipp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -42,14 +43,14 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, boost::asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> tmp(buffers); std::size_t total_transferred = 0; - tmp.set_max_size(detail::adapt_completion_condition_result( + 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.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; @@ -130,51 +131,111 @@ namespace detail { template - class read_handler + class read_op + : detail::base_from_completion_cond { public: - typedef boost::asio::detail::consuming_buffers< - mutable_buffer, MutableBufferSequence> buffers_type; - - read_handler(AsyncReadStream& stream, const buffers_type& buffers, + read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers, CompletionCondition completion_condition, ReadHandler handler) - : stream_(stream), + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), buffers_(buffers), total_transferred_(0), - completion_condition_(completion_condition), - handler_(handler) + handler_(handler), + start_(true) { } void operator()(const boost::system::error_code& ec, std::size_t bytes_transferred) { - total_transferred_ += bytes_transferred; - buffers_.consume(bytes_transferred); - buffers_.set_max_size(detail::adapt_completion_condition_result( - completion_condition_(ec, total_transferred_))); - if (buffers_.begin() == buffers_.end()) + switch (start_) { + case true: start_ = false; + buffers_.prepare(this->check(ec, total_transferred_)); + for (;;) + { + stream_.async_read_some(buffers_, *this); + return; default: + total_transferred_ += bytes_transferred; + buffers_.consume(bytes_transferred); + buffers_.prepare(this->check(ec, total_transferred_)); + if ((!ec && bytes_transferred == 0) + || buffers_.begin() == buffers_.end()) + break; + } + handler_(ec, total_transferred_); } - else - { - stream_.async_read_some(buffers_, *this); - } } //private: AsyncReadStream& stream_; - buffers_type buffers_; + boost::asio::detail::consuming_buffers< + mutable_buffer, MutableBufferSequence> buffers_; std::size_t total_transferred_; - CompletionCondition completion_condition_; ReadHandler handler_; + bool start_; + }; + + template + class read_op + : detail::base_from_completion_cond + { + 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), + total_transferred_(0), + handler_(handler), + start_(true) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + std::size_t n = 0; + switch (start_) + { + case true: start_ = false; + n = this->check(ec, total_transferred_); + for (;;) + { + stream_.async_read_some(boost::asio::buffer( + buffer_ + total_transferred_, n), *this); + return; default: + total_transferred_ += bytes_transferred; + if ((!ec && bytes_transferred == 0) + || (n = this->check(ec, total_transferred_)) == 0 + || total_transferred_ == boost::asio::buffer_size(buffer_)) + break; + } + + handler_(ec, total_transferred_); + } + } + + //private: + AsyncReadStream& stream_; + boost::asio::mutable_buffer buffer_; + std::size_t total_transferred_; + ReadHandler handler_; + bool start_; }; template inline void* asio_handler_allocate(std::size_t size, - read_handler* this_handler) { return boost_asio_handler_alloc_helpers::allocate( @@ -184,7 +245,7 @@ namespace detail template inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( @@ -195,7 +256,7 @@ namespace detail typename MutableBufferSequence, typename CompletionCondition, typename ReadHandler> inline void asio_handler_invoke(const Function& function, - read_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -208,24 +269,10 @@ template tmp(buffers); - - boost::system::error_code ec; - std::size_t total_transferred = 0; - tmp.set_max_size(detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred))); - if (tmp.begin() == tmp.end()) - { - s.get_io_service().post(detail::bind_handler( - handler, ec, total_transferred)); - return; - } - - s.async_read_some(tmp, - detail::read_handler( - s, tmp, completion_condition, handler)); + detail::read_op( + s, buffers, completion_condition, handler)( + boost::system::error_code(), 0); } template - class read_streambuf_handler + class read_streambuf_op + : detail::base_from_completion_cond { public: - read_streambuf_handler(AsyncReadStream& stream, + read_streambuf_op(AsyncReadStream& stream, basic_streambuf& streambuf, CompletionCondition completion_condition, ReadHandler handler) - : stream_(stream), + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), streambuf_(streambuf), total_transferred_(0), - completion_condition_(completion_condition), - handler_(handler) + handler_(handler), + start_(true) { } void operator()(const boost::system::error_code& ec, std::size_t bytes_transferred) { - total_transferred_ += bytes_transferred; - streambuf_.commit(bytes_transferred); - std::size_t max_size = detail::adapt_completion_condition_result( - completion_condition_(ec, total_transferred_)); - std::size_t bytes_available = std::min(512, - std::min(max_size, - streambuf_.max_size() - streambuf_.size())); - if (bytes_available == 0) + std::size_t max_size, bytes_available; + switch (start_) { + case true: start_ = false; + max_size = this->check(ec, total_transferred_); + bytes_available = std::min(512, + std::min(max_size, + streambuf_.max_size() - streambuf_.size())); + for (;;) + { + stream_.async_read_some(streambuf_.prepare(bytes_available), *this); + return; default: + total_transferred_ += bytes_transferred; + streambuf_.commit(bytes_transferred); + max_size = this->check(ec, total_transferred_); + bytes_available = std::min(512, + std::min(max_size, + streambuf_.max_size() - streambuf_.size())); + if ((!ec && bytes_transferred == 0) || bytes_available == 0) + break; + } + handler_(ec, total_transferred_); } - else - { - stream_.async_read_some(streambuf_.prepare(bytes_available), *this); - } } //private: AsyncReadStream& stream_; boost::asio::basic_streambuf& streambuf_; std::size_t total_transferred_; - CompletionCondition completion_condition_; ReadHandler handler_; + bool start_; }; template inline void* asio_handler_allocate(std::size_t size, - read_streambuf_handler* this_handler) { return boost_asio_handler_alloc_helpers::allocate( @@ -297,7 +356,7 @@ namespace detail template inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_streambuf_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( @@ -307,7 +366,7 @@ namespace detail template inline void asio_handler_invoke(const Function& function, - read_streambuf_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -321,23 +380,10 @@ inline void async_read(AsyncReadStream& s, boost::asio::basic_streambuf& b, CompletionCondition completion_condition, ReadHandler handler) { - boost::system::error_code ec; - 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 = std::min(512, - std::min(max_size, b.max_size() - b.size())); - if (bytes_available == 0) - { - s.get_io_service().post(detail::bind_handler( - handler, ec, total_transferred)); - return; - } - - s.async_read_some(b.prepare(bytes_available), - detail::read_streambuf_handler( - s, b, completion_condition, handler)); + detail::read_streambuf_op( + s, b, completion_condition, handler)( + boost::system::error_code(), 0); } template diff --git a/include/boost/asio/impl/read_at.ipp b/include/boost/asio/impl/read_at.ipp index 91fd0145..eb3c3f89 100644 --- a/include/boost/asio/impl/read_at.ipp +++ b/include/boost/asio/impl/read_at.ipp @@ -43,7 +43,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, boost::asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> tmp(buffers); std::size_t total_transferred = 0; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { @@ -51,7 +51,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, offset + total_transferred, tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; @@ -158,7 +158,7 @@ namespace detail { total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - buffers_.set_max_size(detail::adapt_completion_condition_result( + buffers_.prepare(detail::adapt_completion_condition_result( completion_condition_(ec, total_transferred_))); if (buffers_.begin() == buffers_.end()) { @@ -225,7 +225,7 @@ inline void async_read_at(AsyncRandomAccessReadDevice& d, boost::system::error_code ec; std::size_t total_transferred = 0; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); if (tmp.begin() == tmp.end()) { diff --git a/include/boost/asio/impl/write.ipp b/include/boost/asio/impl/write.ipp index 76bace37..28a5273c 100644 --- a/include/boost/asio/impl/write.ipp +++ b/include/boost/asio/impl/write.ipp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -37,14 +38,14 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, boost::asio::detail::consuming_buffers< const_buffer, ConstBufferSequence> tmp(buffers); std::size_t total_transferred = 0; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { std::size_t bytes_transferred = s.write_some(tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; @@ -111,51 +112,164 @@ namespace detail { template - class write_handler + class write_op + : detail::base_from_completion_cond { public: - typedef boost::asio::detail::consuming_buffers< - const_buffer, ConstBufferSequence> buffers_type; - - write_handler(AsyncWriteStream& stream, const buffers_type& buffers, + write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers, CompletionCondition completion_condition, WriteHandler handler) - : stream_(stream), + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), buffers_(buffers), total_transferred_(0), - completion_condition_(completion_condition), - handler_(handler) + handler_(handler), + start_(true) { } void operator()(const boost::system::error_code& ec, std::size_t bytes_transferred) { - total_transferred_ += bytes_transferred; - buffers_.consume(bytes_transferred); - buffers_.set_max_size(detail::adapt_completion_condition_result( - completion_condition_(ec, total_transferred_))); - if (buffers_.begin() == buffers_.end()) + switch (start_) { + case true: start_ = false; + buffers_.prepare(this->check(ec, total_transferred_)); + for (;;) + { + stream_.async_write_some(buffers_, *this); + return; default: + total_transferred_ += bytes_transferred; + buffers_.consume(bytes_transferred); + buffers_.prepare(this->check(ec, total_transferred_)); + if ((!ec && bytes_transferred == 0) + || buffers_.begin() == buffers_.end()) + break; + } + handler_(ec, total_transferred_); } - else - { - stream_.async_write_some(buffers_, *this); - } } //private: AsyncWriteStream& stream_; - buffers_type buffers_; + boost::asio::detail::consuming_buffers< + const_buffer, ConstBufferSequence> buffers_; std::size_t total_transferred_; - CompletionCondition completion_condition_; WriteHandler handler_; + bool start_; + }; + + template + class write_op + : detail::base_from_completion_cond + { + 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), + total_transferred_(0), + handler_(handler), + start_(true) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + std::size_t n = 0; + switch (start_) + { + case true: start_ = false; + n = this->check(ec, total_transferred_); + for (;;) + { + stream_.async_write_some(boost::asio::buffer( + buffer_ + total_transferred_, n), *this); + return; default: + total_transferred_ += bytes_transferred; + if ((!ec && bytes_transferred == 0) + || (n = this->check(ec, total_transferred_)) == 0 + || total_transferred_ == boost::asio::buffer_size(buffer_)) + break; + } + + handler_(ec, total_transferred_); + } + } + + //private: + AsyncWriteStream& stream_; + boost::asio::mutable_buffer buffer_; + std::size_t total_transferred_; + WriteHandler handler_; + bool start_; + }; + + template + class write_op + : detail::base_from_completion_cond + { + 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), + total_transferred_(0), + handler_(handler), + start_(true) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + std::size_t n = 0; + switch (start_) + { + case true: start_ = false; + n = this->check(ec, total_transferred_); + for (;;) + { + stream_.async_write_some(boost::asio::buffer( + buffer_ + total_transferred_, n), *this); + return; default: + total_transferred_ += bytes_transferred; + if ((!ec && bytes_transferred == 0) + || (n = this->check(ec, total_transferred_)) == 0 + || total_transferred_ == boost::asio::buffer_size(buffer_)) + break; + } + + handler_(ec, total_transferred_); + } + } + + //private: + AsyncWriteStream& stream_; + boost::asio::const_buffer buffer_; + std::size_t total_transferred_; + WriteHandler handler_; + bool start_; }; template inline void* asio_handler_allocate(std::size_t size, - write_handler* this_handler) { return boost_asio_handler_alloc_helpers::allocate( @@ -165,7 +279,7 @@ namespace detail template inline void asio_handler_deallocate(void* pointer, std::size_t size, - write_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( @@ -176,7 +290,7 @@ namespace detail typename ConstBufferSequence, typename CompletionCondition, typename WriteHandler> inline void asio_handler_invoke(const Function& function, - write_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -189,24 +303,10 @@ template tmp(buffers); - - boost::system::error_code ec; - std::size_t total_transferred = 0; - tmp.set_max_size(detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred))); - if (tmp.begin() == tmp.end()) - { - s.get_io_service().post(detail::bind_handler( - handler, ec, total_transferred)); - return; - } - - s.async_write_some(tmp, - detail::write_handler( - s, tmp, completion_condition, handler)); + detail::write_op( + s, buffers, completion_condition, handler)( + boost::system::error_code(), 0); } template tmp(buffers); std::size_t total_transferred = 0; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { @@ -46,7 +46,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, offset + total_transferred, tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; @@ -142,7 +142,7 @@ namespace detail { total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - buffers_.set_max_size(detail::adapt_completion_condition_result( + buffers_.prepare(detail::adapt_completion_condition_result( completion_condition_(ec, total_transferred_))); if (buffers_.begin() == buffers_.end()) { @@ -207,7 +207,7 @@ inline void async_write_at(AsyncRandomAccessWriteDevice& d, boost::system::error_code ec; std::size_t total_transferred = 0; - tmp.set_max_size(detail::adapt_completion_condition_result( + tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); if (tmp.begin() == tmp.end()) { diff --git a/include/boost/asio/io_service.hpp b/include/boost/asio/io_service.hpp index a34d8742..57794cf5 100644 --- a/include/boost/asio/io_service.hpp +++ b/include/boost/asio/io_service.hpp @@ -26,11 +26,8 @@ #include #include -#include -#include -#include #include -#include +#include #include #include #include @@ -46,6 +43,12 @@ template Service& use_service(io_service& ios); template void add_service(io_service& ios, Service* svc); template bool has_service(io_service& ios); +#if defined(BOOST_ASIO_HAS_IOCP) +namespace detail { typedef win_iocp_io_service io_service_impl; } +#else +namespace detail { typedef task_io_service io_service_impl; } +#endif + /// Provides core I/O functionality. /** * The io_service class provides the core I/O functionality for users of the @@ -178,18 +181,9 @@ class io_service : private noncopyable { private: - // The type of the platform-specific implementation. + typedef detail::io_service_impl impl_type; #if defined(BOOST_ASIO_HAS_IOCP) - typedef detail::win_iocp_io_service impl_type; friend class detail::win_iocp_overlapped_ptr; -#elif defined(BOOST_ASIO_HAS_EPOLL) - typedef detail::task_io_service > impl_type; -#elif defined(BOOST_ASIO_HAS_KQUEUE) - typedef detail::task_io_service > impl_type; -#elif defined(BOOST_ASIO_HAS_DEV_POLL) - typedef detail::task_io_service > impl_type; -#else - typedef detail::task_io_service > impl_type; #endif public: @@ -606,9 +600,14 @@ private: virtual void shutdown_service() = 0; 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_; - const std::type_info* type_info_; - const boost::asio::io_service::id* id_; service* next_; }; diff --git a/include/boost/asio/ip/basic_resolver_iterator.hpp b/include/boost/asio/ip/basic_resolver_iterator.hpp index 90644a22..5f4937bf 100644 --- a/include/boost/asio/ip/basic_resolver_iterator.hpp +++ b/include/boost/asio/ip/basic_resolver_iterator.hpp @@ -18,8 +18,7 @@ #include #include -#include -#include +#include #include #include #include @@ -48,14 +47,18 @@ namespace ip { */ template class basic_resolver_iterator - : public boost::iterator_facade< - basic_resolver_iterator, - const basic_resolver_entry, - boost::forward_traversal_tag> +#if defined(GENERATING_DOCUMENTATION) + : public std::iterator< +#else // defined(GENERATING_DOCUMENTATION) + : public boost::iterator< +#endif // defined(GENERATING_DOCUMENTATION) + std::forward_iterator_tag, + const basic_resolver_entry > { public: /// Default constructor creates an end iterator. basic_resolver_iterator() + : index_(0) { } @@ -91,11 +94,6 @@ public: address_info = address_info->ai_next; } - if (iter.values_->size()) - iter.iter_ = iter.values_->begin(); - else - iter.values_.reset(); - return iter; } @@ -109,21 +107,58 @@ public: iter.values_->push_back( basic_resolver_entry( endpoint, host_name, service_name)); - iter.iter_ = iter.values_->begin(); return iter; } -private: - friend class boost::iterator_core_access; + /// Dereference an iterator. + const basic_resolver_entry& operator*() const + { + return dereference(); + } + /// Dereference an iterator. + const basic_resolver_entry* operator->() const + { + return &dereference(); + } + + /// Increment operator (prefix). + basic_resolver_iterator& operator++() + { + increment(); + return *this; + } + + /// Increment operator (postfix). + basic_resolver_iterator operator++(int) + { + basic_resolver_iterator tmp(*this); + ++*this; + return tmp; + } + + /// Test two iterators for equality. + friend bool operator==(const basic_resolver_iterator& a, + const basic_resolver_iterator& b) + { + return a.equal(b); + } + + /// Test two iterators for inequality. + friend bool operator!=(const basic_resolver_iterator& a, + const basic_resolver_iterator& b) + { + return !a.equal(b); + } + +private: void increment() { - if (++*iter_ == values_->end()) + if (++index_ == values_->size()) { // Reset state to match a default constructed end iterator. values_.reset(); - typedef typename values_type::const_iterator values_iterator_type; - iter_.reset(); + index_ = 0; } } @@ -133,18 +168,17 @@ private: return true; if (values_ != other.values_) return false; - return *iter_ == *other.iter_; + return index_ == other.index_; } const basic_resolver_entry& dereference() const { - return **iter_; + return (*values_)[index_]; } typedef std::vector > values_type; - typedef typename values_type::const_iterator values_iter_type; boost::shared_ptr values_; - boost::optional iter_; + std::size_t index_; }; } // namespace ip diff --git a/include/boost/asio/posix/stream_descriptor_service.hpp b/include/boost/asio/posix/stream_descriptor_service.hpp index e64a6172..89b9ef4f 100644 --- a/include/boost/asio/posix/stream_descriptor_service.hpp +++ b/include/boost/asio/posix/stream_descriptor_service.hpp @@ -35,19 +35,7 @@ #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) -#if defined(BOOST_ASIO_HAS_EPOLL) -# include -# include -#elif defined(BOOST_ASIO_HAS_KQUEUE) -# include -# include -#elif defined(BOOST_ASIO_HAS_DEV_POLL) -# include -# include -#else -# include -# include -#endif +#include namespace boost { namespace asio { @@ -69,19 +57,7 @@ public: private: // The type of the platform-specific implementation. -#if defined(BOOST_ASIO_HAS_EPOLL) - typedef detail::reactive_descriptor_service< - detail::epoll_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_KQUEUE) - typedef detail::reactive_descriptor_service< - detail::kqueue_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_DEV_POLL) - typedef detail::reactive_descriptor_service< - detail::dev_poll_reactor > service_impl_type; -#else - typedef detail::reactive_descriptor_service< - detail::select_reactor > service_impl_type; -#endif + typedef detail::reactive_descriptor_service service_impl_type; public: /// The type of a stream descriptor implementation. @@ -101,13 +77,14 @@ public: /// 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(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined descriptorr objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new stream descriptor implementation. @@ -196,8 +173,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace posix diff --git a/include/boost/asio/raw_socket_service.hpp b/include/boost/asio/raw_socket_service.hpp index 1b5c03cf..23427d7f 100644 --- a/include/boost/asio/raw_socket_service.hpp +++ b/include/boost/asio/raw_socket_service.hpp @@ -28,17 +28,7 @@ #if defined(BOOST_ASIO_HAS_IOCP) # include -#elif defined(BOOST_ASIO_HAS_EPOLL) -# include -# include -#elif defined(BOOST_ASIO_HAS_KQUEUE) -# include -# include -#elif defined(BOOST_ASIO_HAS_DEV_POLL) -# include -# include #else -# include # include #endif @@ -70,18 +60,8 @@ private: // The type of the platform-specific implementation. #if defined(BOOST_ASIO_HAS_IOCP) typedef detail::win_iocp_socket_service service_impl_type; -#elif defined(BOOST_ASIO_HAS_EPOLL) - typedef detail::reactive_socket_service< - Protocol, detail::epoll_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_KQUEUE) - typedef detail::reactive_socket_service< - Protocol, detail::kqueue_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_DEV_POLL) - typedef detail::reactive_socket_service< - Protocol, detail::dev_poll_reactor > service_impl_type; #else - typedef detail::reactive_socket_service< - Protocol, detail::select_reactor > service_impl_type; + typedef detail::reactive_socket_service service_impl_type; #endif public: @@ -103,13 +83,14 @@ public: explicit raw_socket_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base< raw_socket_service >(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new raw socket implementation. @@ -324,8 +305,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace asio diff --git a/include/boost/asio/serial_port_service.hpp b/include/boost/asio/serial_port_service.hpp index 3abd244a..f1a23446 100644 --- a/include/boost/asio/serial_port_service.hpp +++ b/include/boost/asio/serial_port_service.hpp @@ -54,18 +54,8 @@ private: // The type of the platform-specific implementation. #if defined(BOOST_ASIO_HAS_IOCP) typedef detail::win_iocp_serial_port_service service_impl_type; -#elif defined(BOOST_ASIO_HAS_EPOLL) - typedef detail::reactive_serial_port_service< - detail::epoll_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_KQUEUE) - typedef detail::reactive_serial_port_service< - detail::kqueue_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_DEV_POLL) - typedef detail::reactive_serial_port_service< - detail::dev_poll_reactor > service_impl_type; #else - typedef detail::reactive_serial_port_service< - detail::select_reactor > service_impl_type; + typedef detail::reactive_serial_port_service service_impl_type; #endif public: @@ -86,13 +76,14 @@ public: /// 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(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new serial port implementation. @@ -203,8 +194,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace asio diff --git a/include/boost/asio/socket_acceptor_service.hpp b/include/boost/asio/socket_acceptor_service.hpp index edca5b7a..184580fb 100644 --- a/include/boost/asio/socket_acceptor_service.hpp +++ b/include/boost/asio/socket_acceptor_service.hpp @@ -24,17 +24,7 @@ #if defined(BOOST_ASIO_HAS_IOCP) # include -#elif defined(BOOST_ASIO_HAS_EPOLL) -# include -# include -#elif defined(BOOST_ASIO_HAS_KQUEUE) -# include -# include -#elif defined(BOOST_ASIO_HAS_DEV_POLL) -# include -# include #else -# include # include #endif @@ -66,18 +56,8 @@ private: // The type of the platform-specific implementation. #if defined(BOOST_ASIO_HAS_IOCP) typedef detail::win_iocp_socket_service service_impl_type; -#elif defined(BOOST_ASIO_HAS_EPOLL) - typedef detail::reactive_socket_service< - Protocol, detail::epoll_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_KQUEUE) - typedef detail::reactive_socket_service< - Protocol, detail::kqueue_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_DEV_POLL) - typedef detail::reactive_socket_service< - Protocol, detail::dev_poll_reactor > service_impl_type; #else - typedef detail::reactive_socket_service< - Protocol, detail::select_reactor > service_impl_type; + typedef detail::reactive_socket_service service_impl_type; #endif public: @@ -99,13 +79,14 @@ public: explicit socket_acceptor_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base< socket_acceptor_service >(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new socket acceptor implementation. @@ -226,8 +207,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace asio diff --git a/include/boost/asio/ssl/detail/openssl_operation.hpp b/include/boost/asio/ssl/detail/openssl_operation.hpp index 0f7ec381..89b21f63 100644 --- a/include/boost/asio/ssl/detail/openssl_operation.hpp +++ b/include/boost/asio/ssl/detail/openssl_operation.hpp @@ -173,7 +173,8 @@ public: ((::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) + 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); diff --git a/include/boost/asio/ssl/detail/openssl_stream_service.hpp b/include/boost/asio/ssl/detail/openssl_stream_service.hpp index d2b1e4cc..5d9a99cd 100644 --- a/include/boost/asio/ssl/detail/openssl_stream_service.hpp +++ b/include/boost/asio/ssl/detail/openssl_stream_service.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -333,13 +334,22 @@ public: size_t bytes_transferred = 0; try { - std::size_t buffer_size = boost::asio::buffer_size(*buffers.begin()); + 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 send_func = boost::bind(boost::type(), &::SSL_write, boost::arg<1>(), - boost::asio::buffer_cast(*buffers.begin()), + boost::asio::buffer_cast(buffer), static_cast(buffer_size)); openssl_operation op( send_func, @@ -367,15 +377,25 @@ public: { typedef io_handler send_handler; - send_handler* local_handler = new send_handler(handler, get_io_service()); + 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(*buffers.begin()); + 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 send_func = boost::bind(boost::type(), &::SSL_write, boost::arg<1>(), - boost::asio::buffer_cast(*buffers.begin()), + boost::asio::buffer_cast(buffer), static_cast(buffer_size)); openssl_operation* op = new openssl_operation @@ -407,13 +427,22 @@ public: size_t bytes_transferred = 0; try { - std::size_t buffer_size = boost::asio::buffer_size(*buffers.begin()); + 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 recv_func = boost::bind(boost::type(), &::SSL_read, boost::arg<1>(), - boost::asio::buffer_cast(*buffers.begin()), + boost::asio::buffer_cast(buffer), static_cast(buffer_size)); openssl_operation op(recv_func, next_layer, @@ -441,15 +470,25 @@ public: { typedef io_handler recv_handler; - recv_handler* local_handler = new recv_handler(handler, get_io_service()); + 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(*buffers.begin()); + 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 recv_func = boost::bind(boost::type(), &::SSL_read, boost::arg<1>(), - boost::asio::buffer_cast(*buffers.begin()), + boost::asio::buffer_cast(buffer), static_cast(buffer_size)); openssl_operation* op = new openssl_operation diff --git a/include/boost/asio/stream_socket_service.hpp b/include/boost/asio/stream_socket_service.hpp index 6a8dd36f..15aa6832 100644 --- a/include/boost/asio/stream_socket_service.hpp +++ b/include/boost/asio/stream_socket_service.hpp @@ -28,17 +28,7 @@ #if defined(BOOST_ASIO_HAS_IOCP) # include -#elif defined(BOOST_ASIO_HAS_EPOLL) -# include -# include -#elif defined(BOOST_ASIO_HAS_KQUEUE) -# include -# include -#elif defined(BOOST_ASIO_HAS_DEV_POLL) -# include -# include #else -# include # include #endif @@ -70,18 +60,8 @@ private: // The type of the platform-specific implementation. #if defined(BOOST_ASIO_HAS_IOCP) typedef detail::win_iocp_socket_service service_impl_type; -#elif defined(BOOST_ASIO_HAS_EPOLL) - typedef detail::reactive_socket_service< - Protocol, detail::epoll_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_KQUEUE) - typedef detail::reactive_socket_service< - Protocol, detail::kqueue_reactor > service_impl_type; -#elif defined(BOOST_ASIO_HAS_DEV_POLL) - typedef detail::reactive_socket_service< - Protocol, detail::dev_poll_reactor > service_impl_type; #else - typedef detail::reactive_socket_service< - Protocol, detail::select_reactor > service_impl_type; + typedef detail::reactive_socket_service service_impl_type; #endif public: @@ -103,13 +83,14 @@ public: explicit stream_socket_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base< stream_socket_service >(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new stream socket implementation. @@ -287,8 +268,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace asio diff --git a/include/boost/asio/windows/random_access_handle_service.hpp b/include/boost/asio/windows/random_access_handle_service.hpp index fbbde676..1dcbee4b 100644 --- a/include/boost/asio/windows/random_access_handle_service.hpp +++ b/include/boost/asio/windows/random_access_handle_service.hpp @@ -78,13 +78,14 @@ public: explicit random_access_handle_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base< random_access_handle_service>(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new random-access handle implementation. @@ -165,8 +166,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace windows diff --git a/include/boost/asio/windows/stream_handle_service.hpp b/include/boost/asio/windows/stream_handle_service.hpp index c2224e47..cc6c6e86 100644 --- a/include/boost/asio/windows/stream_handle_service.hpp +++ b/include/boost/asio/windows/stream_handle_service.hpp @@ -76,13 +76,14 @@ public: /// 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(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new stream handle implementation. @@ -163,8 +164,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace windows From 8717cac1358d8f7d18f5573abc8567319733f473 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Thu, 18 Mar 2010 01:32:34 +0000 Subject: [PATCH 05/38] Define NOMINMAX for all Windows compilers, not just Cygwin. Users can define BOOST_ASIO_NO_NOMINMAX to suppress this definition. [SVN r60681] --- doc/using.qbk | 9 +++++++++ include/boost/asio/detail/socket_types.hpp | 8 +++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/doc/using.qbk b/doc/using.qbk index 02052818..07f641d4 100644 --- a/doc/using.qbk +++ b/doc/using.qbk @@ -205,6 +205,15 @@ Boost.Asio. being defined. ] ] + [ + [`BOOST_ASIO_NO_NOMINMAX`] + [ + By default, Boost.Asio will automatically define `NOMINMAX` when + compiling for Windows, to suppress the definition of the `min()` and + `max()` macros. The presence of `BOOST_ASIO_NO_NOMINMAX` prevents + `NOMINMAX` from being defined. + ] + ] [ [`BOOST_ASIO_NO_DEFAULT_LINKED_LIBS`] [ diff --git a/include/boost/asio/detail/socket_types.hpp b/include/boost/asio/detail/socket_types.hpp index 7395ee48..10091649 100644 --- a/include/boost/asio/detail/socket_types.hpp +++ b/include/boost/asio/detail/socket_types.hpp @@ -68,13 +68,15 @@ # define WIN32_LEAN_AND_MEAN # endif // !defined(WIN32_LEAN_AND_MEAN) # endif // !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +# if !defined(BOOST_ASIO_NO_NOMINMAX) +# if !defined(NOMINMAX) +# define NOMINMAX 1 +# endif // !defined(NOMINMAX) +# endif // !defined(BOOST_ASIO_NO_NOMINMAX) # if defined(__CYGWIN__) # if !defined(__USE_W32_SOCKETS) # error You must add -D__USE_W32_SOCKETS to your compiler options. # endif // !defined(__USE_W32_SOCKETS) -# if !defined(NOMINMAX) -# define NOMINMAX 1 -# endif // !defined(NOMINMAX) # endif // defined(__CYGWIN__) # include # include From 481e0b03d9db314efd1f662174c75524c47adea4 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Thu, 18 Mar 2010 01:54:43 +0000 Subject: [PATCH 06/38] Clarify that to_bytes() returns addresses in network byte order. Refs #4005. [SVN r60683] --- include/boost/asio/ip/address_v4.hpp | 2 +- include/boost/asio/ip/address_v6.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/asio/ip/address_v4.hpp b/include/boost/asio/ip/address_v4.hpp index e0088dcc..47d36b5d 100644 --- a/include/boost/asio/ip/address_v4.hpp +++ b/include/boost/asio/ip/address_v4.hpp @@ -102,7 +102,7 @@ public: return *this; } - /// Get the address in bytes. + /// Get the address in bytes, in network byte order. bytes_type to_bytes() const { using namespace std; // For memcpy. diff --git a/include/boost/asio/ip/address_v6.hpp b/include/boost/asio/ip/address_v6.hpp index 4105c8d0..5685f082 100644 --- a/include/boost/asio/ip/address_v6.hpp +++ b/include/boost/asio/ip/address_v6.hpp @@ -115,7 +115,7 @@ public: scope_id_ = id; } - /// Get the address in bytes. + /// Get the address in bytes, in network byte order. bytes_type to_bytes() const { using namespace std; // For memcpy. From 3f3c9aefa1dc34875f93691e956e4dbacd5f3c4f Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Thu, 18 Mar 2010 02:15:23 +0000 Subject: [PATCH 07/38] Add note to examples on how to limit asio::streambuf growth. [SVN r60685] --- example/http/client/async_client.cpp | 4 +++- example/http/client/sync_client.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/example/http/client/async_client.cpp b/example/http/client/async_client.cpp index 1218cd00..c65c98f4 100644 --- a/example/http/client/async_client.cpp +++ b/example/http/client/async_client.cpp @@ -91,7 +91,9 @@ private: { if (!err) { - // Read the response status line. + // Read the response status line. The response_ streambuf will + // automatically grow to accommodate the entire line. The growth may be + // limited by passing a maximum size to the streambuf constructor. boost::asio::async_read_until(socket_, response_, "\r\n", boost::bind(&client::handle_read_status_line, this, boost::asio::placeholders::error)); diff --git a/example/http/client/sync_client.cpp b/example/http/client/sync_client.cpp index a61b10ad..88fd3a35 100644 --- a/example/http/client/sync_client.cpp +++ b/example/http/client/sync_client.cpp @@ -60,7 +60,9 @@ int main(int argc, char* argv[]) // Send the request. boost::asio::write(socket, request); - // Read the response status line. + // Read the response status line. The response streambuf will automatically + // grow to accommodate the entire line. The growth may be limited by passing + // a maximum size to the streambuf constructor. boost::asio::streambuf response; boost::asio::read_until(socket, response, "\r\n"); From 96ad484574e4e9c6618ffd11ad9b43f5ffca3633 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Thu, 18 Mar 2010 06:23:38 +0000 Subject: [PATCH 08/38] Use a bitmask type for the resolver flags, as per the TR2 proposal. This will prevent implicit conversion from int to flags, allowing the compiler to catch cases where users incorrectly pass a numeric port number as the service name. [SVN r60687] --- .../boost/asio/ip/basic_resolver_query.hpp | 17 ++-- include/boost/asio/ip/resolver_query_base.hpp | 89 ++++++++++++++----- 2 files changed, 78 insertions(+), 28 deletions(-) diff --git a/include/boost/asio/ip/basic_resolver_query.hpp b/include/boost/asio/ip/basic_resolver_query.hpp index e95362be..9c5f0f32 100644 --- a/include/boost/asio/ip/basic_resolver_query.hpp +++ b/include/boost/asio/ip/basic_resolver_query.hpp @@ -48,13 +48,13 @@ public: /// Construct with specified service name for any protocol. basic_resolver_query(const std::string& service_name, - int flags = passive | address_configured) + resolver_query_base::flags resolve_flags = passive | address_configured) : hints_(), host_name_(), service_name_(service_name) { typename InternetProtocol::endpoint endpoint; - hints_.ai_flags = flags; + hints_.ai_flags = static_cast(resolve_flags); hints_.ai_family = PF_UNSPEC; hints_.ai_socktype = endpoint.protocol().type(); hints_.ai_protocol = endpoint.protocol().protocol(); @@ -67,12 +67,12 @@ public: /// Construct with specified service name for a given protocol. basic_resolver_query(const protocol_type& protocol, const std::string& service_name, - int flags = passive | address_configured) + resolver_query_base::flags resolve_flags = passive | address_configured) : hints_(), host_name_(), service_name_(service_name) { - hints_.ai_flags = flags; + hints_.ai_flags = static_cast(resolve_flags); hints_.ai_family = protocol.family(); hints_.ai_socktype = protocol.type(); hints_.ai_protocol = protocol.protocol(); @@ -84,13 +84,14 @@ public: /// Construct with specified host name and service name for any protocol. basic_resolver_query(const std::string& host_name, - const std::string& service_name, int flags = address_configured) + const std::string& service_name, + resolver_query_base::flags resolve_flags = address_configured) : hints_(), host_name_(host_name), service_name_(service_name) { typename InternetProtocol::endpoint endpoint; - hints_.ai_flags = flags; + hints_.ai_flags = static_cast(resolve_flags); hints_.ai_family = PF_UNSPEC; hints_.ai_socktype = endpoint.protocol().type(); hints_.ai_protocol = endpoint.protocol().protocol(); @@ -103,12 +104,12 @@ public: /// Construct with specified host name and service name for a given protocol. basic_resolver_query(const protocol_type& protocol, const std::string& host_name, const std::string& service_name, - int flags = address_configured) + resolver_query_base::flags resolve_flags = address_configured) : hints_(), host_name_(host_name), service_name_(service_name) { - hints_.ai_flags = flags; + hints_.ai_flags = static_cast(resolve_flags); hints_.ai_family = protocol.family(); hints_.ai_socktype = protocol.type(); hints_.ai_protocol = protocol.protocol(); diff --git a/include/boost/asio/ip/resolver_query_base.hpp b/include/boost/asio/ip/resolver_query_base.hpp index d21b462e..7c74a0ec 100644 --- a/include/boost/asio/ip/resolver_query_base.hpp +++ b/include/boost/asio/ip/resolver_query_base.hpp @@ -35,58 +35,107 @@ class resolver_query_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 int canonical_name = implementation_defined; + static const flags canonical_name = implementation_defined; /// Indicate that returned endpoint is intended for use as a locally bound /// socket endpoint. - static const int passive = implementation_defined; + 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 int numeric_host = implementation_defined; + 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 int numeric_service = implementation_defined; + 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 int v4_mapped = implementation_defined; + static const flags v4_mapped = implementation_defined; /// If used with v4_mapped, return all matching IPv6 and IPv4 addresses. - static const int all_matching = implementation_defined; + static const flags xll_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 int address_configured = implementation_defined; + static const flags xddress_configured = implementation_defined; #else - BOOST_STATIC_CONSTANT(int, canonical_name = AI_CANONNAME); - BOOST_STATIC_CONSTANT(int, passive = AI_PASSIVE); - BOOST_STATIC_CONSTANT(int, numeric_host = AI_NUMERICHOST); + enum flags + { + canonical_name = AI_CANONNAME, + passive = AI_PASSIVE, + numeric_host = AI_NUMERICHOST, # if defined(AI_NUMERICSERV) - BOOST_STATIC_CONSTANT(int, numeric_service = AI_NUMERICSERV); + numeric_service = AI_NUMERICSERV, # else - BOOST_STATIC_CONSTANT(int, numeric_service = 0); + numeric_service = 0, # endif - // Note: QNX Neutrino 6.3 defines AI_V4MAPPED, AI_ALL and AI_ADDRCONFIG but - // does not implement them. Therefore they are specifically excluded here. + // Note: QNX Neutrino 6.3 defines AI_V4MAPPED, AI_ALL and AI_ADDRCONFIG but + // does not implement them. Therefore they are specifically excluded here. # if defined(AI_V4MAPPED) && !defined(__QNXNTO__) - BOOST_STATIC_CONSTANT(int, v4_mapped = AI_V4MAPPED); + v4_mapped = AI_V4MAPPED, # else - BOOST_STATIC_CONSTANT(int, v4_mapped = 0); + v4_mapped = 0, # endif # if defined(AI_ALL) && !defined(__QNXNTO__) - BOOST_STATIC_CONSTANT(int, all_matching = AI_ALL); + all_matching = AI_ALL, # else - BOOST_STATIC_CONSTANT(int, all_matching = 0); + all_matching = 0, # endif # if defined(AI_ADDRCONFIG) && !defined(__QNXNTO__) - BOOST_STATIC_CONSTANT(int, address_configured = AI_ADDRCONFIG); + address_configured = AI_ADDRCONFIG # else - BOOST_STATIC_CONSTANT(int, address_configured = 0); + address_configured = 0 # endif + }; + + // Implement bitmask operations as shown in C++ Std [lib.bitmask.types]. + + friend flags operator&(flags x, flags y) + { + return static_cast( + static_cast(x) & static_cast(y)); + } + + friend flags operator|(flags x, flags y) + { + return static_cast( + static_cast(x) | static_cast(y)); + } + + friend flags operator^(flags x, flags y) + { + return static_cast( + static_cast(x) ^ static_cast(y)); + } + + friend flags operator~(flags x) + { + return static_cast(static_cast(~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: From 1683a90e861c8fcb59fb7a14ed46fd17b0d5fed0 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Thu, 18 Mar 2010 11:08:19 +0000 Subject: [PATCH 09/38] Fix bug where 0-byte reads were incorrectly passing an eof error_code to the handler. Refs #4023. [SVN r60689] --- .../asio/detail/win_iocp_socket_service.hpp | 2 + test/ip/tcp.cpp | 144 ++++++++++++++++++ 2 files changed, 146 insertions(+) diff --git a/include/boost/asio/detail/win_iocp_socket_service.hpp b/include/boost/asio/detail/win_iocp_socket_service.hpp index 7114f04f..2b0bbe56 100644 --- a/include/boost/asio/detail/win_iocp_socket_service.hpp +++ b/include/boost/asio/detail/win_iocp_socket_service.hpp @@ -1059,6 +1059,8 @@ public: // Check for connection closed. else if (!ec && bytes_transferred == 0 && o->protocol_type_ == SOCK_STREAM + && !buffer_sequence_adapter::all_empty(o->buffers_) && !boost::is_same::value) { ec = boost::asio::error::eof; diff --git a/test/ip/tcp.cpp b/test/ip/tcp.cpp index d6a9cbb2..12c60ab3 100644 --- a/test/ip/tcp.cpp +++ b/test/ip/tcp.cpp @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include "../unit_test.hpp" #include "../archetypes/io_control_command.hpp" @@ -300,6 +303,146 @@ void test() //------------------------------------------------------------------------------ +// ip_tcp_socket_runtime test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks the runtime operation of the ip::tcp::socket class. + +namespace ip_tcp_socket_runtime { + +static const char write_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +void handle_read_noop(const boost::system::error_code& err, + size_t bytes_transferred, bool* called) +{ + *called = true; + BOOST_CHECK(!err); + BOOST_CHECK(bytes_transferred == 0); +} + +void handle_write_noop(const boost::system::error_code& err, + size_t bytes_transferred, bool* called) +{ + *called = true; + BOOST_CHECK(!err); + BOOST_CHECK(bytes_transferred == 0); +} + +void handle_read(const boost::system::error_code& err, + size_t bytes_transferred, bool* called) +{ + *called = true; + BOOST_CHECK(!err); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); +} + +void handle_write(const boost::system::error_code& err, + size_t bytes_transferred, bool* called) +{ + *called = true; + BOOST_CHECK(!err); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); +} + +void handle_read_eof(const boost::system::error_code& err, + size_t bytes_transferred, bool* called) +{ + *called = true; + BOOST_CHECK(err == boost::asio::error::eof); + BOOST_CHECK(bytes_transferred == 0); +} + +void test() +{ + using namespace std; // For memcmp. + using namespace boost::asio; + namespace ip = boost::asio::ip; + + io_service ios; + + ip::tcp::acceptor acceptor(ios, ip::tcp::endpoint(ip::tcp::v4(), 0)); + ip::tcp::endpoint server_endpoint = acceptor.local_endpoint(); + server_endpoint.address(ip::address_v4::loopback()); + + ip::tcp::socket client_side_socket(ios); + ip::tcp::socket server_side_socket(ios); + + client_side_socket.connect(server_endpoint); + acceptor.accept(server_side_socket); + + // No-op read. + + bool read_noop_completed = false; + client_side_socket.async_read_some( + boost::asio::mutable_buffers_1(0, 0), + boost::bind(handle_read_noop, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + &read_noop_completed)); + + ios.run(); + BOOST_CHECK(read_noop_completed); + + // No-op write. + + bool write_noop_completed = false; + client_side_socket.async_write_some( + boost::asio::const_buffers_1(0, 0), + boost::bind(handle_write_noop, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + &write_noop_completed)); + + ios.reset(); + ios.run(); + BOOST_CHECK(write_noop_completed); + + // Read and write to transfer data. + + char read_buffer[sizeof(write_data)]; + bool read_completed = false; + boost::asio::async_read(client_side_socket, + boost::asio::buffer(read_buffer), + boost::bind(handle_read, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + &read_completed)); + + bool write_completed = false; + boost::asio::async_write(server_side_socket, + boost::asio::buffer(write_data), + boost::bind(handle_write, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + &write_completed)); + + ios.reset(); + ios.run(); + BOOST_CHECK(read_completed); + BOOST_CHECK(write_completed); + BOOST_CHECK(memcmp(read_buffer, write_data, sizeof(write_data)) == 0); + + // A read when the peer closes socket should fail with eof. + + bool read_eof_completed = false; + boost::asio::async_read(client_side_socket, + boost::asio::buffer(read_buffer), + boost::bind(handle_read_eof, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + &read_eof_completed)); + + server_side_socket.close(); + + ios.reset(); + ios.run(); + BOOST_CHECK(read_eof_completed); +} + +} // namespace ip_tcp_socket_runtime + +//------------------------------------------------------------------------------ + // ip_tcp_acceptor_runtime test // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // The following test checks the runtime operation of the ip::tcp::acceptor @@ -383,6 +526,7 @@ test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(&ip_tcp_compile::test)); test->add(BOOST_TEST_CASE(&ip_tcp_runtime::test)); test->add(BOOST_TEST_CASE(&ip_tcp_socket_compile::test)); + test->add(BOOST_TEST_CASE(&ip_tcp_socket_runtime::test)); test->add(BOOST_TEST_CASE(&ip_tcp_acceptor_runtime::test)); return test; } From 4ab0d73c105d0453af2f261e6d0fd562071a9296 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Fri, 19 Mar 2010 13:08:04 +0000 Subject: [PATCH 10/38] Fix epoll_reactor bug where cancelled operations would complete with a "success" error_code. [SVN r60705] --- include/boost/asio/detail/epoll_reactor.hpp | 18 +++++++++++-- test/ip/tcp.cpp | 30 +++++++++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/include/boost/asio/detail/epoll_reactor.hpp b/include/boost/asio/detail/epoll_reactor.hpp index c4c2dea7..b07de7cc 100644 --- a/include/boost/asio/detail/epoll_reactor.hpp +++ b/include/boost/asio/detail/epoll_reactor.hpp @@ -212,7 +212,14 @@ public: op_queue ops; for (int i = 0; i < max_ops; ++i) - ops.push(descriptor_data->op_queue_[i]); + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } descriptor_lock.unlock(); @@ -233,7 +240,14 @@ public: op_queue ops; for (int i = 0; i < max_ops; ++i) - ops.push(descriptor_data->op_queue_[i]); + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } descriptor_lock.unlock(); diff --git a/test/ip/tcp.cpp b/test/ip/tcp.cpp index 12c60ab3..f05dad87 100644 --- a/test/ip/tcp.cpp +++ b/test/ip/tcp.cpp @@ -344,6 +344,14 @@ void handle_write(const boost::system::error_code& err, BOOST_CHECK(bytes_transferred == sizeof(write_data)); } +void handle_read_cancel(const boost::system::error_code& err, + size_t bytes_transferred, bool* called) +{ + *called = true; + BOOST_CHECK(err == boost::asio::error::operation_aborted); + BOOST_CHECK(bytes_transferred == 0); +} + void handle_read_eof(const boost::system::error_code& err, size_t bytes_transferred, bool* called) { @@ -422,6 +430,26 @@ void test() BOOST_CHECK(write_completed); BOOST_CHECK(memcmp(read_buffer, write_data, sizeof(write_data)) == 0); + // Cancelled read. + + bool read_cancel_completed = false; + boost::asio::async_read(server_side_socket, + boost::asio::buffer(read_buffer), + boost::bind(handle_read_cancel, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + &read_cancel_completed)); + + ios.reset(); + ios.poll(); + BOOST_CHECK(!read_cancel_completed); + + server_side_socket.close(); + + ios.reset(); + ios.run(); + BOOST_CHECK(read_cancel_completed); + // A read when the peer closes socket should fail with eof. bool read_eof_completed = false; @@ -432,8 +460,6 @@ void test() boost::asio::placeholders::bytes_transferred, &read_eof_completed)); - server_side_socket.close(); - ios.reset(); ios.run(); BOOST_CHECK(read_eof_completed); From b80ddc193519bc234a693daff39004872fff0517 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Fri, 19 Mar 2010 23:23:28 +0000 Subject: [PATCH 11/38] More extensive read and write tests. [SVN r60717] --- test/read.cpp | 1392 +++++++++++++++++++++++++++++++++++++++++++++++- test/write.cpp | 1214 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 2586 insertions(+), 20 deletions(-) diff --git a/test/read.cpp b/test/read.cpp index 6b412678..1e9401d8 100644 --- a/test/read.cpp +++ b/test/read.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "unit_test.hpp" using namespace std; // For memcmp, memcpy and memset. @@ -134,7 +135,7 @@ private: static const char read_data[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -void test_2_arg_read() +void test_2_arg_mutable_buffers_1_read() { boost::asio::io_service ios; test_stream s(ios); @@ -163,6 +164,66 @@ void test_2_arg_read() BOOST_CHECK(s.check(buffers, sizeof(read_data))); } +void test_2_arg_multi_buffers_read() +{ + boost::asio::io_service ios; + test_stream s(ios); + char read_buf[sizeof(read_data)]; + boost::array buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + size_t bytes_transferred = boost::asio::read(s, buffers); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); +} + +void test_2_arg_streambuf_read() +{ + boost::asio::io_service ios; + test_stream s(ios); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + size_t bytes_transferred = boost::asio::read(s, sb); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); +} + bool old_style_transfer_all(const boost::system::error_code& ec, size_t /*bytes_transferred*/) { @@ -175,7 +236,7 @@ size_t short_transfer(const boost::system::error_code& ec, return !!ec ? 0 : 3; } -void test_3_arg_read() +void test_3_arg_mutable_buffers_1_read() { boost::asio::io_service ios; test_stream s(ios); @@ -316,7 +377,306 @@ void test_3_arg_read() BOOST_CHECK(s.check(buffers, sizeof(read_data))); } -void test_4_arg_read() +void test_3_arg_multi_buffers_read() +{ + boost::asio::io_service ios; + test_stream s(ios); + char read_buf[sizeof(read_data)]; + boost::array buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + size_t bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check(buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); +} + +void test_3_arg_streambuf_read() +{ + boost::asio::io_service ios; + test_stream s(ios); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + size_t bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(sb.size() == 1); + BOOST_CHECK(s.check(sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(sb.size() == 42); + BOOST_CHECK(s.check(sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(sb.size() == 50); + BOOST_CHECK(s.check(sb.data(), 50)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); +} + +void test_4_arg_mutable_buffers_1_read() { boost::asio::io_service ios; test_stream s(ios); @@ -494,6 +854,379 @@ void test_4_arg_read() BOOST_CHECK(!error); } +void test_4_arg_multi_buffers_read() +{ + boost::asio::io_service ios; + test_stream s(ios); + char read_buf[sizeof(read_data)]; + boost::array buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(!error); +} + +void test_4_arg_streambuf_read() +{ + boost::asio::io_service ios; + test_stream s(ios); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(sb.size() == 1); + BOOST_CHECK(s.check(sb.data(), 1)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(sb.size() == 42); + BOOST_CHECK(s.check(sb.data(), 42)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(sb.size() == 50); + BOOST_CHECK(s.check(sb.data(), 50)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); +} + void async_read_handler(const boost::system::error_code& e, size_t bytes_transferred, size_t expected_bytes_transferred, bool* called) { @@ -502,7 +1235,7 @@ void async_read_handler(const boost::system::error_code& e, BOOST_CHECK(bytes_transferred == expected_bytes_transferred); } -void test_3_arg_async_read() +void test_3_arg_mutable_buffers_1_async_read() { boost::asio::io_service ios; test_stream s(ios); @@ -552,7 +1285,109 @@ void test_3_arg_async_read() BOOST_CHECK(s.check(buffers, sizeof(read_data))); } -void test_4_arg_async_read() +void test_3_arg_multi_buffers_async_read() +{ + boost::asio::io_service ios; + test_stream s(ios); + char read_buf[sizeof(read_data)]; + boost::array buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read(s, buffers, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); +} + +void test_3_arg_streambuf_async_read() +{ + boost::asio::io_service ios; + test_stream s(ios); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bool called = false; + boost::asio::async_read(s, sb, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); +} + +void test_4_arg_mutable_buffers_1_async_read() { boost::asio::io_service ios; test_stream s(ios); @@ -807,13 +1642,550 @@ void test_4_arg_async_read() BOOST_CHECK(s.check(buffers, sizeof(read_data))); } +void test_4_arg_multi_buffers_async_read() +{ + boost::asio::io_service ios; + test_stream s(ios); + char read_buf[sizeof(read_data)]; + boost::array buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(read_data))); +} + +void test_4_arg_streambuf_async_read() +{ + boost::asio::io_service ios; + test_stream s(ios); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bool called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 1); + BOOST_CHECK(s.check(sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 42); + BOOST_CHECK(s.check(sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 50); + BOOST_CHECK(s.check(sb.data(), 50)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); +} + test_suite* init_unit_test_suite(int, char*[]) { test_suite* test = BOOST_TEST_SUITE("read"); - test->add(BOOST_TEST_CASE(&test_2_arg_read)); - test->add(BOOST_TEST_CASE(&test_3_arg_read)); - test->add(BOOST_TEST_CASE(&test_4_arg_read)); - test->add(BOOST_TEST_CASE(&test_3_arg_async_read)); - test->add(BOOST_TEST_CASE(&test_4_arg_async_read)); + test->add(BOOST_TEST_CASE(&test_2_arg_mutable_buffers_1_read)); + test->add(BOOST_TEST_CASE(&test_2_arg_multi_buffers_read)); + test->add(BOOST_TEST_CASE(&test_2_arg_streambuf_read)); + test->add(BOOST_TEST_CASE(&test_3_arg_mutable_buffers_1_read)); + test->add(BOOST_TEST_CASE(&test_3_arg_multi_buffers_read)); + test->add(BOOST_TEST_CASE(&test_3_arg_streambuf_read)); + test->add(BOOST_TEST_CASE(&test_4_arg_mutable_buffers_1_read)); + test->add(BOOST_TEST_CASE(&test_4_arg_multi_buffers_read)); + test->add(BOOST_TEST_CASE(&test_4_arg_streambuf_read)); + test->add(BOOST_TEST_CASE(&test_3_arg_mutable_buffers_1_async_read)); + test->add(BOOST_TEST_CASE(&test_3_arg_multi_buffers_async_read)); + test->add(BOOST_TEST_CASE(&test_3_arg_streambuf_async_read)); + test->add(BOOST_TEST_CASE(&test_4_arg_mutable_buffers_1_async_read)); + test->add(BOOST_TEST_CASE(&test_4_arg_multi_buffers_async_read)); + test->add(BOOST_TEST_CASE(&test_4_arg_streambuf_async_read)); return test; } diff --git a/test/write.cpp b/test/write.cpp index 0fe6c1f8..bdffbabc 100644 --- a/test/write.cpp +++ b/test/write.cpp @@ -16,6 +16,7 @@ // Test that header file is self-contained. #include +#include #include #include #include @@ -134,8 +135,10 @@ private: static const char write_data[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +static char mutable_write_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -void test_2_arg_write() +void test_2_arg_const_buffers_1_write() { boost::asio::io_service ios; test_stream s(ios); @@ -160,6 +163,57 @@ void test_2_arg_write() BOOST_CHECK(s.check(buffers, sizeof(write_data))); } +void test_2_arg_mutable_buffers_1_write() +{ + boost::asio::io_service ios; + test_stream s(ios); + boost::asio::mutable_buffers_1 buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + size_t bytes_transferred = boost::asio::write(s, buffers); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); +} + +void test_2_arg_multi_buffers_write() +{ + boost::asio::io_service ios; + test_stream s(ios); + boost::array buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + size_t bytes_transferred = boost::asio::write(s, buffers); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); +} + bool old_style_transfer_all(const boost::system::error_code& ec, size_t /*bytes_transferred*/) { @@ -172,7 +226,7 @@ size_t short_transfer(const boost::system::error_code& ec, return !!ec ? 0 : 3; } -void test_3_arg_write() +void test_3_arg_const_buffers_1_write() { boost::asio::io_service ios; test_stream s(ios); @@ -294,7 +348,252 @@ void test_3_arg_write() BOOST_CHECK(s.check(buffers, sizeof(write_data))); } -void test_4_arg_write() +void test_3_arg_mutable_buffers_1_write() +{ + boost::asio::io_service ios; + test_stream s(ios); + boost::asio::mutable_buffers_1 buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + size_t bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check(buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check(buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check(buffers, 50)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); +} + +void test_3_arg_multi_buffers_write() +{ + boost::asio::io_service ios; + test_stream s(ios); + boost::array buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + size_t bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check(buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check(buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check(buffers, 50)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); +} + +void test_4_arg_const_buffers_1_write() { boost::asio::io_service ios; test_stream s(ios); @@ -453,6 +752,325 @@ void test_4_arg_write() BOOST_CHECK(!error); } +void test_4_arg_mutable_buffers_1_write() +{ + boost::asio::io_service ios; + test_stream s(ios); + boost::asio::mutable_buffers_1 buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); +} + +void test_4_arg_multi_buffers_write() +{ + boost::asio::io_service ios; + test_stream s(ios); + boost::array buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(!error); +} + void async_write_handler(const boost::system::error_code& e, size_t bytes_transferred, size_t expected_bytes_transferred, bool* called) { @@ -461,7 +1079,7 @@ void async_write_handler(const boost::system::error_code& e, BOOST_CHECK(bytes_transferred == expected_bytes_transferred); } -void test_3_arg_async_write() +void test_3_arg_const_buffers_1_async_write() { boost::asio::io_service ios; test_stream s(ios); @@ -507,7 +1125,100 @@ void test_3_arg_async_write() BOOST_CHECK(s.check(buffers, sizeof(write_data))); } -void test_4_arg_async_write() +void test_3_arg_mutable_buffers_1_async_write() +{ + boost::asio::io_service ios; + test_stream s(ios); + boost::asio::mutable_buffers_1 buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + bool called = false; + boost::asio::async_write(s, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); +} + +void test_3_arg_multi_buffers_async_write() +{ + boost::asio::io_service ios; + test_stream s(ios); + boost::array buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + bool called = false; + boost::asio::async_write(s, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); +} + +void test_4_arg_const_buffers_1_async_write() { boost::asio::io_service ios; test_stream s(ios); @@ -743,13 +1454,496 @@ void test_4_arg_async_write() BOOST_CHECK(s.check(buffers, sizeof(write_data))); } +void test_4_arg_mutable_buffers_1_async_write() +{ + boost::asio::io_service ios; + test_stream s(ios); + boost::asio::mutable_buffers_1 buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + bool called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 50)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); +} + +void test_4_arg_multi_buffers_async_write() +{ + boost::asio::io_service ios; + test_stream s(ios); + boost::array buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + bool called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, 50)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check(buffers, sizeof(write_data))); +} + test_suite* init_unit_test_suite(int, char*[]) { test_suite* test = BOOST_TEST_SUITE("write"); - test->add(BOOST_TEST_CASE(&test_2_arg_write)); - test->add(BOOST_TEST_CASE(&test_3_arg_write)); - test->add(BOOST_TEST_CASE(&test_4_arg_write)); - test->add(BOOST_TEST_CASE(&test_3_arg_async_write)); - test->add(BOOST_TEST_CASE(&test_4_arg_async_write)); + test->add(BOOST_TEST_CASE(&test_2_arg_const_buffers_1_write)); + test->add(BOOST_TEST_CASE(&test_2_arg_mutable_buffers_1_write)); + test->add(BOOST_TEST_CASE(&test_2_arg_multi_buffers_write)); + test->add(BOOST_TEST_CASE(&test_3_arg_const_buffers_1_write)); + test->add(BOOST_TEST_CASE(&test_3_arg_mutable_buffers_1_write)); + test->add(BOOST_TEST_CASE(&test_3_arg_multi_buffers_write)); + test->add(BOOST_TEST_CASE(&test_4_arg_const_buffers_1_write)); + test->add(BOOST_TEST_CASE(&test_4_arg_mutable_buffers_1_write)); + test->add(BOOST_TEST_CASE(&test_4_arg_multi_buffers_write)); + test->add(BOOST_TEST_CASE(&test_3_arg_const_buffers_1_async_write)); + test->add(BOOST_TEST_CASE(&test_3_arg_mutable_buffers_1_async_write)); + test->add(BOOST_TEST_CASE(&test_3_arg_multi_buffers_async_write)); + test->add(BOOST_TEST_CASE(&test_4_arg_const_buffers_1_async_write)); + test->add(BOOST_TEST_CASE(&test_4_arg_mutable_buffers_1_async_write)); + test->add(BOOST_TEST_CASE(&test_4_arg_multi_buffers_async_write)); return test; } From e95406e8b97dc48901c44283d7584b4e2e632229 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Fri, 19 Mar 2010 23:57:50 +0000 Subject: [PATCH 12/38] WinCE doesn't provide InitializeCriticalSectionAndSpinCount. [SVN r60722] --- include/boost/asio/detail/win_mutex.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/boost/asio/detail/win_mutex.hpp b/include/boost/asio/detail/win_mutex.hpp index ff71fbeb..176a5fd9 100644 --- a/include/boost/asio/detail/win_mutex.hpp +++ b/include/boost/asio/detail/win_mutex.hpp @@ -84,12 +84,20 @@ private: #if defined(__MINGW32__) // Not sure if MinGW supports structured exception handling, so for now // we'll just call the Windows API and hope. +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# else ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000); +# endif return 0; #else __try { +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# else ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000); +# endif } __except(GetExceptionCode() == STATUS_NO_MEMORY ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) From 73b7b61c612831a4f1ba944db3fc9fc931a12bae Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Fri, 19 Mar 2010 23:58:48 +0000 Subject: [PATCH 13/38] Fix cancellation. [SVN r60723] --- .../asio/detail/win_iocp_socket_service.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/boost/asio/detail/win_iocp_socket_service.hpp b/include/boost/asio/detail/win_iocp_socket_service.hpp index 2b0bbe56..a81d9442 100644 --- a/include/boost/asio/detail/win_iocp_socket_service.hpp +++ b/include/boost/asio/detail/win_iocp_socket_service.hpp @@ -1693,7 +1693,7 @@ private: std::size_t buffer_count, socket_base::message_flags flags, bool noop, operation* op) { - update_cancellation_thread_id(); + update_cancellation_thread_id(impl); iocp_service_.work_started(); if (noop) @@ -1720,7 +1720,7 @@ private: std::size_t buffer_count, const endpoint_type& destination, socket_base::message_flags flags, operation* op) { - update_cancellation_thread_id(); + update_cancellation_thread_id(impl); iocp_service_.work_started(); if (!is_open(impl)) @@ -1746,7 +1746,7 @@ private: std::size_t buffer_count, socket_base::message_flags flags, bool noop, operation* op) { - update_cancellation_thread_id(); + update_cancellation_thread_id(impl); iocp_service_.work_started(); if (noop) @@ -1776,7 +1776,7 @@ private: std::size_t buffer_count, endpoint_type& sender_endpoint, socket_base::message_flags flags, int* endpoint_size, operation* op) { - update_cancellation_thread_id(); + update_cancellation_thread_id(impl); iocp_service_.work_started(); if (!is_open(impl)) @@ -1803,7 +1803,7 @@ private: bool peer_is_open, socket_holder& new_socket, void* output_buffer, DWORD address_length, operation* op) { - update_cancellation_thread_id(); + update_cancellation_thread_id(impl); iocp_service_.work_started(); if (!is_open(impl)) @@ -1835,7 +1835,7 @@ private: void start_reactor_op(implementation_type& impl, int op_type, reactor_op* op) { reactor& r = get_reactor(); - update_cancellation_thread_id(); + update_cancellation_thread_id(impl); if (is_open(impl)) { @@ -1853,7 +1853,7 @@ private: reactor_op* op, const endpoint_type& peer_endpoint) { reactor& r = get_reactor(); - update_cancellation_thread_id(); + update_cancellation_thread_id(impl); if (is_open(impl)) { @@ -1927,7 +1927,7 @@ private: } // Update the ID of the thread from which cancellation is safe. - void update_cancellation_thread_id() + void update_cancellation_thread_id(implementation_type& impl) { #if defined(BOOST_ASIO_ENABLE_CANCELIO) if (impl.safe_cancellation_thread_id_ == 0) From abaadc54366dd848b86fddf9dd7c3ebcc408ce27 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Fri, 19 Mar 2010 23:59:48 +0000 Subject: [PATCH 14/38] Use cancel() to avoid Windows behaviour where a connection is reset if the socket is closed while there is a pending read operation. [SVN r60725] --- test/ip/tcp.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/ip/tcp.cpp b/test/ip/tcp.cpp index f05dad87..95f550ef 100644 --- a/test/ip/tcp.cpp +++ b/test/ip/tcp.cpp @@ -13,6 +13,9 @@ #define BOOST_ALL_NO_LIB 1 #endif // !defined(BOOST_ALL_NO_LIB) +// Enable cancel() support on Windows. +#define BOOST_ASIO_ENABLE_CANCELIO 1 + // Test that header file is self-contained. #include @@ -444,7 +447,7 @@ void test() ios.poll(); BOOST_CHECK(!read_cancel_completed); - server_side_socket.close(); + server_side_socket.cancel(); ios.reset(); ios.run(); @@ -460,6 +463,8 @@ void test() boost::asio::placeholders::bytes_transferred, &read_eof_completed)); + server_side_socket.close(); + ios.reset(); ios.run(); BOOST_CHECK(read_eof_completed); From c980da551543e22f0f2464c780200ddc49ffdb85 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Sun, 21 Mar 2010 10:54:56 +0000 Subject: [PATCH 15/38] Fix search/replace error in some resolver_query_base enumerators. [SVN r60743] --- include/boost/asio/ip/resolver_query_base.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/asio/ip/resolver_query_base.hpp b/include/boost/asio/ip/resolver_query_base.hpp index 7c74a0ec..7fe16504 100644 --- a/include/boost/asio/ip/resolver_query_base.hpp +++ b/include/boost/asio/ip/resolver_query_base.hpp @@ -58,12 +58,12 @@ public: static const flags v4_mapped = implementation_defined; /// If used with v4_mapped, return all matching IPv6 and IPv4 addresses. - static const flags xll_matching = implementation_defined; + 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 xddress_configured = implementation_defined; + static const flags address_configured = implementation_defined; #else enum flags { From 330af11c6b360341f7acb7c8165d071b9590e4c5 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Sun, 21 Mar 2010 12:38:14 +0000 Subject: [PATCH 16/38] Enhance reference doc generation to handle new operator types. [SVN r60745] --- doc/reference.xsl | 78 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/doc/reference.xsl b/doc/reference.xsl index 64650c3c..c36826b6 100644 --- a/doc/reference.xsl +++ b/doc/reference.xsl @@ -94,6 +94,7 @@ @@ -101,6 +102,7 @@ @@ -195,6 +197,12 @@ select="concat(substring-before($name, '!'), '_not_', substring-after($name, '!'))"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \[ + + + + + + + \] + + + + + + + + + + + @@ -669,7 +725,7 @@ [[link boost_asio.reference.. [*]]] - [] + [] @@ -707,6 +763,11 @@ + + + + + @@ -728,7 +789,7 @@ [ [[link boost_asio.reference.. - [*]]] + [*]]] [ @@ -945,6 +1006,11 @@ + + + + + @@ -966,10 +1032,10 @@ [section: -::] +::] [indexterm2 - + .. ] @@ -1005,7 +1071,7 @@ [section: overload - :: + :: ( of overloads)] @@ -1020,7 +1086,7 @@ [indexterm2 - + .. ] From ae4f8aa53fc0759b0ac396b34e32ea2cac1e96b6 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Sun, 21 Mar 2010 12:39:15 +0000 Subject: [PATCH 17/38] Regenerated documentation. [SVN r60746] --- doc/reference.qbk | 860 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 834 insertions(+), 26 deletions(-) diff --git a/doc/reference.qbk b/doc/reference.qbk index 59fce702..396e4700 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -33877,6 +33877,91 @@ A random access iterator over the bytes in a buffer sequence. [Construct an iterator representing the end of the buffers' data. ] ] + [ + [[link boost_asio.reference.buffers_iterator.operator__star_ [*operator *]]] + [Dereference an iterator. ] + ] + + [ + [[link boost_asio.reference.buffers_iterator.operator_plus__plus_ [*operator++]]] + [Increment operator (prefix). + + Increment operator (postfix). ] + ] + + [ + [[link boost_asio.reference.buffers_iterator.operator_plus__eq_ [*operator+=]]] + [Addition operator. ] + ] + + [ + [[link boost_asio.reference.buffers_iterator.operator_minus__minus_ [*operator--]]] + [Decrement operator (prefix). + + Decrement operator (postfix). ] + ] + + [ + [[link boost_asio.reference.buffers_iterator.operator_minus__eq_ [*operator-=]]] + [Subtraction operator. ] + ] + + [ + [[link boost_asio.reference.buffers_iterator.operator_arrow_ [*operator->]]] + [Dereference an iterator. ] + ] + + [ + [[link boost_asio.reference.buffers_iterator.operator_lb__rb_ [*operator\[\]]]] + [Access an individual element. ] + ] + +] + +[heading Friends] +[table + [[Name][Description]] + + [ + [[link boost_asio.reference.buffers_iterator.operator_not__eq_ [*operator!=]]] + [Test two iterators for inequality. ] + ] + + [ + [[link boost_asio.reference.buffers_iterator.operator_plus_ [*operator+]]] + [Addition operator. ] + ] + + [ + [[link boost_asio.reference.buffers_iterator.operator_minus_ [*operator-]]] + [Subtraction operator. ] + ] + + [ + [[link boost_asio.reference.buffers_iterator.operator_lt_ [*operator<]]] + [Compare two iterators. ] + ] + + [ + [[link boost_asio.reference.buffers_iterator.operator_lt__eq_ [*operator<=]]] + [Compare two iterators. ] + ] + + [ + [[link boost_asio.reference.buffers_iterator.operator_eq__eq_ [*operator==]]] + [Test two iterators for equality. ] + ] + + [ + [[link boost_asio.reference.buffers_iterator.operator_gt_ [*operator>]]] + [Compare two iterators. ] + ] + + [ + [[link boost_asio.reference.buffers_iterator.operator_gt__eq_ [*operator>=]]] + [Compare two iterators. ] + ] + ] [heading Requirements] @@ -33930,6 +34015,391 @@ Construct an iterator representing the end of the buffers' data. +[section:operator__star_ buffers_iterator::operator *] + +[indexterm2 operator *..buffers_iterator] +Dereference an iterator. + + + byte_type & operator *() const; + + + +[endsect] + + + +[section:operator_not__eq_ buffers_iterator::operator!=] + +[indexterm2 operator!=..buffers_iterator] +Test two iterators for inequality. + + + friend bool operator!=( + const buffers_iterator & a, + const buffers_iterator & b); + + +[heading Requirements] + +[*Header: ][^boost/asio/buffers_iterator.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + +[section:operator_plus_ buffers_iterator::operator+] + +[indexterm2 operator+..buffers_iterator] +Addition operator. + + + friend buffers_iterator operator+( + const buffers_iterator & iter, + std::ptrdiff_t difference); + + +[heading Requirements] + +[*Header: ][^boost/asio/buffers_iterator.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + +[section:operator_plus__plus_ buffers_iterator::operator++] + +[indexterm2 operator++..buffers_iterator] +Increment operator (prefix). + + + buffers_iterator & ``[link boost_asio.reference.buffers_iterator.operator_plus__plus_.overload1 operator++]``(); + `` [''''»''' [link boost_asio.reference.buffers_iterator.operator_plus__plus_.overload1 more...]]`` + + +Increment operator (postfix). + + + buffers_iterator ``[link boost_asio.reference.buffers_iterator.operator_plus__plus_.overload2 operator++]``( + int ); + `` [''''»''' [link boost_asio.reference.buffers_iterator.operator_plus__plus_.overload2 more...]]`` + + +[section:overload1 buffers_iterator::operator++ (1 of 2 overloads)] + + +Increment operator (prefix). + + + buffers_iterator & operator++(); + + + +[endsect] + + + +[section:overload2 buffers_iterator::operator++ (2 of 2 overloads)] + + +Increment operator (postfix). + + + buffers_iterator operator++( + int ); + + + +[endsect] + + +[endsect] + + +[section:operator_plus__eq_ buffers_iterator::operator+=] + +[indexterm2 operator+=..buffers_iterator] +Addition operator. + + + buffers_iterator & operator+=( + std::ptrdiff_t difference); + + + +[endsect] + + +[section:operator_minus_ buffers_iterator::operator-] + +[indexterm2 operator-..buffers_iterator] +Subtraction operator. + + + friend buffers_iterator ``[link boost_asio.reference.buffers_iterator.operator_minus_.overload1 operator-]``( + const buffers_iterator & iter, + std::ptrdiff_t difference); + `` [''''»''' [link boost_asio.reference.buffers_iterator.operator_minus_.overload1 more...]]`` + + friend std::ptrdiff_t ``[link boost_asio.reference.buffers_iterator.operator_minus_.overload2 operator-]``( + const buffers_iterator & a, + const buffers_iterator & b); + `` [''''»''' [link boost_asio.reference.buffers_iterator.operator_minus_.overload2 more...]]`` + + +[section:overload1 buffers_iterator::operator- (1 of 2 overloads)] + + +Subtraction operator. + + + friend buffers_iterator operator-( + const buffers_iterator & iter, + std::ptrdiff_t difference); + + +[heading Requirements] + +[*Header: ][^boost/asio/buffers_iterator.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + +[section:overload2 buffers_iterator::operator- (2 of 2 overloads)] + + +Subtraction operator. + + + friend std::ptrdiff_t operator-( + const buffers_iterator & a, + const buffers_iterator & b); + + +[heading Requirements] + +[*Header: ][^boost/asio/buffers_iterator.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + +[endsect] + +[section:operator_minus__minus_ buffers_iterator::operator--] + +[indexterm2 operator--..buffers_iterator] +Decrement operator (prefix). + + + buffers_iterator & ``[link boost_asio.reference.buffers_iterator.operator_minus__minus_.overload1 operator--]``(); + `` [''''»''' [link boost_asio.reference.buffers_iterator.operator_minus__minus_.overload1 more...]]`` + + +Decrement operator (postfix). + + + buffers_iterator ``[link boost_asio.reference.buffers_iterator.operator_minus__minus_.overload2 operator--]``( + int ); + `` [''''»''' [link boost_asio.reference.buffers_iterator.operator_minus__minus_.overload2 more...]]`` + + +[section:overload1 buffers_iterator::operator-- (1 of 2 overloads)] + + +Decrement operator (prefix). + + + buffers_iterator & operator--(); + + + +[endsect] + + + +[section:overload2 buffers_iterator::operator-- (2 of 2 overloads)] + + +Decrement operator (postfix). + + + buffers_iterator operator--( + int ); + + + +[endsect] + + +[endsect] + + +[section:operator_minus__eq_ buffers_iterator::operator-=] + +[indexterm2 operator-=..buffers_iterator] +Subtraction operator. + + + buffers_iterator & operator-=( + std::ptrdiff_t difference); + + + +[endsect] + + + +[section:operator_arrow_ buffers_iterator::operator->] + +[indexterm2 operator->..buffers_iterator] +Dereference an iterator. + + + byte_type * operator->() const; + + + +[endsect] + + + +[section:operator_lt_ buffers_iterator::operator<] + +[indexterm2 operator<..buffers_iterator] +Compare two iterators. + + + friend bool operator<( + const buffers_iterator & a, + const buffers_iterator & b); + + +[heading Requirements] + +[*Header: ][^boost/asio/buffers_iterator.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + +[section:operator_lt__eq_ buffers_iterator::operator<=] + +[indexterm2 operator<=..buffers_iterator] +Compare two iterators. + + + friend bool operator<=( + const buffers_iterator & a, + const buffers_iterator & b); + + +[heading Requirements] + +[*Header: ][^boost/asio/buffers_iterator.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + +[section:operator_eq__eq_ buffers_iterator::operator==] + +[indexterm2 operator==..buffers_iterator] +Test two iterators for equality. + + + friend bool operator==( + const buffers_iterator & a, + const buffers_iterator & b); + + +[heading Requirements] + +[*Header: ][^boost/asio/buffers_iterator.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + +[section:operator_gt_ buffers_iterator::operator>] + +[indexterm2 operator>..buffers_iterator] +Compare two iterators. + + + friend bool operator>( + const buffers_iterator & a, + const buffers_iterator & b); + + +[heading Requirements] + +[*Header: ][^boost/asio/buffers_iterator.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + +[section:operator_gt__eq_ buffers_iterator::operator>=] + +[indexterm2 operator>=..buffers_iterator] +Compare two iterators. + + + friend bool operator>=( + const buffers_iterator & a, + const buffers_iterator & b); + + +[heading Requirements] + +[*Header: ][^boost/asio/buffers_iterator.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + +[section:operator_lb__rb_ buffers_iterator::operator\[\]] + +[indexterm2 operator\[\]..buffers_iterator] +Access an individual element. + + + byte_type & operator[]( + std::ptrdiff_t difference) const; + + + +[endsect] + + + [endsect] [section:const_buffer const_buffer] @@ -39102,7 +39572,7 @@ Implements IP version 4 style addresses. [ [[link boost_asio.reference.ip__address_v4.to_bytes [*to_bytes]]] - [Get the address in bytes. ] + [Get the address in bytes, in network byte order. ] ] [ @@ -39724,7 +40194,7 @@ Compare addresses for ordering. [section:to_bytes ip::address_v4::to_bytes] [indexterm2 to_bytes..ip::address_v4] -Get the address in bytes. +Get the address in bytes, in network byte order. bytes_type to_bytes() const; @@ -39917,7 +40387,7 @@ Implements IP version 6 style addresses. [ [[link boost_asio.reference.ip__address_v6.to_bytes [*to_bytes]]] - [Get the address in bytes. ] + [Get the address in bytes, in network byte order. ] ] [ @@ -40623,7 +41093,7 @@ Modifies the scope ID associated with the IPv6 address. [section:to_bytes ip::address_v6::to_bytes] [indexterm2 to_bytes..ip::address_v6] -Get the address in bytes. +Get the address in bytes, in network byte order. bytes_type to_bytes() const; @@ -42334,6 +42804,39 @@ An iterator over the entries produced by a resolver. Create an iterator from an endpoint, host name and service name. ] ] + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator__star_ [*operator *]]] + [Dereference an iterator. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_plus__plus_ [*operator++]]] + [Increment operator (prefix). + + Increment operator (postfix). ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_arrow_ [*operator->]]] + [Dereference an iterator. ] + ] + +] + +[heading Friends] +[table + [[Name][Description]] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_not__eq_ [*operator!=]]] + [Test two iterators for inequality. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_eq__eq_ [*operator==]]] + [Test two iterators for equality. ] + ] + ] The [link boost_asio.reference.ip__basic_resolver_iterator `ip::basic_resolver_iterator`] class template is used to define iterators over the results returned by a resolver. @@ -42433,6 +42936,126 @@ Create an iterator from an endpoint, host name and service name. [endsect] +[section:operator__star_ ip::basic_resolver_iterator::operator *] + +[indexterm2 operator *..ip::basic_resolver_iterator] +Dereference an iterator. + + + const basic_resolver_entry< InternetProtocol > & operator *() const; + + + +[endsect] + + + +[section:operator_not__eq_ ip::basic_resolver_iterator::operator!=] + +[indexterm2 operator!=..ip::basic_resolver_iterator] +Test two iterators for inequality. + + + friend bool operator!=( + const basic_resolver_iterator & a, + const basic_resolver_iterator & b); + + +[heading Requirements] + +[*Header: ][^boost/asio/ip/basic_resolver_iterator.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + +[section:operator_plus__plus_ ip::basic_resolver_iterator::operator++] + +[indexterm2 operator++..ip::basic_resolver_iterator] +Increment operator (prefix). + + + basic_resolver_iterator & ``[link boost_asio.reference.ip__basic_resolver_iterator.operator_plus__plus_.overload1 operator++]``(); + `` [''''»''' [link boost_asio.reference.ip__basic_resolver_iterator.operator_plus__plus_.overload1 more...]]`` + + +Increment operator (postfix). + + + basic_resolver_iterator ``[link boost_asio.reference.ip__basic_resolver_iterator.operator_plus__plus_.overload2 operator++]``( + int ); + `` [''''»''' [link boost_asio.reference.ip__basic_resolver_iterator.operator_plus__plus_.overload2 more...]]`` + + +[section:overload1 ip::basic_resolver_iterator::operator++ (1 of 2 overloads)] + + +Increment operator (prefix). + + + basic_resolver_iterator & operator++(); + + + +[endsect] + + + +[section:overload2 ip::basic_resolver_iterator::operator++ (2 of 2 overloads)] + + +Increment operator (postfix). + + + basic_resolver_iterator operator++( + int ); + + + +[endsect] + + +[endsect] + + +[section:operator_arrow_ ip::basic_resolver_iterator::operator->] + +[indexterm2 operator->..ip::basic_resolver_iterator] +Dereference an iterator. + + + const basic_resolver_entry< InternetProtocol > * operator->() const; + + + +[endsect] + + + +[section:operator_eq__eq_ ip::basic_resolver_iterator::operator==] + +[indexterm2 operator==..ip::basic_resolver_iterator] +Test two iterators for equality. + + + friend bool operator==( + const basic_resolver_iterator & a, + const basic_resolver_iterator & b); + + +[heading Requirements] + +[*Header: ][^boost/asio/ip/basic_resolver_iterator.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + [endsect] [section:ip__basic_resolver_query ip::basic_resolver_query] @@ -42451,6 +43074,13 @@ An query to be passed to a resolver. [table [[Name][Description]] + [ + + [[link boost_asio.reference.ip__basic_resolver_query.flags [*flags]]] + [A bitmask type (C++ Std \[lib.bitmask.types\]). ] + + ] + [ [[link boost_asio.reference.ip__basic_resolver_query.protocol_type [*protocol_type]]] @@ -42560,7 +43190,7 @@ The [link boost_asio.reference.ip__basic_resolver_query `ip::basic_resolver_quer 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 int address_configured = implementation_defined; + static const flags address_configured = implementation_defined; @@ -42577,7 +43207,7 @@ Only return IPv4 addresses if a non-loopback IPv4 address is configured for the If used with v4\_mapped, return all matching IPv6 and IPv4 addresses. - static const int all_matching = implementation_defined; + static const flags all_matching = implementation_defined; @@ -42592,7 +43222,7 @@ Construct with specified service name for any protocol. ``[link boost_asio.reference.ip__basic_resolver_query.basic_resolver_query.overload1 basic_resolver_query]``( const std::string & service_name, - int flags = passive|address_configured); + resolver_query_base::flags resolve_flags = passive|address_configured); `` [''''»''' [link boost_asio.reference.ip__basic_resolver_query.basic_resolver_query.overload1 more...]]`` @@ -42602,7 +43232,7 @@ Construct with specified service name for a given protocol. ``[link boost_asio.reference.ip__basic_resolver_query.basic_resolver_query.overload2 basic_resolver_query]``( const protocol_type & protocol, const std::string & service_name, - int flags = passive|address_configured); + resolver_query_base::flags resolve_flags = passive|address_configured); `` [''''»''' [link boost_asio.reference.ip__basic_resolver_query.basic_resolver_query.overload2 more...]]`` @@ -42612,7 +43242,7 @@ Construct with specified host name and service name for any protocol. ``[link boost_asio.reference.ip__basic_resolver_query.basic_resolver_query.overload3 basic_resolver_query]``( const std::string & host_name, const std::string & service_name, - int flags = address_configured); + resolver_query_base::flags resolve_flags = address_configured); `` [''''»''' [link boost_asio.reference.ip__basic_resolver_query.basic_resolver_query.overload3 more...]]`` @@ -42623,7 +43253,7 @@ Construct with specified host name and service name for a given protocol. const protocol_type & protocol, const std::string & host_name, const std::string & service_name, - int flags = address_configured); + resolver_query_base::flags resolve_flags = address_configured); `` [''''»''' [link boost_asio.reference.ip__basic_resolver_query.basic_resolver_query.overload4 more...]]`` @@ -42635,7 +43265,7 @@ Construct with specified service name for any protocol. basic_resolver_query( const std::string & service_name, - int flags = passive|address_configured); + resolver_query_base::flags resolve_flags = passive|address_configured); @@ -42652,7 +43282,7 @@ Construct with specified service name for a given protocol. basic_resolver_query( const protocol_type & protocol, const std::string & service_name, - int flags = passive|address_configured); + resolver_query_base::flags resolve_flags = passive|address_configured); @@ -42669,7 +43299,7 @@ Construct with specified host name and service name for any protocol. basic_resolver_query( const std::string & host_name, const std::string & service_name, - int flags = address_configured); + resolver_query_base::flags resolve_flags = address_configured); @@ -42687,7 +43317,7 @@ Construct with specified host name and service name for a given protocol. const protocol_type & protocol, const std::string & host_name, const std::string & service_name, - int flags = address_configured); + resolver_query_base::flags resolve_flags = address_configured); @@ -42706,7 +43336,7 @@ Construct with specified host name and service name for a given protocol. Determine the canonical name of the host specified in the query. - static const int canonical_name = implementation_defined; + static const flags canonical_name = implementation_defined; @@ -42714,6 +43344,30 @@ Determine the canonical name of the host specified in the query. +[section:flags ip::basic_resolver_query::flags] + + +['Inherited from ip::resolver_query_base.] + +[indexterm2 flags..ip::basic_resolver_query] +A bitmask type (C++ Std [lib.bitmask.types]). + + + typedef unspecified flags; + + + +[heading Requirements] + +[*Header: ][^boost/asio/ip/basic_resolver_query.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + [section:hints ip::basic_resolver_query::hints] [indexterm2 hints..ip::basic_resolver_query] @@ -42751,7 +43405,7 @@ Get the host name associated with the query. Host name should be treated as a numeric string defining an IPv4 or IPv6 address and no name resolution should be attempted. - static const int numeric_host = implementation_defined; + static const flags numeric_host = implementation_defined; @@ -42768,7 +43422,7 @@ Host name should be treated as a numeric string defining an IPv4 or IPv6 address Service name should be treated as a numeric string defining a port number and no name resolution should be attempted. - static const int numeric_service = implementation_defined; + static const flags numeric_service = implementation_defined; @@ -42785,7 +43439,7 @@ Service name should be treated as a numeric string defining a port number and no Indicate that returned endpoint is intended for use as a locally bound socket endpoint. - static const int passive = implementation_defined; + static const flags passive = implementation_defined; @@ -42837,7 +43491,7 @@ Get the service name associated with the query. If the query protocol family is specified as IPv6, return IPv4-mapped IPv6 addresses on finding no IPv6 addresses. - static const int v4_mapped = implementation_defined; + static const flags v4_mapped = implementation_defined; @@ -43392,6 +44046,39 @@ The type of a resolver iterator. Create an iterator from an endpoint, host name and service name. ] ] + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator__star_ [*operator *]]] + [Dereference an iterator. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_plus__plus_ [*operator++]]] + [Increment operator (prefix). + + Increment operator (postfix). ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_arrow_ [*operator->]]] + [Dereference an iterator. ] + ] + +] + +[heading Friends] +[table + [[Name][Description]] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_not__eq_ [*operator!=]]] + [Test two iterators for inequality. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_eq__eq_ [*operator==]]] + [Test two iterators for equality. ] + ] + ] The [link boost_asio.reference.ip__basic_resolver_iterator `ip::basic_resolver_iterator`] class template is used to define iterators over the results returned by a resolver. @@ -43437,6 +44124,13 @@ The type of a resolver query. [table [[Name][Description]] + [ + + [[link boost_asio.reference.ip__basic_resolver_query.flags [*flags]]] + [A bitmask type (C++ Std \[lib.bitmask.types\]). ] + + ] + [ [[link boost_asio.reference.ip__basic_resolver_query.protocol_type [*protocol_type]]] @@ -44206,6 +44900,19 @@ The [link boost_asio.reference.ip__resolver_query_base `ip::resolver_query_base` class resolver_query_base +[heading Types] +[table + [[Name][Description]] + + [ + + [[link boost_asio.reference.ip__resolver_query_base.flags [*flags]]] + [A bitmask type (C++ Std \[lib.bitmask.types\]). ] + + ] + +] + [heading Protected Member Functions] [table [[Name][Description]] @@ -44271,7 +44978,7 @@ The [link boost_asio.reference.ip__resolver_query_base `ip::resolver_query_base` 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 int address_configured = implementation_defined; + static const flags address_configured = implementation_defined; @@ -44285,7 +44992,7 @@ Only return IPv4 addresses if a non-loopback IPv4 address is configured for the If used with v4\_mapped, return all matching IPv6 and IPv4 addresses. - static const int all_matching = implementation_defined; + static const flags all_matching = implementation_defined; @@ -44299,7 +45006,7 @@ If used with v4\_mapped, return all matching IPv6 and IPv4 addresses. Determine the canonical name of the host specified in the query. - static const int canonical_name = implementation_defined; + static const flags canonical_name = implementation_defined; @@ -44307,13 +45014,34 @@ Determine the canonical name of the host specified in the query. +[section:flags ip::resolver_query_base::flags] + +[indexterm2 flags..ip::resolver_query_base] +A bitmask type (C++ Std [lib.bitmask.types]). + + + typedef unspecified flags; + + + +[heading Requirements] + +[*Header: ][^boost/asio/ip/resolver_query_base.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + [section:numeric_host ip::resolver_query_base::numeric_host] [indexterm2 numeric_host..ip::resolver_query_base] Host name should be treated as a numeric string defining an IPv4 or IPv6 address and no name resolution should be attempted. - static const int numeric_host = implementation_defined; + static const flags numeric_host = implementation_defined; @@ -44327,7 +45055,7 @@ Host name should be treated as a numeric string defining an IPv4 or IPv6 address Service name should be treated as a numeric string defining a port number and no name resolution should be attempted. - static const int numeric_service = implementation_defined; + static const flags numeric_service = implementation_defined; @@ -44341,7 +45069,7 @@ Service name should be treated as a numeric string defining a port number and no Indicate that returned endpoint is intended for use as a locally bound socket endpoint. - static const int passive = implementation_defined; + static const flags passive = implementation_defined; @@ -44355,7 +45083,7 @@ Indicate that returned endpoint is intended for use as a locally bound socket en If the query protocol family is specified as IPv6, return IPv4-mapped IPv6 addresses on finding no IPv6 addresses. - static const int v4_mapped = implementation_defined; + static const flags v4_mapped = implementation_defined; @@ -45803,6 +46531,39 @@ The type of a resolver iterator. Create an iterator from an endpoint, host name and service name. ] ] + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator__star_ [*operator *]]] + [Dereference an iterator. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_plus__plus_ [*operator++]]] + [Increment operator (prefix). + + Increment operator (postfix). ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_arrow_ [*operator->]]] + [Dereference an iterator. ] + ] + +] + +[heading Friends] +[table + [[Name][Description]] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_not__eq_ [*operator!=]]] + [Test two iterators for inequality. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_eq__eq_ [*operator==]]] + [Test two iterators for equality. ] + ] + ] The [link boost_asio.reference.ip__basic_resolver_iterator `ip::basic_resolver_iterator`] class template is used to define iterators over the results returned by a resolver. @@ -45848,6 +46609,13 @@ The type of a resolver query. [table [[Name][Description]] + [ + + [[link boost_asio.reference.ip__basic_resolver_query.flags [*flags]]] + [A bitmask type (C++ Std \[lib.bitmask.types\]). ] + + ] + [ [[link boost_asio.reference.ip__basic_resolver_query.protocol_type [*protocol_type]]] @@ -46881,6 +47649,39 @@ The type of a resolver iterator. Create an iterator from an endpoint, host name and service name. ] ] + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator__star_ [*operator *]]] + [Dereference an iterator. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_plus__plus_ [*operator++]]] + [Increment operator (prefix). + + Increment operator (postfix). ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_arrow_ [*operator->]]] + [Dereference an iterator. ] + ] + +] + +[heading Friends] +[table + [[Name][Description]] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_not__eq_ [*operator!=]]] + [Test two iterators for inequality. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_eq__eq_ [*operator==]]] + [Test two iterators for equality. ] + ] + ] The [link boost_asio.reference.ip__basic_resolver_iterator `ip::basic_resolver_iterator`] class template is used to define iterators over the results returned by a resolver. @@ -46926,6 +47727,13 @@ The type of a resolver query. [table [[Name][Description]] + [ + + [[link boost_asio.reference.ip__basic_resolver_query.flags [*flags]]] + [A bitmask type (C++ Std \[lib.bitmask.types\]). ] + + ] + [ [[link boost_asio.reference.ip__basic_resolver_query.protocol_type [*protocol_type]]] From 41bcacc9e2602e975e461a8cbc2c59dbf2aac87a Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 22 Mar 2010 03:32:56 +0000 Subject: [PATCH 18/38] Fix cancellation in Windows HANDLE backend. [SVN r60756] --- include/boost/asio/detail/win_iocp_handle_service.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/asio/detail/win_iocp_handle_service.hpp b/include/boost/asio/detail/win_iocp_handle_service.hpp index 3f90a6f2..6fb1910f 100644 --- a/include/boost/asio/detail/win_iocp_handle_service.hpp +++ b/include/boost/asio/detail/win_iocp_handle_service.hpp @@ -618,7 +618,7 @@ private: void start_write_op(implementation_type& impl, boost::uint64_t offset, const boost::asio::const_buffer& buffer, operation* op) { - update_cancellation_thread_id(); + update_cancellation_thread_id(impl); iocp_service_.work_started(); if (!is_open(impl)) @@ -656,7 +656,7 @@ private: void start_read_op(implementation_type& impl, boost::uint64_t offset, const boost::asio::mutable_buffer& buffer, operation* op) { - update_cancellation_thread_id(); + update_cancellation_thread_id(impl); iocp_service_.work_started(); if (!is_open(impl)) @@ -691,7 +691,7 @@ private: } // Update the ID of the thread from which cancellation is safe. - void update_cancellation_thread_id() + void update_cancellation_thread_id(implementation_type& impl) { #if defined(BOOST_ASIO_ENABLE_CANCELIO) if (impl.safe_cancellation_thread_id_ == 0) From 3c5fe939c915878cda8c691aa37e33da9e99059a Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Tue, 23 Mar 2010 01:39:12 +0000 Subject: [PATCH 19/38] Async connect operations using the reactor should not allow speculative completion. [SVN r60781] --- include/boost/asio/detail/reactive_socket_service.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/asio/detail/reactive_socket_service.hpp b/include/boost/asio/detail/reactive_socket_service.hpp index 1b81f242..2653facf 100644 --- a/include/boost/asio/detail/reactive_socket_service.hpp +++ b/include/boost/asio/detail/reactive_socket_service.hpp @@ -1714,7 +1714,7 @@ private: { op->ec_ = boost::system::error_code(); reactor_.start_op(reactor::connect_op, - impl.socket_, impl.reactor_data_, op, true); + impl.socket_, impl.reactor_data_, op, false); return; } } From 7efbb6060d85665675f7134b1d2c0e49ec3ee31b Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Fri, 26 Mar 2010 02:44:27 +0000 Subject: [PATCH 20/38] Update to reflect reworked implementation. [SVN r60850] --- doc/overview/allocation.qbk | 7 +------ doc/overview/threads.qbk | 10 ---------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/doc/overview/allocation.qbk b/doc/overview/allocation.qbk index fcd91601..47afc8c8 100644 --- a/doc/overview/allocation.qbk +++ b/doc/overview/allocation.qbk @@ -51,12 +51,7 @@ threads. Custom memory allocation support is currently implemented for all asynchronous operations with the following exceptions: -* `ip::basic_resolver::async_resolve()` on all platforms. - -* `basic_socket::async_connect()` on Windows. - -* Any operation involving `null_buffers()` on Windows, other than an - asynchronous read performed on a stream-oriented socket. +* Asynchronous SSL operations. [heading See Also] diff --git a/doc/overview/threads.qbk b/doc/overview/threads.qbk index f26464f5..8ce9b2ca 100644 --- a/doc/overview/threads.qbk +++ b/doc/overview/threads.qbk @@ -35,16 +35,6 @@ these threads must be invisible to the library user. In particular, the threads: * must block all signals. -[note The implementation currently violates the first of these rules for the -following functions: - -[mdash] `ip::basic_resolver::async_resolve()` on all platforms. - -[mdash] `basic_socket::async_connect()` on Windows. - -[mdash] Any operation involving `null_buffers()` on Windows, other than an -asynchronous read performed on a stream-oriented socket.] - This approach is complemented by the following guarantee: * Asynchronous completion handlers will only be called from threads that are From d32559c6436632e8d5085b7abb44f2e06e8b3f49 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Sat, 27 Mar 2010 10:54:44 +0000 Subject: [PATCH 21/38] Always call ioctl on underlying descriptor when modifying blocking mode. Refs #3307. [SVN r60869] --- .../detail/reactive_descriptor_service.hpp | 32 ++++++++----- .../asio/detail/reactive_socket_service.hpp | 45 +++++++------------ 2 files changed, 38 insertions(+), 39 deletions(-) diff --git a/include/boost/asio/detail/reactive_descriptor_service.hpp b/include/boost/asio/detail/reactive_descriptor_service.hpp index a3a087d6..536b96a5 100644 --- a/include/boost/asio/detail/reactive_descriptor_service.hpp +++ b/include/boost/asio/detail/reactive_descriptor_service.hpp @@ -68,7 +68,7 @@ public: // The descriptor has been set non-blocking. internal_non_blocking = 2, - // Helper "flag" used to determine whether the socket is non-blocking. + // Helper "flag" used to determine whether the descriptor is non-blocking. non_blocking = user_set_non_blocking | internal_non_blocking }; @@ -214,19 +214,31 @@ public: return ec; } - if (command.name() == static_cast(FIONBIO)) + descriptor_ops::ioctl(impl.descriptor_, command.name(), + static_cast(command.data()), ec); + + // When updating the non-blocking mode we always perform the ioctl syscall, + // even if the flags would otherwise indicate that the descriptor is + // already in the correct state. This ensures that the underlying + // descriptor is put into the state that has been requested by the user. If + // the ioctl syscall was successful then we need to update the flags to + // match. + if (!ec && command.name() == static_cast(FIONBIO)) { - if (command.get()) + if (*static_cast(command.data())) + { impl.flags_ |= implementation_type::user_set_non_blocking; + } else - impl.flags_ &= ~implementation_type::user_set_non_blocking; - ec = boost::system::error_code(); - } - else - { - descriptor_ops::ioctl(impl.descriptor_, command.name(), - static_cast(command.data()), ec); + { + // Clearing the non-blocking mode always overrides any internally-set + // non-blocking flag. Any subsequent asynchronous operations will need + // to re-enable non-blocking I/O. + impl.flags_ &= ~(implementation_type::user_set_non_blocking + | implementation_type::internal_non_blocking); + } } + return ec; } diff --git a/include/boost/asio/detail/reactive_socket_service.hpp b/include/boost/asio/detail/reactive_socket_service.hpp index 2653facf..884ce759 100644 --- a/include/boost/asio/detail/reactive_socket_service.hpp +++ b/include/boost/asio/detail/reactive_socket_service.hpp @@ -445,43 +445,30 @@ public: return ec; } - if (command.name() == static_cast(FIONBIO)) + socket_ops::ioctl(impl.socket_, command.name(), + static_cast(command.data()), ec); + + // When updating the non-blocking mode we always perform the ioctl + // syscall, even if the flags would otherwise indicate that the socket is + // already in the correct state. This ensures that the underlying socket + // is put into the state that has been requested by the user. If the ioctl + // syscall was successful then we need to update the flags to match. + if (!ec && command.name() == static_cast(FIONBIO)) { - // Flags are manipulated in a temporary variable so that the socket - // implementation is not updated unless the ioctl operation succeeds. - unsigned char new_flags = impl.flags_; if (*static_cast(command.data())) - new_flags |= implementation_type::user_set_non_blocking; - else - new_flags &= ~implementation_type::user_set_non_blocking; - - // Perform ioctl on socket if the non-blocking state has changed. - if (!(impl.flags_ & implementation_type::non_blocking) - && (new_flags & implementation_type::non_blocking)) { - ioctl_arg_type non_blocking = 1; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec); - } - else if ((impl.flags_ & implementation_type::non_blocking) - && !(new_flags & implementation_type::non_blocking)) - { - ioctl_arg_type non_blocking = 0; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec); + impl.flags_ |= implementation_type::user_set_non_blocking; } else { - ec = boost::system::error_code(); + // Clearing the non-blocking mode always overrides any internally-set + // non-blocking flag. Any subsequent asynchronous operations will need + // to re-enable non-blocking I/O. + impl.flags_ &= ~(implementation_type::user_set_non_blocking + | implementation_type::internal_non_blocking); } + } - // Update socket implementation's flags only if successful. - if (!ec) - impl.flags_ = new_flags; - } - else - { - socket_ops::ioctl(impl.socket_, command.name(), - static_cast(command.data()), ec); - } return ec; } From 7b4fabf4e3a506a4636be30625604cf9527116e8 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Sat, 27 Mar 2010 22:22:59 +0000 Subject: [PATCH 22/38] Change the resolver implementation to no longer require the typedefs InternetProtocol::resolver_query and InternetProtocol::resolver_iterator, as neither typedef is part of the documented InternetProtocol requirements. The following typedefs are now marked as deprecated: - ip::icmp::resolver_query - ip::icmp::resolver_iterator - ip::tcp::resolver_query - ip::tcp::resolver_iterator - ip::udp::resolver_query - ip::udp::resolver_iterator [SVN r60882] --- doc/reference.qbk | 378 +++++++++++++++++- include/boost/asio/basic_socket_streambuf.hpp | 8 +- .../boost/asio/detail/resolver_service.hpp | 6 +- include/boost/asio/ip/basic_resolver.hpp | 6 +- include/boost/asio/ip/icmp.hpp | 4 +- include/boost/asio/ip/resolver_service.hpp | 6 +- include/boost/asio/ip/tcp.hpp | 4 +- include/boost/asio/ip/udp.hpp | 4 +- 8 files changed, 385 insertions(+), 31 deletions(-) diff --git a/doc/reference.qbk b/doc/reference.qbk index 396e4700..3c11e1f5 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -42231,7 +42231,76 @@ A reference to the [link boost_asio.reference.io_service `io_service`] object th The iterator type. - typedef InternetProtocol::resolver_iterator iterator; + typedef basic_resolver_iterator< InternetProtocol > iterator; + + +[heading Member Functions] +[table + [[Name][Description]] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.basic_resolver_iterator [*basic_resolver_iterator]]] + [Default constructor creates an end iterator. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.create [*create]]] + [Create an iterator from an addrinfo list returned by getaddrinfo. + + Create an iterator from an endpoint, host name and service name. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator__star_ [*operator *]]] + [Dereference an iterator. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_plus__plus_ [*operator++]]] + [Increment operator (prefix). + + Increment operator (postfix). ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_arrow_ [*operator->]]] + [Dereference an iterator. ] + ] + +] + +[heading Friends] +[table + [[Name][Description]] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_not__eq_ [*operator!=]]] + [Test two iterators for inequality. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_eq__eq_ [*operator==]]] + [Test two iterators for equality. ] + ] + +] + +The [link boost_asio.reference.ip__basic_resolver_iterator `ip::basic_resolver_iterator`] class template is used to define iterators over the results returned by a resolver. + +The iterator's value\_type, obtained when the iterator is dereferenced, is: + + const basic_resolver_entry + + + + + +[heading Thread Safety] + +[*Distinct] [*objects:] Safe. + +[*Shared] [*objects:] Unsafe. + @@ -42273,7 +42342,111 @@ The protocol type. The query type. - typedef InternetProtocol::resolver_query query; + typedef basic_resolver_query< InternetProtocol > query; + + +[heading Types] +[table + [[Name][Description]] + + [ + + [[link boost_asio.reference.ip__basic_resolver_query.flags [*flags]]] + [A bitmask type (C++ Std \[lib.bitmask.types\]). ] + + ] + + [ + + [[link boost_asio.reference.ip__basic_resolver_query.protocol_type [*protocol_type]]] + [The protocol type associated with the endpoint query. ] + + ] + +] + +[heading Member Functions] +[table + [[Name][Description]] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.basic_resolver_query [*basic_resolver_query]]] + [Construct with specified service name for any protocol. + + Construct with specified service name for a given protocol. + + Construct with specified host name and service name for any protocol. + + Construct with specified host name and service name for a given protocol. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.hints [*hints]]] + [Get the hints associated with the query. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.host_name [*host_name]]] + [Get the host name associated with the query. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.service_name [*service_name]]] + [Get the service name associated with the query. ] + ] + +] + +[heading Data Members] +[table + [[Name][Description]] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.address_configured [*address_configured]]] + [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. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.all_matching [*all_matching]]] + [If used with v4_mapped, return all matching IPv6 and IPv4 addresses. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.canonical_name [*canonical_name]]] + [Determine the canonical name of the host specified in the query. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.numeric_host [*numeric_host]]] + [Host name should be treated as a numeric string defining an IPv4 or IPv6 address and no name resolution should be attempted. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.numeric_service [*numeric_service]]] + [Service name should be treated as a numeric string defining a port number and no name resolution should be attempted. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.passive [*passive]]] + [Indicate that returned endpoint is intended for use as a locally bound socket endpoint. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.v4_mapped [*v4_mapped]]] + [If the query protocol family is specified as IPv6, return IPv4-mapped IPv6 addresses on finding no IPv6 addresses. ] + ] + +] + +The [link boost_asio.reference.ip__basic_resolver_query `ip::basic_resolver_query`] class template describes a query that can be passed to a resolver. + + +[heading Thread Safety] + +[*Distinct] [*objects:] Safe. + +[*Shared] [*objects:] Unsafe. + @@ -43581,14 +43754,14 @@ Encapsulates the flags needed for ICMP. [ [[link boost_asio.reference.ip__icmp.resolver_iterator [*resolver_iterator]]] - [The type of a resolver iterator. ] + [(Deprecated: use resolver::iterator.) The type of a resolver iterator. ] ] [ [[link boost_asio.reference.ip__icmp.resolver_query [*resolver_query]]] - [The type of a resolver query. ] + [(Deprecated: use resolver::query.) The type of a resolver query. ] ] @@ -44024,7 +44197,7 @@ The [link boost_asio.reference.ip__basic_resolver `ip::basic_resolver`] class te [section:resolver_iterator ip::icmp::resolver_iterator] [indexterm2 resolver_iterator..ip::icmp] -The type of a resolver iterator. +(Deprecated: use `resolver::iterator`.) The type of a resolver iterator. typedef basic_resolver_iterator< icmp > resolver_iterator; @@ -44114,7 +44287,7 @@ The iterator's value\_type, obtained when the iterator is dereferenced, is: [section:resolver_query ip::icmp::resolver_query] [indexterm2 resolver_query..ip::icmp] -The type of a resolver query. +(Deprecated: use `resolver::query`.) The type of a resolver query. typedef basic_resolver_query< icmp > resolver_query; @@ -45440,7 +45613,76 @@ The type of a resolver implementation. The iterator type. - typedef InternetProtocol::resolver_iterator iterator_type; + typedef basic_resolver_iterator< InternetProtocol > iterator_type; + + +[heading Member Functions] +[table + [[Name][Description]] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.basic_resolver_iterator [*basic_resolver_iterator]]] + [Default constructor creates an end iterator. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.create [*create]]] + [Create an iterator from an addrinfo list returned by getaddrinfo. + + Create an iterator from an endpoint, host name and service name. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator__star_ [*operator *]]] + [Dereference an iterator. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_plus__plus_ [*operator++]]] + [Increment operator (prefix). + + Increment operator (postfix). ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_arrow_ [*operator->]]] + [Dereference an iterator. ] + ] + +] + +[heading Friends] +[table + [[Name][Description]] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_not__eq_ [*operator!=]]] + [Test two iterators for inequality. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_iterator.operator_eq__eq_ [*operator==]]] + [Test two iterators for equality. ] + ] + +] + +The [link boost_asio.reference.ip__basic_resolver_iterator `ip::basic_resolver_iterator`] class template is used to define iterators over the results returned by a resolver. + +The iterator's value\_type, obtained when the iterator is dereferenced, is: + + const basic_resolver_entry + + + + + +[heading Thread Safety] + +[*Distinct] [*objects:] Safe. + +[*Shared] [*objects:] Unsafe. + @@ -45482,7 +45724,111 @@ The protocol type. The query type. - typedef InternetProtocol::resolver_query query_type; + typedef basic_resolver_query< InternetProtocol > query_type; + + +[heading Types] +[table + [[Name][Description]] + + [ + + [[link boost_asio.reference.ip__basic_resolver_query.flags [*flags]]] + [A bitmask type (C++ Std \[lib.bitmask.types\]). ] + + ] + + [ + + [[link boost_asio.reference.ip__basic_resolver_query.protocol_type [*protocol_type]]] + [The protocol type associated with the endpoint query. ] + + ] + +] + +[heading Member Functions] +[table + [[Name][Description]] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.basic_resolver_query [*basic_resolver_query]]] + [Construct with specified service name for any protocol. + + Construct with specified service name for a given protocol. + + Construct with specified host name and service name for any protocol. + + Construct with specified host name and service name for a given protocol. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.hints [*hints]]] + [Get the hints associated with the query. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.host_name [*host_name]]] + [Get the host name associated with the query. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.service_name [*service_name]]] + [Get the service name associated with the query. ] + ] + +] + +[heading Data Members] +[table + [[Name][Description]] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.address_configured [*address_configured]]] + [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. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.all_matching [*all_matching]]] + [If used with v4_mapped, return all matching IPv6 and IPv4 addresses. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.canonical_name [*canonical_name]]] + [Determine the canonical name of the host specified in the query. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.numeric_host [*numeric_host]]] + [Host name should be treated as a numeric string defining an IPv4 or IPv6 address and no name resolution should be attempted. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.numeric_service [*numeric_service]]] + [Service name should be treated as a numeric string defining a port number and no name resolution should be attempted. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.passive [*passive]]] + [Indicate that returned endpoint is intended for use as a locally bound socket endpoint. ] + ] + + [ + [[link boost_asio.reference.ip__basic_resolver_query.v4_mapped [*v4_mapped]]] + [If the query protocol family is specified as IPv6, return IPv4-mapped IPv6 addresses on finding no IPv6 addresses. ] + ] + +] + +The [link boost_asio.reference.ip__basic_resolver_query `ip::basic_resolver_query`] class template describes a query that can be passed to a resolver. + + +[heading Thread Safety] + +[*Distinct] [*objects:] Safe. + +[*Shared] [*objects:] Unsafe. + @@ -45637,14 +45983,14 @@ Encapsulates the flags needed for TCP. [ [[link boost_asio.reference.ip__tcp.resolver_iterator [*resolver_iterator]]] - [The type of a resolver iterator. ] + [(Deprecated: use resolver::iterator.) The type of a resolver iterator. ] ] [ [[link boost_asio.reference.ip__tcp.resolver_query [*resolver_query]]] - [The type of a resolver query. ] + [(Deprecated: use resolver::query.) The type of a resolver query. ] ] @@ -46509,7 +46855,7 @@ The [link boost_asio.reference.ip__basic_resolver `ip::basic_resolver`] class te [section:resolver_iterator ip::tcp::resolver_iterator] [indexterm2 resolver_iterator..ip::tcp] -The type of a resolver iterator. +(Deprecated: use `resolver::iterator`.) The type of a resolver iterator. typedef basic_resolver_iterator< tcp > resolver_iterator; @@ -46599,7 +46945,7 @@ The iterator's value\_type, obtained when the iterator is dereferenced, is: [section:resolver_query ip::tcp::resolver_query] [indexterm2 resolver_query..ip::tcp] -The type of a resolver query. +(Deprecated: use `resolver::query`.) The type of a resolver query. typedef basic_resolver_query< tcp > resolver_query; @@ -47184,14 +47530,14 @@ Encapsulates the flags needed for UDP. [ [[link boost_asio.reference.ip__udp.resolver_iterator [*resolver_iterator]]] - [The type of a resolver iterator. ] + [(Deprecated: use resolver::iterator.) The type of a resolver iterator. ] ] [ [[link boost_asio.reference.ip__udp.resolver_query [*resolver_query]]] - [The type of a resolver query. ] + [(Deprecated: use resolver::query.) The type of a resolver query. ] ] @@ -47627,7 +47973,7 @@ The [link boost_asio.reference.ip__basic_resolver `ip::basic_resolver`] class te [section:resolver_iterator ip::udp::resolver_iterator] [indexterm2 resolver_iterator..ip::udp] -The type of a resolver iterator. +(Deprecated: use `resolver::iterator`.) The type of a resolver iterator. typedef basic_resolver_iterator< udp > resolver_iterator; @@ -47717,7 +48063,7 @@ The iterator's value\_type, obtained when the iterator is dereferenced, is: [section:resolver_query ip::udp::resolver_query] [indexterm2 resolver_query..ip::udp] -The type of a resolver query. +(Deprecated: use `resolver::query`.) The type of a resolver query. typedef basic_resolver_query< udp > resolver_query; diff --git a/include/boost/asio/basic_socket_streambuf.hpp b/include/boost/asio/basic_socket_streambuf.hpp index 9e96401b..695e8e11 100644 --- a/include/boost/asio/basic_socket_streambuf.hpp +++ b/include/boost/asio/basic_socket_streambuf.hpp @@ -50,7 +50,8 @@ // init_buffers(); // boost::system::error_code ec; // this->basic_socket::close(ec); -// typedef typename Protocol::resolver_query resolver_query; +// typedef typename Protocol::resolver resolver_type; +// typedef typename resolver_type::query resolver_query; // resolver_query query(x1, ..., xn); // resolve_and_connect(query, ec); // return !ec ? this : 0; @@ -65,7 +66,8 @@ init_buffers(); \ boost::system::error_code ec; \ this->basic_socket::close(ec); \ - typedef typename Protocol::resolver_query resolver_query; \ + typedef typename Protocol::resolver resolver_type; \ + typedef typename resolver_type::query resolver_query; \ resolver_query query(BOOST_PP_ENUM_PARAMS(n, x)); \ resolve_and_connect(query, ec); \ return !ec ? this : 0; \ @@ -259,7 +261,7 @@ private: boost::system::error_code& ec) { typedef typename Protocol::resolver resolver_type; - typedef typename Protocol::resolver_iterator iterator_type; + typedef typename resolver_type::iterator iterator_type; resolver_type resolver( boost::base_from_member::member); iterator_type i = resolver.resolve(query, ec); diff --git a/include/boost/asio/detail/resolver_service.hpp b/include/boost/asio/detail/resolver_service.hpp index 22f98601..f9b7a98a 100644 --- a/include/boost/asio/detail/resolver_service.hpp +++ b/include/boost/asio/detail/resolver_service.hpp @@ -26,6 +26,8 @@ #include #include +#include +#include #include #include #include @@ -81,10 +83,10 @@ public: typedef typename Protocol::endpoint endpoint_type; // The query type. - typedef typename Protocol::resolver_query query_type; + typedef boost::asio::ip::basic_resolver_query query_type; // The iterator type. - typedef typename Protocol::resolver_iterator iterator_type; + typedef boost::asio::ip::basic_resolver_iterator iterator_type; // Constructor. resolver_service(boost::asio::io_service& io_service) diff --git a/include/boost/asio/ip/basic_resolver.hpp b/include/boost/asio/ip/basic_resolver.hpp index c4f13abc..0660ce58 100644 --- a/include/boost/asio/ip/basic_resolver.hpp +++ b/include/boost/asio/ip/basic_resolver.hpp @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include @@ -48,10 +50,10 @@ public: typedef typename InternetProtocol::endpoint endpoint_type; /// The query type. - typedef typename InternetProtocol::resolver_query query; + typedef basic_resolver_query query; /// The iterator type. - typedef typename InternetProtocol::resolver_iterator iterator; + typedef basic_resolver_iterator iterator; /// Constructor. /** diff --git a/include/boost/asio/ip/icmp.hpp b/include/boost/asio/ip/icmp.hpp index b70d87d8..5d2fcabd 100644 --- a/include/boost/asio/ip/icmp.hpp +++ b/include/boost/asio/ip/icmp.hpp @@ -45,10 +45,10 @@ public: /// The type of a ICMP endpoint. typedef basic_endpoint endpoint; - /// The type of a resolver query. + /// (Deprecated: use resolver::query.) The type of a resolver query. typedef basic_resolver_query resolver_query; - /// The type of a resolver iterator. + /// (Deprecated: use resolver::iterator.) The type of a resolver iterator. typedef basic_resolver_iterator resolver_iterator; /// Construct to represent the IPv4 ICMP protocol. diff --git a/include/boost/asio/ip/resolver_service.hpp b/include/boost/asio/ip/resolver_service.hpp index 1cd12b91..ba59f6d5 100644 --- a/include/boost/asio/ip/resolver_service.hpp +++ b/include/boost/asio/ip/resolver_service.hpp @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include @@ -49,10 +51,10 @@ public: typedef typename InternetProtocol::endpoint endpoint_type; /// The query type. - typedef typename InternetProtocol::resolver_query query_type; + typedef basic_resolver_query query_type; /// The iterator type. - typedef typename InternetProtocol::resolver_iterator iterator_type; + typedef basic_resolver_iterator iterator_type; private: // The type of the platform-specific implementation. diff --git a/include/boost/asio/ip/tcp.hpp b/include/boost/asio/ip/tcp.hpp index a42c999d..541c95c7 100644 --- a/include/boost/asio/ip/tcp.hpp +++ b/include/boost/asio/ip/tcp.hpp @@ -48,10 +48,10 @@ public: /// The type of a TCP endpoint. typedef basic_endpoint endpoint; - /// The type of a resolver query. + /// (Deprecated: use resolver::query.) The type of a resolver query. typedef basic_resolver_query resolver_query; - /// The type of a resolver iterator. + /// (Deprecated: use resolver::iterator.) The type of a resolver iterator. typedef basic_resolver_iterator resolver_iterator; /// Construct to represent the IPv4 TCP protocol. diff --git a/include/boost/asio/ip/udp.hpp b/include/boost/asio/ip/udp.hpp index e1793c75..e592e066 100644 --- a/include/boost/asio/ip/udp.hpp +++ b/include/boost/asio/ip/udp.hpp @@ -45,10 +45,10 @@ public: /// The type of a UDP endpoint. typedef basic_endpoint endpoint; - /// The type of a resolver query. + /// (Deprecated: use resolver::query.) The type of a resolver query. typedef basic_resolver_query resolver_query; - /// The type of a resolver iterator. + /// (Deprecated: use resolver::iterator.) The type of a resolver iterator. typedef basic_resolver_iterator resolver_iterator; /// Construct to represent the IPv4 UDP protocol. From 399786e7378b5a28d125013bd28cbb14233df132 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Sat, 27 Mar 2010 23:04:56 +0000 Subject: [PATCH 23/38] Fix unused variable warnings. [SVN r60883] --- include/boost/asio/detail/win_iocp_handle_service.hpp | 2 ++ include/boost/asio/detail/win_iocp_socket_service.hpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/include/boost/asio/detail/win_iocp_handle_service.hpp b/include/boost/asio/detail/win_iocp_handle_service.hpp index 6fb1910f..a6d65990 100644 --- a/include/boost/asio/detail/win_iocp_handle_service.hpp +++ b/include/boost/asio/detail/win_iocp_handle_service.hpp @@ -698,6 +698,8 @@ private: impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) impl.safe_cancellation_thread_id_ = ~DWORD(0); +#else // defined(BOOST_ASIO_ENABLE_CANCELIO) + (void)impl; #endif // defined(BOOST_ASIO_ENABLE_CANCELIO) } diff --git a/include/boost/asio/detail/win_iocp_socket_service.hpp b/include/boost/asio/detail/win_iocp_socket_service.hpp index a81d9442..5d545a87 100644 --- a/include/boost/asio/detail/win_iocp_socket_service.hpp +++ b/include/boost/asio/detail/win_iocp_socket_service.hpp @@ -1934,6 +1934,8 @@ private: impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) impl.safe_cancellation_thread_id_ = ~DWORD(0); +#else // defined(BOOST_ASIO_ENABLE_CANCELIO) + (void)impl; #endif // defined(BOOST_ASIO_ENABLE_CANCELIO) } From f1debcc4725a1104ae79e73f7cd9681a61bb4168 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 29 Mar 2010 23:51:15 +0000 Subject: [PATCH 24/38] Document basic_resolver_query's constructor arguments. [SVN r60921] --- .../boost/asio/ip/basic_resolver_query.hpp | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/include/boost/asio/ip/basic_resolver_query.hpp b/include/boost/asio/ip/basic_resolver_query.hpp index 9c5f0f32..75d3c477 100644 --- a/include/boost/asio/ip/basic_resolver_query.hpp +++ b/include/boost/asio/ip/basic_resolver_query.hpp @@ -47,6 +47,22 @@ public: typedef InternetProtocol protocol_type; /// Construct with specified service name for any protocol. + /** + * This constructor is typically used to perform name resolution for local + * service binding. + * + * @param service_name A string identifying the requested service. This may + * be a descriptive name or a numeric string corresponding to a port number. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for local service + * binding. + * + * @note On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ basic_resolver_query(const std::string& service_name, resolver_query_base::flags resolve_flags = passive | address_configured) : hints_(), @@ -65,6 +81,25 @@ public: } /// Construct with specified service name for a given protocol. + /** + * This constructor is typically used to perform name resolution for local + * service binding with a specific protocol version. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param service_name A string identifying the requested service. This may + * be a descriptive name or a numeric string corresponding to a port number. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for local service + * binding. + * + * @note On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ basic_resolver_query(const protocol_type& protocol, const std::string& service_name, resolver_query_base::flags resolve_flags = passive | address_configured) @@ -83,6 +118,36 @@ public: } /// Construct with specified host name and service name for any protocol. + /** + * This constructor is typically used to perform name resolution for + * communication with remote hosts. + * + * @param host_name 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_name 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. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. 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 + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ basic_resolver_query(const std::string& host_name, const std::string& service_name, resolver_query_base::flags resolve_flags = address_configured) @@ -102,6 +167,39 @@ public: } /// Construct with specified host name and service name for a given protocol. + /** + * This constructor is typically used to perform name resolution for + * communication with remote hosts. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param host_name 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_name 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. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. 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 + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ basic_resolver_query(const protocol_type& protocol, const std::string& host_name, const std::string& service_name, resolver_query_base::flags resolve_flags = address_configured) From 5f141a2fa1ea8957e294b1ca600eb6df19888a24 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 29 Mar 2010 23:55:00 +0000 Subject: [PATCH 25/38] Work around an apparent doxygen bug to show template parameter lists on inherited member functions. [SVN r60922] --- doc/reference.xsl | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/doc/reference.xsl b/doc/reference.xsl index c36826b6..55d817f9 100644 --- a/doc/reference.xsl +++ b/doc/reference.xsl @@ -1205,7 +1205,18 @@ - + + + + + + + + + + + + static ( Date: Mon, 29 Mar 2010 23:57:25 +0000 Subject: [PATCH 26/38] Regenerate documentation. [SVN r60923] --- doc/reference.qbk | 152 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/doc/reference.qbk b/doc/reference.qbk index 3c11e1f5..58bf3928 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -2622,6 +2622,8 @@ Assign an existing native socket to the socket. Start an asynchronous connect. + template< + typename ``[link boost_asio.reference.ConnectHandler ConnectHandler]``> void async_connect( const endpoint_type & peer_endpoint, ConnectHandler handler); @@ -4386,6 +4388,8 @@ Get an option from the socket. Get an option from the socket. + template< + typename ``[link boost_asio.reference.GettableSocketOption GettableSocketOption]``> void get_option( GettableSocketOption & option) const; @@ -4443,6 +4447,8 @@ Getting the value of the SOL\_SOCKET/SO\_KEEPALIVE option: Get an option from the socket. + template< + typename ``[link boost_asio.reference.GettableSocketOption GettableSocketOption]``> boost::system::error_code get_option( GettableSocketOption & option, boost::system::error_code & ec) const; @@ -4556,6 +4562,8 @@ Perform an IO control command on the socket. Perform an IO control command on the socket. + template< + typename ``[link boost_asio.reference.IoControlCommand IoControlCommand]``> void io_control( IoControlCommand & command); @@ -4613,6 +4621,8 @@ Getting the number of bytes ready to read: Perform an IO control command on the socket. + template< + typename ``[link boost_asio.reference.IoControlCommand IoControlCommand]``> boost::system::error_code io_control( IoControlCommand & command, boost::system::error_code & ec); @@ -6890,6 +6900,8 @@ Set an option on the socket. Set an option on the socket. + template< + typename ``[link boost_asio.reference.SettableSocketOption SettableSocketOption]``> void set_option( const SettableSocketOption & option); @@ -6946,6 +6958,8 @@ Setting the IPPROTO\_TCP/TCP\_NODELAY option: Set an option on the socket. + template< + typename ``[link boost_asio.reference.SettableSocketOption SettableSocketOption]``> boost::system::error_code set_option( const SettableSocketOption & option, boost::system::error_code & ec); @@ -8918,6 +8932,8 @@ Assign an existing native socket to the socket. Start an asynchronous connect. + template< + typename ``[link boost_asio.reference.ConnectHandler ConnectHandler]``> void async_connect( const endpoint_type & peer_endpoint, ConnectHandler handler); @@ -10682,6 +10698,8 @@ Get an option from the socket. Get an option from the socket. + template< + typename ``[link boost_asio.reference.GettableSocketOption GettableSocketOption]``> void get_option( GettableSocketOption & option) const; @@ -10739,6 +10757,8 @@ Getting the value of the SOL\_SOCKET/SO\_KEEPALIVE option: Get an option from the socket. + template< + typename ``[link boost_asio.reference.GettableSocketOption GettableSocketOption]``> boost::system::error_code get_option( GettableSocketOption & option, boost::system::error_code & ec) const; @@ -10852,6 +10872,8 @@ Perform an IO control command on the socket. Perform an IO control command on the socket. + template< + typename ``[link boost_asio.reference.IoControlCommand IoControlCommand]``> void io_control( IoControlCommand & command); @@ -10909,6 +10931,8 @@ Getting the number of bytes ready to read: Perform an IO control command on the socket. + template< + typename ``[link boost_asio.reference.IoControlCommand IoControlCommand]``> boost::system::error_code io_control( IoControlCommand & command, boost::system::error_code & ec); @@ -13186,6 +13210,8 @@ Set an option on the socket. Set an option on the socket. + template< + typename ``[link boost_asio.reference.SettableSocketOption SettableSocketOption]``> void set_option( const SettableSocketOption & option); @@ -13242,6 +13268,8 @@ Setting the IPPROTO\_TCP/TCP\_NODELAY option: Set an option on the socket. + template< + typename ``[link boost_asio.reference.SettableSocketOption SettableSocketOption]``> boost::system::error_code set_option( const SettableSocketOption & option, boost::system::error_code & ec); @@ -22254,6 +22282,8 @@ Assign an existing native socket to the socket. Start an asynchronous connect. + template< + typename ``[link boost_asio.reference.ConnectHandler ConnectHandler]``> void async_connect( const endpoint_type & peer_endpoint, ConnectHandler handler); @@ -23306,6 +23336,8 @@ Get an option from the socket. Get an option from the socket. + template< + typename ``[link boost_asio.reference.GettableSocketOption GettableSocketOption]``> void get_option( GettableSocketOption & option) const; @@ -23363,6 +23395,8 @@ Getting the value of the SOL\_SOCKET/SO\_KEEPALIVE option: Get an option from the socket. + template< + typename ``[link boost_asio.reference.GettableSocketOption GettableSocketOption]``> boost::system::error_code get_option( GettableSocketOption & option, boost::system::error_code & ec) const; @@ -23476,6 +23510,8 @@ Perform an IO control command on the socket. Perform an IO control command on the socket. + template< + typename ``[link boost_asio.reference.IoControlCommand IoControlCommand]``> void io_control( IoControlCommand & command); @@ -23533,6 +23569,8 @@ Getting the number of bytes ready to read: Perform an IO control command on the socket. + template< + typename ``[link boost_asio.reference.IoControlCommand IoControlCommand]``> boost::system::error_code io_control( IoControlCommand & command, boost::system::error_code & ec); @@ -25067,6 +25105,8 @@ Set an option on the socket. Set an option on the socket. + template< + typename ``[link boost_asio.reference.SettableSocketOption SettableSocketOption]``> void set_option( const SettableSocketOption & option); @@ -25123,6 +25163,8 @@ Setting the IPPROTO\_TCP/TCP\_NODELAY option: Set an option on the socket. + template< + typename ``[link boost_asio.reference.SettableSocketOption SettableSocketOption]``> boost::system::error_code set_option( const SettableSocketOption & option, boost::system::error_code & ec); @@ -25843,6 +25885,8 @@ Assign an existing native socket to the socket. Start an asynchronous connect. + template< + typename ``[link boost_asio.reference.ConnectHandler ConnectHandler]``> void async_connect( const endpoint_type & peer_endpoint, ConnectHandler handler); @@ -27477,6 +27521,8 @@ Get an option from the socket. Get an option from the socket. + template< + typename ``[link boost_asio.reference.GettableSocketOption GettableSocketOption]``> void get_option( GettableSocketOption & option) const; @@ -27534,6 +27580,8 @@ Getting the value of the SOL\_SOCKET/SO\_KEEPALIVE option: Get an option from the socket. + template< + typename ``[link boost_asio.reference.GettableSocketOption GettableSocketOption]``> boost::system::error_code get_option( GettableSocketOption & option, boost::system::error_code & ec) const; @@ -27647,6 +27695,8 @@ Perform an IO control command on the socket. Perform an IO control command on the socket. + template< + typename ``[link boost_asio.reference.IoControlCommand IoControlCommand]``> void io_control( IoControlCommand & command); @@ -27704,6 +27754,8 @@ Getting the number of bytes ready to read: Perform an IO control command on the socket. + template< + typename ``[link boost_asio.reference.IoControlCommand IoControlCommand]``> boost::system::error_code io_control( IoControlCommand & command, boost::system::error_code & ec); @@ -29751,6 +29803,8 @@ Set an option on the socket. Set an option on the socket. + template< + typename ``[link boost_asio.reference.SettableSocketOption SettableSocketOption]``> void set_option( const SettableSocketOption & option); @@ -29807,6 +29861,8 @@ Setting the IPPROTO\_TCP/TCP\_NODELAY option: Set an option on the socket. + template< + typename ``[link boost_asio.reference.SettableSocketOption SettableSocketOption]``> boost::system::error_code set_option( const SettableSocketOption & option, boost::system::error_code & ec); @@ -43441,6 +43497,27 @@ Construct with specified service name for any protocol. resolver_query_base::flags resolve_flags = passive|address_configured); +This constructor is typically used to perform name resolution for local service binding. + + +[heading Parameters] + + +[variablelist + +[[service_name][A string identifying the requested service. This may be a descriptive name or a numeric string corresponding to a port number.]] + +[[resolve_flags][A set of flags that determine how name resolution should be performed. The default flags are suitable for local service binding.]] + +] + + +[heading Remarks] + +On POSIX systems, service names are typically defined in the file `/etc/services`. On Windows, service names may be found in the file `c:\windows\system32\drivers\etc\services`. Operating systems may use additional locations when resolving service names. + + + [endsect] @@ -43458,6 +43535,29 @@ Construct with specified service name for a given protocol. resolver_query_base::flags resolve_flags = passive|address_configured); +This constructor is typically used to perform name resolution for local service binding with a specific protocol version. + + +[heading Parameters] + + +[variablelist + +[[protocol][A protocol object, normally representing either the IPv4 or IPv6 version of an internet protocol.]] + +[[service_name][A string identifying the requested service. This may be a descriptive name or a numeric string corresponding to a port number.]] + +[[resolve_flags][A set of flags that determine how name resolution should be performed. The default flags are suitable for local service binding.]] + +] + + +[heading Remarks] + +On POSIX systems, service names are typically defined in the file `/etc/services`. On Windows, service names may be found in the file `c:\windows\system32\drivers\etc\services`. Operating systems may use additional locations when resolving service names. + + + [endsect] @@ -43475,6 +43575,29 @@ Construct with specified host name and service name for any protocol. resolver_query_base::flags resolve_flags = address_configured); +This constructor is typically used to perform name resolution for communication with remote hosts. + + +[heading Parameters] + + +[variablelist + +[[host_name][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.]] + +[[service_name][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.]] + +[[resolve_flags][A set of flags that determine how name resolution should be performed. The default flags are suitable for communication with remote hosts.]] + +] + + +[heading Remarks] + +On POSIX systems, host names may be locally defined in the file `/etc/hosts`. On Windows, host names may be defined in the file `c:\windows\system32\drivers\etc\hosts`. 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 `/etc/services`. On Windows, service names may be found in the file `c:\windows\system32\drivers\etc\services`. Operating systems may use additional locations when resolving service names. + [endsect] @@ -43493,6 +43616,31 @@ Construct with specified host name and service name for a given protocol. resolver_query_base::flags resolve_flags = address_configured); +This constructor is typically used to perform name resolution for communication with remote hosts. + + +[heading Parameters] + + +[variablelist + +[[protocol][A protocol object, normally representing either the IPv4 or IPv6 version of an internet protocol.]] + +[[host_name][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.]] + +[[service_name][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.]] + +[[resolve_flags][A set of flags that determine how name resolution should be performed. The default flags are suitable for communication with remote hosts.]] + +] + + +[heading Remarks] + +On POSIX systems, host names may be locally defined in the file `/etc/hosts`. On Windows, host names may be defined in the file `c:\windows\system32\drivers\etc\hosts`. 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 `/etc/services`. On Windows, service names may be found in the file `c:\windows\system32\drivers\etc\services`. Operating systems may use additional locations when resolving service names. + [endsect] @@ -53709,6 +53857,8 @@ Perform an IO control command on the descriptor. Perform an IO control command on the descriptor. + template< + typename ``[link boost_asio.reference.IoControlCommand IoControlCommand]``> void io_control( IoControlCommand & command); @@ -53766,6 +53916,8 @@ Getting the number of bytes ready to read: Perform an IO control command on the descriptor. + template< + typename ``[link boost_asio.reference.IoControlCommand IoControlCommand]``> boost::system::error_code io_control( IoControlCommand & command, boost::system::error_code & ec); From d02eb70ec95443ab9ba19c214211901a8ad999d1 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Tue, 30 Mar 2010 12:28:22 +0000 Subject: [PATCH 27/38] Don't allow speculative reads when message_out_of_band is specified. [SVN r60938] --- include/boost/asio/detail/reactive_socket_service.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/asio/detail/reactive_socket_service.hpp b/include/boost/asio/detail/reactive_socket_service.hpp index 884ce759..5f7bbf5c 100644 --- a/include/boost/asio/detail/reactive_socket_service.hpp +++ b/include/boost/asio/detail/reactive_socket_service.hpp @@ -1070,7 +1070,7 @@ public: start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, - ptr.get(), true, + ptr.get(), (flags & socket_base::message_out_of_band) == 0, (impl.protocol_.type() == SOCK_STREAM && buffer_sequence_adapter::all_empty(buffers))); From 1ea2d5330f7491b4eb49f0c2ed3155d22a17fe59 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Tue, 30 Mar 2010 12:30:00 +0000 Subject: [PATCH 28/38] Don't perform a speculative read when an out-of-band read is pending. [SVN r60939] --- include/boost/asio/detail/dev_poll_reactor.hpp | 14 ++++++++------ include/boost/asio/detail/epoll_reactor.hpp | 4 +++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/include/boost/asio/detail/dev_poll_reactor.hpp b/include/boost/asio/detail/dev_poll_reactor.hpp index 873e4359..e00f501b 100644 --- a/include/boost/asio/detail/dev_poll_reactor.hpp +++ b/include/boost/asio/detail/dev_poll_reactor.hpp @@ -126,18 +126,20 @@ public: if (allow_speculative) { - if (!op_queue_[op_type].has_operation(descriptor)) + if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor)) { - if (op->perform()) + if (!op_queue_[op_type].has_operation(descriptor)) { - lock.unlock(); - io_service_.post_immediate_completion(op); - return; + if (op->perform()) + { + lock.unlock(); + io_service_.post_immediate_completion(op); + return; + } } } } - bool first = op_queue_[op_type].enqueue_operation(descriptor, op); io_service_.work_started(); if (first) diff --git a/include/boost/asio/detail/epoll_reactor.hpp b/include/boost/asio/detail/epoll_reactor.hpp index b07de7cc..46849448 100644 --- a/include/boost/asio/detail/epoll_reactor.hpp +++ b/include/boost/asio/detail/epoll_reactor.hpp @@ -180,7 +180,9 @@ public: if (descriptor_data->op_queue_[op_type].empty()) { - if (allow_speculative) + if (allow_speculative + && (op_type != read_op + || descriptor_data->op_queue_[except_op].empty())) { if (op->perform()) { From d3a2b42be1554504add955ce7b1a669f858604d6 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Tue, 30 Mar 2010 12:31:51 +0000 Subject: [PATCH 29/38] New kqueue reactor implementation using one-shot event registration. [SVN r60940] --- include/boost/asio/detail/kqueue_reactor.hpp | 372 ++++++++++--------- 1 file changed, 201 insertions(+), 171 deletions(-) diff --git a/include/boost/asio/detail/kqueue_reactor.hpp b/include/boost/asio/detail/kqueue_reactor.hpp index 9b8599ba..c1a67058 100644 --- a/include/boost/asio/detail/kqueue_reactor.hpp +++ b/include/boost/asio/detail/kqueue_reactor.hpp @@ -34,10 +34,10 @@ #include #include +#include #include #include #include -#include #include #include #include @@ -59,15 +59,24 @@ class kqueue_reactor : public boost::asio::detail::service_base { public: - enum { read_op = 0, write_op = 1, + enum op_types { read_op = 0, write_op = 1, connect_op = 1, except_op = 2, max_ops = 3 }; - // Per-descriptor data. - struct per_descriptor_data + // Per-descriptor queues. + struct descriptor_state { - bool allow_speculative[max_ops]; + descriptor_state() {} + descriptor_state(const descriptor_state&) {} + void operator=(const descriptor_state&) {} + + mutex mutex_; + op_queue op_queue_[max_ops]; + bool shutdown_; }; + // Per-descriptor data. + typedef descriptor_state* per_descriptor_data; + // Constructor. kqueue_reactor(boost::asio::io_service& io_service) : boost::asio::detail::service_base(io_service), @@ -75,34 +84,38 @@ public: mutex_(), kqueue_fd_(do_kqueue_create()), interrupter_(), - shutdown_(false), - need_kqueue_wait_(true) + shutdown_(false) { - // Add the interrupter's descriptor to the kqueue. - struct kevent event; - EV_SET(&event, interrupter_.read_descriptor(), - EVFILT_READ, EV_ADD, 0, 0, 0); - ::kevent(kqueue_fd_, &event, 1, 0, 0, 0); + // The interrupter is put into a permanently readable state. Whenever we + // want to interrupt the blocked kevent call we register a one-shot read + // operation against the descriptor. + interrupter_.interrupt(); } // Destructor. ~kqueue_reactor() { - shutdown_service(); close(kqueue_fd_); } // Destroy all user-defined handler objects owned by the service. void shutdown_service() { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock lock(mutex_); shutdown_ = true; lock.unlock(); op_queue ops; - for (int i = 0; i < max_ops; ++i) - op_queue_[i].get_all_operations(ops); + descriptor_map::iterator iter = registered_descriptors_.begin(); + descriptor_map::iterator end = registered_descriptors_.end(); + while (iter != end) + { + for (int i = 0; i < max_ops; ++i) + ops.push(iter->second.op_queue_[i]); + iter->second.shutdown_ = true; + ++iter; + } timer_queues_.get_all_timers(ops); } @@ -115,11 +128,16 @@ public: // Register a socket with the reactor. Returns 0 on success, system error // code on failure. - int register_descriptor(socket_type, per_descriptor_data& descriptor_data) + int register_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data) { - descriptor_data.allow_speculative[read_op] = true; - descriptor_data.allow_speculative[write_op] = true; - descriptor_data.allow_speculative[except_op] = true; + mutex::scoped_lock lock(registered_descriptors_mutex_); + + descriptor_map::iterator new_entry = registered_descriptors_.insert( + std::make_pair(descriptor, descriptor_state())).first; + descriptor_data = &new_entry->second; + + descriptor_data->shutdown_ = false; return 0; } @@ -130,66 +148,57 @@ public: per_descriptor_data& descriptor_data, reactor_op* op, bool allow_speculative) { - if (allow_speculative && descriptor_data.allow_speculative[op_type]) - { - if (op->perform()) - { - io_service_.post_immediate_completion(op); - return; - } - - // We only get one shot at a speculative read in this function. - allow_speculative = false; - } - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + if (descriptor_data->shutdown_) return; - if (!allow_speculative) - need_kqueue_wait_ = true; - else if (!op_queue_[op_type].has_operation(descriptor)) + bool first = descriptor_data->op_queue_[op_type].empty(); + if (first) { - // Speculative reads are ok as there are no queued read operations. - descriptor_data.allow_speculative[op_type] = true; - - if (op->perform()) + if (allow_speculative) { - lock.unlock(); - io_service_.post_immediate_completion(op); - return; + if (op_type != read_op || descriptor_data->op_queue_[except_op].empty()) + { + if (op->perform()) + { + descriptor_lock.unlock(); + io_service_.post_immediate_completion(op); + return; + } + } } } - // Speculative reads are not ok as there will be queued read operations. - descriptor_data.allow_speculative[op_type] = false; - - bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + descriptor_data->op_queue_[op_type].push(op); io_service_.work_started(); + if (first) { struct kevent event; switch (op_type) { case read_op: - EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0); + EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); break; case write_op: - EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0); + EV_SET(&event, descriptor, EVFILT_WRITE, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); break; case except_op: - if (op_queue_[read_op].has_operation(descriptor)) - EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0); - else - EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, EV_OOBAND, 0, 0); + if (!descriptor_data->op_queue_[read_op].empty()) + return; // Already registered for read events. + EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); break; } + if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { - boost::system::error_code ec(errno, + op->ec_ = boost::system::error_code(errno, boost::asio::error::get_system_category()); - cancel_ops_unlocked(descriptor, ec); + descriptor_data->op_queue_[op_type].pop(); + io_service_.post_deferred_completion(op); } } } @@ -197,33 +206,63 @@ public: // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the // operation_aborted error. - void cancel_ops(socket_type descriptor, per_descriptor_data&) + void cancel_ops(socket_type descriptor, per_descriptor_data& descriptor_data) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + io_service_.post_deferred_completions(ops); } // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. - void close_descriptor(socket_type descriptor, per_descriptor_data&) + void close_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); - // Remove the descriptor from kqueue. - struct kevent event[2]; - EV_SET(&event[0], descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0); - EV_SET(&event[1], descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0); - ::kevent(kqueue_fd_, event, 2, 0, 0, 0); - - // Cancel any outstanding operations associated with the descriptor. - cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); + // Remove the descriptor from the set of known descriptors. The descriptor + // will be automatically removed from the kqueue set when it is closed. + descriptor_data->shutdown_ = true; + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + registered_descriptors_.erase(descriptor); + + descriptors_lock.unlock(); + + io_service_.post_deferred_completions(ops); } // Add a new timer queue to the reactor. template void add_timer_queue(timer_queue& timer_queue) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock lock(mutex_); timer_queues_.insert(&timer_queue); } @@ -231,7 +270,7 @@ public: template void remove_timer_queue(timer_queue& timer_queue) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock lock(mutex_); timer_queues_.erase(&timer_queue); } @@ -241,13 +280,13 @@ public: void schedule_timer(timer_queue& timer_queue, const typename Time_Traits::time_type& time, timer_op* op, void* token) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock lock(mutex_); if (!shutdown_) { bool earliest = timer_queue.enqueue_timer(time, op, token); io_service_.work_started(); if (earliest) - interrupter_.interrupt(); + interrupt(); } } @@ -256,7 +295,7 @@ public: template std::size_t cancel_timer(timer_queue& timer_queue, void* token) { - boost::asio::detail::mutex::scoped_lock lock(mutex_); + mutex::scoped_lock lock(mutex_); op_queue ops; std::size_t n = timer_queue.cancel_timer(token, ops); lock.unlock(); @@ -267,13 +306,7 @@ public: // Run the kqueue loop. void run(bool block, op_queue& 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() - && op_queue_[except_op].empty() && timer_queues_.all_empty()) - return; + mutex::scoped_lock lock(mutex_); // Determine how long to block while waiting for events. timespec timeout_buf = { 0, 0 }; @@ -283,103 +316,104 @@ public: // Block on the kqueue descriptor. struct kevent events[128]; - int num_events = (block || need_kqueue_wait_) - ? kevent(kqueue_fd_, 0, 0, events, 128, timeout) - : 0; - - lock.lock(); + int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout); // Dispatch the waiting events. for (int i = 0; i < num_events; ++i) { int descriptor = events[i].ident; - if (descriptor == interrupter_.read_descriptor()) + void* ptr = events[i].udata; + if (ptr == &interrupter_) { - interrupter_.reset(); + // No need to reset the interrupter since we're leaving the descriptor + // in a ready-to-read state and relying on one-shot notifications. } - else if (events[i].filter == EVFILT_READ) + else { - // Dispatch operations associated with the descriptor. - bool more_reads = false; - bool more_except = false; - if (events[i].flags & EV_ERROR) + descriptor_state* descriptor_data = static_cast(ptr); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + static const int filter[max_ops] = + { EVFILT_READ, EVFILT_WRITE, EVFILT_READ }; + for (int j = max_ops - 1; j >= 0; --j) { - boost::system::error_code error( - events[i].data, boost::asio::error::get_system_category()); - op_queue_[except_op].perform_operations(descriptor, ops); - op_queue_[read_op].perform_operations(descriptor, ops); + if (events[i].filter == filter[j]) + { + if (j != except_op || events[i].flags & EV_OOBAND) + { + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + if (events[i].flags & EV_ERROR) + { + op->ec_ = boost::system::error_code(events[i].data, + boost::asio::error::get_system_category()); + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + if (op->perform()) + { + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + else + break; + } + } + } } - else if (events[i].flags & EV_OOBAND) + + // Renew registration for event notifications. + struct kevent event; + switch (events[i].filter) { - more_except - = op_queue_[except_op].perform_operations(descriptor, ops); - if (events[i].data > 0) - more_reads = op_queue_[read_op].perform_operations(descriptor, ops); + case EVFILT_READ: + if (!descriptor_data->op_queue_[read_op].empty()) + EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + else if (!descriptor_data->op_queue_[except_op].empty()) + EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); else - more_reads = op_queue_[read_op].has_operation(descriptor); + continue; + case EVFILT_WRITE: + if (!descriptor_data->op_queue_[write_op].empty()) + EV_SET(&event, descriptor, EVFILT_WRITE, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + else + continue; + default: + break; } - else - { - more_reads = op_queue_[read_op].perform_operations(descriptor, ops); - more_except = op_queue_[except_op].has_operation(descriptor); - } - - // Update the descriptor in the kqueue. - struct kevent event; - if (more_reads) - EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0); - else if (more_except) - EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0); - else - EV_SET(&event, descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { boost::system::error_code error(errno, boost::asio::error::get_system_category()); - op_queue_[except_op].cancel_operations(descriptor, ops, error); - op_queue_[read_op].cancel_operations(descriptor, ops, error); - } - } - else if (events[i].filter == EVFILT_WRITE) - { - // Dispatch operations associated with the descriptor. - bool more_writes = false; - if (events[i].flags & EV_ERROR) - { - boost::system::error_code error( - events[i].data, boost::asio::error::get_system_category()); - op_queue_[write_op].cancel_operations(descriptor, ops, error); - } - else - { - more_writes = op_queue_[write_op].perform_operations(descriptor, ops); - } - - // Update the descriptor in the kqueue. - struct kevent event; - if (more_writes) - EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0); - else - EV_SET(&event, descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0); - if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) - { - boost::system::error_code error(errno, - boost::asio::error::get_system_category()); - op_queue_[write_op].cancel_operations(descriptor, ops, error); + for (int j = 0; j < max_ops; ++j) + { + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + op->ec_ = error; + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + } } } } - timer_queues_.get_ready_timers(ops); - // Determine whether kqueue needs to be called next time the reactor is run. - need_kqueue_wait_ = !op_queue_[read_op].empty() - || !op_queue_[write_op].empty() || !op_queue_[except_op].empty(); + lock.lock(); + timer_queues_.get_ready_timers(ops); } - // Interrupt the select loop. + // Interrupt the kqueue loop. void interrupt() { - interrupter_.interrupt(); + struct kevent event; + EV_SET(&event, interrupter_.read_descriptor(), + EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &interrupter_); + ::kevent(kqueue_fd_, &event, 1, 0, 0, 0); } private: @@ -410,22 +444,11 @@ private: return &ts; } - // Cancel all operations associated with the given descriptor. This function - // does not acquire the kqueue_reactor's mutex. - void cancel_ops_unlocked(socket_type descriptor, - const boost::system::error_code& ec) - { - op_queue ops; - for (int i = 0; i < max_ops; ++i) - op_queue_[i].cancel_operations(descriptor, ops, ec); - io_service_.post_deferred_completions(ops); - } - // The io_service implementation used to post completions. io_service_impl& io_service_; // Mutex to protect access to internal data. - boost::asio::detail::mutex mutex_; + mutex mutex_; // The kqueue file descriptor. int kqueue_fd_; @@ -433,17 +456,24 @@ private: // The interrupter is used to break a blocking kevent call. select_interrupter interrupter_; - // The queues of read, write and except operations. - reactor_op_queue op_queue_[max_ops]; - // The timer queues. timer_queue_set timer_queues_; // Whether the service has been shut down. bool shutdown_; - // Whether we need to call kqueue the next time the reactor is run. - bool need_kqueue_wait_; + // Mutex to protect access to the registered descriptors. + mutex registered_descriptors_mutex_; + + // Keep track of all registered descriptors. This code relies on the fact that + // the hash_map implementation pools deleted nodes, meaning that we can assume + // our descriptor_state pointer remains valid even after the entry is removed. + // Technically this is not true for C++98, as that standard says that spliced + // elements in a list are invalidated. However, C++0x fixes this shortcoming + // so we'll just assume that C++98 std::list implementations will do the right + // thing anyway. + typedef detail::hash_map descriptor_map; + descriptor_map registered_descriptors_; }; } // namespace detail From 51ae6ad776010c48086606cb08876d1857164957 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Wed, 31 Mar 2010 12:13:47 +0000 Subject: [PATCH 30/38] Uncomment ifdef test that was accidentally left commented. [SVN r60961] --- include/boost/asio/detail/fenced_block.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/asio/detail/fenced_block.hpp b/include/boost/asio/detail/fenced_block.hpp index f43097c4..90a6acae 100644 --- a/include/boost/asio/detail/fenced_block.hpp +++ b/include/boost/asio/detail/fenced_block.hpp @@ -21,7 +21,7 @@ #include #include -#if 1//!defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) # include #elif defined(__MACH__) && defined(__APPLE__) # include @@ -42,7 +42,7 @@ namespace boost { namespace asio { namespace detail { -#if 1//!defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) typedef null_fenced_block fenced_block; #elif defined(__MACH__) && defined(__APPLE__) typedef macos_fenced_block fenced_block; From 5dbcf53b1751da2cad7b71f8f8140ec3a9cda6d3 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Wed, 31 Mar 2010 12:22:10 +0000 Subject: [PATCH 31/38] Fix so that lock is not held while reactor is running. [SVN r60962] --- include/boost/asio/detail/task_io_service.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/boost/asio/detail/task_io_service.hpp b/include/boost/asio/detail/task_io_service.hpp index fe6af3ce..f6de3706 100644 --- a/include/boost/asio/detail/task_io_service.hpp +++ b/include/boost/asio/detail/task_io_service.hpp @@ -290,9 +290,7 @@ private: } task_has_run = true; - if (more_handlers) - wake_one_idle_thread_and_unlock(lock); - else + if (!more_handlers || !wake_one_idle_thread_and_unlock(lock)) lock.unlock(); op_queue completed_ops; From 03645c054ca2243a385070441c060fdf1167ea19 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Fri, 2 Apr 2010 22:51:42 +0000 Subject: [PATCH 32/38] Add ifdef to allow asio's threading support to be independently disabled. [SVN r61009] --- include/boost/asio/detail/event.hpp | 4 ++-- include/boost/asio/detail/fenced_block.hpp | 4 ++-- include/boost/asio/detail/mutex.hpp | 4 ++-- include/boost/asio/detail/null_event.hpp | 4 ++-- include/boost/asio/detail/null_mutex.hpp | 4 ++-- include/boost/asio/detail/null_signal_blocker.hpp | 4 ++-- include/boost/asio/detail/null_thread.hpp | 4 ++-- include/boost/asio/detail/null_tss_ptr.hpp | 4 ++-- include/boost/asio/detail/signal_blocker.hpp | 4 ++-- include/boost/asio/detail/thread.hpp | 4 ++-- include/boost/asio/detail/tss_ptr.hpp | 6 +++--- 11 files changed, 23 insertions(+), 23 deletions(-) diff --git a/include/boost/asio/detail/event.hpp b/include/boost/asio/detail/event.hpp index 89f9896a..e8d185fe 100644 --- a/include/boost/asio/detail/event.hpp +++ b/include/boost/asio/detail/event.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include #elif defined(BOOST_WINDOWS) # include @@ -35,7 +35,7 @@ namespace boost { namespace asio { namespace detail { -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) typedef null_event event; #elif defined(BOOST_WINDOWS) typedef win_event event; diff --git a/include/boost/asio/detail/fenced_block.hpp b/include/boost/asio/detail/fenced_block.hpp index 90a6acae..a7e81b20 100644 --- a/include/boost/asio/detail/fenced_block.hpp +++ b/include/boost/asio/detail/fenced_block.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include #elif defined(__MACH__) && defined(__APPLE__) # include @@ -42,7 +42,7 @@ namespace boost { namespace asio { namespace detail { -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) typedef null_fenced_block fenced_block; #elif defined(__MACH__) && defined(__APPLE__) typedef macos_fenced_block fenced_block; diff --git a/include/boost/asio/detail/mutex.hpp b/include/boost/asio/detail/mutex.hpp index fc7ed83c..e804ec25 100644 --- a/include/boost/asio/detail/mutex.hpp +++ b/include/boost/asio/detail/mutex.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include #elif defined(BOOST_WINDOWS) # include @@ -35,7 +35,7 @@ namespace boost { namespace asio { namespace detail { -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) typedef null_mutex mutex; #elif defined(BOOST_WINDOWS) typedef win_mutex mutex; diff --git a/include/boost/asio/detail/null_event.hpp b/include/boost/asio/detail/null_event.hpp index e926d4e3..2dc0bf6d 100644 --- a/include/boost/asio/detail/null_event.hpp +++ b/include/boost/asio/detail/null_event.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include @@ -72,7 +72,7 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include diff --git a/include/boost/asio/detail/null_mutex.hpp b/include/boost/asio/detail/null_mutex.hpp index bdf56179..edc13584 100644 --- a/include/boost/asio/detail/null_mutex.hpp +++ b/include/boost/asio/detail/null_mutex.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include #include @@ -61,7 +61,7 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include diff --git a/include/boost/asio/detail/null_signal_blocker.hpp b/include/boost/asio/detail/null_signal_blocker.hpp index 7fe5c108..65b55e96 100644 --- a/include/boost/asio/detail/null_signal_blocker.hpp +++ b/include/boost/asio/detail/null_signal_blocker.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include @@ -58,7 +58,7 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include diff --git a/include/boost/asio/detail/null_thread.hpp b/include/boost/asio/detail/null_thread.hpp index 0a508f34..ba163114 100644 --- a/include/boost/asio/detail/null_thread.hpp +++ b/include/boost/asio/detail/null_thread.hpp @@ -22,7 +22,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include #include @@ -63,7 +63,7 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include diff --git a/include/boost/asio/detail/null_tss_ptr.hpp b/include/boost/asio/detail/null_tss_ptr.hpp index 7c35b151..bd83e7ee 100644 --- a/include/boost/asio/detail/null_tss_ptr.hpp +++ b/include/boost/asio/detail/null_tss_ptr.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include @@ -65,7 +65,7 @@ private: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include diff --git a/include/boost/asio/detail/signal_blocker.hpp b/include/boost/asio/detail/signal_blocker.hpp index db11fe4d..0197e04d 100644 --- a/include/boost/asio/detail/signal_blocker.hpp +++ b/include/boost/asio/detail/signal_blocker.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) # include @@ -35,7 +35,7 @@ namespace boost { namespace asio { namespace detail { -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) typedef null_signal_blocker signal_blocker; #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef win_signal_blocker signal_blocker; diff --git a/include/boost/asio/detail/thread.hpp b/include/boost/asio/detail/thread.hpp index 24a7a8ca..3e2e2159 100644 --- a/include/boost/asio/detail/thread.hpp +++ b/include/boost/asio/detail/thread.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include #elif defined(BOOST_WINDOWS) # if defined(UNDER_CE) @@ -39,7 +39,7 @@ namespace boost { namespace asio { namespace detail { -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) typedef null_thread thread; #elif defined(BOOST_WINDOWS) # if defined(UNDER_CE) diff --git a/include/boost/asio/detail/tss_ptr.hpp b/include/boost/asio/detail/tss_ptr.hpp index 9af4965a..7ccfcf32 100644 --- a/include/boost/asio/detail/tss_ptr.hpp +++ b/include/boost/asio/detail/tss_ptr.hpp @@ -21,7 +21,7 @@ #include #include -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include #elif defined(BOOST_WINDOWS) # include @@ -37,7 +37,7 @@ namespace detail { template class tss_ptr -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) : public null_tss_ptr #elif defined(BOOST_WINDOWS) : public win_tss_ptr @@ -48,7 +48,7 @@ class tss_ptr public: void operator=(T* value) { -#if !defined(BOOST_HAS_THREADS) +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) null_tss_ptr::operator=(value); #elif defined(BOOST_WINDOWS) win_tss_ptr::operator=(value); From 58ca677b0fef04e2673118a1273ad17d82ead678 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Sat, 3 Apr 2010 00:29:06 +0000 Subject: [PATCH 33/38] Try to fix compile errors on various platforms in fenced_block. [SVN r61010] --- include/boost/asio/detail/fenced_block.hpp | 12 ++++++---- .../boost/asio/detail/gcc_fenced_block.hpp | 6 ++++- .../boost/asio/detail/win_fenced_block.hpp | 24 +++++++++++++++++-- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/include/boost/asio/detail/fenced_block.hpp b/include/boost/asio/detail/fenced_block.hpp index a7e81b20..a0b14481 100644 --- a/include/boost/asio/detail/fenced_block.hpp +++ b/include/boost/asio/detail/fenced_block.hpp @@ -28,11 +28,13 @@ #elif defined(__sun) # include #elif defined(__GNUC__) \ - && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ + && !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !defined(__ICC) && !defined(__ECC) # include #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) # include -#elif defined(BOOST_WINDOWS) +#elif defined(BOOST_WINDOWS) && !defined(UNDER_CE) # include #else # include @@ -49,11 +51,13 @@ typedef macos_fenced_block fenced_block; #elif defined(__sun) typedef solaris_fenced_block fenced_block; #elif defined(__GNUC__) \ - && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ + && !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !defined(__ICC) && !defined(__ECC) typedef gcc_fenced_block fenced_block; #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) typedef gcc_x86_fenced_block fenced_block; -#elif defined(BOOST_WINDOWS) +#elif defined(BOOST_WINDOWS) && !defined(UNDER_CE) typedef win_fenced_block fenced_block; #else typedef null_fenced_block fenced_block; diff --git a/include/boost/asio/detail/gcc_fenced_block.hpp b/include/boost/asio/detail/gcc_fenced_block.hpp index 6b58ee89..6c5edc8d 100644 --- a/include/boost/asio/detail/gcc_fenced_block.hpp +++ b/include/boost/asio/detail/gcc_fenced_block.hpp @@ -22,7 +22,9 @@ #include #if defined(__GNUC__) \ - && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ + && !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !defined(__ICC) && !defined(__ECC) namespace boost { namespace asio { @@ -55,6 +57,8 @@ private: #endif // defined(__GNUC__) // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) + // && !defined(__INTEL_COMPILER) && !defined(__ICL) + // && !defined(__ICC) && !defined(__ECC) #include diff --git a/include/boost/asio/detail/win_fenced_block.hpp b/include/boost/asio/detail/win_fenced_block.hpp index 443b50c9..ff4a21cb 100644 --- a/include/boost/asio/detail/win_fenced_block.hpp +++ b/include/boost/asio/detail/win_fenced_block.hpp @@ -21,7 +21,7 @@ #include #include -#if defined(BOOST_WINDOWS) +#if defined(BOOST_WINDOWS) && !defined(UNDER_CE) #include @@ -36,13 +36,33 @@ public: // Constructor. win_fenced_block() { +#if defined(BOOST_MSVC) && (BOOST_MSVC < 1400) +# if defined(_M_IX86) +# pragma warning(push) +# pragma warning(disable:4793) + LONG barrier; + __asm { xchg barrier, eax } +# pragma warning(pop) +# endif // defined(_M_IX86) +#else // defined(BOOST_MSVC) && (BOOST_MSVC < 1400) MemoryBarrier(); +#endif // defined(BOOST_MSVC) && (BOOST_MSVC < 1400) } // Destructor. ~win_fenced_block() { +#if defined(BOOST_MSVC) && (BOOST_MSVC < 1400) +# if defined(_M_IX86) +# pragma warning(push) +# pragma warning(disable:4793) + LONG barrier; + __asm { xchg barrier, eax } +# pragma warning(pop) +# endif // defined(_M_IX86) +#else // defined(BOOST_MSVC) && (BOOST_MSVC < 1400) MemoryBarrier(); +#endif // defined(BOOST_MSVC) && (BOOST_MSVC < 1400) } }; @@ -50,7 +70,7 @@ public: } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) +#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) #include From b59ac3d3883037a5c63e3b12b6e97b4f4404acee Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Sat, 10 Apr 2010 06:54:34 +0000 Subject: [PATCH 34/38] Try using asm-based fenced block for pathscale. [SVN r61172] --- include/boost/asio/detail/fenced_block.hpp | 4 ++-- include/boost/asio/detail/gcc_fenced_block.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/asio/detail/fenced_block.hpp b/include/boost/asio/detail/fenced_block.hpp index a0b14481..c80161f3 100644 --- a/include/boost/asio/detail/fenced_block.hpp +++ b/include/boost/asio/detail/fenced_block.hpp @@ -30,7 +30,7 @@ #elif defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ - && !defined(__ICC) && !defined(__ECC) + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) # include #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) # include @@ -53,7 +53,7 @@ typedef solaris_fenced_block fenced_block; #elif defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ - && !defined(__ICC) && !defined(__ECC) + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) typedef gcc_fenced_block fenced_block; #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) typedef gcc_x86_fenced_block fenced_block; diff --git a/include/boost/asio/detail/gcc_fenced_block.hpp b/include/boost/asio/detail/gcc_fenced_block.hpp index 6c5edc8d..0c086a6c 100644 --- a/include/boost/asio/detail/gcc_fenced_block.hpp +++ b/include/boost/asio/detail/gcc_fenced_block.hpp @@ -24,7 +24,7 @@ #if defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ - && !defined(__ICC) && !defined(__ECC) + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) namespace boost { namespace asio { @@ -58,7 +58,7 @@ private: #endif // defined(__GNUC__) // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) // && !defined(__INTEL_COMPILER) && !defined(__ICL) - // && !defined(__ICC) && !defined(__ECC) + // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) #include From 33eeb63378fa493f66a9cb4dfd3fcd5178a27b5c Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Wed, 28 Apr 2010 12:39:06 +0000 Subject: [PATCH 35/38] Doc updates. [SVN r61643] --- doc/history.qbk | 35 ++++++++ doc/overview/serial_ports.qbk | 9 +- doc/reference.qbk | 134 +++++++++++++++++++++++++++--- include/boost/asio/io_service.hpp | 16 ++++ include/boost/asio/read.hpp | 15 +++- include/boost/asio/read_until.hpp | 93 +++++++++++++++++++-- include/boost/asio/write.hpp | 20 ++++- 7 files changed, 292 insertions(+), 30 deletions(-) diff --git a/doc/history.qbk b/doc/history.qbk index 6721ada4..81281bbb 100644 --- a/doc/history.qbk +++ b/doc/history.qbk @@ -7,6 +7,41 @@ [section:history Revision History] +[heading Asio 1.4.5 / Boost 1.43] + +* Improved performance. +* Reduced compile times. +* Reduced the size of generated code. +* Extended the guarantee that background threads don't call user code to all + asynchronous operations + ([@https://svn.boost.org/trac/boost/ticket/3923 #3923]). +* Changed to use edge-triggered epoll on Linux. +* Changed to use `timerfd` for dispatching timers on Linux, when available. +* Changed to use one-shot notifications with kqueue on Mac OS X and BSD + platforms. +* Added a bitmask type `ip::resolver_query_base::flags` as per the TR2 proposal. + This type prevents implicit conversion from `int` to `flags`, allowing the + compiler to catch cases where users incorrectly pass a numeric port number as + the service name. +* Added `#define NOMINMAX` for all Windows compilers. Users can define + `BOOST_ASIO_NO_NOMINMAX` to suppress this definition + ([@https://svn.boost.org/trac/boost/ticket/3901 #3901]). +* Fixed a bug where 0-byte asynchronous reads were incorrectly passing an + `error::eof` result to the completion handler + ([@https://svn.boost.org/trac/boost/ticket/4023 #4023]). +* Changed the `io_control()` member functions to always call `ioctl` on the + underlying descriptor when modifying blocking mode + ([@https://svn.boost.org/trac/boost/ticket/3307 #3307]). +* Changed the resolver implementation to longer require the typedefs + `InternetProtocol::resolver_query` and `InternetProtocol::resolver_iterator`, + as neither typedef is part of the documented `InternetProtocol` requirements. + The corresponding typedefs in the `ip::tcp`, `ip::udp` and `ip::icmp` classes + have been deprecated. +* Fixed out-of-band handling for reactors not based on `select()`. +* Added new `BOOST_ASIO_DISABLE_THREADS` macro that allows Asio's threading + support to be independently disabled. +* Minor documentation improvements. + [heading Asio 1.4.4 / Boost 1.42] * Added a new HTTP Server 4 example illustrating the use of stackless coroutines diff --git a/doc/overview/serial_ports.qbk b/doc/overview/serial_ports.qbk index a603a4cc..f905d2d6 100644 --- a/doc/overview/serial_ports.qbk +++ b/doc/overview/serial_ports.qbk @@ -15,10 +15,11 @@ manner. For example, a serial port may be opened using: where name is something like `"COM1"` on Windows, and `"/dev/ttyS0"` on POSIX platforms. -Once opened the serial port may be used as a stream. This means the objects can -be used with any of the [link boost_asio.reference.read read()], [link -boost_asio.reference.async_read async_read()], [link boost_asio.reference.write write()], -[link boost_asio.reference.async_write async_write()], [link +Once opened, the serial port may be used as a [link +boost_asio.overview.core.streams stream]. This means the objects can be used +with any of the [link boost_asio.reference.read read()], [link +boost_asio.reference.async_read async_read()], [link boost_asio.reference.write +write()], [link boost_asio.reference.async_write async_write()], [link boost_asio.reference.read_until read_until()] or [link boost_asio.reference.async_read_until async_read_until()] free functions. diff --git a/doc/reference.qbk b/doc/reference.qbk index 58bf3928..d08c67c6 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -342,7 +342,7 @@ This function is used to asynchronously read a certain number of bytes of data f * An error occurred. -This operation is implemented in terms of zero or more calls to the stream's async\_read\_some function. +This operation is implemented in terms of zero or more calls to the stream's async\_read\_some function, and is known as a [*composed operation]. 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. [heading Parameters] @@ -505,7 +505,7 @@ This function is used to asynchronously read a certain number of bytes of data f * An error occurred. -This operation is implemented in terms of zero or more calls to the stream's async\_read\_some function. +This operation is implemented in terms of zero or more calls to the stream's async\_read\_some function, and is known as a [*composed operation]. 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. [heading Parameters] @@ -576,7 +576,7 @@ This function is used to asynchronously read a certain number of bytes of data f * 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. +This operation is implemented in terms of zero or more calls to the stream's async\_read\_some function, and is known as a [*composed operation]. 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. [heading Parameters] @@ -1087,7 +1087,7 @@ This function is used to asynchronously read data into the specified streambuf u * An error occurred. -This operation is implemented in terms of zero or more calls to the stream's async\_read\_some function. If the streambuf's get area already contains the delimiter, the asynchronous operation completes immediately. +This operation is implemented in terms of zero or more calls to the stream's async\_read\_some function, and is known as a [*composed operation]. If the streambuf'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. [heading Parameters] @@ -1143,7 +1143,22 @@ To asynchronously read data into a streambuf until a newline is encountered: boost::asio::async_read_until(s, b, '\n', handler); +After the `async_read_until` operation completes successfully, the buffer `b` contains the delimiter: + { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } + + +The call to `std::getline` then extracts the data up to and including the delimiter, so that the string `line` contains: + + { 'a', 'b', ..., 'c', '\n' } + + +The remaining data is left in the buffer `b` as follows: + + { 'd', 'e', ... } + + +This data may be the start of a new line, to be extracted by a subsequent `async_read_until` operation. @@ -1177,7 +1192,7 @@ This function is used to asynchronously read data into the specified streambuf u * An error occurred. -This operation is implemented in terms of zero or more calls to the stream's async\_read\_some function. If the streambuf's get area already contains the delimiter, the asynchronous operation completes immediately. +This operation is implemented in terms of zero or more calls to the stream's async\_read\_some function, and is known as a [*composed operation]. If the streambuf'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. [heading Parameters] @@ -1233,7 +1248,22 @@ To asynchronously read data into a streambuf until a newline is encountered: boost::asio::async_read_until(s, b, "\r\n", handler); +After the `async_read_until` operation completes successfully, the buffer `b` contains the delimiter: + { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } + + +The call to `std::getline` then extracts the data up to and including the delimiter, so that the string `line` contains: + + { 'a', 'b', ..., 'c', '\r', '\n' } + + +The remaining data is left in the buffer `b` as follows: + + { 'd', 'e', ... } + + +This data may be the start of a new line, to be extracted by a subsequent `async_read_until` operation. @@ -1267,7 +1297,7 @@ This function is used to asynchronously read data into the specified streambuf u * An error occurred. -This operation is implemented in terms of zero or more calls to the stream's async\_read\_some function. If the streambuf's get area already contains data that matches the regular expression, the function returns immediately. +This operation is implemented in terms of zero or more calls to the stream's async\_read\_some function, and is known as a [*composed operation]. If the streambuf'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. [heading Parameters] @@ -1324,7 +1354,22 @@ To asynchronously read data into a streambuf until a CR-LF sequence is encounter boost::asio::async_read_until(s, b, boost::regex("\r\n"), handler); +After the `async_read_until` operation completes successfully, the buffer `b` contains the data which matched the regular expression: + { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } + + +The call to `std::getline` then extracts the data up to and including the match, so that the string `line` contains: + + { 'a', 'b', ..., 'c', '\r', '\n' } + + +The remaining data is left in the buffer `b` as follows: + + { 'd', 'e', ... } + + +This data may be the start of a new line, to be extracted by a subsequent `async_read_until` operation. @@ -1360,7 +1405,7 @@ This function is used to asynchronously read data into the specified streambuf u * An error occurred. -This operation is implemented in terms of zero or more calls to the stream's async\_read\_some function. If the match condition function object already indicates a match, the operation completes immediately. +This operation is implemented in terms of zero or more calls to the stream's async\_read\_some function, and is known as a [*composed operation]. 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. [heading Parameters] @@ -1553,7 +1598,7 @@ This function is used to asynchronously write a certain number of bytes of data * An error occurred. -This operation is implemented in terms of zero or more calls to the stream's async\_write\_some function. +This operation is implemented in terms of zero or more calls to the stream's async\_write\_some function, and is known as a [*composed operation]. 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. [heading Parameters] @@ -1623,7 +1668,7 @@ This function is used to asynchronously write a certain number of bytes of data * 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. +This operation is implemented in terms of zero or more calls to the stream's async\_write\_some function, and is known as a [*composed operation]. 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. [heading Parameters] @@ -1706,7 +1751,7 @@ This function is used to asynchronously write a certain number of bytes of data * An error occurred. -This operation is implemented in terms of zero or more calls to the stream's async\_write\_some function. +This operation is implemented in terms of zero or more calls to the stream's async\_write\_some function, and is known as a [*composed operation]. 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. [heading Parameters] @@ -1766,7 +1811,7 @@ This function is used to asynchronously write a certain number of bytes of data * 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. +This operation is implemented in terms of zero or more calls to the stream's async\_write\_some function, and is known as a [*composed operation]. 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. [heading Parameters] @@ -37638,6 +37683,17 @@ The [link boost_asio.reference.io_service `io_service`] guarantees that the hand ] +[heading Remarks] + +This function throws an exception only if: + + +* the handler's asio_handler_allocate function; or + + +* the handler's copy constructor + +throws an exception. [endsect] @@ -37939,6 +37995,17 @@ The [link boost_asio.reference.io_service `io_service`] guarantees that the hand ] +[heading Remarks] + +This function throws an exception only if: + + +* the handler's asio_handler_allocate function; or + + +* the handler's copy constructor + +throws an exception. [endsect] @@ -57460,7 +57527,22 @@ To read data into a streambuf until a newline is encountered: std::getline(is, line); +After the `read_until` operation completes successfully, the buffer `b` contains the delimiter: + { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } + + +The call to `std::getline` then extracts the data up to and including the delimiter, so that the string `line` contains: + + { 'a', 'b', ..., 'c', '\n' } + + +The remaining data is left in the buffer `b` as follows: + + { 'd', 'e', ... } + + +This data may be the start of a new line, to be extracted by a subsequent `read_until` operation. @@ -57599,7 +57681,22 @@ To read data into a streambuf until a newline is encountered: std::getline(is, line); +After the `read_until` operation completes successfully, the buffer `b` contains the delimiter: + { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } + + +The call to `std::getline` then extracts the data up to and including the delimiter, so that the string `line` contains: + + { 'a', 'b', ..., 'c', '\r', '\n' } + + +The remaining data is left in the buffer `b` as follows: + + { 'd', 'e', ... } + + +This data may be the start of a new line, to be extracted by a subsequent `read_until` operation. @@ -57738,7 +57835,22 @@ To read data into a streambuf until a CR-LF sequence is encountered: std::getline(is, line); +After the `read_until` operation completes successfully, the buffer `b` contains the data which matched the regular expression: + { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } + + +The call to `std::getline` then extracts the data up to and including the match, so that the string `line` contains: + + { 'a', 'b', ..., 'c', '\r', '\n' } + + +The remaining data is left in the buffer `b` as follows: + + { 'd', 'e', ... } + + +This data may be the start of a new line, to be extracted by a subsequent `read_until` operation. diff --git a/include/boost/asio/io_service.hpp b/include/boost/asio/io_service.hpp index 57794cf5..3863e96f 100644 --- a/include/boost/asio/io_service.hpp +++ b/include/boost/asio/io_service.hpp @@ -400,6 +400,14 @@ public: * @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 void dispatch(CompletionHandler handler); @@ -417,6 +425,14 @@ public: * @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 void post(CompletionHandler handler); diff --git a/include/boost/asio/read.hpp b/include/boost/asio/read.hpp index 8243d0f8..40ccc008 100644 --- a/include/boost/asio/read.hpp +++ b/include/boost/asio/read.hpp @@ -301,7 +301,10 @@ std::size_t read(SyncReadStream& s, basic_streambuf& b, * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's - * async_read_some function. + * async_read_some function, and is known as a composed operation. 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. @@ -430,7 +433,10 @@ void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's - * async_read_some function. + * async_read_some function, and is known as a composed operation. 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. @@ -477,7 +483,10 @@ void async_read(AsyncReadStream& s, basic_streambuf& b, * @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. + * async_read_some function, and is known as a composed operation. 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. diff --git a/include/boost/asio/read_until.hpp b/include/boost/asio/read_until.hpp index 2f50072f..ec6cb426 100644 --- a/include/boost/asio/read_until.hpp +++ b/include/boost/asio/read_until.hpp @@ -129,6 +129,16 @@ struct is_match_condition * std::istream is(&b); * std::string line; * std::getline(is, line); @endcode + * After the @c read_until operation completes successfully, the buffer @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 + * 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 std::size_t read_until(SyncReadStream& s, @@ -206,6 +216,16 @@ std::size_t read_until(SyncReadStream& s, * std::istream is(&b); * std::string line; * std::getline(is, line); @endcode + * After the @c read_until operation completes successfully, the buffer @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 + * 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 std::size_t read_until(SyncReadStream& s, @@ -285,6 +305,16 @@ std::size_t read_until(SyncReadStream& s, * std::istream is(&b); * std::string line; * std::getline(is, line); @endcode + * After the @c read_until operation completes successfully, the buffer @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 + * 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 std::size_t read_until(SyncReadStream& s, @@ -511,8 +541,12 @@ std::size_t read_until(SyncReadStream& s, * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's - * async_read_some function. If the streambuf's get area already contains the - * delimiter, the asynchronous operation completes immediately. + * async_read_some function, and is known as a composed operation. If + * the streambuf'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. @@ -561,6 +595,16 @@ std::size_t read_until(SyncReadStream& s, * } * ... * boost::asio::async_read_until(s, b, '\n', handler); @endcode + * After the @c async_read_until operation completes successfully, the buffer + * @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 + * 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 async_read_until operation. */ template void async_read_until(AsyncReadStream& s, @@ -580,8 +624,12 @@ void async_read_until(AsyncReadStream& s, * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's - * async_read_some function. If the streambuf's get area already contains the - * delimiter, the asynchronous operation completes immediately. + * async_read_some function, and is known as a composed operation. If + * the streambuf'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. @@ -630,6 +678,16 @@ void async_read_until(AsyncReadStream& s, * } * ... * boost::asio::async_read_until(s, b, "\r\n", handler); @endcode + * After the @c async_read_until operation completes successfully, the buffer + * @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 + * 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 async_read_until operation. */ template void async_read_until(AsyncReadStream& s, @@ -650,8 +708,13 @@ void async_read_until(AsyncReadStream& s, * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's - * async_read_some function. If the streambuf's get area already contains data - * that matches the regular expression, the function returns immediately. + * async_read_some function, and is known as a composed operation. If + * the streambuf'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. @@ -702,6 +765,16 @@ void async_read_until(AsyncReadStream& s, * } * ... * boost::asio::async_read_until(s, b, boost::regex("\r\n"), handler); @endcode + * After the @c async_read_until operation completes successfully, the buffer + * @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 + * 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 async_read_until operation. */ template void async_read_until(AsyncReadStream& s, @@ -723,8 +796,12 @@ void async_read_until(AsyncReadStream& s, * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's - * async_read_some function. If the match condition function object already - * indicates a match, the operation completes immediately. + * async_read_some function, and is known as a composed operation. 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. diff --git a/include/boost/asio/write.hpp b/include/boost/asio/write.hpp index 2b9d4b7b..2a95735d 100644 --- a/include/boost/asio/write.hpp +++ b/include/boost/asio/write.hpp @@ -306,7 +306,10 @@ std::size_t write(SyncWriteStream& s, basic_streambuf& b, * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's - * async_write_some function. + * async_write_some function, and is known as a composed operation. 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. @@ -360,7 +363,10 @@ void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, * @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. + * async_write_some function, and is known as a composed operation. 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. @@ -430,7 +436,10 @@ void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's - * async_write_some function. + * async_write_some function, and is known as a composed operation. 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. @@ -472,7 +481,10 @@ void async_write(AsyncWriteStream& s, basic_streambuf& b, * @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. + * async_write_some function, and is known as a composed operation. 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. From e5dac272e70bf3ba830478d83e4765eef47729af Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Thu, 29 Apr 2010 13:25:53 +0000 Subject: [PATCH 36/38] More doc updates. [SVN r61674] --- doc/using.qbk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/using.qbk b/doc/using.qbk index 07f641d4..8b1786dd 100644 --- a/doc/using.qbk +++ b/doc/using.qbk @@ -195,6 +195,13 @@ Boost.Asio. use of a `select`-based implementation. ] ] + [ + [`BOOST_ASIO_DISABLE_THREADS`] + [ + Explicitly disables Boost.Asio's threading support, independent of whether + or not Boost as a whole supports threads. + ] + ] [ [`BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN`] [ @@ -311,6 +318,6 @@ Gmane]. [heading Wiki] Users are encouraged to share examples, tips and FAQs on the Boost.Asio wiki, -which is located at [@http://asio.sourceforge.net]. +which is located at [@http://think-async.com/Asio/]. [endsect] From b7bc3ff637bd238c9abf75a81520ce4998108bcc Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Sun, 6 Jun 2010 23:28:58 +0000 Subject: [PATCH 37/38] Fix handling of small but non-zero timeouts. Fixes #4205. [SVN r62497] --- include/boost/asio/detail/timer_queue.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/boost/asio/detail/timer_queue.hpp b/include/boost/asio/detail/timer_queue.hpp index 164b3420..56ae0dcd 100644 --- a/include/boost/asio/detail/timer_queue.hpp +++ b/include/boost/asio/detail/timer_queue.hpp @@ -98,8 +98,10 @@ public: if (duration > boost::posix_time::milliseconds(max_duration)) duration = boost::posix_time::milliseconds(max_duration); - else if (duration < boost::posix_time::milliseconds(0)) + else if (duration <= boost::posix_time::milliseconds(0)) duration = boost::posix_time::milliseconds(0); + else if (duration < boost::posix_time::milliseconds(1)) + duration = boost::posix_time::milliseconds(1); return duration.total_milliseconds(); } @@ -115,8 +117,10 @@ public: if (duration > boost::posix_time::microseconds(max_duration)) duration = boost::posix_time::microseconds(max_duration); - else if (duration < boost::posix_time::microseconds(0)) + else if (duration <= boost::posix_time::microseconds(0)) duration = boost::posix_time::microseconds(0); + else if (duration < boost::posix_time::microseconds(1)) + duration = boost::posix_time::microseconds(1); return duration.total_microseconds(); } From 0f5629d4456a15bf99ff978df782927c1ca48d27 Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Mon, 7 Jun 2010 00:00:45 +0000 Subject: [PATCH 38/38] Reworked implementation MkII [SVN r62499] --- doc/reference.qbk | 518 ++- doc/reference.xsl | 56 +- example/local/iostream_client.cpp | 7 +- include/boost/asio/basic_datagram_socket.hpp | 11 +- include/boost/asio/basic_deadline_timer.hpp | 11 +- include/boost/asio/basic_io_object.hpp | 7 +- include/boost/asio/basic_raw_socket.hpp | 13 +- include/boost/asio/basic_serial_port.hpp | 26 +- include/boost/asio/basic_socket.hpp | 11 +- include/boost/asio/basic_socket_acceptor.hpp | 7 +- include/boost/asio/basic_socket_iostream.hpp | 15 +- include/boost/asio/basic_socket_streambuf.hpp | 17 +- include/boost/asio/basic_stream_socket.hpp | 11 +- include/boost/asio/basic_streambuf.hpp | 36 +- include/boost/asio/basic_streambuf_fwd.hpp | 35 + include/boost/asio/buffer.hpp | 20 +- include/boost/asio/buffered_read_stream.hpp | 13 +- .../boost/asio/buffered_read_stream_fwd.hpp | 4 - include/boost/asio/buffered_stream.hpp | 11 +- include/boost/asio/buffered_stream_fwd.hpp | 4 - include/boost/asio/buffered_write_stream.hpp | 15 +- .../boost/asio/buffered_write_stream_fwd.hpp | 4 - include/boost/asio/buffers_iterator.hpp | 9 +- include/boost/asio/completion_condition.hpp | 6 +- .../boost/asio/datagram_socket_service.hpp | 10 +- include/boost/asio/deadline_timer.hpp | 8 +- include/boost/asio/deadline_timer_service.hpp | 12 +- include/boost/asio/detail/array_fwd.hpp | 25 + .../asio/detail/base_from_completion_cond.hpp | 15 +- include/boost/asio/detail/bind_handler.hpp | 9 +- .../boost/asio/detail/buffer_resize_guard.hpp | 10 +- .../asio/detail/buffer_sequence_adapter.hpp | 14 +- .../asio/detail/buffered_stream_storage.hpp | 12 +- include/boost/asio/detail/call_stack.hpp | 9 +- .../boost/asio/detail/completion_handler.hpp | 32 +- include/boost/asio/detail/config.hpp | 203 ++ .../boost/asio/detail/consuming_buffers.hpp | 14 +- .../asio/detail/deadline_timer_service.hpp | 71 +- include/boost/asio/detail/descriptor_ops.hpp | 173 +- .../boost/asio/detail/descriptor_read_op.hpp | 116 + .../boost/asio/detail/descriptor_write_op.hpp | 116 + .../boost/asio/detail/dev_poll_reactor.hpp | 362 +- .../asio/detail/dev_poll_reactor_fwd.hpp | 17 +- include/boost/asio/detail/epoll_reactor.hpp | 397 +-- .../boost/asio/detail/epoll_reactor_fwd.hpp | 24 +- include/boost/asio/detail/event.hpp | 12 +- .../detail/eventfd_select_interrupter.hpp | 118 +- include/boost/asio/detail/fd_set_adapter.hpp | 13 +- include/boost/asio/detail/fenced_block.hpp | 12 +- .../boost/asio/detail/gcc_fenced_block.hpp | 16 +- .../asio/detail/gcc_x86_fenced_block.hpp | 16 +- .../asio/detail/handler_alloc_helpers.hpp | 238 +- .../asio/detail/handler_invoke_helpers.hpp | 12 +- include/boost/asio/detail/hash_map.hpp | 33 +- .../boost/asio/detail/impl/descriptor_ops.ipp | 357 ++ .../asio/detail/impl/dev_poll_reactor.hpp | 74 + .../asio/detail/impl/dev_poll_reactor.ipp | 337 ++ .../boost/asio/detail/impl/epoll_reactor.hpp | 72 + .../boost/asio/detail/impl/epoll_reactor.ipp | 375 +++ .../impl/eventfd_select_interrupter.ipp | 127 + .../boost/asio/detail/impl/kqueue_reactor.hpp | 76 + .../boost/asio/detail/impl/kqueue_reactor.ipp | 355 ++ .../detail/impl/pipe_select_interrupter.ipp | 94 + .../boost/asio/detail/impl/posix_event.ipp | 48 + .../boost/asio/detail/impl/posix_mutex.ipp | 48 + .../boost/asio/detail/impl/posix_thread.ipp | 76 + .../boost/asio/detail/impl/posix_tss_ptr.ipp | 48 + .../impl/reactive_descriptor_service.ipp | 138 + .../impl/reactive_serial_port_service.ipp | 153 + .../impl/reactive_socket_service_base.ipp | 214 ++ .../detail/impl/resolver_service_base.ipp | 108 + .../boost/asio/detail/impl/select_reactor.hpp | 81 + .../boost/asio/detail/impl/select_reactor.ipp | 271 ++ .../asio/detail/impl/service_registry.hpp | 72 + .../asio/detail/impl/service_registry.ipp | 166 + include/boost/asio/detail/impl/socket_ops.ipp | 2828 ++++++++++++++++ .../detail/impl/socket_select_interrupter.ipp | 149 + .../boost/asio/detail/impl/strand_service.hpp | 142 + .../boost/asio/detail/impl/strand_service.ipp | 108 + .../asio/detail/impl/task_io_service.hpp | 62 + .../asio/detail/impl/task_io_service.ipp | 356 ++ .../boost/asio/detail/impl/throw_error.ipp | 47 + .../boost/asio/detail/impl/timer_queue.ipp | 87 + .../asio/detail/impl/timer_queue_set.ipp | 103 + include/boost/asio/detail/impl/win_event.ipp | 52 + .../detail/impl/win_iocp_handle_service.ipp | 454 +++ .../asio/detail/impl/win_iocp_io_service.hpp | 113 + .../asio/detail/impl/win_iocp_io_service.ipp | 493 +++ .../impl/win_iocp_serial_port_service.ipp | 182 + .../impl/win_iocp_socket_service_base.ipp | 567 ++++ include/boost/asio/detail/impl/win_mutex.ipp | 78 + include/boost/asio/detail/impl/win_thread.ipp | 140 + .../boost/asio/detail/impl/win_tss_ptr.ipp | 59 + .../boost/asio/detail/impl/winsock_init.ipp | 71 + include/boost/asio/detail/io_control.hpp | 12 +- include/boost/asio/detail/kqueue_reactor.hpp | 381 +-- .../boost/asio/detail/kqueue_reactor_fwd.hpp | 21 +- .../asio/detail/local_free_on_block_exit.hpp | 16 +- .../boost/asio/detail/macos_fenced_block.hpp | 18 +- include/boost/asio/detail/mutex.hpp | 12 +- include/boost/asio/detail/noncopyable.hpp | 12 +- include/boost/asio/detail/null_buffers_op.hpp | 79 - include/boost/asio/detail/null_event.hpp | 16 +- .../boost/asio/detail/null_fenced_block.hpp | 4 +- include/boost/asio/detail/null_mutex.hpp | 16 +- .../boost/asio/detail/null_signal_blocker.hpp | 16 +- include/boost/asio/detail/null_thread.hpp | 29 +- include/boost/asio/detail/null_tss_ptr.hpp | 16 +- .../boost/asio/detail/old_win_sdk_compat.hpp | 16 +- include/boost/asio/detail/op_queue.hpp | 8 +- include/boost/asio/detail/operation.hpp | 13 +- .../asio/detail/pipe_select_interrupter.hpp | 76 +- include/boost/asio/detail/pop_options.hpp | 4 +- include/boost/asio/detail/posix_event.hpp | 42 +- .../asio/detail/posix_fd_set_adapter.hpp | 21 +- include/boost/asio/detail/posix_mutex.hpp | 41 +- .../asio/detail/posix_signal_blocker.hpp | 21 +- include/boost/asio/detail/posix_thread.hpp | 78 +- include/boost/asio/detail/posix_tss_ptr.hpp | 42 +- include/boost/asio/detail/push_options.hpp | 4 +- .../detail/reactive_descriptor_service.hpp | 547 +-- .../asio/detail/reactive_null_buffers_op.hpp | 85 + .../detail/reactive_serial_port_service.hpp | 184 +- .../asio/detail/reactive_socket_accept_op.hpp | 133 + .../detail/reactive_socket_connect_op.hpp | 103 + .../asio/detail/reactive_socket_recv_op.hpp | 120 + .../detail/reactive_socket_recvfrom_op.hpp | 130 + .../asio/detail/reactive_socket_send_op.hpp | 117 + .../asio/detail/reactive_socket_sendto_op.hpp | 120 + .../asio/detail/reactive_socket_service.hpp | 1574 +-------- .../detail/reactive_socket_service_base.hpp | 300 ++ include/boost/asio/detail/reactor.hpp | 8 +- include/boost/asio/detail/reactor_fwd.hpp | 28 +- include/boost/asio/detail/reactor_op.hpp | 9 +- .../boost/asio/detail/reactor_op_queue.hpp | 11 +- include/boost/asio/detail/regex_fwd.hpp | 31 + .../boost/asio/detail/resolve_endpoint_op.hpp | 118 + include/boost/asio/detail/resolve_op.hpp | 128 + .../boost/asio/detail/resolver_service.hpp | 395 +-- .../asio/detail/resolver_service_base.hpp | 125 + include/boost/asio/detail/scoped_lock.hpp | 8 +- .../boost/asio/detail/select_interrupter.hpp | 15 +- include/boost/asio/detail/select_reactor.hpp | 304 +- .../boost/asio/detail/select_reactor_fwd.hpp | 9 +- include/boost/asio/detail/service_base.hpp | 51 - .../boost/asio/detail/service_registry.hpp | 190 +- .../asio/detail/service_registry_fwd.hpp | 8 +- .../detail/{service_id.hpp => shared_ptr.hpp} | 31 +- include/boost/asio/detail/signal_blocker.hpp | 12 +- include/boost/asio/detail/signal_init.hpp | 18 +- include/boost/asio/detail/socket_holder.hpp | 15 +- include/boost/asio/detail/socket_ops.hpp | 2023 ++--------- include/boost/asio/detail/socket_option.hpp | 12 +- .../asio/detail/socket_select_interrupter.hpp | 150 +- include/boost/asio/detail/socket_types.hpp | 61 +- .../asio/detail/solaris_fenced_block.hpp | 18 +- include/boost/asio/detail/strand_service.hpp | 202 +- include/boost/asio/detail/task_io_service.hpp | 381 +-- .../boost/asio/detail/task_io_service_fwd.hpp | 9 +- .../asio/detail/task_io_service_operation.hpp | 18 +- include/boost/asio/detail/thread.hpp | 12 +- include/boost/asio/detail/throw_error.hpp | 33 +- include/boost/asio/detail/timer_op.hpp | 9 +- include/boost/asio/detail/timer_queue.hpp | 72 +- .../boost/asio/detail/timer_queue_base.hpp | 9 +- include/boost/asio/detail/timer_queue_fwd.hpp | 8 +- include/boost/asio/detail/timer_queue_set.hpp | 83 +- include/boost/asio/detail/timer_scheduler.hpp | 9 +- .../boost/asio/detail/timer_scheduler_fwd.hpp | 26 +- include/boost/asio/detail/tss_ptr.hpp | 12 +- include/boost/asio/detail/wait_handler.hpp | 78 + include/boost/asio/detail/weak_ptr.hpp | 41 + include/boost/asio/detail/win_event.hpp | 38 +- .../boost/asio/detail/win_fd_set_adapter.hpp | 14 +- .../boost/asio/detail/win_fenced_block.hpp | 16 +- .../asio/detail/win_iocp_handle_read_op.hpp | 103 + .../asio/detail/win_iocp_handle_service.hpp | 573 +--- .../asio/detail/win_iocp_handle_write_op.hpp | 99 + .../boost/asio/detail/win_iocp_io_service.hpp | 590 +--- .../asio/detail/win_iocp_io_service_fwd.hpp | 28 +- .../asio/detail/win_iocp_null_buffers_op.hpp | 114 + .../boost/asio/detail/win_iocp_operation.hpp | 17 +- .../asio/detail/win_iocp_overlapped_op.hpp | 86 + .../asio/detail/win_iocp_overlapped_ptr.hpp | 70 +- .../detail/win_iocp_serial_port_service.hpp | 212 +- .../asio/detail/win_iocp_socket_accept_op.hpp | 160 + .../asio/detail/win_iocp_socket_recv_op.hpp | 110 + .../detail/win_iocp_socket_recvfrom_op.hpp | 118 + .../asio/detail/win_iocp_socket_send_op.hpp | 104 + .../asio/detail/win_iocp_socket_service.hpp | 1804 +--------- .../detail/win_iocp_socket_service_base.hpp | 387 +++ include/boost/asio/detail/win_mutex.hpp | 67 +- .../boost/asio/detail/win_signal_blocker.hpp | 16 +- include/boost/asio/detail/win_thread.hpp | 151 +- include/boost/asio/detail/win_tss_ptr.hpp | 42 +- include/boost/asio/detail/wince_thread.hpp | 30 +- include/boost/asio/detail/winsock_init.hpp | 118 +- include/boost/asio/detail/wrapped_handler.hpp | 16 +- include/boost/asio/error.hpp | 143 +- include/boost/asio/handler_alloc_hook.hpp | 6 +- include/boost/asio/handler_invoke_hook.hpp | 2 + include/boost/asio/impl/error.ipp | 155 + include/boost/asio/impl/io_service.hpp | 126 + include/boost/asio/impl/io_service.ipp | 141 +- .../boost/asio/impl/{read.ipp => read.hpp} | 79 +- .../asio/impl/{read_at.ipp => read_at.hpp} | 237 +- include/boost/asio/impl/read_until.hpp | 876 +++++ include/boost/asio/impl/read_until.ipp | 989 ------ include/boost/asio/impl/serial_port_base.hpp | 61 + include/boost/asio/impl/serial_port_base.ipp | 93 +- include/boost/asio/impl/src.cpp | 59 + .../boost/asio/impl/{write.ipp => write.hpp} | 58 +- .../asio/impl/{write_at.ipp => write_at.hpp} | 216 +- include/boost/asio/io_service.hpp | 103 +- include/boost/asio/ip/address.hpp | 207 +- include/boost/asio/ip/address_v4.hpp | 173 +- include/boost/asio/ip/address_v6.hpp | 303 +- include/boost/asio/ip/basic_endpoint.hpp | 245 +- include/boost/asio/ip/basic_resolver.hpp | 11 +- .../boost/asio/ip/basic_resolver_entry.hpp | 9 +- .../boost/asio/ip/basic_resolver_iterator.hpp | 16 +- .../boost/asio/ip/basic_resolver_query.hpp | 13 +- include/boost/asio/ip/detail/endpoint.hpp | 142 + .../boost/asio/ip/detail/impl/endpoint.ipp | 193 ++ .../boost/asio/ip/detail/socket_option.hpp | 15 +- include/boost/asio/ip/host_name.hpp | 42 +- include/boost/asio/ip/icmp.hpp | 11 +- include/boost/asio/ip/impl/address.hpp | 55 + include/boost/asio/ip/impl/address.ipp | 188 ++ include/boost/asio/ip/impl/address_v4.hpp | 55 + include/boost/asio/ip/impl/address_v4.ipp | 164 + include/boost/asio/ip/impl/address_v6.hpp | 55 + include/boost/asio/ip/impl/address_v6.ipp | 286 ++ include/boost/asio/ip/impl/basic_endpoint.hpp | 57 + include/boost/asio/ip/impl/host_name.ipp | 56 + include/boost/asio/ip/multicast.hpp | 13 +- include/boost/asio/ip/resolver_query_base.hpp | 13 +- include/boost/asio/ip/resolver_service.hpp | 21 +- include/boost/asio/ip/tcp.hpp | 13 +- include/boost/asio/ip/udp.hpp | 11 +- include/boost/asio/ip/unicast.hpp | 13 +- include/boost/asio/ip/v6_only.hpp | 9 +- include/boost/asio/is_read_buffered.hpp | 9 +- include/boost/asio/is_write_buffered.hpp | 9 +- include/boost/asio/local/basic_endpoint.hpp | 143 +- include/boost/asio/local/connect_pair.hpp | 32 +- .../boost/asio/local/datagram_protocol.hpp | 20 +- include/boost/asio/local/detail/endpoint.hpp | 135 + .../boost/asio/local/detail/impl/endpoint.ipp | 130 + include/boost/asio/local/stream_protocol.hpp | 18 +- include/boost/asio/placeholders.hpp | 7 +- include/boost/asio/posix/basic_descriptor.hpp | 18 +- .../asio/posix/basic_stream_descriptor.hpp | 28 +- include/boost/asio/posix/descriptor_base.hpp | 17 +- .../boost/asio/posix/stream_descriptor.hpp | 12 +- .../asio/posix/stream_descriptor_service.hpp | 30 +- include/boost/asio/raw_socket_service.hpp | 10 +- include/boost/asio/read.hpp | 15 +- include/boost/asio/read_at.hpp | 15 +- include/boost/asio/read_until.hpp | 19 +- include/boost/asio/serial_port.hpp | 8 +- include/boost/asio/serial_port_base.hpp | 69 +- include/boost/asio/serial_port_service.hpp | 29 +- .../boost/asio/socket_acceptor_service.hpp | 6 +- include/boost/asio/socket_base.hpp | 9 +- include/boost/asio/ssl/basic_context.hpp | 14 +- include/boost/asio/ssl/context.hpp | 9 +- include/boost/asio/ssl/context_base.hpp | 13 +- include/boost/asio/ssl/context_service.hpp | 13 +- .../ssl/detail/openssl_context_service.hpp | 13 +- .../boost/asio/ssl/detail/openssl_init.hpp | 13 +- .../asio/ssl/detail/openssl_operation.hpp | 18 +- .../ssl/detail/openssl_stream_service.hpp | 24 +- .../boost/asio/ssl/detail/openssl_types.hpp | 14 +- include/boost/asio/ssl/stream.hpp | 15 +- include/boost/asio/ssl/stream_base.hpp | 9 +- include/boost/asio/ssl/stream_service.hpp | 16 +- include/boost/asio/strand.hpp | 7 +- include/boost/asio/stream_socket_service.hpp | 10 +- include/boost/asio/streambuf.hpp | 8 +- include/boost/asio/time_traits.hpp | 4 +- include/boost/asio/version.hpp | 2 +- include/boost/asio/windows/basic_handle.hpp | 20 +- .../windows/basic_random_access_handle.hpp | 28 +- .../asio/windows/basic_stream_handle.hpp | 20 +- include/boost/asio/windows/overlapped_ptr.hpp | 26 +- .../asio/windows/random_access_handle.hpp | 12 +- .../windows/random_access_handle_service.hpp | 36 +- include/boost/asio/windows/stream_handle.hpp | 12 +- .../asio/windows/stream_handle_service.hpp | 33 +- include/boost/asio/write.hpp | 15 +- include/boost/asio/write_at.hpp | 15 +- test/Jamfile | 1 + test/Jamfile.v2 | 1 + test/buffer.cpp | 1 + test/buffered_read_stream.cpp | 1 + test/buffered_stream.cpp | 1 + test/buffered_write_stream.cpp | 1 + test/buffers_iterator.cpp | 25 +- test/ip/multicast.cpp | 8 +- test/ip/tcp.cpp | 69 +- test/ip/udp.cpp | 63 + test/ip/unicast.cpp | 2 +- test/ip/v6_only.cpp | 6 +- test/read.cpp | 363 +- test/read_at.cpp | 2983 ++++++++++++++++- test/serial_port_base.cpp | 11 +- test/socket_base.cpp | 48 +- test/write.cpp | 362 +- test/write_at.cpp | 2648 ++++++++++++++- 310 files changed, 25263 insertions(+), 14928 deletions(-) create mode 100644 include/boost/asio/basic_streambuf_fwd.hpp create mode 100644 include/boost/asio/detail/array_fwd.hpp create mode 100644 include/boost/asio/detail/config.hpp create mode 100644 include/boost/asio/detail/descriptor_read_op.hpp create mode 100644 include/boost/asio/detail/descriptor_write_op.hpp create mode 100644 include/boost/asio/detail/impl/descriptor_ops.ipp create mode 100644 include/boost/asio/detail/impl/dev_poll_reactor.hpp create mode 100644 include/boost/asio/detail/impl/dev_poll_reactor.ipp create mode 100644 include/boost/asio/detail/impl/epoll_reactor.hpp create mode 100644 include/boost/asio/detail/impl/epoll_reactor.ipp create mode 100644 include/boost/asio/detail/impl/eventfd_select_interrupter.ipp create mode 100644 include/boost/asio/detail/impl/kqueue_reactor.hpp create mode 100644 include/boost/asio/detail/impl/kqueue_reactor.ipp create mode 100644 include/boost/asio/detail/impl/pipe_select_interrupter.ipp create mode 100644 include/boost/asio/detail/impl/posix_event.ipp create mode 100644 include/boost/asio/detail/impl/posix_mutex.ipp create mode 100644 include/boost/asio/detail/impl/posix_thread.ipp create mode 100644 include/boost/asio/detail/impl/posix_tss_ptr.ipp create mode 100644 include/boost/asio/detail/impl/reactive_descriptor_service.ipp create mode 100644 include/boost/asio/detail/impl/reactive_serial_port_service.ipp create mode 100644 include/boost/asio/detail/impl/reactive_socket_service_base.ipp create mode 100644 include/boost/asio/detail/impl/resolver_service_base.ipp create mode 100644 include/boost/asio/detail/impl/select_reactor.hpp create mode 100644 include/boost/asio/detail/impl/select_reactor.ipp create mode 100644 include/boost/asio/detail/impl/service_registry.hpp create mode 100644 include/boost/asio/detail/impl/service_registry.ipp create mode 100644 include/boost/asio/detail/impl/socket_ops.ipp create mode 100644 include/boost/asio/detail/impl/socket_select_interrupter.ipp create mode 100644 include/boost/asio/detail/impl/strand_service.hpp create mode 100644 include/boost/asio/detail/impl/strand_service.ipp create mode 100644 include/boost/asio/detail/impl/task_io_service.hpp create mode 100644 include/boost/asio/detail/impl/task_io_service.ipp create mode 100644 include/boost/asio/detail/impl/throw_error.ipp create mode 100644 include/boost/asio/detail/impl/timer_queue.ipp create mode 100644 include/boost/asio/detail/impl/timer_queue_set.ipp create mode 100644 include/boost/asio/detail/impl/win_event.ipp create mode 100644 include/boost/asio/detail/impl/win_iocp_handle_service.ipp create mode 100644 include/boost/asio/detail/impl/win_iocp_io_service.hpp create mode 100644 include/boost/asio/detail/impl/win_iocp_io_service.ipp create mode 100644 include/boost/asio/detail/impl/win_iocp_serial_port_service.ipp create mode 100644 include/boost/asio/detail/impl/win_iocp_socket_service_base.ipp create mode 100644 include/boost/asio/detail/impl/win_mutex.ipp create mode 100644 include/boost/asio/detail/impl/win_thread.ipp create mode 100644 include/boost/asio/detail/impl/win_tss_ptr.ipp create mode 100644 include/boost/asio/detail/impl/winsock_init.ipp delete mode 100644 include/boost/asio/detail/null_buffers_op.hpp create mode 100644 include/boost/asio/detail/reactive_null_buffers_op.hpp create mode 100644 include/boost/asio/detail/reactive_socket_accept_op.hpp create mode 100644 include/boost/asio/detail/reactive_socket_connect_op.hpp create mode 100644 include/boost/asio/detail/reactive_socket_recv_op.hpp create mode 100644 include/boost/asio/detail/reactive_socket_recvfrom_op.hpp create mode 100644 include/boost/asio/detail/reactive_socket_send_op.hpp create mode 100644 include/boost/asio/detail/reactive_socket_sendto_op.hpp create mode 100644 include/boost/asio/detail/reactive_socket_service_base.hpp create mode 100644 include/boost/asio/detail/regex_fwd.hpp create mode 100644 include/boost/asio/detail/resolve_endpoint_op.hpp create mode 100644 include/boost/asio/detail/resolve_op.hpp create mode 100644 include/boost/asio/detail/resolver_service_base.hpp delete mode 100644 include/boost/asio/detail/service_base.hpp rename include/boost/asio/detail/{service_id.hpp => shared_ptr.hpp} (51%) create mode 100644 include/boost/asio/detail/wait_handler.hpp create mode 100644 include/boost/asio/detail/weak_ptr.hpp create mode 100644 include/boost/asio/detail/win_iocp_handle_read_op.hpp create mode 100644 include/boost/asio/detail/win_iocp_handle_write_op.hpp create mode 100644 include/boost/asio/detail/win_iocp_null_buffers_op.hpp create mode 100644 include/boost/asio/detail/win_iocp_overlapped_op.hpp create mode 100644 include/boost/asio/detail/win_iocp_socket_accept_op.hpp create mode 100644 include/boost/asio/detail/win_iocp_socket_recv_op.hpp create mode 100644 include/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp create mode 100644 include/boost/asio/detail/win_iocp_socket_send_op.hpp create mode 100644 include/boost/asio/detail/win_iocp_socket_service_base.hpp create mode 100644 include/boost/asio/impl/error.ipp create mode 100644 include/boost/asio/impl/io_service.hpp rename include/boost/asio/impl/{read.ipp => read.hpp} (87%) rename include/boost/asio/impl/{read_at.ipp => read_at.hpp} (63%) create mode 100644 include/boost/asio/impl/read_until.hpp delete mode 100644 include/boost/asio/impl/read_until.ipp create mode 100644 include/boost/asio/impl/serial_port_base.hpp create mode 100644 include/boost/asio/impl/src.cpp rename include/boost/asio/impl/{write.ipp => write.hpp} (92%) rename include/boost/asio/impl/{write_at.ipp => write_at.hpp} (61%) create mode 100644 include/boost/asio/ip/detail/endpoint.hpp create mode 100644 include/boost/asio/ip/detail/impl/endpoint.ipp create mode 100644 include/boost/asio/ip/impl/address.hpp create mode 100644 include/boost/asio/ip/impl/address.ipp create mode 100644 include/boost/asio/ip/impl/address_v4.hpp create mode 100644 include/boost/asio/ip/impl/address_v4.ipp create mode 100644 include/boost/asio/ip/impl/address_v6.hpp create mode 100644 include/boost/asio/ip/impl/address_v6.ipp create mode 100644 include/boost/asio/ip/impl/basic_endpoint.hpp create mode 100644 include/boost/asio/ip/impl/host_name.ipp create mode 100644 include/boost/asio/local/detail/endpoint.hpp create mode 100644 include/boost/asio/local/detail/impl/endpoint.ipp diff --git a/doc/reference.qbk b/doc/reference.qbk index d08c67c6..07fe13c1 100644 --- a/doc/reference.qbk +++ b/doc/reference.qbk @@ -424,7 +424,7 @@ This function is used to asynchronously read a certain number of bytes of data f * The supplied buffers are full. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. [heading Parameters] @@ -574,7 +574,7 @@ 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: -* The completion_condition function object returns 0. +* 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 [*composed operation]. 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. @@ -795,7 +795,7 @@ This function is used to asynchronously read a certain number of bytes of data f * The supplied buffers are full. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. [heading Parameters] @@ -951,7 +951,7 @@ Start an asynchronous operation to read a certain amount of data at the specifie This function is used to asynchronously read a certain number of bytes of data from a random access device at the specified offset. The function call always returns immediately. The asynchronous operation will continue until one of the following conditions is true: -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's async\_read\_some\_at function. @@ -1666,7 +1666,7 @@ This function is used to asynchronously write a certain number of bytes of data * All of the data in the supplied buffers has been written. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* 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 [*composed operation]. 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. @@ -1746,7 +1746,7 @@ 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: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. * An error occurred. @@ -1806,10 +1806,10 @@ 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: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. -* The completion_condition function object returns 0. +* 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 [*composed operation]. 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. @@ -2015,7 +2015,7 @@ This function is used to asynchronously write a certain number of bytes of data * All of the data in the supplied buffers has been written. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's async\_write\_some\_at function. @@ -2098,7 +2098,7 @@ Start an asynchronous operation to write all of the supplied data at the specifi This function is used to asynchronously write a certain number of bytes of data to a random access device at a specified offset. The function call always returns immediately. The asynchronous operation will continue until one of the following conditions is true: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. * An error occurred. @@ -2161,10 +2161,10 @@ Start an asynchronous operation to write a certain amount of data at the specifi This function is used to asynchronously write a certain number of bytes of data to a random access device at a specified offset. The function call always returns immediately. The asynchronous operation will continue until one of the following conditions is true: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's async\_write\_some\_at function. @@ -3901,10 +3901,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -3952,10 +3952,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -7430,10 +7430,10 @@ Changing the expiry time of a timer while there are pending asynchronous waits c -* The boost::asio::basic_deadline_timer::expires_from_now() 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 executed. If it returns 1 then the wait handler was successfully cancelled. +* The `boost::asio::basic_deadline_timer::expires_from_now()` 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 executed. If it returns 1 then the wait handler was successfully cancelled. -* If a wait handler is cancelled, the boost::system::error_code passed to it contains the value boost::asio::error::operation_aborted. +* If a wait handler is cancelled, the boost::system::error\_code passed to it contains the value `boost::asio::error::operation_aborted`. @@ -7464,7 +7464,7 @@ For each call to `async_wait()`, the supplied handler will be called exactly onc * The timer has expired. -* The timer was cancelled, in which case the handler is passed the error code boost::asio::error::operation_aborted. +* The timer was cancelled, in which case the handler is passed the error code `boost::asio::error::operation_aborted`. [heading Parameters] @@ -10211,10 +10211,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -10262,10 +10262,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -16320,10 +16320,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -16368,10 +16368,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -22849,10 +22849,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -22900,10 +22900,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -27034,10 +27034,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -27085,10 +27085,10 @@ Calls to `cancel()` will always fail with `boost::asio::error::operation_not_sup For portable cancellation, consider using one of the following alternatives: -* Disable asio's I/O completion port backend by defining BOOST_ASIO_DISABLE_IOCP. +* Disable asio's I/O completion port backend by defining BOOST\_ASIO\_DISABLE\_IOCP. -* Use the close() function to simultaneously cancel the outstanding operations and close the socket. +* Use the `close()` function to simultaneously cancel the outstanding operations and close the socket. When running on Windows Vista, Windows Server 2008, and later, the CancelIoEx function is always used. This function does not have the problems described above. @@ -35911,7 +35911,7 @@ Disable sends or receives on the socket. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -36129,10 +36129,10 @@ Changing the expiry time of a timer while there are pending asynchronous waits c -* The boost::asio::basic_deadline_timer::expires_from_now() 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 executed. If it returns 1 then the wait handler was successfully cancelled. +* The `boost::asio::basic_deadline_timer::expires_from_now()` 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 executed. If it returns 1 then the wait handler was successfully cancelled. -* If a wait handler is cancelled, the boost::system::error_code passed to it contains the value boost::asio::error::operation_aborted. +* If a wait handler is cancelled, the boost::system::error\_code passed to it contains the value `boost::asio::error::operation_aborted`. @@ -36558,7 +36558,7 @@ The implementation type of the deadline timer. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -37483,13 +37483,13 @@ Provides core I/O functionality. The [link boost_asio.reference.io_service `io_service`] class provides the core I/O functionality for users of the asynchronous I/O objects, including: -* boost::asio::ip::tcp::socket +* `boost::asio::ip::tcp::socket` -* boost::asio::ip::tcp::acceptor +* `boost::asio::ip::tcp::acceptor` -* boost::asio::ip::udp::socket +* `boost::asio::ip::udp::socket` -* boost::asio::deadline_timer. +* `boost::asio::deadline_timer`. The [link boost_asio.reference.io_service `io_service`] class also includes facilities intended for developers of custom asynchronous services. @@ -37688,7 +37688,7 @@ The [link boost_asio.reference.io_service `io_service`] guarantees that the hand This function throws an exception only if: -* the handler's asio_handler_allocate function; or +* the handler's `asio_handler_allocate` function; or * the handler's copy constructor @@ -38000,7 +38000,7 @@ The [link boost_asio.reference.io_service `io_service`] guarantees that the hand This function throws an exception only if: -* the handler's asio_handler_allocate function; or +* the handler's `asio_handler_allocate` function; or * the handler's copy constructor @@ -38342,13 +38342,13 @@ Destructor. On destruction, the [link boost_asio.reference.io_service `io_service`] performs the following sequence of operations: -* For each service object svc in the io_service set, in reverse order of the beginning of service object lifetime, performs svc->shutdown_service(). +* For each service object `svc` in the [link boost_asio.reference.io_service `io_service`] set, in reverse order of the beginning of service object lifetime, performs `svc->shutdown_service()`. -* Uninvoked handler objects that were scheduled for deferred invocation on the io_service, or any associated strand, are destroyed. +* Uninvoked handler objects that were scheduled for deferred invocation on the [link boost_asio.reference.io_service `io_service`], or any associated strand, are destroyed. -* For each service object svc in the io_service set, in reverse order of the beginning of service object lifetime, performs delete static_cast(svc). +* For each service object `svc` in the [link boost_asio.reference.io_service `io_service`] set, in reverse order of the beginning of service object lifetime, performs `delete static_cast(svc)`. [heading Remarks] @@ -38356,10 +38356,10 @@ On destruction, the [link boost_asio.reference.io_service `io_service`] performs The destruction sequence described above permits programs to simplify their resource management by using `shared_ptr<>`. Where an object's lifetime is tied to the lifetime of a connection (or some other sequence of asynchronous operations), a `shared_ptr` to the object would be bound into the handlers for all asynchronous operations associated with it. This works as follows: -* When a single connection ends, all associated asynchronous operations complete. The corresponding handler objects are destroyed, and all shared_ptr references to the objects are destroyed. +* When a single connection ends, all associated asynchronous operations complete. The corresponding handler objects are destroyed, and all `shared_ptr` references to the objects are destroyed. -* 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 shared_ptr references to all connection objects to be destroyed. +* To shut down the whole program, the [link boost_asio.reference.io_service `io_service`] function `stop()` is called to terminate any `run()` calls as soon as possible. The [link boost_asio.reference.io_service `io_service`] destructor defined above destroys all handlers, causing all `shared_ptr` references to all connection objects to be destroyed. @@ -38592,33 +38592,33 @@ The [link boost_asio.reference.io_service__strand `io_service::strand`] class pr Given: -* a strand object s +* a strand object `s` -* an object a meeting completion handler requirements +* an object `a` meeting completion handler requirements -* an object a1 which is an arbitrary copy of a made by the implementation +* an object `a1` which is an arbitrary copy of `a` made by the implementation -* an object b meeting completion handler requirements +* an object `b` meeting completion handler requirements -* an object b1 which is an arbitrary copy of b made by the implementation +* an object `b1` which is an arbitrary copy of `b` made by the implementation if any of the following conditions are true: -* s.post(a) happens-before s.post(b) +* `s.post(a)` happens-before `s.post(b)` -* s.post(a) happens-before s.dispatch(b), where the latter is performed outside the strand +* `s.post(a)` happens-before `s.dispatch(b)`, where the latter is performed outside the strand -* s.dispatch(a) happens-before s.post(b), where the former is performed outside the strand +* `s.dispatch(a)` happens-before `s.post(b)`, where the former is performed outside the strand -* s.dispatch(a) happens-before s.dispatch(b), where both are performed outside the strand +* `s.dispatch(a)` happens-before `s.dispatch(b)`, where both are performed outside the strand then `asio_handler_invoke(a1, &a1)` happens-before `asio_handler_invoke(b1, &b1)`. @@ -39105,11 +39105,26 @@ Implements version-independent IP addresses. [Compare addresses for ordering. ] ] + [ + [[link boost_asio.reference.ip__address.operator_lt__eq_ [*operator<=]]] + [Compare addresses for ordering. ] + ] + [ [[link boost_asio.reference.ip__address.operator_eq__eq_ [*operator==]]] [Compare two addresses for equality. ] ] + [ + [[link boost_asio.reference.ip__address.operator_gt_ [*operator>]]] + [Compare addresses for ordering. ] + ] + + [ + [[link boost_asio.reference.ip__address.operator_gt__eq_ [*operator>=]]] + [Compare addresses for ordering. ] + ] + ] [heading Related Functions] @@ -39431,6 +39446,28 @@ The output stream. +[endsect] + + + +[section:operator_lt__eq_ ip::address::operator<=] + +[indexterm2 operator<=..ip::address] +Compare addresses for ordering. + + + friend bool operator<=( + const address & a1, + const address & a2); + + +[heading Requirements] + +[*Header: ][^boost/asio/ip/address.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + [endsect] @@ -39529,6 +39566,50 @@ Compare two addresses for equality. [endsect] + +[section:operator_gt_ ip::address::operator>] + +[indexterm2 operator>..ip::address] +Compare addresses for ordering. + + + friend bool operator>( + const address & a1, + const address & a2); + + +[heading Requirements] + +[*Header: ][^boost/asio/ip/address.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + +[section:operator_gt__eq_ ip::address::operator>=] + +[indexterm2 operator>=..ip::address] +Compare addresses for ordering. + + + friend bool operator>=( + const address & a1, + const address & a2); + + +[heading Requirements] + +[*Header: ][^boost/asio/ip/address.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + [section:to_string ip::address::to_string] [indexterm2 to_string..ip::address] @@ -41423,11 +41504,26 @@ Describes an endpoint for a version-independent IP socket. [Compare endpoints for ordering. ] ] + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_lt__eq_ [*operator<=]]] + [Compare endpoints for ordering. ] + ] + [ [[link boost_asio.reference.ip__basic_endpoint.operator_eq__eq_ [*operator==]]] [Compare two endpoints for equality. ] ] + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_gt_ [*operator>]]] + [Compare endpoints for ordering. ] + ] + + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_gt__eq_ [*operator>=]]] + [Compare endpoints for ordering. ] + ] + ] [heading Related Functions] @@ -41781,6 +41877,28 @@ The output stream. +[section:operator_lt__eq_ ip::basic_endpoint::operator<=] + +[indexterm2 operator<=..ip::basic_endpoint] +Compare endpoints for ordering. + + + friend bool operator<=( + const basic_endpoint< InternetProtocol > & e1, + const basic_endpoint< InternetProtocol > & e2); + + +[heading Requirements] + +[*Header: ][^boost/asio/ip/basic_endpoint.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + [section:operator_eq_ ip::basic_endpoint::operator=] [indexterm2 operator=..ip::basic_endpoint] @@ -41817,6 +41935,50 @@ Compare two endpoints for equality. [endsect] + +[section:operator_gt_ ip::basic_endpoint::operator>] + +[indexterm2 operator>..ip::basic_endpoint] +Compare endpoints for ordering. + + + friend bool operator>( + const basic_endpoint< InternetProtocol > & e1, + const basic_endpoint< InternetProtocol > & e2); + + +[heading Requirements] + +[*Header: ][^boost/asio/ip/basic_endpoint.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + +[section:operator_gt__eq_ ip::basic_endpoint::operator>=] + +[indexterm2 operator>=..ip::basic_endpoint] +Compare endpoints for ordering. + + + friend bool operator>=( + const basic_endpoint< InternetProtocol > & e1, + const basic_endpoint< InternetProtocol > & e2); + + +[heading Requirements] + +[*Header: ][^boost/asio/ip/basic_endpoint.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + [section:port ip::basic_endpoint::port] [indexterm2 port..ip::basic_endpoint] @@ -44159,11 +44321,26 @@ The type of a ICMP endpoint. [Compare endpoints for ordering. ] ] + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_lt__eq_ [*operator<=]]] + [Compare endpoints for ordering. ] + ] + [ [[link boost_asio.reference.ip__basic_endpoint.operator_eq__eq_ [*operator==]]] [Compare two endpoints for equality. ] ] + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_gt_ [*operator>]]] + [Compare endpoints for ordering. ] + ] + + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_gt__eq_ [*operator>=]]] + [Compare endpoints for ordering. ] + ] + ] [heading Related Functions] @@ -46137,7 +46314,7 @@ Construct a new resolver service for the specified [link boost_asio.reference.io Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -46717,11 +46894,26 @@ The type of a TCP endpoint. [Compare endpoints for ordering. ] ] + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_lt__eq_ [*operator<=]]] + [Compare endpoints for ordering. ] + ] + [ [[link boost_asio.reference.ip__basic_endpoint.operator_eq__eq_ [*operator==]]] [Compare two endpoints for equality. ] ] + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_gt_ [*operator>]]] + [Compare endpoints for ordering. ] + ] + + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_gt__eq_ [*operator>=]]] + [Compare endpoints for ordering. ] + ] + ] [heading Related Functions] @@ -47935,11 +48127,26 @@ The type of a UDP endpoint. [Compare endpoints for ordering. ] ] + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_lt__eq_ [*operator<=]]] + [Compare endpoints for ordering. ] + ] + [ [[link boost_asio.reference.ip__basic_endpoint.operator_eq__eq_ [*operator==]]] [Compare two endpoints for equality. ] ] + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_gt_ [*operator>]]] + [Compare endpoints for ordering. ] + ] + + [ + [[link boost_asio.reference.ip__basic_endpoint.operator_gt__eq_ [*operator>=]]] + [Compare endpoints for ordering. ] + ] + ] [heading Related Functions] @@ -49164,11 +49371,26 @@ Describes an endpoint for a UNIX socket. [Compare endpoints for ordering. ] ] + [ + [[link boost_asio.reference.local__basic_endpoint.operator_lt__eq_ [*operator<=]]] + [Compare endpoints for ordering. ] + ] + [ [[link boost_asio.reference.local__basic_endpoint.operator_eq__eq_ [*operator==]]] [Compare two endpoints for equality. ] ] + [ + [[link boost_asio.reference.local__basic_endpoint.operator_gt_ [*operator>]]] + [Compare endpoints for ordering. ] + ] + + [ + [[link boost_asio.reference.local__basic_endpoint.operator_gt__eq_ [*operator>=]]] + [Compare endpoints for ordering. ] + ] + ] [heading Related Functions] @@ -49449,6 +49671,28 @@ The output stream. +[section:operator_lt__eq_ local::basic_endpoint::operator<=] + +[indexterm2 operator<=..local::basic_endpoint] +Compare endpoints for ordering. + + + friend bool operator<=( + const basic_endpoint< Protocol > & e1, + const basic_endpoint< Protocol > & e2); + + +[heading Requirements] + +[*Header: ][^boost/asio/local/basic_endpoint.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + [section:operator_eq_ local::basic_endpoint::operator=] [indexterm2 operator=..local::basic_endpoint] @@ -49485,6 +49729,50 @@ Compare two endpoints for equality. [endsect] + +[section:operator_gt_ local::basic_endpoint::operator>] + +[indexterm2 operator>..local::basic_endpoint] +Compare endpoints for ordering. + + + friend bool operator>( + const basic_endpoint< Protocol > & e1, + const basic_endpoint< Protocol > & e2); + + +[heading Requirements] + +[*Header: ][^boost/asio/local/basic_endpoint.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + + +[section:operator_gt__eq_ local::basic_endpoint::operator>=] + +[indexterm2 operator>=..local::basic_endpoint] +Compare endpoints for ordering. + + + friend bool operator>=( + const basic_endpoint< Protocol > & e1, + const basic_endpoint< Protocol > & e2); + + +[heading Requirements] + +[*Header: ][^boost/asio/local/basic_endpoint.hpp] + +[*Convenience header: ][^boost/asio.hpp] + + +[endsect] + + [section:path local::basic_endpoint::path] [indexterm2 path..local::basic_endpoint] @@ -49857,11 +50145,26 @@ The type of a UNIX domain endpoint. [Compare endpoints for ordering. ] ] + [ + [[link boost_asio.reference.local__basic_endpoint.operator_lt__eq_ [*operator<=]]] + [Compare endpoints for ordering. ] + ] + [ [[link boost_asio.reference.local__basic_endpoint.operator_eq__eq_ [*operator==]]] [Compare two endpoints for equality. ] ] + [ + [[link boost_asio.reference.local__basic_endpoint.operator_gt_ [*operator>]]] + [Compare endpoints for ordering. ] + ] + + [ + [[link boost_asio.reference.local__basic_endpoint.operator_gt__eq_ [*operator>=]]] + [Compare endpoints for ordering. ] + ] + ] [heading Related Functions] @@ -50836,11 +51139,26 @@ The type of a UNIX domain endpoint. [Compare endpoints for ordering. ] ] + [ + [[link boost_asio.reference.local__basic_endpoint.operator_lt__eq_ [*operator<=]]] + [Compare endpoints for ordering. ] + ] + [ [[link boost_asio.reference.local__basic_endpoint.operator_eq__eq_ [*operator==]]] [Compare two endpoints for equality. ] ] + [ + [[link boost_asio.reference.local__basic_endpoint.operator_gt_ [*operator>]]] + [Compare endpoints for ordering. ] + ] + + [ + [[link boost_asio.reference.local__basic_endpoint.operator_gt__eq_ [*operator>=]]] + [Compare endpoints for ordering. ] + ] + ] [heading Related Functions] @@ -55429,7 +55747,7 @@ Read some data from the stream. Destroy all user-defined descriptorr objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -56333,7 +56651,7 @@ Disable sends or receives on the socket. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -56516,7 +56834,7 @@ This function is used to read a certain number of bytes of data from a stream. T * The supplied buffers are full. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* 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. @@ -56600,7 +56918,7 @@ This function is used to read a certain number of bytes of data from a stream. T * The supplied buffers are full. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* 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. @@ -56728,7 +57046,7 @@ 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: -* The completion_condition function object returns 0. +* 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. @@ -56798,7 +57116,7 @@ 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: -* The completion_condition function object returns 0. +* 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. @@ -57024,7 +57342,7 @@ This function is used to read a certain number of bytes of data from a random ac * The supplied buffers are full. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's read\_some\_at function. @@ -57111,7 +57429,7 @@ This function is used to read a certain number of bytes of data from a random ac * The supplied buffers are full. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's read\_some\_at function. @@ -57245,7 +57563,7 @@ Attempt to read a certain amount of data at the specified offset before returnin This function is used to read a certain number of bytes of data from a random access device at the specified offset. The call will block until one of the following conditions is true: -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's read\_some\_at function. @@ -57318,7 +57636,7 @@ Attempt to read a certain amount of data at the specified offset before returnin This function is used to read a certain number of bytes of data from a random access device at the specified offset. The call will block until one of the following conditions is true: -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's read\_some\_at function. @@ -59527,7 +59845,7 @@ Set a serial port option. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -60180,7 +60498,7 @@ Set a socket option. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -63730,7 +64048,7 @@ Set peer verification mode. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -65605,7 +65923,7 @@ Shut down SSL on the stream. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -65710,33 +66028,33 @@ The [link boost_asio.reference.io_service__strand `io_service::strand`] class pr Given: -* a strand object s +* a strand object `s` -* an object a meeting completion handler requirements +* an object `a` meeting completion handler requirements -* an object a1 which is an arbitrary copy of a made by the implementation +* an object `a1` which is an arbitrary copy of `a` made by the implementation -* an object b meeting completion handler requirements +* an object `b` meeting completion handler requirements -* an object b1 which is an arbitrary copy of b made by the implementation +* an object `b1` which is an arbitrary copy of `b` made by the implementation if any of the following conditions are true: -* s.post(a) happens-before s.post(b) +* `s.post(a)` happens-before `s.post(b)` -* s.post(a) happens-before s.dispatch(b), where the latter is performed outside the strand +* `s.post(a)` happens-before `s.dispatch(b)`, where the latter is performed outside the strand -* s.dispatch(a) happens-before s.post(b), where the former is performed outside the strand +* `s.dispatch(a)` happens-before `s.post(b)`, where the former is performed outside the strand -* s.dispatch(a) happens-before s.dispatch(b), where both are performed outside the strand +* `s.dispatch(a)` happens-before `s.dispatch(b)`, where both are performed outside the strand then `asio_handler_invoke(a1, &a1)` happens-before `asio_handler_invoke(b1, &b1)`. @@ -66512,7 +66830,7 @@ Disable sends or receives on the socket. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -71192,7 +71510,7 @@ Read some data from the specified offset. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -71773,7 +72091,7 @@ Read some data from the stream. Destroy all user-defined handler objects owned by the service. - void shutdown_service(); + virtual void shutdown_service(); @@ -71990,7 +72308,7 @@ This function is used to write a certain number of bytes of data to a stream. Th * All of the data in the supplied buffers has been written. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* 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. @@ -72074,7 +72392,7 @@ This function is used to write a certain number of bytes of data to a stream. Th * All of the data in the supplied buffers has been written. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* 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. @@ -72133,7 +72451,7 @@ 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: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. * An error occurred. @@ -72205,10 +72523,10 @@ 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: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. -* The completion_condition function object returns 0. +* 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. @@ -72278,10 +72596,10 @@ 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: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. -* The completion_condition function object returns 0. +* 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. @@ -72507,7 +72825,7 @@ This function is used to write a certain number of bytes of data to a random acc * All of the data in the supplied buffers has been written. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's write\_some\_at function. @@ -72594,7 +72912,7 @@ This function is used to write a certain number of bytes of data to a random acc * All of the data in the supplied buffers has been written. That is, the bytes transferred is equal to the sum of the buffer sizes. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's write\_some\_at function. @@ -72656,7 +72974,7 @@ Write all of the supplied data at the specified offset before returning. This function is used to write a certain number of bytes of data to a random access device at a specified offset. The call will block until one of the following conditions is true: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. * An error occurred. @@ -72731,10 +73049,10 @@ Write a certain amount of data at a specified offset before returning. This function is used to write a certain number of bytes of data to a random access device at a specified offset. The call will block until one of the following conditions is true: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's write\_some\_at function. @@ -72807,10 +73125,10 @@ Write a certain amount of data at a specified offset before returning. This function is used to write a certain number of bytes of data to a random access device at a specified offset. The call will block until one of the following conditions is true: -* All of the data in the supplied basic_streambuf has been written. +* All of the data in the supplied [link boost_asio.reference.basic_streambuf `basic_streambuf`] has been written. -* The completion_condition function object returns 0. +* The completion\_condition function object returns 0. This operation is implemented in terms of zero or more calls to the device's write\_some\_at function. diff --git a/doc/reference.xsl b/doc/reference.xsl index 55d817f9..684292cc 100644 --- a/doc/reference.xsl +++ b/doc/reference.xsl @@ -103,7 +103,8 @@ + not(contains(ancestor::*/compoundname, '_helper')) and + not(contains(name, '_helper'))"> @@ -164,6 +165,23 @@ + + + + + + + + + + + + + + + + + @@ -365,8 +383,11 @@ -* - +* + + + + @@ -1054,8 +1075,14 @@ explicit static - - + virtual + + + + + + + ``[link boost_asio.reference...overload ]``( - static + + + + + + static virtual () const; @@ -1394,10 +1427,15 @@ + + + + + - ``[link boost_asio.reference. ``[link boost_asio.reference..overload ]``(); `` [''''&raquo;''' diff --git a/example/local/iostream_client.cpp b/example/local/iostream_client.cpp index 34eff7eb..f4453997 100644 --- a/example/local/iostream_client.cpp +++ b/example/local/iostream_client.cpp @@ -28,10 +28,13 @@ int main(int argc, char* argv[]) return 1; } - boost::asio::io_service io_service; - stream_protocol::endpoint ep(argv[1]); stream_protocol::iostream s(ep); + if (!s) + { + std::cerr << "Unable to connect\n"; + return 1; + } using namespace std; // For strlen. std::cout << "Enter message: "; diff --git a/include/boost/asio/basic_datagram_socket.hpp b/include/boost/asio/basic_datagram_socket.hpp index 3b3dedbb..52728099 100644 --- a/include/boost/asio/basic_datagram_socket.hpp +++ b/include/boost/asio/basic_datagram_socket.hpp @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include #include -#include #include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/basic_deadline_timer.hpp b/include/boost/asio/basic_deadline_timer.hpp index 1284daaf..dc471e29 100644 --- a/include/boost/asio/basic_deadline_timer.hpp +++ b/include/boost/asio/basic_deadline_timer.hpp @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include #include -#include #include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/basic_io_object.hpp b/include/boost/asio/basic_io_object.hpp index 3cb6b68c..414f3656 100644 --- a/include/boost/asio/basic_io_object.hpp +++ b/include/boost/asio/basic_io_object.hpp @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/basic_raw_socket.hpp b/include/boost/asio/basic_raw_socket.hpp index 09810d41..0b877dee 100644 --- a/include/boost/asio/basic_raw_socket.hpp +++ b/include/boost/asio/basic_raw_socket.hpp @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include -#include -#include #include +#include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/basic_serial_port.hpp b/include/boost/asio/basic_serial_port.hpp index 539119a0..4936c9c2 100644 --- a/include/boost/asio/basic_serial_port.hpp +++ b/include/boost/asio/basic_serial_port.hpp @@ -16,22 +16,20 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include +#include #if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include +#include +#include +#include + +#include + namespace boost { namespace asio { @@ -616,9 +614,9 @@ public: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_BASIC_SERIAL_PORT_HPP diff --git a/include/boost/asio/basic_socket.hpp b/include/boost/asio/basic_socket.hpp index 6b89623a..50a0c477 100644 --- a/include/boost/asio/basic_socket.hpp +++ b/include/boost/asio/basic_socket.hpp @@ -15,16 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include - +#include #include +#include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/basic_socket_acceptor.hpp b/include/boost/asio/basic_socket_acceptor.hpp index d23dc33b..5192df73 100644 --- a/include/boost/asio/basic_socket_acceptor.hpp +++ b/include/boost/asio/basic_socket_acceptor.hpp @@ -15,14 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include +#include #include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/basic_socket_iostream.hpp b/include/boost/asio/basic_socket_iostream.hpp index e4c7ec16..a8cea4fe 100644 --- a/include/boost/asio/basic_socket_iostream.hpp +++ b/include/boost/asio/basic_socket_iostream.hpp @@ -15,22 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_NO_IOSTREAM) -#include #include #include #include #include #include -#include - #include #include @@ -79,6 +72,8 @@ } \ /**/ +#include + namespace boost { namespace asio { @@ -148,11 +143,11 @@ public: } // namespace asio } // namespace boost +#include + #undef BOOST_ASIO_PRIVATE_CTR_DEF #undef BOOST_ASIO_PRIVATE_CONNECT_DEF #endif // defined(BOOST_NO_IOSTREAM) -#include - #endif // BOOST_ASIO_BASIC_SOCKET_IOSTREAM_HPP diff --git a/include/boost/asio/basic_socket_streambuf.hpp b/include/boost/asio/basic_socket_streambuf.hpp index 695e8e11..35e96d0d 100644 --- a/include/boost/asio/basic_socket_streambuf.hpp +++ b/include/boost/asio/basic_socket_streambuf.hpp @@ -15,15 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_NO_IOSTREAM) -#include #include #include #include @@ -31,12 +26,10 @@ #include #include #include -#include - #include +#include #include #include -#include #if !defined(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY) #define BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY 5 @@ -74,6 +67,8 @@ } \ /**/ +#include + namespace boost { namespace asio { @@ -288,10 +283,10 @@ private: } // namespace asio } // namespace boost +#include + #undef BOOST_ASIO_PRIVATE_CONNECT_DEF #endif // !defined(BOOST_NO_IOSTREAM) -#include - #endif // BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP diff --git a/include/boost/asio/basic_stream_socket.hpp b/include/boost/asio/basic_stream_socket.hpp index 15658bc7..956d6236 100644 --- a/include/boost/asio/basic_stream_socket.hpp +++ b/include/boost/asio/basic_stream_socket.hpp @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include +#include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/basic_streambuf.hpp b/include/boost/asio/basic_streambuf.hpp index e5f8a8dc..546a4aca 100644 --- a/include/boost/asio/basic_streambuf.hpp +++ b/include/boost/asio/basic_streambuf.hpp @@ -15,28 +15,23 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_NO_IOSTREAM) -#include #include #include -#include #include #include #include #include #include -#include - +#include #include #include +#include + namespace boost { namespace asio { @@ -108,7 +103,11 @@ namespace asio { * is >> s; * @endcode */ +#if defined(GENERATING_DOCUMENTATION) template > +#else +template +#endif class basic_streambuf : public std::streambuf, private noncopyable @@ -338,8 +337,27 @@ protected: private: std::size_t max_size_; std::vector buffer_; + + // Helper function to get the preferred size for reading data. + friend std::size_t read_size_helper( + basic_streambuf& sb, std::size_t max_size) + { + return std::min( + std::max(512, sb.buffer_.capacity() - sb.size()), + std::min(max_size, sb.max_size() - sb.size())); + } }; +// Helper function to get the preferred size for reading data. Used for any +// user-provided specialisations of basic_streambuf. +template +inline std::size_t read_size_helper( + basic_streambuf& sb, std::size_t max_size) +{ + return std::min(512, + std::min(max_size, sb.max_size() - sb.size())); +} + } // namespace asio } // namespace boost diff --git a/include/boost/asio/basic_streambuf_fwd.hpp b/include/boost/asio/basic_streambuf_fwd.hpp new file mode 100644 index 00000000..215937ea --- /dev/null +++ b/include/boost/asio/basic_streambuf_fwd.hpp @@ -0,0 +1,35 @@ +// +// basic_streambuf_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_BASIC_STREAMBUF_FWD_HPP +#define BOOST_ASIO_BASIC_STREAMBUF_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_NO_IOSTREAM) + +#include + +namespace boost { +namespace asio { + +template > +class basic_streambuf; + +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_NO_IOSTREAM) + +#endif // BOOST_ASIO_BASIC_STREAMBUF_FWD_HPP diff --git a/include/boost/asio/buffer.hpp b/include/boost/asio/buffer.hpp index 3fe81923..f925361c 100644 --- a/include/boost/asio/buffer.hpp +++ b/include/boost/asio/buffer.hpp @@ -15,16 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include -#include #include #include -#include +#include +#include #if defined(BOOST_MSVC) # if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0) @@ -43,11 +39,17 @@ #endif // defined(__GNUC__) #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) -# include # include -# include #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \ + || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) +# include +#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) + +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/buffered_read_stream.hpp b/include/boost/asio/buffered_read_stream.hpp index d7bf6ff1..935f5b91 100644 --- a/include/boost/asio/buffered_read_stream.hpp +++ b/include/boost/asio/buffered_read_stream.hpp @@ -15,23 +15,20 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include #include -#include - #include #include -#include -#include #include #include #include #include +#include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/buffered_read_stream_fwd.hpp b/include/boost/asio/buffered_read_stream_fwd.hpp index 8eb24f86..87f27d9f 100644 --- a/include/boost/asio/buffered_read_stream_fwd.hpp +++ b/include/boost/asio/buffered_read_stream_fwd.hpp @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - namespace boost { namespace asio { @@ -26,6 +24,4 @@ class buffered_read_stream; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_BUFFERED_READ_STREAM_FWD_HPP diff --git a/include/boost/asio/buffered_stream.hpp b/include/boost/asio/buffered_stream.hpp index 0cbc2807..ceeb6f29 100644 --- a/include/boost/asio/buffered_stream.hpp +++ b/include/boost/asio/buffered_stream.hpp @@ -15,19 +15,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include #include #include +#include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/buffered_stream_fwd.hpp b/include/boost/asio/buffered_stream_fwd.hpp index 066f52cf..d23bc26f 100644 --- a/include/boost/asio/buffered_stream_fwd.hpp +++ b/include/boost/asio/buffered_stream_fwd.hpp @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - namespace boost { namespace asio { @@ -26,6 +24,4 @@ class buffered_stream; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_BUFFERED_STREAM_FWD_HPP diff --git a/include/boost/asio/buffered_write_stream.hpp b/include/boost/asio/buffered_write_stream.hpp index fb38b257..c918a0a2 100644 --- a/include/boost/asio/buffered_write_stream.hpp +++ b/include/boost/asio/buffered_write_stream.hpp @@ -15,24 +15,21 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include #include -#include - #include #include #include -#include -#include -#include #include #include #include +#include +#include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/buffered_write_stream_fwd.hpp b/include/boost/asio/buffered_write_stream_fwd.hpp index 74cdb83a..8f0f4095 100644 --- a/include/boost/asio/buffered_write_stream_fwd.hpp +++ b/include/boost/asio/buffered_write_stream_fwd.hpp @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - namespace boost { namespace asio { @@ -26,6 +24,4 @@ class buffered_write_stream; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_BUFFERED_WRITE_STREAM_FWD_HPP diff --git a/include/boost/asio/buffers_iterator.hpp b/include/boost/asio/buffers_iterator.hpp index 0b654b8c..254e4e86 100644 --- a/include/boost/asio/buffers_iterator.hpp +++ b/include/boost/asio/buffers_iterator.hpp @@ -15,20 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include #include #include #include #include -#include - #include +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/completion_condition.hpp b/include/boost/asio/completion_condition.hpp index 747591c6..dfb48edb 100644 --- a/include/boost/asio/completion_condition.hpp +++ b/include/boost/asio/completion_condition.hpp @@ -15,12 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#include #include -#include -#include -#include namespace boost { namespace asio { diff --git a/include/boost/asio/datagram_socket_service.hpp b/include/boost/asio/datagram_socket_service.hpp index 74bf7033..4d324e28 100644 --- a/include/boost/asio/datagram_socket_service.hpp +++ b/include/boost/asio/datagram_socket_service.hpp @@ -15,16 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include #include -#include #if defined(BOOST_ASIO_HAS_IOCP) # include @@ -32,6 +26,8 @@ # include #endif +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/deadline_timer.hpp b/include/boost/asio/deadline_timer.hpp index 7f8d1e38..3ed7b676 100644 --- a/include/boost/asio/deadline_timer.hpp +++ b/include/boost/asio/deadline_timer.hpp @@ -15,16 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include // Must come before posix_time. +#include #include #include #include -#include - namespace boost { namespace asio { @@ -34,6 +32,4 @@ typedef basic_deadline_timer deadline_timer; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DEADLINE_TIMER_HPP diff --git a/include/boost/asio/deadline_timer_service.hpp b/include/boost/asio/deadline_timer_service.hpp index 624791db..77060c44 100644 --- a/include/boost/asio/deadline_timer_service.hpp +++ b/include/boost/asio/deadline_timer_service.hpp @@ -15,17 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - +#include #include #include -#include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/detail/array_fwd.hpp b/include/boost/asio/detail/array_fwd.hpp new file mode 100644 index 00000000..3d47a9af --- /dev/null +++ b/include/boost/asio/detail/array_fwd.hpp @@ -0,0 +1,25 @@ +// +// detail/array_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_ARRAY_FWD_HPP +#define BOOST_ASIO_DETAIL_ARRAY_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +namespace boost { + +template +class array; + +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_ARRAY_FWD_HPP diff --git a/include/boost/asio/detail/base_from_completion_cond.hpp b/include/boost/asio/detail/base_from_completion_cond.hpp index 1b1f1422..797e3ced 100644 --- a/include/boost/asio/detail/base_from_completion_cond.hpp +++ b/include/boost/asio/detail/base_from_completion_cond.hpp @@ -1,6 +1,6 @@ // -// base_from_completion_cond.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/base_from_completion_cond.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include +#include + namespace boost { namespace asio { namespace detail { @@ -32,7 +33,8 @@ protected: { } - std::size_t check(const boost::system::error_code& ec, + std::size_t check_for_completion( + const boost::system::error_code& ec, std::size_t total_transferred) { return detail::adapt_completion_condition_result( @@ -51,7 +53,8 @@ protected: { } - static std::size_t check(const boost::system::error_code& ec, + static std::size_t check_for_completion( + const boost::system::error_code& ec, std::size_t total_transferred) { return transfer_all_t()(ec, total_transferred); diff --git a/include/boost/asio/detail/bind_handler.hpp b/include/boost/asio/detail/bind_handler.hpp index e161893e..c8136a1f 100644 --- a/include/boost/asio/detail/bind_handler.hpp +++ b/include/boost/asio/detail/bind_handler.hpp @@ -1,6 +1,6 @@ // -// bind_handler.hpp -// ~~~~~~~~~~~~~~~~ +// detail/bind_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/buffer_resize_guard.hpp b/include/boost/asio/detail/buffer_resize_guard.hpp index af67c468..bcffc1ab 100644 --- a/include/boost/asio/detail/buffer_resize_guard.hpp +++ b/include/boost/asio/detail/buffer_resize_guard.hpp @@ -1,6 +1,6 @@ // -// buffer_resize_guard.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// detail/buffer_resize_guard.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,12 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#include #include -#include -#include -#include namespace boost { namespace asio { diff --git a/include/boost/asio/detail/buffer_sequence_adapter.hpp b/include/boost/asio/detail/buffer_sequence_adapter.hpp index ce9652ef..2cfd880f 100644 --- a/include/boost/asio/detail/buffer_sequence_adapter.hpp +++ b/include/boost/asio/detail/buffer_sequence_adapter.hpp @@ -1,6 +1,6 @@ // -// buffer_sequence_adapter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/buffer_sequence_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,9 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include +#include + +#include namespace boost { namespace asio { @@ -33,14 +35,14 @@ protected: const boost::asio::mutable_buffer& buffer) { buf.buf = boost::asio::buffer_cast(buffer); - buf.len = boost::asio::buffer_size(buffer); + buf.len = static_cast(boost::asio::buffer_size(buffer)); } static void init_native_buffer(WSABUF& buf, const boost::asio::const_buffer& buffer) { buf.buf = const_cast(boost::asio::buffer_cast(buffer)); - buf.len = boost::asio::buffer_size(buffer); + buf.len = static_cast(boost::asio::buffer_size(buffer)); } #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef iovec native_buffer_type; diff --git a/include/boost/asio/detail/buffered_stream_storage.hpp b/include/boost/asio/detail/buffered_stream_storage.hpp index 9b834269..9a2929e9 100644 --- a/include/boost/asio/detail/buffered_stream_storage.hpp +++ b/include/boost/asio/detail/buffered_stream_storage.hpp @@ -1,6 +1,6 @@ // -// buffered_stream_storage.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/buffered_stream_storage.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include #include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/detail/call_stack.hpp b/include/boost/asio/detail/call_stack.hpp index 0d7d52c3..561a8265 100644 --- a/include/boost/asio/detail/call_stack.hpp +++ b/include/boost/asio/detail/call_stack.hpp @@ -1,6 +1,6 @@ // -// call_stack.hpp -// ~~~~~~~~~~~~~~ +// detail/call_stack.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/completion_handler.hpp b/include/boost/asio/detail/completion_handler.hpp index d78e6c89..6701fb32 100644 --- a/include/boost/asio/detail/completion_handler.hpp +++ b/include/boost/asio/detail/completion_handler.hpp @@ -1,6 +1,6 @@ // -// completion_handler.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/completion_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include #include #include +#include + namespace boost { namespace asio { namespace detail { @@ -30,6 +31,8 @@ template class completion_handler : public operation { public: + BOOST_ASIO_DEFINE_HANDLER_PTR(completion_handler); + completion_handler(Handler h) : operation(&completion_handler::do_complete), handler_(h) @@ -41,20 +44,21 @@ public: { // Take ownership of the handler object. completion_handler* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(h->handler_, h); + ptr p = { boost::addressof(h->handler_), h, 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 + // 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(h->handler_); + p.h = boost::addressof(handler); + p.reset(); // Make the upcall if required. if (owner) { - // 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(h->handler_); - ptr.reset(); boost::asio::detail::fenced_block b; boost_asio_handler_invoke_helpers::invoke(handler, handler); } diff --git a/include/boost/asio/detail/config.hpp b/include/boost/asio/detail/config.hpp new file mode 100644 index 00000000..800e32a8 --- /dev/null +++ b/include/boost/asio/detail/config.hpp @@ -0,0 +1,203 @@ +// +// detail/config.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_CONFIG_HPP +#define BOOST_ASIO_DETAIL_CONFIG_HPP + +#include + +// Default to a header-only implementation. The user must specifically request +// separate compilation by defining either BOOST_ASIO_SEPARATE_COMPILATION or +// BOOST_ASIO_DYN_LINK (as a DLL/shared library implies separate compilation). +#if !defined(BOOST_ASIO_HEADER_ONLY) +# if !defined(BOOST_ASIO_SEPARATE_COMPILATION) +# if !defined(BOOST_ASIO_DYN_LINK) +# define BOOST_ASIO_HEADER_ONLY +# endif // !defined(BOOST_ASIO_DYN_LINK) +# endif // !defined(BOOST_ASIO_SEPARATE_COMPILATION) +#endif // !defined(BOOST_ASIO_HEADER_ONLY) + +#if defined(BOOST_ASIO_HEADER_ONLY) +# define BOOST_ASIO_DECL inline +#else // defined(BOOST_ASIO_HEADER_ONLY) +# if defined(BOOST_HAS_DECLSPEC) +// We need to import/export our code only if the user has specifically asked +// for it by defining BOOST_ASIO_DYN_LINK. +# if defined(BOOST_ASIO_DYN_LINK) +// Export if this is our own source, otherwise import. +# if defined(BOOST_ASIO_SOURCE) +# define BOOST_ASIO_DECL __declspec(dllexport) +# else // defined(BOOST_ASIO_SOURCE) +# define BOOST_ASIO_DECL __declspec(dllimport) +# endif // defined(BOOST_ASIO_SOURCE) +# endif // defined(BOOST_ASIO_DYN_LINK) +# endif // defined(BOOST_HAS_DECLSPEC) +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +// If BOOST_ASIO_DECL isn't defined yet define it now. +#if !defined(BOOST_ASIO_DECL) +# define BOOST_ASIO_DECL +#endif // !defined(BOOST_ASIO_DECL) + +// Windows: target OS version. +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) || defined(__BORLANDC__) +# pragma message( \ + "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ + "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\ + "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\ + "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).") +# else // defined(_MSC_VER) || defined(__BORLANDC__) +# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. +# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line. +# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target). +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +# define _WIN32_WINNT 0x0501 +# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) +# if defined(_WIN32) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(_WIN32) && !defined(WIN32) +# endif // defined(_MSC_VER) +# if defined(__BORLANDC__) +# if defined(__WIN32__) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(__WIN32__) && !defined(WIN32) +# endif // defined(__BORLANDC__) +# if defined(__CYGWIN__) +# if !defined(__USE_W32_SOCKETS) +# error You must add -D__USE_W32_SOCKETS to your compiler options. +# endif // !defined(__USE_W32_SOCKETS) +# endif // defined(__CYGWIN__) +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +// Windows: minimise header inclusion. +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +# if !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif // !defined(WIN32_LEAN_AND_MEAN) +# endif // !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +// Windows: suppress definition of "min" and "max" macros. +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if !defined(BOOST_ASIO_NO_NOMINMAX) +# if !defined(NOMINMAX) +# define NOMINMAX 1 +# endif // !defined(NOMINMAX) +# endif // !defined(BOOST_ASIO_NO_NOMINMAX) +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +// Windows: IO Completion Ports. +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# if !defined(UNDER_CE) +# if !defined(BOOST_ASIO_DISABLE_IOCP) +# define BOOST_ASIO_HAS_IOCP 1 +# endif // !defined(BOOST_ASIO_DISABLE_IOCP) +# endif // !defined(UNDER_CE) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +// Linux: epoll, eventfd and timerfd. +#if defined(__linux__) +# include +# if !defined(BOOST_ASIO_DISABLE_EPOLL) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# define BOOST_ASIO_HAS_EPOLL 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# endif // !defined(BOOST_ASIO_DISABLE_EVENTFD) +# if !defined(BOOST_ASIO_DISABLE_EVENTFD) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# define BOOST_ASIO_HAS_EVENTFD 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# endif // !defined(BOOST_ASIO_DISABLE_EVENTFD) +# if defined(BOOST_ASIO_HAS_EPOLL) +# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# define BOOST_ASIO_HAS_TIMERFD 1 +# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# endif // defined(BOOST_ASIO_HAS_EPOLL) +#endif // defined(__linux__) + +// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. +#if (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) +# if !defined(BOOST_ASIO_DISABLE_KQUEUE) +# define BOOST_ASIO_HAS_KQUEUE 1 +# endif // !defined(BOOST_ASIO_DISABLE_KQUEUE) +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || defined(__FreeBSD__) + // || defined(__NetBSD__) + // || defined(__OpenBSD__) + +// Solaris: /dev/poll. +#if defined(__sun) +# if !defined(BOOST_ASIO_DISABLE_DEV_POLL) +# define BOOST_ASIO_HAS_DEV_POLL 1 +# endif // !defined(BOOST_ASIO_DISABLE_DEV_POLL) +#endif // defined(__sun) + +// Serial ports. +#if defined(BOOST_ASIO_HAS_IOCP) \ + || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +# if !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) +# define BOOST_ASIO_HAS_SERIAL_PORT 1 +# endif // !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) +#endif // defined(BOOST_ASIO_HAS_IOCP) + // || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +// Windows: stream handles. +#if !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +#endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) + +// Windows: random access handles. +#if !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +#endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) + +// Windows: OVERLAPPED wrapper. +#if !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +#endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) + +// POSIX: stream-oriented file descriptors. +#if !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +# define BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1 +# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) + +// UNIX domain sockets. +#if !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) +# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +# define BOOST_ASIO_HAS_LOCAL_SOCKETS 1 +# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) + +#endif // BOOST_ASIO_DETAIL_CONFIG_HPP diff --git a/include/boost/asio/detail/consuming_buffers.hpp b/include/boost/asio/detail/consuming_buffers.hpp index 3604cbaa..60fac4a6 100644 --- a/include/boost/asio/detail/consuming_buffers.hpp +++ b/include/boost/asio/detail/consuming_buffers.hpp @@ -1,6 +1,6 @@ // -// consuming_buffers.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// detail/consuming_buffers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,18 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include -#include #include #include -#include - #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/deadline_timer_service.hpp b/include/boost/asio/detail/deadline_timer_service.hpp index 5ba21b15..f1ab2f82 100644 --- a/include/boost/asio/detail/deadline_timer_service.hpp +++ b/include/boost/asio/detail/deadline_timer_service.hpp @@ -1,6 +1,6 @@ // -// deadline_timer_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/deadline_timer_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,14 +15,8 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include -#include - #include #include #include @@ -33,6 +27,13 @@ #include #include #include +#include + +#include +#include +#include + +#include namespace boost { namespace asio { @@ -152,59 +153,21 @@ public: ec = boost::system::error_code(); } - template - class wait_handler : public timer_op - { - public: - wait_handler(Handler handler) - : timer_op(&wait_handler::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - wait_handler* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(h->handler_, h); - - // Make the upcall if required. - if (owner) - { - // 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(h->handler_, h->ec_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous wait on the timer. template void async_wait(implementation_type& impl, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef wait_handler value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + typedef wait_handler op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); impl.might_have_pending_waits = true; - scheduler_.schedule_timer(timer_queue_, impl.expiry, ptr.get(), &impl); - ptr.release(); + scheduler_.schedule_timer(timer_queue_, impl.expiry, p.p, &impl); + p.v = p.p = 0; } private: diff --git a/include/boost/asio/detail/descriptor_ops.hpp b/include/boost/asio/detail/descriptor_ops.hpp index c4969f70..4f82cd65 100644 --- a/include/boost/asio/detail/descriptor_ops.hpp +++ b/include/boost/asio/detail/descriptor_ops.hpp @@ -1,6 +1,6 @@ // -// descriptor_ops.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/descriptor_ops.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,28 +15,35 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include - -#include -#include +#include #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#include +#include +#include + +#include + namespace boost { namespace asio { namespace detail { namespace descriptor_ops { -inline void clear_error(boost::system::error_code& ec) +// Descriptor state bits. +enum { - errno = 0; - ec = boost::system::error_code(); -} + // The user wants a non-blocking descriptor. + user_set_non_blocking = 1, + + // The descriptor has been set non-blocking. + internal_non_blocking = 2, + + // Helper "state" used to determine whether the descriptor is non-blocking. + non_blocking = user_set_non_blocking | internal_non_blocking +}; + +typedef unsigned char state_type; template inline ReturnType error_wrapper(ReturnType return_value, @@ -47,132 +54,54 @@ inline ReturnType error_wrapper(ReturnType return_value, return return_value; } -inline int open(const char* path, int flags, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::open(path, flags), ec); - if (result >= 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL int open(const char* path, int flags, + boost::system::error_code& ec); -inline int close(int d, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::close(d), ec); - if (result == 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL int close(int d, state_type& state, + boost::system::error_code& ec); -inline void init_buf_iov_base(void*& base, void* addr) -{ - base = addr; -} - -template -inline void init_buf_iov_base(T& base, void* addr) -{ - base = static_cast(addr); -} +BOOST_ASIO_DECL bool set_internal_non_blocking(int d, + state_type& state, boost::system::error_code& ec); typedef iovec buf; -inline void init_buf(buf& b, void* data, size_t size) -{ - init_buf_iov_base(b.iov_base, data); - b.iov_len = size; -} +BOOST_ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs, + std::size_t count, bool all_empty, boost::system::error_code& ec); -inline void init_buf(buf& b, const void* data, size_t size) -{ - init_buf_iov_base(b.iov_base, const_cast(data)); - b.iov_len = size; -} +BOOST_ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count, + boost::system::error_code& ec, std::size_t& bytes_transferred); -inline int scatter_read(int d, buf* bufs, size_t count, - boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::readv(d, bufs, static_cast(count)), ec); - if (result >= 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL std::size_t sync_write(int d, state_type state, + const buf* bufs, std::size_t count, bool all_empty, + boost::system::error_code& ec); -inline int gather_write(int d, const buf* bufs, size_t count, - boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::writev(d, bufs, static_cast(count)), ec); - if (result >= 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL bool non_blocking_write(int d, + const buf* bufs, std::size_t count, + boost::system::error_code& ec, std::size_t& bytes_transferred); -inline int ioctl(int d, long cmd, ioctl_arg_type* arg, - boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::ioctl(d, cmd, arg), ec); - if (result >= 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL int ioctl(int d, state_type& state, long cmd, + ioctl_arg_type* arg, boost::system::error_code& ec); -inline int fcntl(int d, long cmd, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::fcntl(d, cmd), ec); - if (result != -1) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL int fcntl(int d, long cmd, boost::system::error_code& ec); -inline int fcntl(int d, long cmd, long arg, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::fcntl(d, cmd, arg), ec); - if (result != -1) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL int fcntl(int d, long cmd, + long arg, boost::system::error_code& ec); -inline int poll_read(int d, boost::system::error_code& ec) -{ - clear_error(ec); - pollfd fds; - fds.fd = d; - fds.events = POLLIN; - fds.revents = 0; - clear_error(ec); - int result = error_wrapper(::poll(&fds, 1, -1), ec); - if (result >= 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL int poll_read(int d, boost::system::error_code& ec); -inline int poll_write(int d, boost::system::error_code& ec) -{ - clear_error(ec); - pollfd fds; - fds.fd = d; - fds.events = POLLOUT; - fds.revents = 0; - clear_error(ec); - int result = error_wrapper(::poll(&fds, 1, -1), ec); - if (result >= 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL int poll_write(int d, boost::system::error_code& ec); } // namespace descriptor_ops } // namespace detail } // namespace asio } // namespace boost -#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_DESCRIPTOR_OPS_HPP diff --git a/include/boost/asio/detail/descriptor_read_op.hpp b/include/boost/asio/detail/descriptor_read_op.hpp new file mode 100644 index 00000000..c068108f --- /dev/null +++ b/include/boost/asio/detail/descriptor_read_op.hpp @@ -0,0 +1,116 @@ +// +// detail/descriptor_read_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_DESCRIPTOR_READ_OP_HPP +#define BOOST_ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class descriptor_read_op_base : public reactor_op +{ +public: + descriptor_read_op_base(int descriptor, + const MutableBufferSequence& buffers, func_type complete_func) + : reactor_op(&descriptor_read_op_base::do_perform, complete_func), + descriptor_(descriptor), + buffers_(buffers) + { + } + + static bool do_perform(reactor_op* base) + { + descriptor_read_op_base* o(static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + return descriptor_ops::non_blocking_read(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_); + } + +private: + int descriptor_; + MutableBufferSequence buffers_; +}; + +template +class descriptor_read_op + : public descriptor_read_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(descriptor_read_op); + + descriptor_read_op(int descriptor, + const MutableBufferSequence& buffers, Handler handler) + : descriptor_read_op_base( + descriptor, buffers, &descriptor_read_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + descriptor_read_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, 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(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP diff --git a/include/boost/asio/detail/descriptor_write_op.hpp b/include/boost/asio/detail/descriptor_write_op.hpp new file mode 100644 index 00000000..09838548 --- /dev/null +++ b/include/boost/asio/detail/descriptor_write_op.hpp @@ -0,0 +1,116 @@ +// +// detail/descriptor_write_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_DESCRIPTOR_WRITE_OP_HPP +#define BOOST_ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class descriptor_write_op_base : public reactor_op +{ +public: + descriptor_write_op_base(int descriptor, + const ConstBufferSequence& buffers, func_type complete_func) + : reactor_op(&descriptor_write_op_base::do_perform, complete_func), + descriptor_(descriptor), + buffers_(buffers) + { + } + + static bool do_perform(reactor_op* base) + { + descriptor_write_op_base* o(static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + return descriptor_ops::non_blocking_write(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_); + } + +private: + int descriptor_; + ConstBufferSequence buffers_; +}; + +template +class descriptor_write_op + : public descriptor_write_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(descriptor_write_op); + + descriptor_write_op(int descriptor, + const ConstBufferSequence& buffers, Handler handler) + : descriptor_write_op_base( + descriptor, buffers, &descriptor_write_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + descriptor_write_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, 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(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP diff --git a/include/boost/asio/detail/dev_poll_reactor.hpp b/include/boost/asio/detail/dev_poll_reactor.hpp index e00f501b..963def3d 100644 --- a/include/boost/asio/detail/dev_poll_reactor.hpp +++ b/include/boost/asio/detail/dev_poll_reactor.hpp @@ -1,6 +1,6 @@ // -// dev_poll_reactor.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/dev_poll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,36 +15,28 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_DEV_POLL) -#include #include #include -#include -#include -#include #include -#include -#include - -#include -#include +#include #include #include #include #include #include #include -#include #include #include #include #include #include +#include + +#include namespace boost { namespace asio { @@ -63,358 +55,91 @@ public: }; // Constructor. - dev_poll_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base(io_service), - io_service_(use_service(io_service)), - mutex_(), - dev_poll_fd_(do_dev_poll_create()), - interrupter_(), - shutdown_(false) - { - // Add the interrupter's descriptor to /dev/poll. - ::pollfd ev = { 0 }; - ev.fd = interrupter_.read_descriptor(); - ev.events = POLLIN | POLLERR; - ev.revents = 0; - ::write(dev_poll_fd_, &ev, sizeof(ev)); - } + BOOST_ASIO_DECL dev_poll_reactor(boost::asio::io_service& io_service); // Destructor. - ~dev_poll_reactor() - { - shutdown_service(); - ::close(dev_poll_fd_); - } + BOOST_ASIO_DECL ~dev_poll_reactor(); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - shutdown_ = true; - lock.unlock(); - - op_queue ops; - - for (int i = 0; i < max_ops; ++i) - op_queue_[i].get_all_operations(ops); - - timer_queues_.get_all_timers(ops); - } + BOOST_ASIO_DECL void shutdown_service(); // Initialise the task. - void init_task() - { - io_service_.init_task(); - } + BOOST_ASIO_DECL void init_task(); // Register a socket with the reactor. Returns 0 on success, system error // code on failure. - int register_descriptor(socket_type, per_descriptor_data&) + BOOST_ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op) { - return 0; + io_service_.post_immediate_completion(op); } // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. - void start_op(int op_type, socket_type descriptor, - per_descriptor_data&, reactor_op* op, bool allow_speculative) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (shutdown_) - return; - - if (allow_speculative) - { - if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor)) - { - if (!op_queue_[op_type].has_operation(descriptor)) - { - if (op->perform()) - { - lock.unlock(); - io_service_.post_immediate_completion(op); - return; - } - } - } - } - - bool first = op_queue_[op_type].enqueue_operation(descriptor, op); - io_service_.work_started(); - if (first) - { - ::pollfd& ev = add_pending_event_change(descriptor); - ev.events = POLLERR | POLLHUP; - if (op_type == read_op - || op_queue_[read_op].has_operation(descriptor)) - ev.events |= POLLIN; - if (op_type == write_op - || op_queue_[write_op].has_operation(descriptor)) - ev.events |= POLLOUT; - if (op_type == except_op - || op_queue_[except_op].has_operation(descriptor)) - ev.events |= POLLPRI; - interrupter_.interrupt(); - } - } + BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data&, reactor_op* op, bool allow_speculative); // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the // operation_aborted error. - void cancel_ops(socket_type descriptor, per_descriptor_data&) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); - } + BOOST_ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. - void close_descriptor(socket_type descriptor, per_descriptor_data&) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - // Remove the descriptor from /dev/poll. - ::pollfd& ev = add_pending_event_change(descriptor); - ev.events = POLLREMOVE; - interrupter_.interrupt(); - - // Cancel any outstanding operations associated with the descriptor. - cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); - } + BOOST_ASIO_DECL void close_descriptor( + socket_type descriptor, per_descriptor_data&); // Add a new timer queue to the reactor. template - void add_timer_queue(timer_queue& timer_queue) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.insert(&timer_queue); - } + void add_timer_queue(timer_queue& queue); // Remove a timer queue from the reactor. template - void remove_timer_queue(timer_queue& timer_queue) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.erase(&timer_queue); - } + void remove_timer_queue(timer_queue& queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template - void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, timer_op* op, void* token) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_) - { - bool earliest = timer_queue.enqueue_timer(time, op, token); - io_service_.work_started(); - if (earliest) - interrupter_.interrupt(); - } - } + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token); // Cancel the timer operations associated with the given token. Returns the // number of operations that have been posted or dispatched. template - std::size_t cancel_timer(timer_queue& timer_queue, void* token) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - op_queue ops; - std::size_t n = timer_queue.cancel_timer(token, ops); - lock.unlock(); - io_service_.post_deferred_completions(ops); - return n; - } + std::size_t cancel_timer(timer_queue& queue, void* token); // Run /dev/poll once until interrupted or events are ready to be dispatched. - void run(bool block, op_queue& 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() - && op_queue_[except_op].empty() && timer_queues_.all_empty()) - return; - - // Write the pending event registration changes to the /dev/poll descriptor. - std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size(); - if (events_size > 0) - { - errno = 0; - int result = ::write(dev_poll_fd_, - &pending_event_changes_[0], events_size); - if (result != static_cast(events_size)) - { - boost::system::error_code ec = boost::system::error_code( - errno, boost::asio::error::get_system_category()); - for (std::size_t i = 0; i < pending_event_changes_.size(); ++i) - { - int descriptor = pending_event_changes_[i].fd; - for (int j = 0; j < max_ops; ++j) - op_queue_[j].cancel_operations(descriptor, ops, ec); - } - } - pending_event_changes_.clear(); - pending_event_change_index_.clear(); - } - - int timeout = block ? get_timeout() : 0; - lock.unlock(); - - // Block on the /dev/poll descriptor. - ::pollfd events[128] = { { 0 } }; - ::dvpoll dp = { 0 }; - dp.dp_fds = events; - dp.dp_nfds = 128; - dp.dp_timeout = timeout; - int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp); - - lock.lock(); - - // Dispatch the waiting events. - for (int i = 0; i < num_events; ++i) - { - int descriptor = events[i].fd; - if (descriptor == interrupter_.read_descriptor()) - { - interrupter_.reset(); - } - else - { - bool more_reads = false; - bool more_writes = false; - bool more_except = false; - - // Exception operations must be processed first to ensure that any - // out-of-band data is read before normal data. - if (events[i].events & (POLLPRI | POLLERR | POLLHUP)) - more_except = - op_queue_[except_op].perform_operations(descriptor, ops); - else - more_except = op_queue_[except_op].has_operation(descriptor); - - if (events[i].events & (POLLIN | POLLERR | POLLHUP)) - more_reads = op_queue_[read_op].perform_operations(descriptor, ops); - else - more_reads = op_queue_[read_op].has_operation(descriptor); - - if (events[i].events & (POLLOUT | POLLERR | POLLHUP)) - more_writes = op_queue_[write_op].perform_operations(descriptor, ops); - else - more_writes = op_queue_[write_op].has_operation(descriptor); - - if ((events[i].events & (POLLERR | POLLHUP)) != 0 - && !more_except && !more_reads && !more_writes) - { - // If we have an event and no operations associated with the - // descriptor then we need to delete the descriptor from /dev/poll. - // The poll operation can produce POLLHUP or POLLERR events when there - // is no operation pending, so if we do not remove the descriptor we - // can end up in a tight polling loop. - ::pollfd ev = { 0 }; - ev.fd = descriptor; - ev.events = POLLREMOVE; - ev.revents = 0; - ::write(dev_poll_fd_, &ev, sizeof(ev)); - } - else - { - ::pollfd ev = { 0 }; - ev.fd = descriptor; - ev.events = POLLERR | POLLHUP; - if (more_reads) - ev.events |= POLLIN; - if (more_writes) - ev.events |= POLLOUT; - if (more_except) - ev.events |= POLLPRI; - ev.revents = 0; - int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); - if (result != sizeof(ev)) - { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - for (int j = 0; j < max_ops; ++j) - op_queue_[j].cancel_operations(descriptor, ops, ec); - } - } - } - } - timer_queues_.get_ready_timers(ops); - } + BOOST_ASIO_DECL void run(bool block, op_queue& ops); // Interrupt the select loop. - void interrupt() - { - interrupter_.interrupt(); - } + BOOST_ASIO_DECL void interrupt(); private: // Create the /dev/poll file descriptor. Throws an exception if the descriptor // cannot be created. - static int do_dev_poll_create() - { - int fd = ::open("/dev/poll", O_RDWR); - if (fd == -1) - { - boost::throw_exception( - boost::system::system_error( - boost::system::error_code(errno, - boost::asio::error::get_system_category()), - "/dev/poll")); - } - return fd; - } + BOOST_ASIO_DECL static int do_dev_poll_create(); + + // Helper function to add a new timer queue. + BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); // 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. - int get_timeout() - { - // 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); - } + BOOST_ASIO_DECL int get_timeout(); // Cancel all operations associated with the given descriptor. The do_cancel // function of the handler objects will be invoked. This function does not // acquire the dev_poll_reactor's mutex. - void cancel_ops_unlocked(socket_type descriptor, - const boost::system::error_code& ec) - { - bool need_interrupt = false; - op_queue ops; - 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); - if (need_interrupt) - interrupter_.interrupt(); - } + BOOST_ASIO_DECL void cancel_ops_unlocked(socket_type descriptor, + const boost::system::error_code& ec); // Add a pending event entry for the given descriptor. - ::pollfd& add_pending_event_change(int descriptor) - { - hash_map::iterator iter - = pending_event_change_index_.find(descriptor); - if (iter == pending_event_change_index_.end()) - { - std::size_t index = pending_event_changes_.size(); - pending_event_changes_.reserve(pending_event_changes_.size() + 1); - pending_event_change_index_.insert(std::make_pair(descriptor, index)); - pending_event_changes_.push_back(::pollfd()); - pending_event_changes_[index].fd = descriptor; - pending_event_changes_[index].revents = 0; - return pending_event_changes_[index]; - } - else - { - return pending_event_changes_[iter->second]; - } - } + BOOST_ASIO_DECL ::pollfd& add_pending_event_change(int descriptor); // The io_service implementation used to post completions. io_service_impl& io_service_; @@ -448,8 +173,13 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_DEV_POLL) - #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_DEV_POLL) + #endif // BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_HPP diff --git a/include/boost/asio/detail/dev_poll_reactor_fwd.hpp b/include/boost/asio/detail/dev_poll_reactor_fwd.hpp index 238cee52..7e8defc5 100644 --- a/include/boost/asio/detail/dev_poll_reactor_fwd.hpp +++ b/include/boost/asio/detail/dev_poll_reactor_fwd.hpp @@ -1,6 +1,6 @@ // -// dev_poll_reactor_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/dev_poll_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,9 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#if !defined(BOOST_ASIO_DISABLE_DEV_POLL) -#if defined(__sun) // This service is only supported on Solaris. - -// Define this to indicate that /dev/poll is supported on the target platform. -#define BOOST_ASIO_HAS_DEV_POLL 1 +#if defined(BOOST_ASIO_HAS_DEV_POLL) namespace boost { namespace asio { @@ -33,9 +29,6 @@ class dev_poll_reactor; } // namespace asio } // namespace boost -#endif // defined(__sun) -#endif // !defined(BOOST_ASIO_DISABLE_DEV_POLL) - -#include +#endif // defined(BOOST_ASIO_HAS_DEV_POLL) #endif // BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP diff --git a/include/boost/asio/detail/epoll_reactor.hpp b/include/boost/asio/detail/epoll_reactor.hpp index 46849448..0471436a 100644 --- a/include/boost/asio/detail/epoll_reactor.hpp +++ b/include/boost/asio/detail/epoll_reactor.hpp @@ -1,6 +1,6 @@ // -// epoll_reactor.hpp -// ~~~~~~~~~~~~~~~~~ +// detail/epoll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,43 +15,24 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_EPOLL) -#include -#include -#include -#include -#include -#include -#include - -#include #include +#include #include #include #include #include #include -#include #include #include #include #include #include -#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) -# define BOOST_ASIO_HAS_TIMERFD 1 -#endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) - -#if defined(BOOST_ASIO_HAS_TIMERFD) -# include -# include -# include -#endif // defined(BOOST_ASIO_HAS_TIMERFD) +#include namespace boost { namespace asio { @@ -80,342 +61,69 @@ public: typedef descriptor_state* per_descriptor_data; // Constructor. - epoll_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base(io_service), - io_service_(use_service(io_service)), - mutex_(), - epoll_fd_(do_epoll_create()), -#if defined(BOOST_ASIO_HAS_TIMERFD) - timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)), -#else // defined(BOOST_ASIO_HAS_TIMERFD) - timer_fd_(-1), -#endif // defined(BOOST_ASIO_HAS_TIMERFD) - interrupter_(), - shutdown_(false) - { - // Add the interrupter's descriptor to epoll. - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLIN | EPOLLERR | EPOLLET; - ev.data.ptr = &interrupter_; - epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); - interrupter_.interrupt(); - - // Add the timer descriptor to epoll. - if (timer_fd_ != -1) - { - ev.events = EPOLLIN | EPOLLERR; - ev.data.ptr = &timer_fd_; - epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); - } - } + BOOST_ASIO_DECL epoll_reactor(boost::asio::io_service& io_service); // Destructor. - ~epoll_reactor() - { - close(epoll_fd_); - if (timer_fd_ != -1) - close(timer_fd_); - } + BOOST_ASIO_DECL ~epoll_reactor(); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - mutex::scoped_lock lock(mutex_); - shutdown_ = true; - lock.unlock(); - - op_queue ops; - - descriptor_map::iterator iter = registered_descriptors_.begin(); - descriptor_map::iterator end = registered_descriptors_.end(); - while (iter != end) - { - for (int i = 0; i < max_ops; ++i) - ops.push(iter->second.op_queue_[i]); - iter->second.shutdown_ = true; - ++iter; - } - - timer_queues_.get_all_timers(ops); - } + BOOST_ASIO_DECL void shutdown_service(); // Initialise the task. - void init_task() - { - io_service_.init_task(); - } + BOOST_ASIO_DECL void init_task(); // Register a socket with the reactor. Returns 0 on success, system error // code on failure. - int register_descriptor(socket_type descriptor, - per_descriptor_data& descriptor_data) + BOOST_ASIO_DECL int register_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op) { - mutex::scoped_lock lock(registered_descriptors_mutex_); - - descriptor_map::iterator new_entry = registered_descriptors_.insert( - std::make_pair(descriptor, descriptor_state())).first; - descriptor_data = &new_entry->second; - - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET; - ev.data.ptr = descriptor_data; - int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); - if (result != 0) - return errno; - - descriptor_data->shutdown_ = false; - - return 0; + io_service_.post_immediate_completion(op); } // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. - void start_op(int op_type, socket_type descriptor, + BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, per_descriptor_data& descriptor_data, - reactor_op* op, bool allow_speculative) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - if (descriptor_data->shutdown_) - return; - - if (descriptor_data->op_queue_[op_type].empty()) - { - if (allow_speculative - && (op_type != read_op - || descriptor_data->op_queue_[except_op].empty())) - { - if (op->perform()) - { - descriptor_lock.unlock(); - io_service_.post_immediate_completion(op); - return; - } - } - else - { - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLIN | EPOLLERR | EPOLLHUP - | EPOLLOUT | EPOLLPRI | EPOLLET; - ev.data.ptr = descriptor_data; - epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); - } - } - - descriptor_data->op_queue_[op_type].push(op); - io_service_.work_started(); - } + reactor_op* op, bool allow_speculative); // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the // operation_aborted error. - void cancel_ops(socket_type descriptor, per_descriptor_data& descriptor_data) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - - op_queue ops; - for (int i = 0; i < max_ops; ++i) - { - while (reactor_op* op = descriptor_data->op_queue_[i].front()) - { - op->ec_ = boost::asio::error::operation_aborted; - descriptor_data->op_queue_[i].pop(); - ops.push(op); - } - } - - descriptor_lock.unlock(); - - io_service_.post_deferred_completions(ops); - } + BOOST_ASIO_DECL void cancel_ops(socket_type descriptor, + per_descriptor_data& descriptor_data); // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. - void close_descriptor(socket_type descriptor, - per_descriptor_data& descriptor_data) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); - - // Remove the descriptor from the set of known descriptors. The descriptor - // will be automatically removed from the epoll set when it is closed. - descriptor_data->shutdown_ = true; - - op_queue ops; - for (int i = 0; i < max_ops; ++i) - { - while (reactor_op* op = descriptor_data->op_queue_[i].front()) - { - op->ec_ = boost::asio::error::operation_aborted; - descriptor_data->op_queue_[i].pop(); - ops.push(op); - } - } - - descriptor_lock.unlock(); - - registered_descriptors_.erase(descriptor); - - descriptors_lock.unlock(); - - io_service_.post_deferred_completions(ops); - } + BOOST_ASIO_DECL void close_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); // Add a new timer queue to the reactor. template - void add_timer_queue(timer_queue& timer_queue) - { - mutex::scoped_lock lock(mutex_); - timer_queues_.insert(&timer_queue); - } + void add_timer_queue(timer_queue& timer_queue); // Remove a timer queue from the reactor. template - void remove_timer_queue(timer_queue& timer_queue) - { - mutex::scoped_lock lock(mutex_); - timer_queues_.erase(&timer_queue); - } + void remove_timer_queue(timer_queue& timer_queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, timer_op* op, void* token) - { - mutex::scoped_lock lock(mutex_); - if (!shutdown_) - { - bool earliest = timer_queue.enqueue_timer(time, op, token); - io_service_.work_started(); - if (earliest) - { -#if defined(BOOST_ASIO_HAS_TIMERFD) - if (timer_fd_ != -1) - { - itimerspec new_timeout; - itimerspec old_timeout; - int flags = get_timeout(new_timeout); - timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); - return; - } -#endif // defined(BOOST_ASIO_HAS_TIMERFD) - interrupter_.interrupt(); - } - } - } + const typename Time_Traits::time_type& time, timer_op* op, void* token); // Cancel the timer operations associated with the given token. Returns the // number of operations that have been posted or dispatched. template - std::size_t cancel_timer(timer_queue& timer_queue, void* token) - { - mutex::scoped_lock lock(mutex_); - op_queue ops; - std::size_t n = timer_queue.cancel_timer(token, ops); - lock.unlock(); - io_service_.post_deferred_completions(ops); - return n; - } + std::size_t cancel_timer(timer_queue& timer_queue, void* token); // Run epoll once until interrupted or events are ready to be dispatched. - void run(bool block, op_queue& ops) - { - // Calculate a timeout only if timerfd is not used. - int timeout; - if (timer_fd_ != -1) - timeout = block ? -1 : 0; - else - { - mutex::scoped_lock lock(mutex_); - timeout = block ? get_timeout() : 0; - } - - // Block on the epoll descriptor. - epoll_event events[128]; - int num_events = epoll_wait(epoll_fd_, events, 128, timeout); - -#if defined(BOOST_ASIO_HAS_TIMERFD) - bool check_timers = (timer_fd_ == -1); -#else // defined(BOOST_ASIO_HAS_TIMERFD) - bool check_timers = true; -#endif // defined(BOOST_ASIO_HAS_TIMERFD) - - // Dispatch the waiting events. - for (int i = 0; i < num_events; ++i) - { - void* ptr = events[i].data.ptr; - if (ptr == &interrupter_) - { - // No need to reset the interrupter since we're leaving the descriptor - // in a ready-to-read state and relying on edge-triggered notifications - // to make it so that we only get woken up when the descriptor's epoll - // registration is updated. - -#if defined(BOOST_ASIO_HAS_TIMERFD) - if (timer_fd_ == -1) - check_timers = true; -#else // defined(BOOST_ASIO_HAS_TIMERFD) - check_timers = true; -#endif // defined(BOOST_ASIO_HAS_TIMERFD) - } -#if defined(BOOST_ASIO_HAS_TIMERFD) - else if (ptr == &timer_fd_) - { - check_timers = true; - } -#endif // defined(BOOST_ASIO_HAS_TIMERFD) - else - { - descriptor_state* descriptor_data = static_cast(ptr); - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - - // Exception operations must be processed first to ensure that any - // out-of-band data is read before normal data. - static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI }; - for (int j = max_ops - 1; j >= 0; --j) - { - if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP)) - { - while (reactor_op* op = descriptor_data->op_queue_[j].front()) - { - if (op->perform()) - { - descriptor_data->op_queue_[j].pop(); - ops.push(op); - } - else - break; - } - } - } - } - } - - if (check_timers) - { - mutex::scoped_lock common_lock(mutex_); - timer_queues_.get_ready_timers(ops); - -#if defined(BOOST_ASIO_HAS_TIMERFD) - if (timer_fd_ != -1) - { - itimerspec new_timeout; - itimerspec old_timeout; - int flags = get_timeout(new_timeout); - timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); - } -#endif // defined(BOOST_ASIO_HAS_TIMERFD) - } - } + BOOST_ASIO_DECL void run(bool block, op_queue& ops); // Interrupt the select loop. - void interrupt() - { - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLIN | EPOLLERR | EPOLLET; - ev.data.ptr = &interrupter_; - epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev); - } + BOOST_ASIO_DECL void interrupt(); private: // The hint to pass to epoll_create to size its data structures. @@ -423,44 +131,26 @@ private: // Create the epoll file descriptor. Throws an exception if the descriptor // cannot be created. - static int do_epoll_create() - { - int fd = epoll_create(epoll_size); - if (fd == -1) - { - boost::throw_exception( - boost::system::system_error( - boost::system::error_code(errno, - boost::asio::error::get_system_category()), - "epoll")); - } - return fd; - } + BOOST_ASIO_DECL static int do_epoll_create(); + + // Helper function to add a new timer queue. + BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Called to recalculate and update the timeout. + BOOST_ASIO_DECL void update_timeout(); // 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. - int get_timeout() - { - // 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); - } + BOOST_ASIO_DECL int get_timeout(); #if defined(BOOST_ASIO_HAS_TIMERFD) // Get the timeout value for the timer descriptor. The return value is the // flag argument to be used when calling timerfd_settime. - int get_timeout(itimerspec& ts) - { - ts.it_interval.tv_sec = 0; - ts.it_interval.tv_nsec = 0; - - long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); - ts.it_value.tv_sec = usec / 1000000; - ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1; - - return usec ? 0 : TFD_TIMER_ABSTIME; - } + BOOST_ASIO_DECL int get_timeout(itimerspec& ts); #endif // defined(BOOST_ASIO_HAS_TIMERFD) // The io_service implementation used to post completions. @@ -502,8 +192,13 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_EPOLL) - #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_EPOLL) + #endif // BOOST_ASIO_DETAIL_EPOLL_REACTOR_HPP diff --git a/include/boost/asio/detail/epoll_reactor_fwd.hpp b/include/boost/asio/detail/epoll_reactor_fwd.hpp index 214cee54..dc0e92de 100644 --- a/include/boost/asio/detail/epoll_reactor_fwd.hpp +++ b/include/boost/asio/detail/epoll_reactor_fwd.hpp @@ -1,6 +1,6 @@ // -// epoll_reactor_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// detail/epoll_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,19 +15,9 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#if !defined(BOOST_ASIO_DISABLE_EPOLL) -#if defined(__linux__) // This service is only supported on Linux. - -#include -#include -#include - -#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45) // Only kernels >= 2.5.45. - -// Define this to indicate that epoll is supported on the target platform. -#define BOOST_ASIO_HAS_EPOLL 1 +#if defined(BOOST_ASIO_HAS_EPOLL) namespace boost { namespace asio { @@ -39,10 +29,6 @@ class epoll_reactor; } // namespace asio } // namespace boost -#endif // LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45) -#endif // defined(__linux__) -#endif // !defined(BOOST_ASIO_DISABLE_EPOLL) - -#include +#endif // defined(BOOST_ASIO_HAS_EPOLL) #endif // BOOST_ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP diff --git a/include/boost/asio/detail/event.hpp b/include/boost/asio/detail/event.hpp index e8d185fe..c33b65ae 100644 --- a/include/boost/asio/detail/event.hpp +++ b/include/boost/asio/detail/event.hpp @@ -1,6 +1,6 @@ // -// event.hpp -// ~~~~~~~~~ +// detail/event.hpp +// ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include @@ -47,6 +43,4 @@ typedef posix_event event; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_EVENT_HPP diff --git a/include/boost/asio/detail/eventfd_select_interrupter.hpp b/include/boost/asio/detail/eventfd_select_interrupter.hpp index 4749ec92..b2cb68b7 100644 --- a/include/boost/asio/detail/eventfd_select_interrupter.hpp +++ b/include/boost/asio/detail/eventfd_select_interrupter.hpp @@ -1,6 +1,6 @@ // -// eventfd_select_interrupter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/eventfd_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) @@ -16,36 +16,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include - -#if defined(__linux__) -# if !defined(BOOST_ASIO_DISABLE_EVENTFD) -# include -# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) -# define BOOST_ASIO_HAS_EVENTFD -# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) -# endif // !defined(BOOST_ASIO_DISABLE_EVENTFD) -#endif // defined(__linux__) +#include #if defined(BOOST_ASIO_HAS_EVENTFD) #include -#include -#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 -# include -#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 -# include -#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 -#include - -#include -#include namespace boost { namespace asio { @@ -55,87 +30,16 @@ class eventfd_select_interrupter { public: // Constructor. - eventfd_select_interrupter() - { -#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 - write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0); -#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 - write_descriptor_ = read_descriptor_ = ::eventfd(0, 0); -#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 - if (read_descriptor_ != -1) - { - ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); - } - else - { - int pipe_fds[2]; - if (pipe(pipe_fds) == 0) - { - read_descriptor_ = pipe_fds[0]; - ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); - write_descriptor_ = pipe_fds[1]; - ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); - } - else - { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - boost::system::system_error e(ec, "eventfd_select_interrupter"); - boost::throw_exception(e); - } - } - } + BOOST_ASIO_DECL eventfd_select_interrupter(); // Destructor. - ~eventfd_select_interrupter() - { - if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_) - ::close(write_descriptor_); - if (read_descriptor_ != -1) - ::close(read_descriptor_); - } + BOOST_ASIO_DECL ~eventfd_select_interrupter(); // Interrupt the select call. - void interrupt() - { - uint64_t counter(1UL); - int result = ::write(write_descriptor_, &counter, sizeof(uint64_t)); - (void)result; - } + BOOST_ASIO_DECL void interrupt(); // Reset the select interrupt. Returns true if the call was interrupted. - bool reset() - { - if (write_descriptor_ == read_descriptor_) - { - for (;;) - { - // Only perform one read. The kernel maintains an atomic counter. - uint64_t counter(0); - errno = 0; - int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t)); - if (bytes_read < 0 && errno == EINTR) - continue; - bool was_interrupted = (bytes_read > 0); - return was_interrupted; - } - } - else - { - for (;;) - { - // Clear all data from the pipe. - char data[1024]; - int bytes_read = ::read(read_descriptor_, data, sizeof(data)); - if (bytes_read < 0 && errno == EINTR) - continue; - bool was_interrupted = (bytes_read > 0); - while (bytes_read == sizeof(data)) - bytes_read = ::read(read_descriptor_, data, sizeof(data)); - return was_interrupted; - } - } - } + BOOST_ASIO_DECL bool reset(); // Get the read descriptor to be passed to select. int read_descriptor() const @@ -161,8 +65,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_EVENTFD) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_EVENTFD) + #endif // BOOST_ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP diff --git a/include/boost/asio/detail/fd_set_adapter.hpp b/include/boost/asio/detail/fd_set_adapter.hpp index 059362ec..138264f4 100644 --- a/include/boost/asio/detail/fd_set_adapter.hpp +++ b/include/boost/asio/detail/fd_set_adapter.hpp @@ -1,6 +1,6 @@ // -// fd_set_adapter.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,12 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include - +#include #include #include @@ -38,6 +33,4 @@ typedef posix_fd_set_adapter fd_set_adapter; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_FD_SET_ADAPTER_HPP diff --git a/include/boost/asio/detail/fenced_block.hpp b/include/boost/asio/detail/fenced_block.hpp index c80161f3..b04ed0d5 100644 --- a/include/boost/asio/detail/fenced_block.hpp +++ b/include/boost/asio/detail/fenced_block.hpp @@ -1,6 +1,6 @@ // -// fenced_block.hpp -// ~~~~~~~~~~~~~~~~ +// detail/fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include @@ -67,6 +63,4 @@ typedef null_fenced_block fenced_block; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/gcc_fenced_block.hpp b/include/boost/asio/detail/gcc_fenced_block.hpp index 0c086a6c..fd737cf0 100644 --- a/include/boost/asio/detail/gcc_fenced_block.hpp +++ b/include/boost/asio/detail/gcc_fenced_block.hpp @@ -1,6 +1,6 @@ // -// gcc_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/gcc_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) +#include + namespace boost { namespace asio { namespace detail { @@ -55,11 +53,11 @@ private: } // namespace asio } // namespace boost +#include + #endif // defined(__GNUC__) // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) // && !defined(__INTEL_COMPILER) && !defined(__ICL) // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) -#include - #endif // BOOST_ASIO_DETAIL_GCC_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/gcc_x86_fenced_block.hpp b/include/boost/asio/detail/gcc_x86_fenced_block.hpp index fc23d662..5353f871 100644 --- a/include/boost/asio/detail/gcc_x86_fenced_block.hpp +++ b/include/boost/asio/detail/gcc_x86_fenced_block.hpp @@ -1,6 +1,6 @@ // -// gcc_x86_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/gcc_x86_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,14 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#include + namespace boost { namespace asio { namespace detail { @@ -56,8 +54,8 @@ private: } // namespace asio } // namespace boost -#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - #include +#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + #endif // BOOST_ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/handler_alloc_helpers.hpp b/include/boost/asio/detail/handler_alloc_helpers.hpp index d385972e..00d4c022 100644 --- a/include/boost/asio/detail/handler_alloc_helpers.hpp +++ b/include/boost/asio/detail/handler_alloc_helpers.hpp @@ -1,6 +1,6 @@ // -// handler_alloc_helpers.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/handler_alloc_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include - -#include #include +#include + +#include // Calls to asio_handler_allocate and asio_handler_deallocate must be made from // a namespace that does not contain any overloads of these functions. The @@ -56,205 +54,31 @@ inline void deallocate(void* p, std::size_t s, Handler& h) } // namespace boost_asio_handler_alloc_helpers -namespace boost { -namespace asio { -namespace detail { - -// Traits for handler allocation. -template -struct handler_alloc_traits -{ - typedef Handler handler_type; - typedef Object value_type; - typedef Object* pointer_type; - BOOST_STATIC_CONSTANT(std::size_t, value_size = sizeof(Object)); -}; - -template -class handler_ptr; - -// Helper class to provide RAII on uninitialised handler memory. -template -class raw_handler_ptr - : private noncopyable -{ -public: - typedef typename Alloc_Traits::handler_type handler_type; - typedef typename Alloc_Traits::value_type value_type; - typedef typename Alloc_Traits::pointer_type pointer_type; - BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size); - - // Constructor allocates the memory. - raw_handler_ptr(handler_type& handler) - : handler_(handler), - pointer_(static_cast( - boost_asio_handler_alloc_helpers::allocate(value_size, handler_))) - { - } - - // Destructor automatically deallocates memory, unless it has been stolen by - // a handler_ptr object. - ~raw_handler_ptr() - { - if (pointer_) - boost_asio_handler_alloc_helpers::deallocate( - pointer_, value_size, handler_); - } - -private: - friend class handler_ptr; - handler_type& handler_; - pointer_type pointer_; -}; - -// Helper class to provide RAII on uninitialised handler memory. -template -class handler_ptr - : private noncopyable -{ -public: - typedef typename Alloc_Traits::handler_type handler_type; - typedef typename Alloc_Traits::value_type value_type; - typedef typename Alloc_Traits::pointer_type pointer_type; - BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size); - typedef raw_handler_ptr raw_ptr_type; - - // Take ownership of existing memory. - handler_ptr(handler_type& handler, pointer_type pointer) - : handler_(handler), - pointer_(pointer) - { - } - - // Construct object in raw memory and take ownership if construction succeeds. - handler_ptr(raw_ptr_type& raw_ptr) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4, - Arg5& a5) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4, - Arg5& a5, Arg6& a6) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4, - Arg5& a5, Arg6& a6, Arg7& a7) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6, a7)) - { - raw_ptr.pointer_ = 0; - } - - // Construct object in raw memory and take ownership if construction succeeds. - template - handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4, - Arg5& a5, Arg6& a6, Arg7& a7, Arg8& a8) - : handler_(raw_ptr.handler_), - pointer_(new (raw_ptr.pointer_) value_type( - a1, a2, a3, a4, a5, a6, a7, a8)) - { - raw_ptr.pointer_ = 0; - } - - // Destructor automatically deallocates memory, unless it has been released. - ~handler_ptr() - { - reset(); - } - - // Get the memory. - pointer_type get() const - { - return pointer_; - } - - // Release ownership of the memory. - pointer_type release() - { - pointer_type tmp = pointer_; - pointer_ = 0; - return tmp; - } - - // Explicitly destroy and deallocate the memory. - void reset() - { - if (pointer_) - { - pointer_->value_type::~value_type(); - boost_asio_handler_alloc_helpers::deallocate( - pointer_, value_size, handler_); - pointer_ = 0; - } - } - -private: - handler_type& handler_; - pointer_type pointer_; -}; - -} // namespace detail -} // namespace asio -} // namespace boost +#define BOOST_ASIO_DEFINE_HANDLER_PTR(op) \ + struct ptr \ + { \ + Handler* h; \ + void* v; \ + op* p; \ + ~ptr() \ + { \ + reset(); \ + } \ + void reset() \ + { \ + if (p) \ + { \ + p->~op(); \ + p = 0; \ + } \ + if (v) \ + { \ + boost_asio_handler_alloc_helpers::deallocate(v, sizeof(op), *h); \ + v = 0; \ + } \ + } \ + } \ + /**/ #include diff --git a/include/boost/asio/detail/handler_invoke_helpers.hpp b/include/boost/asio/detail/handler_invoke_helpers.hpp index 8952d8db..996bde9a 100644 --- a/include/boost/asio/detail/handler_invoke_helpers.hpp +++ b/include/boost/asio/detail/handler_invoke_helpers.hpp @@ -1,6 +1,6 @@ // -// handler_invoke_helpers.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/handler_invoke_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include - #include +#include + // Calls to asio_handler_invoke must be made from a namespace that does not // contain overloads of this function. The boost_asio_handler_invoke_helpers // namespace is defined here for that purpose. diff --git a/include/boost/asio/detail/hash_map.hpp b/include/boost/asio/detail/hash_map.hpp index 36c9a99b..c58096b5 100644 --- a/include/boost/asio/detail/hash_map.hpp +++ b/include/boost/asio/detail/hash_map.hpp @@ -1,6 +1,6 @@ // -// hash_map.hpp -// ~~~~~~~~~~~~ +// detail/hash_map.hpp +// ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,34 +15,39 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include -#include -#include - #include -#include + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# include +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#include namespace boost { namespace asio { namespace detail { -template -inline std::size_t calculate_hash_value(const T& t) +inline std::size_t calculate_hash_value(int i) { - return boost::hash_value(t); + return static_cast(i); } -#if defined(_WIN64) +inline std::size_t calculate_hash_value(void* p) +{ + return reinterpret_cast(p) + + (reinterpret_cast(p) >> 3); +} + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) inline std::size_t calculate_hash_value(SOCKET s) { return static_cast(s); } -#endif // defined(_WIN64) +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Note: assumes K and V are POD types. template diff --git a/include/boost/asio/detail/impl/descriptor_ops.ipp b/include/boost/asio/detail/impl/descriptor_ops.ipp new file mode 100644 index 00000000..00fa3118 --- /dev/null +++ b/include/boost/asio/detail/impl/descriptor_ops.ipp @@ -0,0 +1,357 @@ +// +// detail/impl/descriptor_ops.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_DESCRIPTOR_OPS_IPP +#define BOOST_ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include + +namespace boost { +namespace asio { +namespace detail { +namespace descriptor_ops { + +int open(const char* path, int flags, boost::system::error_code& ec) +{ + errno = 0; + int result = error_wrapper(::open(path, flags), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +} + +int close(int d, state_type& state, boost::system::error_code& ec) +{ + int result = 0; + if (d != -1) + { + if (state & internal_non_blocking) + { + ioctl_arg_type arg = 0; + ::ioctl(d, FIONBIO, &arg); + state &= ~internal_non_blocking; + } + + errno = 0; + result = error_wrapper(::close(d), ec); + } + + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +bool set_internal_non_blocking(int d, + state_type& state, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return false; + } + + errno = 0; + ioctl_arg_type arg = 1; + int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec); + + if (result >= 0) + { + ec = boost::system::error_code(); + state |= internal_non_blocking; + return true; + } + + return false; +} + +std::size_t sync_read(int d, state_type state, buf* bufs, + std::size_t count, bool all_empty, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (all_empty) + { + ec = boost::system::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + errno = 0; + int bytes = error_wrapper(::readv(d, bufs, static_cast(count)), ec); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if (bytes == 0) + { + ec = boost::asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_read(d, ec) < 0) + return 0; + } +} + +bool non_blocking_read(int d, buf* bufs, std::size_t count, + boost::system::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + errno = 0; + int bytes = error_wrapper(::readv(d, bufs, static_cast(count)), ec); + + // Check for end of stream. + if (bytes == 0) + { + ec = boost::asio::error::eof; + return 0; + } + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +std::size_t sync_write(int d, state_type state, const buf* bufs, + std::size_t count, bool all_empty, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a stream is a no-op. + if (all_empty) + { + ec = boost::system::error_code(); + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + errno = 0; + int bytes = error_wrapper(::writev(d, bufs, static_cast(count)), ec); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_write(d, ec) < 0) + return 0; + } +} + +bool non_blocking_write(int d, const buf* bufs, std::size_t count, + boost::system::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + errno = 0; + int bytes = error_wrapper(::writev(d, bufs, static_cast(count)), ec); + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +int ioctl(int d, state_type& state, long cmd, + ioctl_arg_type* arg, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + errno = 0; + int result = error_wrapper(::ioctl(d, cmd, arg), ec); + + if (result >= 0) + { + ec = boost::system::error_code(); + + // When updating the non-blocking mode we always perform the ioctl syscall, + // even if the flags would otherwise indicate that the descriptor is + // already in the correct state. This ensures that the underlying + // descriptor is put into the state that has been requested by the user. If + // the ioctl syscall was successful then we need to update the flags to + // match. + if (cmd == static_cast(FIONBIO)) + { + if (*arg) + { + state |= user_set_non_blocking; + } + else + { + // Clearing the non-blocking mode always overrides any internally-set + // non-blocking flag. Any subsequent asynchronous operations will need + // to re-enable non-blocking I/O. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + } + } + + return result; +} + +int fcntl(int d, long cmd, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + errno = 0; + int result = error_wrapper(::fcntl(d, cmd), ec); + if (result != -1) + ec = boost::system::error_code(); + return result; +} + +int fcntl(int d, long cmd, long arg, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + errno = 0; + int result = error_wrapper(::fcntl(d, cmd, arg), ec); + if (result != -1) + ec = boost::system::error_code(); + return result; +} + +int poll_read(int d, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + pollfd fds; + fds.fd = d; + fds.events = POLLIN; + fds.revents = 0; + errno = 0; + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +} + +int poll_write(int d, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + pollfd fds; + fds.fd = d; + fds.events = POLLOUT; + fds.revents = 0; + errno = 0; + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +} + +} // namespace descriptor_ops +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP diff --git a/include/boost/asio/detail/impl/dev_poll_reactor.hpp b/include/boost/asio/detail/impl/dev_poll_reactor.hpp new file mode 100644 index 00000000..d86faeba --- /dev/null +++ b/include/boost/asio/detail/impl/dev_poll_reactor.hpp @@ -0,0 +1,74 @@ +// +// detail/impl/dev_poll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_DEV_POLL_REACTOR_HPP +#define BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_DEV_POLL) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void dev_poll_reactor::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +template +void dev_poll_reactor::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void dev_poll_reactor::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + { + bool earliest = queue.enqueue_timer(time, op, token); + io_service_.work_started(); + if (earliest) + interrupter_.interrupt(); + } +} + +template +std::size_t dev_poll_reactor::cancel_timer( + timer_queue& queue, void* token) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(token, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); + return n; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_DEV_POLL) + +#endif // BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP diff --git a/include/boost/asio/detail/impl/dev_poll_reactor.ipp b/include/boost/asio/detail/impl/dev_poll_reactor.ipp new file mode 100644 index 00000000..8ea6297e --- /dev/null +++ b/include/boost/asio/detail/impl/dev_poll_reactor.ipp @@ -0,0 +1,337 @@ +// +// detail/impl/dev_poll_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_DEV_POLL_REACTOR_IPP +#define BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_DEV_POLL) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +dev_poll_reactor::dev_poll_reactor(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + io_service_(use_service(io_service)), + mutex_(), + dev_poll_fd_(do_dev_poll_create()), + interrupter_(), + shutdown_(false) +{ + // Add the interrupter's descriptor to /dev/poll. + ::pollfd ev = { 0 }; + ev.fd = interrupter_.read_descriptor(); + ev.events = POLLIN | POLLERR; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); +} + +dev_poll_reactor::~dev_poll_reactor() +{ + shutdown_service(); + ::close(dev_poll_fd_); +} + +void dev_poll_reactor::shutdown_service() +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue ops; + + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); + + timer_queues_.get_all_timers(ops); +} + +void dev_poll_reactor::init_task() +{ + io_service_.init_task(); +} + +int dev_poll_reactor::register_descriptor(socket_type, per_descriptor_data&) +{ + return 0; +} + +void dev_poll_reactor::start_op(int op_type, socket_type descriptor, + dev_poll_reactor::per_descriptor_data&, + reactor_op* op, bool allow_speculative) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + if (allow_speculative) + { + if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor)) + { + if (!op_queue_[op_type].has_operation(descriptor)) + { + if (op->perform()) + { + lock.unlock(); + io_service_.post_immediate_completion(op); + return; + } + } + } + } + + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + io_service_.work_started(); + if (first) + { + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLERR | POLLHUP; + if (op_type == read_op + || op_queue_[read_op].has_operation(descriptor)) + ev.events |= POLLIN; + if (op_type == write_op + || op_queue_[write_op].has_operation(descriptor)) + ev.events |= POLLOUT; + if (op_type == except_op + || op_queue_[except_op].has_operation(descriptor)) + ev.events |= POLLPRI; + interrupter_.interrupt(); + } +} + +void dev_poll_reactor::cancel_ops(socket_type descriptor, + dev_poll_reactor::per_descriptor_data&) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); +} + +void dev_poll_reactor::close_descriptor(socket_type descriptor, + dev_poll_reactor::per_descriptor_data&) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // Remove the descriptor from /dev/poll. + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLREMOVE; + interrupter_.interrupt(); + + // Cancel any outstanding operations associated with the descriptor. + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); +} + +void dev_poll_reactor::run(bool block, op_queue& 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() + && op_queue_[except_op].empty() && timer_queues_.all_empty()) + return; + + // Write the pending event registration changes to the /dev/poll descriptor. + std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size(); + if (events_size > 0) + { + errno = 0; + int result = ::write(dev_poll_fd_, + &pending_event_changes_[0], events_size); + if (result != static_cast(events_size)) + { + boost::system::error_code ec = boost::system::error_code( + errno, boost::asio::error::get_system_category()); + for (std::size_t i = 0; i < pending_event_changes_.size(); ++i) + { + int descriptor = pending_event_changes_[i].fd; + for (int j = 0; j < max_ops; ++j) + op_queue_[j].cancel_operations(descriptor, ops, ec); + } + } + pending_event_changes_.clear(); + pending_event_change_index_.clear(); + } + + int timeout = block ? get_timeout() : 0; + lock.unlock(); + + // Block on the /dev/poll descriptor. + ::pollfd events[128] = { { 0 } }; + ::dvpoll dp = { 0 }; + dp.dp_fds = events; + dp.dp_nfds = 128; + dp.dp_timeout = timeout; + int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp); + + lock.lock(); + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + int descriptor = events[i].fd; + if (descriptor == interrupter_.read_descriptor()) + { + interrupter_.reset(); + } + else + { + bool more_reads = false; + bool more_writes = false; + bool more_except = false; + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + if (events[i].events & (POLLPRI | POLLERR | POLLHUP)) + more_except = + op_queue_[except_op].perform_operations(descriptor, ops); + else + more_except = op_queue_[except_op].has_operation(descriptor); + + if (events[i].events & (POLLIN | POLLERR | POLLHUP)) + more_reads = op_queue_[read_op].perform_operations(descriptor, ops); + else + more_reads = op_queue_[read_op].has_operation(descriptor); + + if (events[i].events & (POLLOUT | POLLERR | POLLHUP)) + more_writes = op_queue_[write_op].perform_operations(descriptor, ops); + else + more_writes = op_queue_[write_op].has_operation(descriptor); + + if ((events[i].events & (POLLERR | POLLHUP)) != 0 + && !more_except && !more_reads && !more_writes) + { + // If we have an event and no operations associated with the + // descriptor then we need to delete the descriptor from /dev/poll. + // The poll operation can produce POLLHUP or POLLERR events when there + // is no operation pending, so if we do not remove the descriptor we + // can end up in a tight polling loop. + ::pollfd ev = { 0 }; + ev.fd = descriptor; + ev.events = POLLREMOVE; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); + } + else + { + ::pollfd ev = { 0 }; + ev.fd = descriptor; + ev.events = POLLERR | POLLHUP; + if (more_reads) + ev.events |= POLLIN; + if (more_writes) + ev.events |= POLLOUT; + if (more_except) + ev.events |= POLLPRI; + ev.revents = 0; + int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); + if (result != sizeof(ev)) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + for (int j = 0; j < max_ops; ++j) + op_queue_[j].cancel_operations(descriptor, ops, ec); + } + } + } + } + timer_queues_.get_ready_timers(ops); +} + +void dev_poll_reactor::interrupt() +{ + interrupter_.interrupt(); +} + +int dev_poll_reactor::do_dev_poll_create() +{ + int fd = ::open("/dev/poll", O_RDWR); + if (fd == -1) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "/dev/poll"); + } + return fd; +} + +void dev_poll_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void dev_poll_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +int dev_poll_reactor::get_timeout() +{ + // 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); +} + +void dev_poll_reactor::cancel_ops_unlocked(socket_type descriptor, + const boost::system::error_code& ec) +{ + bool need_interrupt = false; + op_queue ops; + 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); + if (need_interrupt) + interrupter_.interrupt(); +} + +::pollfd& dev_poll_reactor::add_pending_event_change(int descriptor) +{ + hash_map::iterator iter + = pending_event_change_index_.find(descriptor); + if (iter == pending_event_change_index_.end()) + { + std::size_t index = pending_event_changes_.size(); + pending_event_changes_.reserve(pending_event_changes_.size() + 1); + pending_event_change_index_.insert(std::make_pair(descriptor, index)); + pending_event_changes_.push_back(::pollfd()); + pending_event_changes_[index].fd = descriptor; + pending_event_changes_[index].revents = 0; + return pending_event_changes_[index]; + } + else + { + return pending_event_changes_[iter->second]; + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_DEV_POLL) + +#endif // BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP diff --git a/include/boost/asio/detail/impl/epoll_reactor.hpp b/include/boost/asio/detail/impl/epoll_reactor.hpp new file mode 100644 index 00000000..444ebc86 --- /dev/null +++ b/include/boost/asio/detail/impl/epoll_reactor.hpp @@ -0,0 +1,72 @@ +// +// detail/impl/epoll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_EPOLL_REACTOR_HPP +#define BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if defined(BOOST_ASIO_HAS_EPOLL) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void epoll_reactor::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +template +void epoll_reactor::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void epoll_reactor::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token) +{ + mutex::scoped_lock lock(mutex_); + if (!shutdown_) + { + bool earliest = queue.enqueue_timer(time, op, token); + io_service_.work_started(); + if (earliest) + update_timeout(); + } +} + +template +std::size_t epoll_reactor::cancel_timer( + timer_queue& queue, void* token) +{ + mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(token, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); + return n; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_EPOLL) + +#endif // BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP diff --git a/include/boost/asio/detail/impl/epoll_reactor.ipp b/include/boost/asio/detail/impl/epoll_reactor.ipp new file mode 100644 index 00000000..35c1a5c9 --- /dev/null +++ b/include/boost/asio/detail/impl/epoll_reactor.ipp @@ -0,0 +1,375 @@ +// +// detail/impl/epoll_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_EPOLL_REACTOR_IPP +#define BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_EPOLL) + +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_TIMERFD) +# include +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + +#include + +namespace boost { +namespace asio { +namespace detail { + +epoll_reactor::epoll_reactor(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + io_service_(use_service(io_service)), + mutex_(), + epoll_fd_(do_epoll_create()), +#if defined(BOOST_ASIO_HAS_TIMERFD) + timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)), +#else // defined(BOOST_ASIO_HAS_TIMERFD) + timer_fd_(-1), +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + interrupter_(), + shutdown_(false) +{ + // Add the interrupter's descriptor to epoll. + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLET; + ev.data.ptr = &interrupter_; + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); + interrupter_.interrupt(); + + // Add the timer descriptor to epoll. + if (timer_fd_ != -1) + { + ev.events = EPOLLIN | EPOLLERR; + ev.data.ptr = &timer_fd_; + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); + } +} + +epoll_reactor::~epoll_reactor() +{ + close(epoll_fd_); + if (timer_fd_ != -1) + close(timer_fd_); +} + +void epoll_reactor::shutdown_service() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue ops; + + descriptor_map::iterator iter = registered_descriptors_.begin(); + descriptor_map::iterator end = registered_descriptors_.end(); + while (iter != end) + { + for (int i = 0; i < max_ops; ++i) + ops.push(iter->second.op_queue_[i]); + iter->second.shutdown_ = true; + ++iter; + } + + timer_queues_.get_all_timers(ops); +} + +void epoll_reactor::init_task() +{ + io_service_.init_task(); +} + +int epoll_reactor::register_descriptor(socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + mutex::scoped_lock lock(registered_descriptors_mutex_); + + descriptor_map::iterator new_entry = registered_descriptors_.insert( + std::make_pair(descriptor, descriptor_state())).first; + descriptor_data = &new_entry->second; + + descriptor_data->shutdown_ = false; + + lock.unlock(); + + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET; + ev.data.ptr = descriptor_data; + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); + if (result != 0) + return errno; + + return 0; +} + +void epoll_reactor::start_op(int op_type, socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data, + reactor_op* op, bool allow_speculative) +{ + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + if (descriptor_data->shutdown_) + return; + + if (descriptor_data->op_queue_[op_type].empty()) + { + if (allow_speculative + && (op_type != read_op + || descriptor_data->op_queue_[except_op].empty())) + { + if (op->perform()) + { + descriptor_lock.unlock(); + io_service_.post_immediate_completion(op); + return; + } + } + else + { + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP + | EPOLLOUT | EPOLLPRI | EPOLLET; + ev.data.ptr = descriptor_data; + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + } + } + + descriptor_data->op_queue_[op_type].push(op); + io_service_.work_started(); +} + +void epoll_reactor::cancel_ops(socket_type, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + io_service_.post_deferred_completions(ops); +} + +void epoll_reactor::close_descriptor(socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + + // Remove the descriptor from the set of known descriptors. The descriptor + // will be automatically removed from the epoll set when it is closed. + descriptor_data->shutdown_ = true; + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + registered_descriptors_.erase(descriptor); + + descriptors_lock.unlock(); + + io_service_.post_deferred_completions(ops); +} + +void epoll_reactor::run(bool block, op_queue& ops) +{ + // Calculate a timeout only if timerfd is not used. + int timeout; + if (timer_fd_ != -1) + timeout = block ? -1 : 0; + else + { + mutex::scoped_lock lock(mutex_); + timeout = block ? get_timeout() : 0; + } + + // Block on the epoll descriptor. + epoll_event events[128]; + int num_events = epoll_wait(epoll_fd_, events, 128, timeout); + +#if defined(BOOST_ASIO_HAS_TIMERFD) + bool check_timers = (timer_fd_ == -1); +#else // defined(BOOST_ASIO_HAS_TIMERFD) + bool check_timers = true; +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = events[i].data.ptr; + if (ptr == &interrupter_) + { + // No need to reset the interrupter since we're leaving the descriptor + // in a ready-to-read state and relying on edge-triggered notifications + // to make it so that we only get woken up when the descriptor's epoll + // registration is updated. + +#if defined(BOOST_ASIO_HAS_TIMERFD) + if (timer_fd_ == -1) + check_timers = true; +#else // defined(BOOST_ASIO_HAS_TIMERFD) + check_timers = true; +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + } +#if defined(BOOST_ASIO_HAS_TIMERFD) + else if (ptr == &timer_fd_) + { + check_timers = true; + } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + else + { + descriptor_state* descriptor_data = static_cast(ptr); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI }; + for (int j = max_ops - 1; j >= 0; --j) + { + if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP)) + { + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + if (op->perform()) + { + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + else + break; + } + } + } + } + } + + if (check_timers) + { + mutex::scoped_lock common_lock(mutex_); + timer_queues_.get_ready_timers(ops); + +#if defined(BOOST_ASIO_HAS_TIMERFD) + if (timer_fd_ != -1) + { + itimerspec new_timeout; + itimerspec old_timeout; + int flags = get_timeout(new_timeout); + timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); + } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + } +} + +void epoll_reactor::interrupt() +{ + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLET; + ev.data.ptr = &interrupter_; + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev); +} + +int epoll_reactor::do_epoll_create() +{ + int fd = epoll_create(epoll_size); + if (fd == -1) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "epoll"); + } + return fd; +} + +void epoll_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void epoll_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +void epoll_reactor::update_timeout() +{ +#if defined(BOOST_ASIO_HAS_TIMERFD) + if (timer_fd_ != -1) + { + itimerspec new_timeout; + itimerspec old_timeout; + int flags = get_timeout(new_timeout); + timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); + return; + } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + interrupter_.interrupt(); +} + +int epoll_reactor::get_timeout() +{ + // 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); +} + +#if defined(BOOST_ASIO_HAS_TIMERFD) +int epoll_reactor::get_timeout(itimerspec& ts) +{ + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + + long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + ts.it_value.tv_sec = usec / 1000000; + ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1; + + return usec ? 0 : TFD_TIMER_ABSTIME; +} +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_EPOLL) + +#endif // BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP diff --git a/include/boost/asio/detail/impl/eventfd_select_interrupter.ipp b/include/boost/asio/detail/impl/eventfd_select_interrupter.ipp new file mode 100644 index 00000000..5bcc55be --- /dev/null +++ b/include/boost/asio/detail/impl/eventfd_select_interrupter.ipp @@ -0,0 +1,127 @@ +// +// detail/impl/eventfd_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Roelof Naude (roelof.naude 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_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP +#define BOOST_ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_EVENTFD) + +#include +#include +#include +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +# include +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +# include +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +eventfd_select_interrupter::eventfd_select_interrupter() +{ +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0); +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + write_descriptor_ = read_descriptor_ = ::eventfd(0, 0); +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + if (read_descriptor_ != -1) + { + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + } + else + { + int pipe_fds[2]; + if (pipe(pipe_fds) == 0) + { + read_descriptor_ = pipe_fds[0]; + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + write_descriptor_ = pipe_fds[1]; + ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); + } + else + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "eventfd_select_interrupter"); + } + } +} + +eventfd_select_interrupter::~eventfd_select_interrupter() +{ + if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_) + ::close(write_descriptor_); + if (read_descriptor_ != -1) + ::close(read_descriptor_); +} + +void eventfd_select_interrupter::interrupt() +{ + uint64_t counter(1UL); + int result = ::write(write_descriptor_, &counter, sizeof(uint64_t)); + (void)result; +} + +bool eventfd_select_interrupter::reset() +{ + if (write_descriptor_ == read_descriptor_) + { + for (;;) + { + // Only perform one read. The kernel maintains an atomic counter. + uint64_t counter(0); + errno = 0; + int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t)); + if (bytes_read < 0 && errno == EINTR) + continue; + bool was_interrupted = (bytes_read > 0); + return was_interrupted; + } + } + else + { + for (;;) + { + // Clear all data from the pipe. + char data[1024]; + int bytes_read = ::read(read_descriptor_, data, sizeof(data)); + if (bytes_read < 0 && errno == EINTR) + continue; + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = ::read(read_descriptor_, data, sizeof(data)); + return was_interrupted; + } + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_EVENTFD) + +#endif // BOOST_ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP diff --git a/include/boost/asio/detail/impl/kqueue_reactor.hpp b/include/boost/asio/detail/impl/kqueue_reactor.hpp new file mode 100644 index 00000000..9719086b --- /dev/null +++ b/include/boost/asio/detail/impl/kqueue_reactor.hpp @@ -0,0 +1,76 @@ +// +// detail/impl/kqueue_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze 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_KQUEUE_REACTOR_HPP +#define BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_KQUEUE) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void kqueue_reactor::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +// Remove a timer queue from the reactor. +template +void kqueue_reactor::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void kqueue_reactor::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + { + bool earliest = queue.enqueue_timer(time, op, token); + io_service_.work_started(); + if (earliest) + interrupter_.interrupt(); + } +} + +template +std::size_t kqueue_reactor::cancel_timer( + timer_queue& queue, void* token) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(token, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); + return n; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_KQUEUE) + +#endif // BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP diff --git a/include/boost/asio/detail/impl/kqueue_reactor.ipp b/include/boost/asio/detail/impl/kqueue_reactor.ipp new file mode 100644 index 00000000..8d3dcc04 --- /dev/null +++ b/include/boost/asio/detail/impl/kqueue_reactor.ipp @@ -0,0 +1,355 @@ +// +// detail/impl/kqueue_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze 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_KQUEUE_REACTOR_IPP +#define BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_KQUEUE) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +kqueue_reactor::kqueue_reactor(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + io_service_(use_service(io_service)), + mutex_(), + kqueue_fd_(do_kqueue_create()), + interrupter_(), + shutdown_(false) +{ + // The interrupter is put into a permanently readable state. Whenever we + // want to interrupt the blocked kevent call we register a one-shot read + // operation against the descriptor. + interrupter_.interrupt(); +} + +kqueue_reactor::~kqueue_reactor() +{ + close(kqueue_fd_); +} + +void kqueue_reactor::shutdown_service() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue ops; + + descriptor_map::iterator iter = registered_descriptors_.begin(); + descriptor_map::iterator end = registered_descriptors_.end(); + while (iter != end) + { + for (int i = 0; i < max_ops; ++i) + ops.push(iter->second.op_queue_[i]); + iter->second.shutdown_ = true; + ++iter; + } + + timer_queues_.get_all_timers(ops); +} + +void kqueue_reactor::init_task() +{ + io_service_.init_task(); +} + +int kqueue_reactor::register_descriptor(socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + mutex::scoped_lock lock(registered_descriptors_mutex_); + + descriptor_map::iterator new_entry = registered_descriptors_.insert( + std::make_pair(descriptor, descriptor_state())).first; + descriptor_data = &new_entry->second; + + descriptor_data->shutdown_ = false; + + return 0; +} + +void kqueue_reactor::start_op(int op_type, socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data, + reactor_op* op, bool allow_speculative) +{ + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + if (descriptor_data->shutdown_) + return; + + bool first = descriptor_data->op_queue_[op_type].empty(); + if (first) + { + if (allow_speculative) + { + if (op_type != read_op || descriptor_data->op_queue_[except_op].empty()) + { + if (op->perform()) + { + descriptor_lock.unlock(); + io_service_.post_immediate_completion(op); + return; + } + } + } + } + + descriptor_data->op_queue_[op_type].push(op); + io_service_.work_started(); + + if (first) + { + struct kevent event; + switch (op_type) + { + case read_op: + EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + break; + case write_op: + EV_SET(&event, descriptor, EVFILT_WRITE, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + break; + case except_op: + if (!descriptor_data->op_queue_[read_op].empty()) + return; // Already registered for read events. + EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); + break; + } + + if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) + { + op->ec_ = boost::system::error_code(errno, + boost::asio::error::get_system_category()); + descriptor_data->op_queue_[op_type].pop(); + io_service_.post_deferred_completion(op); + } + } +} + +void kqueue_reactor::cancel_ops(socket_type, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + io_service_.post_deferred_completions(ops); +} + +void kqueue_reactor::close_descriptor(socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + + // Remove the descriptor from the set of known descriptors. The descriptor + // will be automatically removed from the kqueue set when it is closed. + descriptor_data->shutdown_ = true; + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + registered_descriptors_.erase(descriptor); + + descriptors_lock.unlock(); + + io_service_.post_deferred_completions(ops); +} + +void kqueue_reactor::run(bool block, op_queue& 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; + + lock.unlock(); + + // Block on the kqueue descriptor. + struct kevent events[128]; + int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout); + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + int descriptor = events[i].ident; + void* ptr = events[i].udata; + if (ptr == &interrupter_) + { + // No need to reset the interrupter since we're leaving the descriptor + // in a ready-to-read state and relying on one-shot notifications. + } + else + { + descriptor_state* descriptor_data = static_cast(ptr); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + static const int filter[max_ops] = + { EVFILT_READ, EVFILT_WRITE, EVFILT_READ }; + for (int j = max_ops - 1; j >= 0; --j) + { + if (events[i].filter == filter[j]) + { + if (j != except_op || events[i].flags & EV_OOBAND) + { + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + if (events[i].flags & EV_ERROR) + { + op->ec_ = boost::system::error_code(events[i].data, + boost::asio::error::get_system_category()); + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + if (op->perform()) + { + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + else + break; + } + } + } + } + + // Renew registration for event notifications. + struct kevent event; + switch (events[i].filter) + { + case EVFILT_READ: + if (!descriptor_data->op_queue_[read_op].empty()) + EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + else if (!descriptor_data->op_queue_[except_op].empty()) + EV_SET(&event, descriptor, EVFILT_READ, + EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); + else + continue; + case EVFILT_WRITE: + if (!descriptor_data->op_queue_[write_op].empty()) + EV_SET(&event, descriptor, EVFILT_WRITE, + EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); + else + continue; + default: + break; + } + if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) + { + boost::system::error_code error(errno, + boost::asio::error::get_system_category()); + for (int j = 0; j < max_ops; ++j) + { + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + op->ec_ = error; + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + } + } + } + } + + lock.lock(); + timer_queues_.get_ready_timers(ops); +} + +void kqueue_reactor::interrupt() +{ + struct kevent event; + EV_SET(&event, interrupter_.read_descriptor(), + EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &interrupter_); + ::kevent(kqueue_fd_, &event, 1, 0, 0, 0); +} + +int kqueue_reactor::do_kqueue_create() +{ + int fd = ::kqueue(); + if (fd == -1) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "kqueue"); + } + return fd; +} + +void kqueue_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void kqueue_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +timespec* kqueue_reactor::get_timeout(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); + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + return &ts; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_KQUEUE) + +#endif // BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP diff --git a/include/boost/asio/detail/impl/pipe_select_interrupter.ipp b/include/boost/asio/detail/impl/pipe_select_interrupter.ipp new file mode 100644 index 00000000..62a047fa --- /dev/null +++ b/include/boost/asio/detail/impl/pipe_select_interrupter.ipp @@ -0,0 +1,94 @@ +// +// detail/impl/pipe_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_PIPE_SELECT_INTERRUPTER_IPP +#define BOOST_ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#if !defined(BOOST_ASIO_HAS_EVENTFD) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +pipe_select_interrupter::pipe_select_interrupter() +{ + int pipe_fds[2]; + if (pipe(pipe_fds) == 0) + { + read_descriptor_ = pipe_fds[0]; + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + write_descriptor_ = pipe_fds[1]; + ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); + } + else + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "pipe_select_interrupter"); + } +} + +pipe_select_interrupter::~pipe_select_interrupter() +{ + if (read_descriptor_ != -1) + ::close(read_descriptor_); + if (write_descriptor_ != -1) + ::close(write_descriptor_); +} + +void pipe_select_interrupter::interrupt() +{ + char byte = 0; + int result = ::write(write_descriptor_, &byte, 1); + (void)result; +} + +bool pipe_select_interrupter::reset() +{ + for (;;) + { + char data[1024]; + int bytes_read = ::read(read_descriptor_, data, sizeof(data)); + if (bytes_read < 0 && errno == EINTR) + continue; + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = ::read(read_descriptor_, data, sizeof(data)); + return was_interrupted; + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_HAS_EVENTFD) +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP diff --git a/include/boost/asio/detail/impl/posix_event.ipp b/include/boost/asio/detail/impl/posix_event.ipp new file mode 100644 index 00000000..7e89b6c1 --- /dev/null +++ b/include/boost/asio/detail/impl/posix_event.ipp @@ -0,0 +1,48 @@ +// +// detail/impl/posix_event.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_POSIX_EVENT_IPP +#define BOOST_ASIO_DETAIL_IMPL_POSIX_EVENT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +posix_event::posix_event() + : signalled_(false) +{ + int error = ::pthread_cond_init(&cond_, 0); + boost::system::error_code ec(error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "event"); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + +#endif // BOOST_ASIO_DETAIL_IMPL_POSIX_EVENT_IPP diff --git a/include/boost/asio/detail/impl/posix_mutex.ipp b/include/boost/asio/detail/impl/posix_mutex.ipp new file mode 100644 index 00000000..a4f81bb1 --- /dev/null +++ b/include/boost/asio/detail/impl/posix_mutex.ipp @@ -0,0 +1,48 @@ +// +// detail/impl/posix_mutex.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_POSIX_MUTEX_IPP +#define BOOST_ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +posix_mutex::posix_mutex() +{ + int error = ::pthread_mutex_init(&mutex_, 0); + boost::system::error_code ec(error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "mutex"); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + +#endif // BOOST_ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP diff --git a/include/boost/asio/detail/impl/posix_thread.ipp b/include/boost/asio/detail/impl/posix_thread.ipp new file mode 100644 index 00000000..5dc41fa0 --- /dev/null +++ b/include/boost/asio/detail/impl/posix_thread.ipp @@ -0,0 +1,76 @@ +// +// detail/impl/posix_thread.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_POSIX_THREAD_IPP +#define BOOST_ASIO_DETAIL_IMPL_POSIX_THREAD_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +posix_thread::~posix_thread() +{ + if (!joined_) + ::pthread_detach(thread_); +} + +void posix_thread::join() +{ + if (!joined_) + { + ::pthread_join(thread_, 0); + joined_ = true; + } +} + +void posix_thread::start_thread(func_base* arg) +{ + int error = ::pthread_create(&thread_, 0, + boost_asio_detail_posix_thread_function, arg); + if (error != 0) + { + delete arg; + boost::system::error_code ec(error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread"); + } +} + +void* boost_asio_detail_posix_thread_function(void* arg) +{ + posix_thread::auto_func_base_ptr func = { + static_cast(arg) }; + func.ptr->run(); + return 0; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + +#endif // BOOST_ASIO_DETAIL_IMPL_POSIX_THREAD_IPP diff --git a/include/boost/asio/detail/impl/posix_tss_ptr.ipp b/include/boost/asio/detail/impl/posix_tss_ptr.ipp new file mode 100644 index 00000000..1c626e58 --- /dev/null +++ b/include/boost/asio/detail/impl/posix_tss_ptr.ipp @@ -0,0 +1,48 @@ +// +// detail/impl/posix_tss_ptr.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_POSIX_TSS_PTR_IPP +#define BOOST_ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +void posix_tss_ptr_create(pthread_key_t& key) +{ + int error = ::pthread_key_create(&key, 0); + boost::system::error_code ec(error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "tss"); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + +#endif // BOOST_ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP diff --git a/include/boost/asio/detail/impl/reactive_descriptor_service.ipp b/include/boost/asio/detail/impl/reactive_descriptor_service.ipp new file mode 100644 index 00000000..6f0dc5aa --- /dev/null +++ b/include/boost/asio/detail/impl/reactive_descriptor_service.ipp @@ -0,0 +1,138 @@ +// +// detail/impl/reactive_descriptor_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_REACTIVE_DESCRIPTOR_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +reactive_descriptor_service::reactive_descriptor_service( + boost::asio::io_service& io_service) + : reactor_(boost::asio::use_service(io_service)) +{ + reactor_.init_task(); +} + +void reactive_descriptor_service::shutdown_service() +{ +} + +void reactive_descriptor_service::construct( + reactive_descriptor_service::implementation_type& impl) +{ + impl.descriptor_ = -1; + impl.state_ = 0; +} + +void reactive_descriptor_service::destroy( + reactive_descriptor_service::implementation_type& impl) +{ + if (is_open(impl)) + reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_); + + boost::system::error_code ignored_ec; + descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec); +} + +boost::system::error_code reactive_descriptor_service::assign( + reactive_descriptor_service::implementation_type& impl, + const native_type& native_descriptor, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + if (int err = reactor_.register_descriptor( + native_descriptor, impl.reactor_data_)) + { + ec = boost::system::error_code(err, + boost::asio::error::get_system_category()); + return ec; + } + + impl.descriptor_ = native_descriptor; + impl.state_ = 0; + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code reactive_descriptor_service::close( + reactive_descriptor_service::implementation_type& impl, + boost::system::error_code& ec) +{ + if (is_open(impl)) + reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_); + + if (descriptor_ops::close(impl.descriptor_, impl.state_, ec) == 0) + construct(impl); + + return ec; +} + +boost::system::error_code reactive_descriptor_service::cancel( + reactive_descriptor_service::implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_); + ec = boost::system::error_code(); + return ec; +} + +void reactive_descriptor_service::start_op( + reactive_descriptor_service::implementation_type& impl, + int op_type, reactor_op* op, bool non_blocking, bool noop) +{ + if (!noop) + { + if ((impl.state_ & descriptor_ops::non_blocking) || + descriptor_ops::set_internal_non_blocking( + impl.descriptor_, impl.state_, op->ec_)) + { + reactor_.start_op(op_type, impl.descriptor_, + impl.reactor_data_, op, non_blocking); + return; + } + } + + reactor_.post_immediate_completion(op); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP diff --git a/include/boost/asio/detail/impl/reactive_serial_port_service.ipp b/include/boost/asio/detail/impl/reactive_serial_port_service.ipp new file mode 100644 index 00000000..b4672099 --- /dev/null +++ b/include/boost/asio/detail/impl/reactive_serial_port_service.ipp @@ -0,0 +1,153 @@ +// +// detail/impl/reactive_serial_port_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_REACTIVE_SERIAL_PORT_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_SERIAL_PORT) +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +reactive_serial_port_service::reactive_serial_port_service( + boost::asio::io_service& io_service) + : descriptor_service_(io_service) +{ +} + +void reactive_serial_port_service::shutdown_service() +{ + descriptor_service_.shutdown_service(); +} + +boost::system::error_code reactive_serial_port_service::open( + reactive_serial_port_service::implementation_type& impl, + const std::string& device, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + descriptor_ops::state_type state = 0; + int fd = descriptor_ops::open(device.c_str(), + O_RDWR | O_NONBLOCK | O_NOCTTY, ec); + if (fd < 0) + return ec; + + int s = descriptor_ops::fcntl(fd, F_GETFL, ec); + if (s >= 0) + s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec); + if (s < 0) + { + boost::system::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + return ec; + } + + // Set up default serial port options. + termios ios; + errno = 0; + s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec); + if (s >= 0) + { +#if defined(_BSD_SOURCE) + ::cfmakeraw(&ios); +#else + ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK + | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + ios.c_oflag &= ~OPOST; + ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + ios.c_cflag &= ~(CSIZE | PARENB); + ios.c_cflag |= CS8; +#endif + ios.c_iflag |= IGNPAR; + ios.c_cflag |= CREAD | CLOCAL; + errno = 0; + s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec); + } + if (s < 0) + { + boost::system::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + return ec; + } + + // We're done. Take ownership of the serial port descriptor. + if (descriptor_service_.assign(impl, fd, ec)) + { + boost::system::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + } + + return ec; +} + +boost::system::error_code reactive_serial_port_service::do_set_option( + reactive_serial_port_service::implementation_type& impl, + reactive_serial_port_service::store_function_type store, + const void* option, boost::system::error_code& ec) +{ + termios ios; + errno = 0; + descriptor_ops::error_wrapper(::tcgetattr( + descriptor_service_.native(impl), &ios), ec); + if (ec) + return ec; + + if (store(option, ios, ec)) + return ec; + + errno = 0; + descriptor_ops::error_wrapper(::tcsetattr( + descriptor_service_.native(impl), TCSANOW, &ios), ec); + return ec; +} + +boost::system::error_code reactive_serial_port_service::do_get_option( + const reactive_serial_port_service::implementation_type& impl, + reactive_serial_port_service::load_function_type load, + void* option, boost::system::error_code& ec) const +{ + termios ios; + errno = 0; + descriptor_ops::error_wrapper(::tcgetattr( + descriptor_service_.native(impl), &ios), ec); + if (ec) + return ec; + + return load(option, ios, ec); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP diff --git a/include/boost/asio/detail/impl/reactive_socket_service_base.ipp b/include/boost/asio/detail/impl/reactive_socket_service_base.ipp new file mode 100644 index 00000000..cecbe73a --- /dev/null +++ b/include/boost/asio/detail/impl/reactive_socket_service_base.ipp @@ -0,0 +1,214 @@ +// +// detail/reactive_socket_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_REACTIVE_SOCKET_SERVICE_BASE_IPP +#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_IOCP) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +reactive_socket_service_base::reactive_socket_service_base( + boost::asio::io_service& io_service) + : reactor_(use_service(io_service)) +{ + reactor_.init_task(); +} + +void reactive_socket_service_base::shutdown_service() +{ +} + +void reactive_socket_service_base::construct( + reactive_socket_service_base::base_implementation_type& impl) +{ + impl.socket_ = invalid_socket; + impl.state_ = 0; +} + +void reactive_socket_service_base::destroy( + reactive_socket_service_base::base_implementation_type& impl) +{ + if (impl.socket_ != invalid_socket) + { + reactor_.close_descriptor(impl.socket_, impl.reactor_data_); + + boost::system::error_code ignored_ec; + socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); + } +} + +boost::system::error_code reactive_socket_service_base::close( + reactive_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (is_open(impl)) + reactor_.close_descriptor(impl.socket_, impl.reactor_data_); + + if (socket_ops::close(impl.socket_, impl.state_, true, ec) == 0) + construct(impl); + + return ec; +} + +boost::system::error_code reactive_socket_service_base::cancel( + reactive_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + reactor_.cancel_ops(impl.socket_, impl.reactor_data_); + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code reactive_socket_service_base::do_open( + reactive_socket_service_base::base_implementation_type& impl, + int af, int type, int protocol, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + socket_holder sock(socket_ops::socket(af, type, protocol, ec)); + if (sock.get() == invalid_socket) + return ec; + + if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_)) + { + ec = boost::system::error_code(err, + boost::asio::error::get_system_category()); + return ec; + } + + impl.socket_ = sock.release(); + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code reactive_socket_service_base::do_assign( + reactive_socket_service_base::base_implementation_type& impl, int type, + const reactive_socket_service_base::native_type& native_socket, + boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + if (int err = reactor_.register_descriptor( + native_socket, impl.reactor_data_)) + { + ec = boost::system::error_code(err, + boost::asio::error::get_system_category()); + return ec; + } + + impl.socket_ = native_socket; + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + ec = boost::system::error_code(); + return ec; +} + +void reactive_socket_service_base::start_op( + reactive_socket_service_base::base_implementation_type& impl, + int op_type, reactor_op* op, bool non_blocking, bool noop) +{ + if (!noop) + { + if ((impl.state_ & socket_ops::non_blocking) + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, op->ec_)) + { + reactor_.start_op(op_type, impl.socket_, + impl.reactor_data_, op, non_blocking); + return; + } + } + + reactor_.post_immediate_completion(op); +} + +void reactive_socket_service_base::start_accept_op( + reactive_socket_service_base::base_implementation_type& impl, + reactor_op* op, bool peer_is_open) +{ + if (!peer_is_open) + start_op(impl, reactor::read_op, op, true, false); + else + { + op->ec_ = boost::asio::error::already_open; + reactor_.post_immediate_completion(op); + } +} + +void reactive_socket_service_base::start_connect_op( + reactive_socket_service_base::base_implementation_type& impl, + reactor_op* op, const socket_addr_type* addr, size_t addrlen) +{ + if ((impl.state_ & socket_ops::non_blocking) + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, op->ec_)) + { + if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0) + { + if (op->ec_ == boost::asio::error::in_progress + || op->ec_ == boost::asio::error::would_block) + { + op->ec_ = boost::system::error_code(); + reactor_.start_op(reactor::connect_op, + impl.socket_, impl.reactor_data_, op, false); + return; + } + } + } + + reactor_.post_immediate_completion(op); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP diff --git a/include/boost/asio/detail/impl/resolver_service_base.ipp b/include/boost/asio/detail/impl/resolver_service_base.ipp new file mode 100644 index 00000000..d1af0be4 --- /dev/null +++ b/include/boost/asio/detail/impl/resolver_service_base.ipp @@ -0,0 +1,108 @@ +// +// detail/impl/resolver_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_RESOLVER_SERVICE_BASE_IPP +#define BOOST_ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class resolver_service_base::work_io_service_runner +{ +public: + work_io_service_runner(boost::asio::io_service& io_service) + : io_service_(io_service) {} + void operator()() { io_service_.run(); } +private: + boost::asio::io_service& io_service_; +}; + +resolver_service_base::resolver_service_base( + boost::asio::io_service& io_service) + : io_service_impl_(boost::asio::use_service(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_)), + work_thread_(0) +{ +} + +resolver_service_base::~resolver_service_base() +{ + shutdown_service(); +} + +void resolver_service_base::shutdown_service() +{ + work_.reset(); + if (work_io_service_) + { + work_io_service_->stop(); + if (work_thread_) + { + work_thread_->join(); + work_thread_.reset(); + } + work_io_service_.reset(); + } +} + +void resolver_service_base::construct( + resolver_service_base::implementation_type& impl) +{ + impl.reset(static_cast(0), socket_ops::noop_deleter()); +} + +void resolver_service_base::destroy( + resolver_service_base::implementation_type&) +{ +} + +void resolver_service_base::cancel( + resolver_service_base::implementation_type& impl) +{ + impl.reset(static_cast(0), socket_ops::noop_deleter()); +} + +void resolver_service_base::start_resolve_op(operation* op) +{ + start_work_thread(); + io_service_impl_.work_started(); + work_io_service_impl_.post_immediate_completion(op); +} + +void resolver_service_base::start_work_thread() +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!work_thread_) + { + work_thread_.reset(new boost::asio::detail::thread( + work_io_service_runner(*work_io_service_))); + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP diff --git a/include/boost/asio/detail/impl/select_reactor.hpp b/include/boost/asio/detail/impl/select_reactor.hpp new file mode 100644 index 00000000..e4595746 --- /dev/null +++ b/include/boost/asio/detail/impl/select_reactor.hpp @@ -0,0 +1,81 @@ +// +// detail/impl/select_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SELECT_REACTOR_HPP +#define BOOST_ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) \ + || (!defined(BOOST_ASIO_HAS_DEV_POLL) \ + && !defined(BOOST_ASIO_HAS_EPOLL) \ + && !defined(BOOST_ASIO_HAS_KQUEUE)) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void select_reactor::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +// Remove a timer queue from the reactor. +template +void select_reactor::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void select_reactor::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + { + bool earliest = queue.enqueue_timer(time, op, token); + io_service_.work_started(); + if (earliest) + interrupter_.interrupt(); + } +} + +template +std::size_t select_reactor::cancel_timer( + timer_queue& queue, void* token) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(token, ops); + lock.unlock(); + io_service_.post_deferred_completions(ops); + return n; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + // || (!defined(BOOST_ASIO_HAS_DEV_POLL) + // && !defined(BOOST_ASIO_HAS_EPOLL) + // && !defined(BOOST_ASIO_HAS_KQUEUE)) + +#endif // BOOST_ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP diff --git a/include/boost/asio/detail/impl/select_reactor.ipp b/include/boost/asio/detail/impl/select_reactor.ipp new file mode 100644 index 00000000..26582d36 --- /dev/null +++ b/include/boost/asio/detail/impl/select_reactor.ipp @@ -0,0 +1,271 @@ +// +// detail/impl/select_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SELECT_REACTOR_IPP +#define BOOST_ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) \ + || (!defined(BOOST_ASIO_HAS_DEV_POLL) \ + && !defined(BOOST_ASIO_HAS_EPOLL) \ + && !defined(BOOST_ASIO_HAS_KQUEUE)) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +select_reactor::select_reactor(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + io_service_(use_service(io_service)), + mutex_(), + interrupter_(), +#if defined(BOOST_ASIO_HAS_IOCP) + stop_thread_(false), + thread_(0), +#endif // defined(BOOST_ASIO_HAS_IOCP) + shutdown_(false) +{ +#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)); +#endif // defined(BOOST_ASIO_HAS_IOCP) +} + +select_reactor::~select_reactor() +{ + shutdown_service(); +} + +void select_reactor::shutdown_service() +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; +#if defined(BOOST_ASIO_HAS_IOCP) + stop_thread_ = true; +#endif // defined(BOOST_ASIO_HAS_IOCP) + lock.unlock(); + +#if defined(BOOST_ASIO_HAS_IOCP) + if (thread_) + { + interrupter_.interrupt(); + thread_->join(); + delete thread_; + thread_ = 0; + } +#endif // defined(BOOST_ASIO_HAS_IOCP) + + op_queue ops; + + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); + + timer_queues_.get_all_timers(ops); +} + +void select_reactor::init_task() +{ + io_service_.init_task(); +} + +int select_reactor::register_descriptor(socket_type, + select_reactor::per_descriptor_data&) +{ + return 0; +} + +void select_reactor::start_op(int op_type, socket_type descriptor, + select_reactor::per_descriptor_data&, reactor_op* op, bool) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + { + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + io_service_.work_started(); + if (first) + interrupter_.interrupt(); + } +} + +void select_reactor::cancel_ops(socket_type descriptor, + select_reactor::per_descriptor_data&) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); +} + +void select_reactor::close_descriptor(socket_type descriptor, + select_reactor::per_descriptor_data&) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); +} + +void select_reactor::run(bool block, op_queue& ops) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + +#if defined(BOOST_ASIO_HAS_IOCP) + // Check if the thread is supposed to stop. + if (stop_thread_) + return; +#endif // defined(BOOST_ASIO_HAS_IOCP) + + // Set up the descriptor sets. + fd_set_adapter fds[max_select_ops]; + fds[read_op].set(interrupter_.read_descriptor()); + socket_type max_fd = 0; + bool have_work_to_do = !timer_queues_.all_empty(); + for (int i = 0; i < max_select_ops; ++i) + { + have_work_to_do = have_work_to_do || !op_queue_[i].empty(); + op_queue_[i].get_descriptors(fds[i], ops); + if (fds[i].max_descriptor() > max_fd) + max_fd = fds[i].max_descriptor(); + } + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Connection operations on Windows use both except and write fd_sets. + have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty(); + op_queue_[connect_op].get_descriptors(fds[write_op], ops); + if (fds[write_op].max_descriptor() > max_fd) + max_fd = fds[write_op].max_descriptor(); + op_queue_[connect_op].get_descriptors(fds[except_op], ops); + if (fds[except_op].max_descriptor() > max_fd) + max_fd = fds[except_op].max_descriptor(); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + + // 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) + return; + + // Determine how long to block while waiting for events. + timeval tv_buf = { 0, 0 }; + timeval* tv = block ? get_timeout(tv_buf) : &tv_buf; + + lock.unlock(); + + // Block on the select call until descriptors become ready. + boost::system::error_code ec; + int retval = socket_ops::select(static_cast(max_fd + 1), + fds[read_op], fds[write_op], fds[except_op], tv, ec); + + // Reset the interrupter. + if (retval > 0 && fds[read_op].is_set(interrupter_.read_descriptor())) + interrupter_.reset(); + + lock.lock(); + + // Dispatch all ready operations. + if (retval > 0) + { +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Connection operations on Windows use both except and write fd_sets. + op_queue_[connect_op].perform_operations_for_descriptors( + fds[except_op], ops); + op_queue_[connect_op].perform_operations_for_descriptors( + fds[write_op], ops); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + for (int i = max_select_ops - 1; i >= 0; --i) + op_queue_[i].perform_operations_for_descriptors(fds[i], ops); + } + timer_queues_.get_ready_timers(ops); +} + +void select_reactor::interrupt() +{ + interrupter_.interrupt(); +} + +#if defined(BOOST_ASIO_HAS_IOCP) +void select_reactor::run_thread() +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + while (!stop_thread_) + { + lock.unlock(); + op_queue ops; + run(true, ops); + io_service_.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) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void select_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +timeval* select_reactor::get_timeout(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); + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; + return &tv; +} + +void select_reactor::cancel_ops_unlocked(socket_type descriptor, + const boost::system::error_code& ec) +{ + bool need_interrupt = false; + op_queue ops; + 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); + if (need_interrupt) + interrupter_.interrupt(); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + // || (!defined(BOOST_ASIO_HAS_DEV_POLL) + // && !defined(BOOST_ASIO_HAS_EPOLL) + // && !defined(BOOST_ASIO_HAS_KQUEUE)) + +#endif // BOOST_ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP diff --git a/include/boost/asio/detail/impl/service_registry.hpp b/include/boost/asio/detail/impl/service_registry.hpp new file mode 100644 index 00000000..59eb3f78 --- /dev/null +++ b/include/boost/asio/detail/impl/service_registry.hpp @@ -0,0 +1,72 @@ +// +// detail/impl/service_registry.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SERVICE_REGISTRY_HPP +#define BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +Service& service_registry::use_service() +{ + boost::asio::io_service::service::key key; + init_key(key, Service::id); + factory_type factory = &service_registry::create; + return *static_cast(do_use_service(key, factory)); +} + +template +void service_registry::add_service(Service* new_service) +{ + boost::asio::io_service::service::key key; + init_key(key, Service::id); + return do_add_service(key, new_service); +} + +template +bool service_registry::has_service() const +{ + boost::asio::io_service::service::key key; + init_key(key, Service::id); + return do_has_service(key); +} + +#if !defined(BOOST_ASIO_NO_TYPEID) +template +void service_registry::init_key(boost::asio::io_service::service::key& key, + const boost::asio::detail::service_id& /*id*/) +{ + key.type_info_ = &typeid(typeid_wrapper); + key.id_ = 0; +} +#endif // !defined(BOOST_ASIO_NO_TYPEID) + +template +boost::asio::io_service::service* service_registry::create( + boost::asio::io_service& owner) +{ + return new Service(owner); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP diff --git a/include/boost/asio/detail/impl/service_registry.ipp b/include/boost/asio/detail/impl/service_registry.ipp new file mode 100644 index 00000000..9f7381ee --- /dev/null +++ b/include/boost/asio/detail/impl/service_registry.ipp @@ -0,0 +1,166 @@ +// +// detail/impl/service_registry.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SERVICE_REGISTRY_IPP +#define BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +service_registry::service_registry(boost::asio::io_service& o) + : owner_(o), + 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_; + while (service) + { + service->shutdown_service(); + service = service->next_; + } + + // Destroy all services. + while (first_service_) + { + boost::asio::io_service::service* next_service = first_service_->next_; + destroy(first_service_); + first_service_ = next_service; + } +} + +void service_registry::init_key(boost::asio::io_service::service::key& key, + const boost::asio::io_service::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) +{ + if (key1.id_ && key2.id_) + if (key1.id_ == key2.id_) + return true; + if (key1.type_info_ && key2.type_info_) + if (*key1.type_info_ == *key2.type_info_) + return true; + return false; +} + +void service_registry::destroy(boost::asio::io_service::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) +{ + 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_; + while (service) + { + if (keys_match(service->key_, key)) + return service; + service = service->next_; + } + + // Create a new service object. The service registry's mutex is not locked + // 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_) }; + new_service.ptr_->key_ = key; + lock.lock(); + + // Check that nobody else created another service object of the same type + // while the lock was released. + service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return service; + service = service->next_; + } + + // Service was successfully initialised, pass ownership to registry. + new_service.ptr_->next_ = first_service_; + first_service_ = new_service.ptr_; + new_service.ptr_ = 0; + return first_service_; +} + +void service_registry::do_add_service( + const boost::asio::io_service::service::key& key, + boost::asio::io_service::service* new_service) +{ + if (&owner_ != &new_service->io_service()) + boost::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_; + while (service) + { + if (keys_match(service->key_, key)) + boost::throw_exception(service_already_exists()); + service = service->next_; + } + + // Take ownership of the service object. + new_service->key_ = key; + new_service->next_ = first_service_; + first_service_ = new_service; +} + +bool service_registry::do_has_service( + const boost::asio::io_service::service::key& key) const +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + boost::asio::io_service::service* service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return true; + service = service->next_; + } + + return false; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP diff --git a/include/boost/asio/detail/impl/socket_ops.ipp b/include/boost/asio/detail/impl/socket_ops.ipp new file mode 100644 index 00000000..bf1708d6 --- /dev/null +++ b/include/boost/asio/detail/impl/socket_ops.ipp @@ -0,0 +1,2828 @@ +// +// detail/impl/socket_ops.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SOCKET_OPS_IPP +#define BOOST_ASIO_DETAIL_SOCKET_OPS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { +namespace socket_ops { + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +struct msghdr { int msg_namelen; }; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#if defined(__hpux) +// HP-UX doesn't declare these functions extern "C", so they are declared again +// here to avoid linker errors about undefined symbols. +extern "C" char* if_indextoname(unsigned int, char*); +extern "C" unsigned int if_nametoindex(const char*); +#endif // defined(__hpux) + +inline void clear_last_error() +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + WSASetLastError(0); +#else + errno = 0; +#endif +} + +template +inline ReturnType error_wrapper(ReturnType return_value, + boost::system::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + ec = boost::system::error_code(WSAGetLastError(), + boost::asio::error::get_system_category()); +#else + ec = boost::system::error_code(errno, + boost::asio::error::get_system_category()); +#endif + return return_value; +} + +template +inline socket_type call_accept(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; + socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0); + if (addrlen) + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +socket_type accept(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return invalid_socket; + } + + clear_last_error(); + + socket_type new_s = error_wrapper(call_accept( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (new_s == invalid_socket) + return new_s; + +#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) + int optval = 1; + int result = error_wrapper(::setsockopt(new_s, + SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + if (result != 0) + { + ::close(new_s); + return invalid_socket; + } +#endif + + ec = boost::system::error_code(); + return new_s; +} + +socket_type sync_accept(socket_type s, state_type state, + socket_addr_type* addr, std::size_t* addrlen, boost::system::error_code& ec) +{ + // Accept a socket. + for (;;) + { + // Try to complete the operation without blocking. + socket_type new_socket = socket_ops::accept(s, addr, addrlen, ec); + + // Check if operation succeeded. + if (new_socket >= 0) + return new_socket; + + // Operation failed. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + { + if (state & user_set_non_blocking) + return invalid_socket; + // Fall through to retry operation. + } + else if (ec == boost::asio::error::connection_aborted) + { + if (state & enable_connection_aborted) + return invalid_socket; + // Fall through to retry operation. + } +#if defined(EPROTO) + else if (ec.value() == EPROTO) + { + if (state & enable_connection_aborted) + return invalid_socket; + // Fall through to retry operation. + } +#endif // defined(EPROTO) + else + return invalid_socket; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, ec) < 0) + return invalid_socket; + } +} + +#if defined(BOOST_ASIO_HAS_IOCP) + +void complete_iocp_accept(socket_type s, + void* output_buffer, DWORD address_length, + socket_addr_type* addr, std::size_t* addrlen, + socket_type new_socket, boost::system::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_aborted; + + if (!ec) + { + // Get the address of the peer. + if (addr && addrlen) + { + LPSOCKADDR local_addr = 0; + int local_addr_length = 0; + LPSOCKADDR remote_addr = 0; + int remote_addr_length = 0; + GetAcceptExSockaddrs(output_buffer, 0, address_length, + address_length, &local_addr, &local_addr_length, + &remote_addr, &remote_addr_length); + if (static_cast(remote_addr_length) > *addrlen) + { + ec = boost::asio::error::invalid_argument; + } + else + { + using namespace std; // For memcpy. + memcpy(addr, remote_addr, remote_addr_length); + *addrlen = static_cast(remote_addr_length); + } + } + + // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname + // and getpeername will work on the accepted socket. + SOCKET update_ctx_param = s; + socket_ops::state_type state = 0; + socket_ops::setsockopt(new_socket, state, + SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, + &update_ctx_param, sizeof(SOCKET), ec); + } +} + +#else // defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_accept(socket_type s, + state_type state, socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec, socket_type& new_socket) +{ + for (;;) + { + // Accept the waiting connection. + new_socket = socket_ops::accept(s, addr, addrlen, ec); + + // Check if operation succeeded. + if (new_socket >= 0) + return true; + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Operation failed. + 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) + { + if (state & enable_connection_aborted) + return true; + // Fall through to retry operation. + } +#if defined(EPROTO) + else if (ec.value() == EPROTO) + { + if (state & enable_connection_aborted) + return true; + // Fall through to retry operation. + } +#endif // defined(EPROTO) + else + return true; + + return false; + } +} + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +template +inline int call_bind(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::bind(s, addr, (SockLenType)addrlen); +} + +int bind(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(call_bind( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +int close(socket_type s, state_type& state, + bool destruction, boost::system::error_code& ec) +{ + int result = 0; + if (s != invalid_socket) + { +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if ((state & non_blocking) && (state & user_set_linger)) + { + ioctl_arg_type arg = 0; + ::ioctlsocket(s, FIONBIO, &arg); + state &= ~non_blocking; + } +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (state & non_blocking) + { + ioctl_arg_type arg = 0; + ::ioctl(s, FIONBIO, &arg); + state &= ~non_blocking; + } +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + + if (destruction && (state & user_set_linger)) + { + ::linger opt; + opt.l_onoff = 0; + opt.l_linger = 0; + boost::system::error_code ignored_ec; + socket_ops::setsockopt(s, state, SOL_SOCKET, + SO_LINGER, &opt, sizeof(opt), ignored_ec); + } + + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::closesocket(s), ec); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::close(s), ec); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (result == 0) + ec = boost::system::error_code(); + } + + return result; +} + +bool set_internal_non_blocking(socket_type s, + state_type& state, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return false; + } + + clear_last_error(); + ioctl_arg_type arg = 1; +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + + if (result >= 0) + { + ec = boost::system::error_code(); + state |= internal_non_blocking; + return true; + } + + return false; +} + +int shutdown(socket_type s, int what, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(::shutdown(s, what), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +template +inline int call_connect(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::connect(s, addr, (SockLenType)addrlen); +} + +int connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(call_connect( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +void sync_connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec) +{ + // Perform the connect operation. + socket_ops::connect(s, addr, addrlen, ec); + if (ec != boost::asio::error::in_progress + && ec != boost::asio::error::would_block) + { + // The connect operation finished immediately. + return; + } + + // Wait for socket to become ready. + if (socket_ops::poll_connect(s, ec) < 0) + return; + + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, ec) == socket_error_retval) + return; + + // Return the result of the connect operation. + ec = boost::system::error_code(connect_error, + boost::asio::error::get_system_category()); +} + +bool non_blocking_connect(socket_type s, boost::system::error_code& ec) +{ + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, ec) == 0) + { + if (connect_error) + { + ec = boost::system::error_code(connect_error, + boost::asio::error::get_system_category()); + } + else + ec = boost::system::error_code(); + } + + return true; +} + +int socketpair(int af, int type, int protocol, + socket_type sv[2], boost::system::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + (void)(af); + (void)(type); + (void)(protocol); + (void)(sv); + ec = boost::asio::error::operation_not_supported; + return socket_error_retval; +#else + clear_last_error(); + int result = error_wrapper(::socketpair(af, type, protocol, sv), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +#endif +} + +bool sockatmark(socket_type s, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return false; + } + +#if defined(SIOCATMARK) + ioctl_arg_type value = 0; +# if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, SIOCATMARK, &value), ec); +# else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctl(s, SIOCATMARK, &value), ec); +# endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (result == 0) + ec = boost::system::error_code(); +# if defined(ENOTTY) + if (ec.value() == ENOTTY) + ec = boost::asio::error::not_socket; +# endif // defined(ENOTTY) +#else // defined(SIOCATMARK) + int value = error_wrapper(::sockatmark(s), ec); + if (value != -1) + ec = boost::system::error_code(); +#endif // defined(SIOCATMARK) + + return ec ? false : value != 0; +} + +size_t available(socket_type s, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + ioctl_arg_type value = 0; +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, FIONREAD, &value), ec); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctl(s, FIONREAD, &value), ec); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (result == 0) + ec = boost::system::error_code(); +#if defined(ENOTTY) + if (ec.value() == ENOTTY) + ec = boost::asio::error::not_socket; +#endif // defined(ENOTTY) + + return ec ? static_cast(0) : static_cast(value); +} + +int listen(socket_type s, int backlog, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(::listen(s, backlog), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +inline void init_buf_iov_base(void*& base, void* addr) +{ + base = addr; +} + +template +inline void init_buf_iov_base(T& base, void* addr) +{ + base = static_cast(addr); +} + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +typedef WSABUF buf; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +typedef iovec buf; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +void init_buf(buf& b, void* data, size_t size) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + b.buf = static_cast(data); + b.len = static_cast(size); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + init_buf_iov_base(b.iov_base, data); + b.iov_len = size; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +void init_buf(buf& b, const void* data, size_t size) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + b.buf = static_cast(const_cast(data)); + b.len = static_cast(size); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + init_buf_iov_base(b.iov_base, const_cast(data)); + b.iov_len = size; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr) +{ + name = addr; +} + +inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr) +{ + name = const_cast(addr); +} + +template +inline void init_msghdr_msg_name(T& name, socket_addr_type* addr) +{ + name = reinterpret_cast(addr); +} + +template +inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) +{ + name = reinterpret_cast(const_cast(addr)); +} + +int recv(socket_type s, buf* bufs, size_t count, int flags, + boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + DWORD recv_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = error_wrapper(::WSARecv(s, bufs, + recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = boost::asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = boost::system::error_code(); + return bytes_transferred; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = bufs; + msg.msg_iovlen = count; + int result = error_wrapper(::recvmsg(s, &msg, flags), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_recv(socket_type s, state_type state, buf* bufs, + size_t count, int flags, bool all_empty, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (all_empty && (state & stream_oriented)) + { + ec = boost::system::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes = socket_ops::recv(s, bufs, count, flags, ec); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if ((state & stream_oriented) && bytes == 0) + { + ec = boost::asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, ec) < 0) + return 0; + } +} + +#if defined(BOOST_ASIO_HAS_IOCP) + +void complete_iocp_recv(state_type state, + const weak_cancel_token_type& cancel_token, bool all_empty, + boost::system::error_code& ec, size_t bytes_transferred) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (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; + } + + // Check for connection closed. + else if (!ec && bytes_transferred == 0 + && (state & stream_oriented) != 0 + && !all_empty) + { + ec = boost::asio::error::eof; + } +} + +#else // defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_recv(socket_type s, + buf* bufs, size_t count, int flags, bool is_stream, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + int bytes = socket_ops::recv(s, bufs, count, flags, ec); + + // Check for end of stream. + if (is_stream && bytes == 0) + { + ec = boost::asio::error::eof; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +int recvfrom(socket_type s, buf* bufs, size_t count, int flags, + socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + DWORD recv_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int tmp_addrlen = (int)*addrlen; + int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, + &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); + *addrlen = (std::size_t)tmp_addrlen; + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = boost::asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = boost::system::error_code(); + return bytes_transferred; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); + msg.msg_namelen = *addrlen; + msg.msg_iov = bufs; + msg.msg_iovlen = count; + int result = error_wrapper(::recvmsg(s, &msg, flags), ec); + *addrlen = msg.msg_namelen; + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, + size_t count, int flags, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes = socket_ops::recvfrom(s, bufs, count, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, ec) < 0) + return 0; + } +} + +#if defined(BOOST_ASIO_HAS_IOCP) + +void complete_iocp_recvfrom( + const weak_cancel_token_type& cancel_token, + boost::system::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (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; + } +} + +#else // defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_recvfrom(socket_type s, + buf* bufs, size_t count, int flags, + socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + int bytes = socket_ops::recvfrom(s, bufs, count, flags, addr, addrlen, ec); + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +int send(socket_type s, const buf* bufs, size_t count, int flags, + boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Send the data. + DWORD send_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + DWORD send_flags = flags; + int result = error_wrapper(::WSASend(s, const_cast(bufs), + send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = boost::asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = boost::system::error_code(); + return bytes_transferred; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = const_cast(bufs); + msg.msg_iovlen = count; +#if defined(__linux__) + flags |= MSG_NOSIGNAL; +#endif // defined(__linux__) + int result = error_wrapper(::sendmsg(s, &msg, flags), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_send(socket_type s, state_type state, const buf* bufs, + size_t count, int flags, bool all_empty, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes to a stream is a no-op. + if (all_empty && (state & stream_oriented)) + { + ec = boost::system::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes = socket_ops::send(s, bufs, count, flags, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, ec) < 0) + return 0; + } +} + +#if defined(BOOST_ASIO_HAS_IOCP) + +void complete_iocp_send( + const weak_cancel_token_type& cancel_token, + boost::system::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (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; + } +} + +#else // defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_send(socket_type s, + const buf* bufs, size_t count, int flags, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + int bytes = socket_ops::send(s, bufs, count, flags, ec); + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +int sendto(socket_type s, const buf* bufs, size_t count, int flags, + const socket_addr_type* addr, std::size_t addrlen, + boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Send the data. + DWORD send_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + int result = error_wrapper(::WSASendTo(s, const_cast(bufs), + send_buf_count, &bytes_transferred, flags, addr, + static_cast(addrlen), 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = boost::asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = boost::system::error_code(); + return bytes_transferred; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); + msg.msg_namelen = addrlen; + msg.msg_iov = const_cast(bufs); + msg.msg_iovlen = count; +#if defined(__linux__) + flags |= MSG_NOSIGNAL; +#endif // defined(__linux__) + int result = error_wrapper(::sendmsg(s, &msg, flags), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_sendto(socket_type s, state_type state, const buf* bufs, + size_t count, int flags, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes = socket_ops::sendto(s, bufs, count, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, ec) < 0) + return 0; + } +} + +#if !defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_sendto(socket_type s, + const buf* bufs, size_t count, int flags, + const socket_addr_type* addr, std::size_t addrlen, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + int bytes = socket_ops::sendto(s, bufs, count, flags, addr, addrlen, ec); + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // !defined(BOOST_ASIO_HAS_IOCP) + +socket_type socket(int af, int type, int protocol, + boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0, + WSA_FLAG_OVERLAPPED), ec); + if (s == invalid_socket) + return s; + + if (af == AF_INET6) + { + // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to + // false. This will only succeed on Windows Vista and later versions of + // Windows, where a dual-stack IPv4/v6 implementation is available. + DWORD optval = 0; + ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + reinterpret_cast(&optval), sizeof(optval)); + } + + ec = boost::system::error_code(); + + return s; +#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) + socket_type s = error_wrapper(::socket(af, type, protocol), ec); + if (s == invalid_socket) + return s; + + int optval = 1; + int result = error_wrapper(::setsockopt(s, + SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + if (result != 0) + { + ::close(s); + return invalid_socket; + } + + return s; +#else + int s = error_wrapper(::socket(af, type, protocol), ec); + if (s >= 0) + ec = boost::system::error_code(); + return s; +#endif +} + +template +inline int call_setsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + const void* optval, std::size_t optlen) +{ + return ::setsockopt(s, level, optname, + (const char*)optval, (SockLenType)optlen); +} + +int setsockopt(socket_type s, state_type& state, int level, int optname, + const void* optval, std::size_t optlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + if (level == custom_socket_option_level && optname == always_fail_option) + { + ec = boost::asio::error::invalid_argument; + return socket_error_retval; + } + + if (level == custom_socket_option_level + && optname == enable_connection_aborted_option) + { + if (optlen != sizeof(int)) + { + ec = boost::asio::error::invalid_argument; + return socket_error_retval; + } + + if (*static_cast(optval)) + state |= enable_connection_aborted; + else + state &= ~enable_connection_aborted; + ec = boost::system::error_code(); + return 0; + } + + if (level == SOL_SOCKET && optname == SO_LINGER) + state |= user_set_linger; + +#if defined(__BORLANDC__) + // Mysteriously, using the getsockopt and setsockopt functions directly with + // Borland C++ results in incorrect values being set and read. The bug can be + // worked around by using function addresses resolved with GetProcAddress. + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int); + if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt")) + { + clear_last_error(); + return error_wrapper(sso(s, level, optname, + reinterpret_cast(optval), + static_cast(optlen)), ec); + } + } + ec = boost::asio::error::fault; + return socket_error_retval; +#else // defined(__BORLANDC__) + clear_last_error(); + int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); + if (result == 0) + { + ec = boost::system::error_code(); + +#if defined(__MACH__) && defined(__APPLE__) \ + || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + // To implement portable behaviour for SO_REUSEADDR with UDP sockets we + // need to also set SO_REUSEPORT on BSD-based platforms. + if ((state & datagram_oriented) + && level == SOL_SOCKET && optname == SO_REUSEADDR) + { + call_setsockopt(&msghdr::msg_namelen, s, + SOL_SOCKET, SO_REUSEPORT, optval, optlen); + } +#endif + } + + return result; +#endif // defined(__BORLANDC__) +} + +template +inline int call_getsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + void* optval, std::size_t* optlen) +{ + SockLenType tmp_optlen = (SockLenType)*optlen; + int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen); + *optlen = (std::size_t)tmp_optlen; + return result; +} + +int getsockopt(socket_type s, state_type state, int level, int optname, + void* optval, size_t* optlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + if (level == custom_socket_option_level && optname == always_fail_option) + { + ec = boost::asio::error::invalid_argument; + return socket_error_retval; + } + + if (level == custom_socket_option_level + && optname == enable_connection_aborted_option) + { + if (*optlen != sizeof(int)) + { + ec = boost::asio::error::invalid_argument; + return socket_error_retval; + } + + *static_cast(optval) = (state & enable_connection_aborted) ? 1 : 0; + ec = boost::system::error_code(); + return 0; + } + +#if defined(__BORLANDC__) + // Mysteriously, using the getsockopt and setsockopt functions directly with + // Borland C++ results in incorrect values being set and read. The bug can be + // worked around by using function addresses resolved with GetProcAddress. + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*); + if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt")) + { + clear_last_error(); + int tmp_optlen = static_cast(*optlen); + int result = error_wrapper(gso(s, level, optname, + reinterpret_cast(optval), &tmp_optlen), ec); + *optlen = static_cast(tmp_optlen); + if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY + && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) + { + // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are + // only supported on Windows Vista and later. To simplify program logic + // we will fake success of getting this option and specify that the + // value is non-zero (i.e. true). This corresponds to the behavior of + // IPv6 sockets on Windows platforms pre-Vista. + *static_cast(optval) = 1; + ec = boost::system::error_code(); + } + return result; + } + } + ec = boost::asio::error::fault; + return socket_error_retval; +#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) + clear_last_error(); + int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); + if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY + && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) + { + // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only + // supported on Windows Vista and later. To simplify program logic we will + // fake success of getting this option and specify that the value is + // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets + // on Windows platforms pre-Vista. + *static_cast(optval) = 1; + ec = boost::system::error_code(); + } + if (result == 0) + ec = boost::system::error_code(); + return result; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + clear_last_error(); + int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); +#if defined(__linux__) + if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) + && (optname == SO_SNDBUF || optname == SO_RCVBUF)) + { + // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel + // to set the buffer size to N*2. Linux puts additional stuff into the + // buffers so that only about half is actually available to the application. + // The retrieved value is divided by 2 here to make it appear as though the + // correct value has been set. + *static_cast(optval) /= 2; + } +#endif // defined(__linux__) + if (result == 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +template +inline int call_getpeername(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getpeername(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +int getpeername(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, bool cached, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (cached) + { + // Check if socket is still connected. + DWORD connect_time = 0; + size_t connect_time_len = sizeof(connect_time); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_CONNECT_TIME, + &connect_time, &connect_time_len, ec) == socket_error_retval) + { + return socket_error_retval; + } + if (connect_time == 0xFFFFFFFF) + { + ec = boost::asio::error::not_connected; + return socket_error_retval; + } + + // The cached value is still valid. + ec = boost::system::error_code(); + return 0; + } +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + (void)cached; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + + clear_last_error(); + int result = error_wrapper(call_getpeername( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +template +inline int call_getsockname(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getsockname(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +int getsockname(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(call_getsockname( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +int ioctl(socket_type s, state_type& state, long cmd, + ioctl_arg_type* arg, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctl(s, cmd, arg), ec); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (result >= 0) + { + ec = boost::system::error_code(); + + // When updating the non-blocking mode we always perform the ioctl syscall, + // even if the flags would otherwise indicate that the socket is already in + // the correct state. This ensures that the underlying socket is put into + // the state that has been requested by the user. If the ioctl syscall was + // successful then we need to update the flags to match. + if (cmd == static_cast(FIONBIO)) + { + if (*arg) + { + state |= user_set_non_blocking; + } + else + { + // Clearing the non-blocking mode always overrides any internally-set + // non-blocking flag. Any subsequent asynchronous operations will need + // to re-enable non-blocking I/O. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + } + } + + return result; +} + +int select(int nfds, fd_set* readfds, fd_set* writefds, + fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (!readfds && !writefds && !exceptfds && timeout) + { + DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; + if (milliseconds == 0) + milliseconds = 1; // Force context switch. + ::Sleep(milliseconds); + ec = boost::system::error_code(); + return 0; + } + + // The select() call allows timeout values measured in microseconds, but the + // system clock (as wrapped by boost::posix_time::microsec_clock) typically + // has a resolution of 10 milliseconds. This can lead to a spinning select + // reactor, meaning increased CPU usage, when waiting for the earliest + // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight + // spin we'll use a minimum timeout of 1 millisecond. + if (timeout && timeout->tv_sec == 0 + && timeout->tv_usec > 0 && timeout->tv_usec < 1000) + timeout->tv_usec = 1000; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#if defined(__hpux) && defined(__HP_aCC) + timespec ts; + ts.tv_sec = timeout ? timeout->tv_sec : 0; + ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0; + return error_wrapper(::pselect(nfds, readfds, + writefds, exceptfds, timeout ? &ts : 0, 0), ec); +#else + int result = error_wrapper(::select(nfds, readfds, + writefds, exceptfds, timeout), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif +} + +int poll_read(socket_type s, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + FD_SET fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + clear_last_error(); + int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + pollfd fds; + fds.fd = s; + fds.events = POLLIN; + fds.revents = 0; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +int poll_write(socket_type s, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + FD_SET fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + clear_last_error(); + int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +int poll_connect(socket_type s, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + FD_SET write_fds; + FD_ZERO(&write_fds); + FD_SET(s, &write_fds); + FD_SET except_fds; + FD_ZERO(&except_fds); + FD_SET(s, &except_fds); + clear_last_error(); + int result = error_wrapper(::select(s, 0, &write_fds, &except_fds, 0), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +const char* inet_ntop(int af, const void* src, char* dest, size_t length, + unsigned long scope_id, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For memcpy. + + if (af != AF_INET && af != AF_INET6) + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } + + union + { + socket_addr_type base; + sockaddr_storage_type storage; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } address; + DWORD address_length; + if (af == AF_INET) + { + address_length = sizeof(sockaddr_in4_type); + address.v4.sin_family = AF_INET; + address.v4.sin_port = 0; + memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type)); + } + else // AF_INET6 + { + address_length = sizeof(sockaddr_in6_type); + address.v6.sin6_family = AF_INET6; + address.v6.sin6_port = 0; + address.v6.sin6_flowinfo = 0; + address.v6.sin6_scope_id = scope_id; + memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type)); + } + + DWORD string_length = static_cast(length); +#if defined(BOOST_NO_ANSI_APIS) + LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); + int result = error_wrapper(::WSAAddressToStringW(&address.base, + address_length, 0, string_buffer, &string_length), ec); + ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0); +#else + int result = error_wrapper(::WSAAddressToStringA( + &address.base, address_length, 0, dest, &string_length), ec); +#endif + + // Windows may set error code on success. + if (result != socket_error_retval) + ec = boost::system::error_code(); + + // Windows may not set an error code on failure. + else if (result == socket_error_retval && !ec) + ec = boost::asio::error::invalid_argument; + + return result == socket_error_retval ? 0 : dest; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec); + if (result == 0 && !ec) + ec = boost::asio::error::invalid_argument; + if (result != 0 && af == AF_INET6 && scope_id != 0) + { + using namespace std; // For strcat and sprintf. + char if_name[IF_NAMESIZE + 1] = "%"; + const in6_addr_type* ipv6_address = static_cast(src); + bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); + if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0) + sprintf(if_name + 1, "%lu", scope_id); + strcat(dest, if_name); + } + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +int inet_pton(int af, const char* src, void* dest, + unsigned long* scope_id, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For memcpy and strcmp. + + if (af != AF_INET && af != AF_INET6) + { + ec = boost::asio::error::address_family_not_supported; + return -1; + } + + union + { + socket_addr_type base; + sockaddr_storage_type storage; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } address; + int address_length = sizeof(sockaddr_storage_type); +#if defined(BOOST_NO_ANSI_APIS) + int num_wide_chars = strlen(src) + 1; + LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); + ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); + int result = error_wrapper(::WSAStringToAddressW( + wide_buffer, af, 0, &address.base, &address_length), ec); +#else + int result = error_wrapper(::WSAStringToAddressA( + const_cast(src), af, 0, &address.base, &address_length), ec); +#endif + + if (af == AF_INET) + { + if (result != socket_error_retval) + { + memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); + ec = boost::system::error_code(); + } + else if (strcmp(src, "255.255.255.255") == 0) + { + static_cast(dest)->s_addr = INADDR_NONE; + ec = boost::system::error_code(); + } + } + else // AF_INET6 + { + if (result != socket_error_retval) + { + memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); + if (scope_id) + *scope_id = address.v6.sin6_scope_id; + ec = boost::system::error_code(); + } + } + + // Windows may not set an error code on failure. + if (result == socket_error_retval && !ec) + ec = boost::asio::error::invalid_argument; + + if (result != socket_error_retval) + ec = boost::system::error_code(); + + return result == socket_error_retval ? -1 : 1; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::inet_pton(af, src, dest), ec); + if (result <= 0 && !ec) + ec = boost::asio::error::invalid_argument; + if (result > 0 && af == AF_INET6 && scope_id) + { + using namespace std; // For strchr and atoi. + *scope_id = 0; + if (const char* if_name = strchr(src, '%')) + { + in6_addr_type* ipv6_address = static_cast(dest); + bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); + if (is_link_local) + *scope_id = if_nametoindex(if_name + 1); + if (*scope_id == 0) + *scope_id = atoi(if_name + 1); + } + } + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +int gethostname(char* name, int namelen, boost::system::error_code& ec) +{ + clear_last_error(); + int result = error_wrapper(::gethostname(name, namelen), ec); +#if defined(BOOST_WINDOWS) + if (result == 0) + ec = boost::system::error_code(); +#endif + return result; +} + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \ + || defined(__MACH__) && defined(__APPLE__) + +// The following functions are only needed for emulation of getaddrinfo and +// getnameinfo. + +inline boost::system::error_code translate_netdb_error(int error) +{ + switch (error) + { + case 0: + return boost::system::error_code(); + case HOST_NOT_FOUND: + return boost::asio::error::host_not_found; + case TRY_AGAIN: + return boost::asio::error::host_not_found_try_again; + case NO_RECOVERY: + return boost::asio::error::no_recovery; + case NO_DATA: + return boost::asio::error::no_data; + default: + BOOST_ASSERT(false); + return boost::asio::error::invalid_argument; + } +} + +inline hostent* gethostbyaddr(const char* addr, int length, int af, + hostent* result, char* buffer, int buflength, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + (void)(buffer); + (void)(buflength); + hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); + if (!retval) + return 0; + ec = boost::system::error_code(); + *result = *retval; + return retval; +#elif defined(__sun) || defined(__QNX__) + int error = 0; + hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result, + buffer, buflength, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#elif defined(__MACH__) && defined(__APPLE__) + (void)(buffer); + (void)(buflength); + int error = 0; + hostent* retval = error_wrapper(::getipnodebyaddr( + addr, length, af, &error), ec); + if (error) + ec = translate_netdb_error(error); + if (!retval) + return 0; + *result = *retval; + return retval; +#else + hostent* retval = 0; + int error = 0; + error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, + buflength, &retval, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#endif +} + +inline hostent* gethostbyname(const char* name, int af, struct hostent* result, + char* buffer, int buflength, int ai_flags, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + (void)(buffer); + (void)(buflength); + (void)(ai_flags); + if (af != AF_INET) + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } + hostent* retval = error_wrapper(::gethostbyname(name), ec); + if (!retval) + return 0; + ec = boost::system::error_code(); + *result = *retval; + return result; +#elif defined(__sun) || defined(__QNX__) + (void)(ai_flags); + if (af != AF_INET) + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } + int error = 0; + hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer, + buflength, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#elif defined(__MACH__) && defined(__APPLE__) + (void)(buffer); + (void)(buflength); + int error = 0; + hostent* retval = error_wrapper(::getipnodebyname( + name, af, ai_flags, &error), ec); + if (error) + ec = translate_netdb_error(error); + if (!retval) + return 0; + *result = *retval; + return retval; +#else + (void)(ai_flags); + if (af != AF_INET) + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } + hostent* retval = 0; + int error = 0; + error_wrapper(::gethostbyname_r(name, result, + buffer, buflength, &retval, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#endif +} + +inline void freehostent(hostent* h) +{ +#if defined(__MACH__) && defined(__APPLE__) + if (h) + ::freehostent(h); +#else + (void)(h); +#endif +} + +// Emulation of getaddrinfo based on implementation in: +// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998. + +struct gai_search +{ + const char* host; + int family; +}; + +inline int gai_nsearch(const char* host, + const addrinfo_type* hints, gai_search (&search)[2]) +{ + int search_count = 0; + if (host == 0 || host[0] == '\0') + { + if (hints->ai_flags & AI_PASSIVE) + { + // No host and AI_PASSIVE implies wildcard bind. + switch (hints->ai_family) + { + case AF_INET: + search[search_count].host = "0.0.0.0"; + search[search_count].family = AF_INET; + ++search_count; + break; + case AF_INET6: + search[search_count].host = "0::0"; + search[search_count].family = AF_INET6; + ++search_count; + break; + case AF_UNSPEC: + search[search_count].host = "0::0"; + search[search_count].family = AF_INET6; + ++search_count; + search[search_count].host = "0.0.0.0"; + search[search_count].family = AF_INET; + ++search_count; + break; + default: + break; + } + } + else + { + // No host and not AI_PASSIVE means connect to local host. + switch (hints->ai_family) + { + case AF_INET: + search[search_count].host = "localhost"; + search[search_count].family = AF_INET; + ++search_count; + break; + case AF_INET6: + search[search_count].host = "localhost"; + search[search_count].family = AF_INET6; + ++search_count; + break; + case AF_UNSPEC: + search[search_count].host = "localhost"; + search[search_count].family = AF_INET6; + ++search_count; + search[search_count].host = "localhost"; + search[search_count].family = AF_INET; + ++search_count; + break; + default: + break; + } + } + } + else + { + // Host is specified. + switch (hints->ai_family) + { + case AF_INET: + search[search_count].host = host; + search[search_count].family = AF_INET; + ++search_count; + break; + case AF_INET6: + search[search_count].host = host; + search[search_count].family = AF_INET6; + ++search_count; + break; + case AF_UNSPEC: + search[search_count].host = host; + search[search_count].family = AF_INET6; + ++search_count; + search[search_count].host = host; + search[search_count].family = AF_INET; + ++search_count; + break; + default: + break; + } + } + return search_count; +} + +template +inline T* gai_alloc(std::size_t size = sizeof(T)) +{ + using namespace std; + T* p = static_cast(::operator new(size, std::nothrow)); + if (p) + memset(p, 0, size); + return p; +} + +inline void gai_free(void* p) +{ + ::operator delete(p); +} + +inline void gai_strcpy(char* target, const char* source, std::size_t max_size) +{ + using namespace std; +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) + strcpy_s(target, max_size, source); +#else + *target = 0; + strncat(target, source, max_size); +#endif +} + +enum { gai_clone_flag = 1 << 30 }; + +inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints, + const void* addr, int family) +{ + using namespace std; + + addrinfo_type* ai = gai_alloc(); + if (ai == 0) + return EAI_MEMORY; + + ai->ai_next = 0; + **next = ai; + *next = &ai->ai_next; + + ai->ai_canonname = 0; + ai->ai_socktype = hints->ai_socktype; + if (ai->ai_socktype == 0) + ai->ai_flags |= gai_clone_flag; + ai->ai_protocol = hints->ai_protocol; + ai->ai_family = family; + + switch (ai->ai_family) + { + case AF_INET: + { + sockaddr_in4_type* sinptr = gai_alloc(); + if (sinptr == 0) + return EAI_MEMORY; + sinptr->sin_family = AF_INET; + memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type)); + ai->ai_addr = reinterpret_cast(sinptr); + ai->ai_addrlen = sizeof(sockaddr_in4_type); + break; + } + case AF_INET6: + { + sockaddr_in6_type* sin6ptr = gai_alloc(); + if (sin6ptr == 0) + return EAI_MEMORY; + sin6ptr->sin6_family = AF_INET6; + memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type)); + ai->ai_addr = reinterpret_cast(sin6ptr); + ai->ai_addrlen = sizeof(sockaddr_in6_type); + break; + } + default: + break; + } + + return 0; +} + +inline addrinfo_type* gai_clone(addrinfo_type* ai) +{ + using namespace std; + + addrinfo_type* new_ai = gai_alloc(); + if (new_ai == 0) + return new_ai; + + new_ai->ai_next = ai->ai_next; + ai->ai_next = new_ai; + + new_ai->ai_flags = 0; + new_ai->ai_family = ai->ai_family; + new_ai->ai_socktype = ai->ai_socktype; + new_ai->ai_protocol = ai->ai_protocol; + new_ai->ai_canonname = 0; + new_ai->ai_addrlen = ai->ai_addrlen; + new_ai->ai_addr = gai_alloc(ai->ai_addrlen); + memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen); + + return new_ai; +} + +inline int gai_port(addrinfo_type* aihead, int port, int socktype) +{ + int num_found = 0; + + for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next) + { + if (ai->ai_flags & gai_clone_flag) + { + if (ai->ai_socktype != 0) + { + ai = gai_clone(ai); + if (ai == 0) + return -1; + // ai now points to newly cloned entry. + } + } + else if (ai->ai_socktype != socktype) + { + // Ignore if mismatch on socket type. + continue; + } + + ai->ai_socktype = socktype; + + switch (ai->ai_family) + { + case AF_INET: + { + sockaddr_in4_type* sinptr = + reinterpret_cast(ai->ai_addr); + sinptr->sin_port = port; + ++num_found; + break; + } + case AF_INET6: + { + sockaddr_in6_type* sin6ptr = + reinterpret_cast(ai->ai_addr); + sin6ptr->sin6_port = port; + ++num_found; + break; + } + default: + break; + } + } + + return num_found; +} + +inline int gai_serv(addrinfo_type* aihead, + const addrinfo_type* hints, const char* serv) +{ + using namespace std; + + int num_found = 0; + + if ( +#if defined(AI_NUMERICSERV) + (hints->ai_flags & AI_NUMERICSERV) || +#endif + isdigit(serv[0])) + { + int port = htons(atoi(serv)); + if (hints->ai_socktype) + { + // Caller specifies socket type. + int rc = gai_port(aihead, port, hints->ai_socktype); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + else + { + // Caller does not specify socket type. + int rc = gai_port(aihead, port, SOCK_STREAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + rc = gai_port(aihead, port, SOCK_DGRAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + else + { + // Try service name with TCP first, then UDP. + if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM) + { + servent* sptr = getservbyname(serv, "tcp"); + if (sptr != 0) + { + int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM) + { + servent* sptr = getservbyname(serv, "udp"); + if (sptr != 0) + { + int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + } + + if (num_found == 0) + { + if (hints->ai_socktype == 0) + { + // All calls to getservbyname() failed. + return EAI_NONAME; + } + else + { + // Service not supported for socket type. + return EAI_SERVICE; + } + } + + return 0; +} + +inline int gai_echeck(const char* host, const char* service, + int flags, int family, int socktype, int protocol) +{ + (void)(flags); + (void)(protocol); + + // Host or service must be specified. + if (host == 0 || host[0] == '\0') + if (service == 0 || service[0] == '\0') + return EAI_NONAME; + + // Check combination of family and socket type. + switch (family) + { + case AF_UNSPEC: + break; + case AF_INET: + case AF_INET6: + if (service != 0 && service[0] != '\0') + if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM) + return EAI_SOCKTYPE; + break; + default: + return EAI_FAMILY; + } + + return 0; +} + +inline void freeaddrinfo_emulation(addrinfo_type* aihead) +{ + addrinfo_type* ai = aihead; + while (ai) + { + gai_free(ai->ai_addr); + gai_free(ai->ai_canonname); + addrinfo_type* ainext = ai->ai_next; + gai_free(ai); + ai = ainext; + } +} + +inline int getaddrinfo_emulation(const char* host, const char* service, + const addrinfo_type* hintsp, addrinfo_type** result) +{ + // Set up linked list of addrinfo structures. + addrinfo_type* aihead = 0; + addrinfo_type** ainext = &aihead; + char* canon = 0; + + // Supply default hints if not specified by caller. + addrinfo_type hints = addrinfo_type(); + hints.ai_family = AF_UNSPEC; + if (hintsp) + hints = *hintsp; + + // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED + // and AI_ALL flags. +#if defined(AI_V4MAPPED) + if (hints.ai_family != AF_INET6) + hints.ai_flags &= ~AI_V4MAPPED; +#endif +#if defined(AI_ALL) + if (hints.ai_family != AF_INET6) + hints.ai_flags &= ~AI_ALL; +#endif + + // Basic error checking. + int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family, + hints.ai_socktype, hints.ai_protocol); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + return rc; + } + + gai_search search[2]; + int search_count = gai_nsearch(host, &hints, search); + for (gai_search* sptr = search; sptr < search + search_count; ++sptr) + { + // Check for IPv4 dotted decimal string. + in4_addr_type inaddr; + boost::system::error_code ec; + if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1) + { + if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return EAI_FAMILY; + } + if (sptr->family == AF_INET) + { + rc = gai_aistruct(&ainext, &hints, &inaddr, AF_INET); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return rc; + } + } + continue; + } + + // Check for IPv6 hex string. + in6_addr_type in6addr; + if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr, 0, ec) == 1) + { + if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return EAI_FAMILY; + } + if (sptr->family == AF_INET6) + { + rc = gai_aistruct(&ainext, &hints, &in6addr, AF_INET6); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return rc; + } + } + continue; + } + + // Look up hostname. + hostent hent; + char hbuf[8192] = ""; + hostent* hptr = socket_ops::gethostbyname(sptr->host, + sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec); + if (hptr == 0) + { + if (search_count == 2) + { + // Failure is OK if there are multiple searches. + continue; + } + freeaddrinfo_emulation(aihead); + gai_free(canon); + if (ec == boost::asio::error::host_not_found) + return EAI_NONAME; + if (ec == boost::asio::error::host_not_found_try_again) + return EAI_AGAIN; + if (ec == boost::asio::error::no_recovery) + return EAI_FAIL; + if (ec == boost::asio::error::no_data) + return EAI_NONAME; + return EAI_NONAME; + } + + // Check for address family mismatch if one was specified. + if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + socket_ops::freehostent(hptr); + return EAI_FAMILY; + } + + // Save canonical name first time. + if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0] + && (hints.ai_flags & AI_CANONNAME) && canon == 0) + { + std::size_t canon_len = strlen(hptr->h_name) + 1; + canon = gai_alloc(canon_len); + if (canon == 0) + { + freeaddrinfo_emulation(aihead); + socket_ops::freehostent(hptr); + return EAI_MEMORY; + } + gai_strcpy(canon, hptr->h_name, canon_len); + } + + // Create an addrinfo structure for each returned address. + for (char** ap = hptr->h_addr_list; *ap; ++ap) + { + rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + socket_ops::freehostent(hptr); + return EAI_FAMILY; + } + } + + socket_ops::freehostent(hptr); + } + + // Check if we found anything. + if (aihead == 0) + { + gai_free(canon); + return EAI_NONAME; + } + + // Return canonical name in first entry. + if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME)) + { + if (canon) + { + aihead->ai_canonname = canon; + canon = 0; + } + else + { + std::size_t canonname_len = strlen(search[0].host) + 1; + aihead->ai_canonname = gai_alloc(canonname_len); + if (aihead->ai_canonname == 0) + { + freeaddrinfo_emulation(aihead); + return EAI_MEMORY; + } + gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len); + } + } + gai_free(canon); + + // Process the service name. + if (service != 0 && service[0] != '\0') + { + rc = gai_serv(aihead, &hints, service); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + return rc; + } + } + + // Return result to caller. + *result = aihead; + return 0; +} + +inline boost::system::error_code getnameinfo_emulation( + const socket_addr_type* sa, std::size_t salen, char* host, + std::size_t hostlen, char* serv, std::size_t servlen, int flags, + boost::system::error_code& ec) +{ + using namespace std; + + const char* addr; + size_t addr_len; + unsigned short port; + switch (sa->sa_family) + { + case AF_INET: + if (salen != sizeof(sockaddr_in4_type)) + { + return ec = boost::asio::error::invalid_argument; + } + addr = reinterpret_cast( + &reinterpret_cast(sa)->sin_addr); + addr_len = sizeof(in4_addr_type); + port = reinterpret_cast(sa)->sin_port; + break; + case AF_INET6: + if (salen != sizeof(sockaddr_in6_type)) + { + return ec = boost::asio::error::invalid_argument; + } + addr = reinterpret_cast( + &reinterpret_cast(sa)->sin6_addr); + addr_len = sizeof(in6_addr_type); + port = reinterpret_cast(sa)->sin6_port; + break; + default: + return ec = boost::asio::error::address_family_not_supported; + } + + if (host && hostlen > 0) + { + if (flags & NI_NUMERICHOST) + { + if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0) + { + return ec; + } + } + else + { + hostent hent; + char hbuf[8192] = ""; + hostent* hptr = socket_ops::gethostbyaddr(addr, + static_cast(addr_len), sa->sa_family, + &hent, hbuf, sizeof(hbuf), ec); + if (hptr && hptr->h_name && hptr->h_name[0] != '\0') + { + if (flags & NI_NOFQDN) + { + char* dot = strchr(hptr->h_name, '.'); + if (dot) + { + *dot = 0; + } + } + gai_strcpy(host, hptr->h_name, hostlen); + socket_ops::freehostent(hptr); + } + else + { + socket_ops::freehostent(hptr); + if (flags & NI_NAMEREQD) + { + return ec = boost::asio::error::host_not_found; + } + if (socket_ops::inet_ntop(sa->sa_family, + addr, host, hostlen, 0, ec) == 0) + { + return ec; + } + } + } + } + + if (serv && servlen > 0) + { + if (flags & NI_NUMERICSERV) + { + if (servlen < 6) + { + return ec = boost::asio::error::no_buffer_space; + } +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) + sprintf_s(serv, servlen, "%u", ntohs(port)); +#else + sprintf(serv, "%u", ntohs(port)); +#endif + } + else + { +#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) \ + && !defined(BOOST_ASIO_DISABLE_THREADS) + static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + ::pthread_mutex_lock(&mutex); +#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) + // && !defined(BOOST_ASIO_DISABLE_THREADS) + servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0); + if (sptr && sptr->s_name && sptr->s_name[0] != '\0') + { + gai_strcpy(serv, sptr->s_name, servlen); + } + else + { + if (servlen < 6) + { + return ec = boost::asio::error::no_buffer_space; + } +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) + sprintf_s(serv, servlen, "%u", ntohs(port)); +#else + sprintf(serv, "%u", ntohs(port)); +#endif + } +#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) \ + && !defined(BOOST_ASIO_DISABLE_THREADS) + ::pthread_mutex_unlock(&mutex); +#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) + // && !defined(BOOST_ASIO_DISABLE_THREADS) + } + } + + ec = boost::system::error_code(); + return ec; +} + +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // || defined(__MACH__) && defined(__APPLE__) + +inline boost::system::error_code translate_addrinfo_error(int error) +{ + switch (error) + { + case 0: + return boost::system::error_code(); + case EAI_AGAIN: + return boost::asio::error::host_not_found_try_again; + case EAI_BADFLAGS: + return boost::asio::error::invalid_argument; + case EAI_FAIL: + return boost::asio::error::no_recovery; + case EAI_FAMILY: + return boost::asio::error::address_family_not_supported; + case EAI_MEMORY: + return boost::asio::error::no_memory; + case EAI_NONAME: +#if defined(EAI_ADDRFAMILY) + case EAI_ADDRFAMILY: +#endif +#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) + case EAI_NODATA: +#endif + return boost::asio::error::host_not_found; + case EAI_SERVICE: + return boost::asio::error::service_not_found; + case EAI_SOCKTYPE: + return boost::asio::error::socket_type_not_supported; + default: // Possibly the non-portable EAI_SYSTEM. +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + return boost::system::error_code( + WSAGetLastError(), boost::asio::error::get_system_category()); +#else + return boost::system::error_code( + errno, boost::asio::error::get_system_category()); +#endif + } +} + +boost::system::error_code getaddrinfo(const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, boost::system::error_code& ec) +{ + host = (host && *host) ? host : 0; + clear_last_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) + // Building for Windows XP, Windows Server 2003, or later. + int error = ::getaddrinfo(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *gai_t)(const char*, + const char*, const addrinfo_type*, addrinfo_type**); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo")) + { + int error = gai(host, service, &hints, result); + return ec = translate_addrinfo_error(error); + } + } + int error = getaddrinfo_emulation(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +# endif +#elif defined(__MACH__) && defined(__APPLE__) + int error = getaddrinfo_emulation(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +#else + int error = ::getaddrinfo(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +#endif +} + +boost::system::error_code background_getaddrinfo( + const weak_cancel_token_type& cancel_token, const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, boost::system::error_code& ec) +{ + if (cancel_token.expired()) + ec = boost::asio::error::operation_aborted; + else + socket_ops::getaddrinfo(host, service, hints, result, ec); + return ec; +} + +void freeaddrinfo(addrinfo_type* ai) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) + // Building for Windows XP, Windows Server 2003, or later. + ::freeaddrinfo(ai); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *fai_t)(addrinfo_type*); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo")) + { + fai(ai); + return; + } + } + freeaddrinfo_emulation(ai); +# endif +#elif defined(__MACH__) && defined(__APPLE__) + freeaddrinfo_emulation(ai); +#else + ::freeaddrinfo(ai); +#endif +} + +boost::system::error_code getnameinfo(const socket_addr_type* addr, + std::size_t addrlen, char* host, std::size_t hostlen, + char* serv, std::size_t servlen, int flags, boost::system::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) + // Building for Windows XP, Windows Server 2003, or later. + clear_last_error(); + int error = ::getnameinfo(addr, static_cast(addrlen), + host, static_cast(hostlen), + serv, static_cast(servlen), flags); + return ec = translate_addrinfo_error(error); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *gni_t)(const socket_addr_type*, + int, char*, DWORD, char*, DWORD, int); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo")) + { + clear_last_error(); + int error = gni(addr, static_cast(addrlen), + host, static_cast(hostlen), + serv, static_cast(servlen), flags); + return ec = translate_addrinfo_error(error); + } + } + clear_last_error(); + return getnameinfo_emulation(addr, addrlen, + host, hostlen, serv, servlen, flags, ec); +# endif +#elif defined(__MACH__) && defined(__APPLE__) + using namespace std; // For memcpy. + sockaddr_storage_type tmp_addr; + memcpy(&tmp_addr, addr, addrlen); + tmp_addr.ss_len = addrlen; + addr = reinterpret_cast(&tmp_addr); + clear_last_error(); + return getnameinfo_emulation(addr, addrlen, + host, hostlen, serv, servlen, flags, ec); +#else + clear_last_error(); + int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); + return ec = translate_addrinfo_error(error); +#endif +} + +boost::system::error_code sync_getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, boost::system::error_code& ec) +{ + // First try resolving with the service name. If that fails try resolving + // but allow the service to be returned as a number. + int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0; + socket_ops::getnameinfo(addr, addrlen, host, + hostlen, serv, servlen, flags, ec); + if (ec) + { + socket_ops::getnameinfo(addr, addrlen, host, hostlen, + serv, servlen, flags | NI_NUMERICSERV, ec); + } + + return ec; +} + +boost::system::error_code background_getnameinfo( + const weak_cancel_token_type& cancel_token, + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, boost::system::error_code& ec) +{ + if (cancel_token.expired()) + { + ec = boost::asio::error::operation_aborted; + } + else + { + // First try resolving with the service name. If that fails try resolving + // but allow the service to be returned as a number. + int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0; + socket_ops::getnameinfo(addr, addrlen, host, + hostlen, serv, servlen, flags, ec); + if (ec) + { + socket_ops::getnameinfo(addr, addrlen, host, hostlen, + serv, servlen, flags | NI_NUMERICSERV, ec); + } + } + + return ec; +} + +u_long_type network_to_host_long(u_long_type value) +{ + return ntohl(value); +} + +u_long_type host_to_network_long(u_long_type value) +{ + return htonl(value); +} + +u_short_type network_to_host_short(u_short_type value) +{ + return ntohs(value); +} + +u_short_type host_to_network_short(u_short_type value) +{ + return htons(value); +} + +} // namespace socket_ops +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SOCKET_OPS_IPP diff --git a/include/boost/asio/detail/impl/socket_select_interrupter.ipp b/include/boost/asio/detail/impl/socket_select_interrupter.ipp new file mode 100644 index 00000000..36e798ee --- /dev/null +++ b/include/boost/asio/detail/impl/socket_select_interrupter.ipp @@ -0,0 +1,149 @@ +// +// detail/impl/socket_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SOCKET_SELECT_INTERRUPTER_IPP +#define BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +socket_select_interrupter::socket_select_interrupter() +{ + boost::system::error_code ec; + socket_holder acceptor(socket_ops::socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); + if (acceptor.get() == invalid_socket) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + int opt = 1; + socket_ops::state_type acceptor_state = 0; + socket_ops::setsockopt(acceptor.get(), acceptor_state, + SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec); + + using namespace std; // For memset. + sockaddr_in4_type addr; + std::size_t addr_len = sizeof(addr); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + addr.sin_port = 0; + if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr, + addr_len, ec) == socket_error_retval) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr, + &addr_len, ec) == socket_error_retval) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + // Some broken firewalls on Windows will intermittently cause getsockname to + // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We + // explicitly specify the target address here to work around this problem. + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + + if (socket_ops::listen(acceptor.get(), + SOMAXCONN, ec) == socket_error_retval) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + socket_holder client(socket_ops::socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); + if (client.get() == invalid_socket) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr, + addr_len, ec) == socket_error_retval) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec)); + if (server.get() == invalid_socket) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + ioctl_arg_type non_blocking = 1; + socket_ops::state_type client_state = 0; + if (socket_ops::ioctl(client.get(), client_state, + FIONBIO, &non_blocking, ec)) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + opt = 1; + socket_ops::setsockopt(client.get(), client_state, + IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); + + non_blocking = 1; + socket_ops::state_type server_state = 0; + if (socket_ops::ioctl(server.get(), server_state, + FIONBIO, &non_blocking, ec)) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + opt = 1; + socket_ops::setsockopt(server.get(), server_state, + IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); + + read_descriptor_ = server.release(); + write_descriptor_ = client.release(); +} + +socket_select_interrupter::~socket_select_interrupter() +{ + boost::system::error_code ec; + socket_ops::state_type state = socket_ops::internal_non_blocking; + if (read_descriptor_ != invalid_socket) + socket_ops::close(read_descriptor_, state, true, ec); + if (write_descriptor_ != invalid_socket) + socket_ops::close(write_descriptor_, state, true, ec); +} + +void socket_select_interrupter::interrupt() +{ + char byte = 0; + socket_ops::buf b; + socket_ops::init_buf(b, &byte, 1); + boost::system::error_code ec; + socket_ops::send(write_descriptor_, &b, 1, 0, ec); +} + +bool socket_select_interrupter::reset() +{ + char data[1024]; + socket_ops::buf b; + socket_ops::init_buf(b, data, sizeof(data)); + boost::system::error_code ec; + int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); + return was_interrupted; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP diff --git a/include/boost/asio/detail/impl/strand_service.hpp b/include/boost/asio/detail/impl/strand_service.hpp new file mode 100644 index 00000000..e959947a --- /dev/null +++ b/include/boost/asio/detail/impl/strand_service.hpp @@ -0,0 +1,142 @@ +// +// detail/impl/strand_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SERVICE_HPP +#define BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +inline strand_service::strand_impl::strand_impl() + : operation(&strand_service::do_complete), + count_(0) +{ +} + +struct strand_service::on_dispatch_exit +{ + io_service_impl* io_service_; + strand_impl* impl_; + + ~on_dispatch_exit() + { + impl_->mutex_.lock(); + bool more_handlers = (--impl_->count_ > 0); + impl_->mutex_.unlock(); + + if (more_handlers) + io_service_->post_immediate_completion(impl_); + } +}; + +inline void strand_service::destroy(strand_service::implementation_type& impl) +{ + impl = 0; +} + +template +void strand_service::dispatch(strand_service::implementation_type& impl, + Handler handler) +{ + // If we are already in the strand then the handler can run immediately. + if (call_stack::contains(impl)) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + return; + } + + // Allocate and construct an operation to wrap the handler. + typedef completion_handler op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + // If we are running inside the io_service, and no other handler is queued + // or running, then the handler can run immediately. + bool can_dispatch = call_stack::contains(&io_service_); + impl->mutex_.lock(); + bool first = (++impl->count_ == 1); + if (can_dispatch && first) + { + // Immediate invocation is allowed. + impl->mutex_.unlock(); + + // Memory must be releaesed before any upcall is made. + p.reset(); + + // Indicate that this strand is executing on the current thread. + call_stack::context ctx(impl); + + // Ensure the next handler, if any, is scheduled on block exit. + on_dispatch_exit on_exit = { &io_service_, impl }; + (void)on_exit; + + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + return; + } + + // Immediate invocation is not allowed, so enqueue for later. + impl->queue_.push(p.p); + impl->mutex_.unlock(); + p.v = p.p = 0; + + // The first handler to be enqueued is responsible for scheduling the + // strand. + if (first) + io_service_.post_immediate_completion(impl); +} + +// Request the io_service to invoke the given handler and return immediately. +template +void strand_service::post(strand_service::implementation_type& impl, + Handler handler) +{ + // Allocate and construct an operation to wrap the handler. + typedef completion_handler op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + // Add the handler to the queue. + impl->mutex_.lock(); + bool first = (++impl->count_ == 1); + impl->queue_.push(p.p); + impl->mutex_.unlock(); + p.v = p.p = 0; + + // The first handler to be enqueue is responsible for scheduling the strand. + if (first) + io_service_.post_immediate_completion(impl); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP diff --git a/include/boost/asio/detail/impl/strand_service.ipp b/include/boost/asio/detail/impl/strand_service.ipp new file mode 100644 index 00000000..f94570aa --- /dev/null +++ b/include/boost/asio/detail/impl/strand_service.ipp @@ -0,0 +1,108 @@ +// +// detail/impl/strand_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct strand_service::on_do_complete_exit +{ + io_service_impl* owner_; + strand_impl* impl_; + + ~on_do_complete_exit() + { + impl_->mutex_.lock(); + bool more_handlers = (--impl_->count_ > 0); + impl_->mutex_.unlock(); + + if (more_handlers) + owner_->post_immediate_completion(impl_); + } +}; + +strand_service::strand_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + io_service_(boost::asio::use_service(io_service)), + mutex_(), + salt_(0) +{ +} + +void strand_service::shutdown_service() +{ + op_queue ops; + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + for (std::size_t i = 0; i < num_implementations; ++i) + if (strand_impl* impl = implementations_[i].get()) + ops.push(impl->queue_); +} + +void strand_service::construct(strand_service::implementation_type& impl) +{ + std::size_t salt = salt_++; + std::size_t index = reinterpret_cast(&impl); + index += (reinterpret_cast(&impl) >> 3); + index ^= salt + 0x9e3779b9 + (index << 6) + (index >> 2); + index = index % num_implementations; + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (!implementations_[index]) + implementations_[index].reset(new strand_impl); + impl = implementations_[index].get(); +} + +void strand_service::do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) +{ + if (owner) + { + strand_impl* impl = static_cast(base); + + // Get the next handler to be executed. + impl->mutex_.lock(); + operation* o = impl->queue_.front(); + impl->queue_.pop(); + impl->mutex_.unlock(); + + // Indicate that this strand is executing on the current thread. + call_stack::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; + + o->complete(*owner); + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP diff --git a/include/boost/asio/detail/impl/task_io_service.hpp b/include/boost/asio/detail/impl/task_io_service.hpp new file mode 100644 index 00000000..ed5b2c47 --- /dev/null +++ b/include/boost/asio/detail/impl/task_io_service.hpp @@ -0,0 +1,62 @@ +// +// detail/impl/task_io_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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 +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void task_io_service::dispatch(Handler handler) +{ + if (call_stack::contains(this)) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } + else + post(handler); +} + +template +void task_io_service::post(Handler handler) +{ + // Allocate and construct an operation to wrap the handler. + typedef completion_handler op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + post_immediate_completion(p.p); + p.v = p.p = 0; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP diff --git a/include/boost/asio/detail/impl/task_io_service.ipp b/include/boost/asio/detail/impl/task_io_service.ipp new file mode 100644 index 00000000..4cc23262 --- /dev/null +++ b/include/boost/asio/detail/impl/task_io_service.ipp @@ -0,0 +1,356 @@ +// +// detail/impl/task_io_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_IPP +#define BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct task_io_service::task_cleanup +{ + ~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(*ops_); + task_io_service_->op_queue_.push(&task_io_service_->task_operation_); + } + + task_io_service* task_io_service_; + mutex::scoped_lock* lock_; + op_queue* ops_; +}; + +struct task_io_service::work_finished_on_block_exit +{ + ~work_finished_on_block_exit() + { + task_io_service_->work_finished(); + } + + task_io_service* task_io_service_; +}; + +struct task_io_service::idle_thread_info +{ + event wakeup_event; + idle_thread_info* next; +}; + +task_io_service::task_io_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + mutex_(), + task_(0), + task_interrupted_(true), + outstanding_work_(0), + stopped_(false), + shutdown_(false), + first_idle_thread_(0) +{ +} + +void task_io_service::init(std::size_t /*concurrency_hint*/) +{ +} + +void task_io_service::shutdown_service() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + // Destroy handler objects. + while (!op_queue_.empty()) + { + operation* o = op_queue_.front(); + op_queue_.pop(); + if (o != &task_operation_) + o->destroy(); + } + + // Reset to initial state. + task_ = 0; +} + +void task_io_service::init_task() +{ + mutex::scoped_lock lock(mutex_); + if (!shutdown_ && !task_) + { + task_ = &use_service(this->get_io_service()); + op_queue_.push(&task_operation_); + wake_one_thread_and_unlock(lock); + } +} + +std::size_t task_io_service::run(boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + call_stack::context ctx(this); + + idle_thread_info this_idle_thread; + this_idle_thread.next = 0; + + mutex::scoped_lock lock(mutex_); + + std::size_t n = 0; + for (; do_one(lock, &this_idle_thread); lock.lock()) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +std::size_t task_io_service::run_one(boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + call_stack::context ctx(this); + + idle_thread_info this_idle_thread; + this_idle_thread.next = 0; + + mutex::scoped_lock lock(mutex_); + + return do_one(lock, &this_idle_thread); +} + +std::size_t task_io_service::poll(boost::system::error_code& ec) +{ + if (outstanding_work_ == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + call_stack::context ctx(this); + + mutex::scoped_lock lock(mutex_); + + std::size_t n = 0; + for (; do_one(lock, 0); lock.lock()) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +std::size_t task_io_service::poll_one(boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + call_stack::context ctx(this); + + mutex::scoped_lock lock(mutex_); + + return do_one(lock, 0); +} + +void task_io_service::stop() +{ + mutex::scoped_lock lock(mutex_); + stop_all_threads(lock); +} + +void task_io_service::reset() +{ + mutex::scoped_lock lock(mutex_); + stopped_ = false; +} + +void task_io_service::post_immediate_completion(task_io_service::operation* op) +{ + work_started(); + post_deferred_completion(op); +} + +void task_io_service::post_deferred_completion(task_io_service::operation* op) +{ + mutex::scoped_lock lock(mutex_); + op_queue_.push(op); + wake_one_thread_and_unlock(lock); +} + +void task_io_service::post_deferred_completions( + op_queue& ops) +{ + if (!ops.empty()) + { + mutex::scoped_lock lock(mutex_); + op_queue_.push(ops); + wake_one_thread_and_unlock(lock); + } +} + +std::size_t task_io_service::do_one(mutex::scoped_lock& lock, + task_io_service::idle_thread_info* this_idle_thread) +{ + bool polling = !this_idle_thread; + bool task_has_run = false; + while (!stopped_) + { + if (!op_queue_.empty()) + { + // Prepare to execute first handler from queue. + operation* o = op_queue_.front(); + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + if (o == &task_operation_) + { + task_interrupted_ = more_handlers || polling; + + // If the task has already run and we're polling then we're done. + if (task_has_run && polling) + { + task_interrupted_ = true; + op_queue_.push(&task_operation_); + return 0; + } + task_has_run = true; + + if (!more_handlers || !wake_one_idle_thread_and_unlock(lock)) + lock.unlock(); + + op_queue completed_ops; + task_cleanup c = { this, &lock, &completed_ops }; + (void)c; + + // 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 && !polling, completed_ops); + } + else + { + if (more_handlers) + wake_one_thread_and_unlock(lock); + else + lock.unlock(); + + // Ensure the count of outstanding work is decremented on block exit. + work_finished_on_block_exit on_exit = { this }; + (void)on_exit; + + // Complete the operation. May throw an exception. + o->complete(*this); // deletes the operation object + + return 1; + } + } + else if (this_idle_thread) + { + // Nothing to run right now, so just wait for work to do. + this_idle_thread->next = first_idle_thread_; + first_idle_thread_ = this_idle_thread; + this_idle_thread->wakeup_event.clear(lock); + this_idle_thread->wakeup_event.wait(lock); + } + else + { + return 0; + } + } + + return 0; +} + +void task_io_service::stop_all_threads( + mutex::scoped_lock& lock) +{ + stopped_ = true; + + while (first_idle_thread_) + { + idle_thread_info* idle_thread = first_idle_thread_; + first_idle_thread_ = idle_thread->next; + idle_thread->next = 0; + idle_thread->wakeup_event.signal(lock); + } + + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } +} + +bool task_io_service::wake_one_idle_thread_and_unlock( + mutex::scoped_lock& lock) +{ + if (first_idle_thread_) + { + idle_thread_info* idle_thread = first_idle_thread_; + first_idle_thread_ = idle_thread->next; + idle_thread->next = 0; + idle_thread->wakeup_event.signal_and_unlock(lock); + return true; + } + return false; +} + +void task_io_service::wake_one_thread_and_unlock( + mutex::scoped_lock& lock) +{ + if (!wake_one_idle_thread_and_unlock(lock)) + { + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } + lock.unlock(); + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP diff --git a/include/boost/asio/detail/impl/throw_error.ipp b/include/boost/asio/detail/impl/throw_error.ipp new file mode 100644 index 00000000..e66cca59 --- /dev/null +++ b/include/boost/asio/detail/impl/throw_error.ipp @@ -0,0 +1,47 @@ +// +// detail/impl/throw_error.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_THROW_ERROR_IPP +#define BOOST_ASIO_DETAIL_IMPL_THROW_ERROR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +void do_throw_error(const boost::system::error_code& err) +{ + boost::system::system_error e(err); + boost::throw_exception(e); +} + +void do_throw_error(const boost::system::error_code& err, const char* location) +{ + boost::system::system_error e(err, location); + boost::throw_exception(e); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_THROW_ERROR_IPP diff --git a/include/boost/asio/detail/impl/timer_queue.ipp b/include/boost/asio/detail/impl/timer_queue.ipp new file mode 100644 index 00000000..6a12d5a3 --- /dev/null +++ b/include/boost/asio/detail/impl/timer_queue.ipp @@ -0,0 +1,87 @@ +// +// detail/impl/timer_queue.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_TIMER_QUEUE_IPP +#define BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HEADER_ONLY) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +timer_queue >::timer_queue() +{ +} + +timer_queue >::~timer_queue() +{ +} + +bool timer_queue >::enqueue_timer( + const time_type& time, timer_op* op, void* token) +{ + return impl_.enqueue_timer(time, op, token); +} + +bool timer_queue >::empty() const +{ + return impl_.empty(); +} + +long timer_queue >::wait_duration_msec( + long max_duration) const +{ + return impl_.wait_duration_msec(max_duration); +} + +long timer_queue >::wait_duration_usec( + long max_duration) const +{ + return impl_.wait_duration_usec(max_duration); +} + +void timer_queue >::get_ready_timers( + op_queue& ops) +{ + impl_.get_ready_timers(ops); +} + +void timer_queue >::get_all_timers( + op_queue& ops) +{ + impl_.get_all_timers(ops); +} + +std::size_t timer_queue >::cancel_timer( + void* timer_token, op_queue& ops) +{ + return impl_.cancel_timer(timer_token, ops); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP diff --git a/include/boost/asio/detail/impl/timer_queue_set.ipp b/include/boost/asio/detail/impl/timer_queue_set.ipp new file mode 100644 index 00000000..275b9c5a --- /dev/null +++ b/include/boost/asio/detail/impl/timer_queue_set.ipp @@ -0,0 +1,103 @@ +// +// detail/impl/timer_queue_set.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_TIMER_QUEUE_SET_IPP +#define BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +timer_queue_set::timer_queue_set() + : first_(0) +{ +} + +void timer_queue_set::insert(timer_queue_base* q) +{ + q->next_ = first_; + first_ = q; +} + +void timer_queue_set::erase(timer_queue_base* q) +{ + if (first_) + { + if (q == first_) + { + first_ = q->next_; + q->next_ = 0; + return; + } + + for (timer_queue_base* p = first_; p->next_; p = p->next_) + { + if (p->next_ == q) + { + p->next_ = q->next_; + q->next_ = 0; + return; + } + } + } +} + +bool timer_queue_set::all_empty() const +{ + for (timer_queue_base* p = first_; p; p = p->next_) + if (!p->empty()) + return false; + return true; +} + +long timer_queue_set::wait_duration_msec(long max_duration) const +{ + long min_duration = max_duration; + for (timer_queue_base* p = first_; p; p = p->next_) + min_duration = p->wait_duration_msec(min_duration); + return min_duration; +} + +long timer_queue_set::wait_duration_usec(long max_duration) const +{ + long min_duration = max_duration; + for (timer_queue_base* p = first_; p; p = p->next_) + min_duration = p->wait_duration_usec(min_duration); + return min_duration; +} + +void timer_queue_set::get_ready_timers(op_queue& ops) +{ + for (timer_queue_base* p = first_; p; p = p->next_) + p->get_ready_timers(ops); +} + +void timer_queue_set::get_all_timers(op_queue& ops) +{ + for (timer_queue_base* p = first_; p; p = p->next_) + p->get_all_timers(ops); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP diff --git a/include/boost/asio/detail/impl/win_event.ipp b/include/boost/asio/detail/impl/win_event.ipp new file mode 100644 index 00000000..d383c5b6 --- /dev/null +++ b/include/boost/asio/detail/impl/win_event.ipp @@ -0,0 +1,52 @@ +// +// detail/win_event.ipp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_WIN_EVENT_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_EVENT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_WINDOWS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +win_event::win_event() + : event_(::CreateEvent(0, true, false, 0)) +{ + if (!event_) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "event"); + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_WINDOWS) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_EVENT_IPP diff --git a/include/boost/asio/detail/impl/win_iocp_handle_service.ipp b/include/boost/asio/detail/impl/win_iocp_handle_service.ipp new file mode 100644 index 00000000..3169632b --- /dev/null +++ b/include/boost/asio/detail/impl/win_iocp_handle_service.ipp @@ -0,0 +1,454 @@ +// +// detail/impl/win_iocp_handle_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_WIN_IOCP_HANDLE_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_iocp_handle_service::overlapped_wrapper + : public OVERLAPPED +{ +public: + explicit overlapped_wrapper(boost::system::error_code& ec) + { + Internal = 0; + InternalHigh = 0; + Offset = 0; + OffsetHigh = 0; + + // Create a non-signalled manual-reset event, for GetOverlappedResult. + hEvent = ::CreateEvent(0, TRUE, FALSE, 0); + if (hEvent) + { + // As documented in GetQueuedCompletionStatus, setting the low order + // bit of this event prevents our synchronous writes from being treated + // as completion port events. + *reinterpret_cast(&hEvent) |= 1; + } + else + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + } + + ~overlapped_wrapper() + { + if (hEvent) + { + ::CloseHandle(hEvent); + } + } +}; + +win_iocp_handle_service::win_iocp_handle_service( + boost::asio::io_service& io_service) + : iocp_service_(boost::asio::use_service(io_service)), + mutex_(), + impl_list_(0) +{ +} + +void win_iocp_handle_service::shutdown_service() +{ + // Close all implementations, causing all operations to complete. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + implementation_type* impl = impl_list_; + while (impl) + { + close_for_destruction(*impl); + impl = impl->next_; + } +} + +void win_iocp_handle_service::construct( + win_iocp_handle_service::implementation_type& impl) +{ + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + + // Insert implementation into linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_handle_service::destroy( + win_iocp_handle_service::implementation_type& impl) +{ + close_for_destruction(impl); + + // Remove implementation from linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; +} + +boost::system::error_code win_iocp_handle_service::assign( + win_iocp_handle_service::implementation_type& impl, + const native_type& native_handle, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + if (iocp_service_.register_handle(native_handle, ec)) + return ec; + + impl.handle_ = native_handle; + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code win_iocp_handle_service::close( + win_iocp_handle_service::implementation_type& impl, + boost::system::error_code& ec) +{ + if (is_open(impl)) + { + if (!::CloseHandle(impl.handle_)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + } + + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code win_iocp_handle_service::cancel( + win_iocp_handle_service::implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + } + else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( + ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) + { + // The version of Windows supports cancellation from any thread. + typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); + cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; + if (!cancel_io_ex(impl.handle_, 0)) + { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_NOT_FOUND) + { + // ERROR_NOT_FOUND means that there were no operations to be + // cancelled. We swallow this error to match the behaviour on other + // platforms. + ec = boost::system::error_code(); + } + else + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + } + else + { + ec = boost::system::error_code(); + } + } + else if (impl.safe_cancellation_thread_id_ == 0) + { + // No operations have been started, so there's nothing to cancel. + ec = boost::system::error_code(); + } + else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) + { + // Asynchronous operations have been started from the current thread only, + // so it is safe to try to cancel them using CancelIo. + if (!::CancelIo(impl.handle_)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + else + { + ec = boost::system::error_code(); + } + } + else + { + // Asynchronous operations have been started from more than one thread, + // so cancellation is not safe. + ec = boost::asio::error::operation_not_supported; + } + + return ec; +} + +size_t win_iocp_handle_service::do_write( + win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset, + const boost::asio::const_buffer& buffer, boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a handle is a no-op. + if (boost::asio::buffer_size(buffer) == 0) + { + ec = boost::system::error_code(); + return 0; + } + + overlapped_wrapper overlapped(ec); + if (ec) + { + return 0; + } + + // Write the data. + overlapped.Offset = offset & 0xFFFFFFFF; + overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::WriteFile(impl.handle_, + boost::asio::buffer_cast(buffer), + static_cast(boost::asio::buffer_size(buffer)), 0, &overlapped); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error != ERROR_IO_PENDING) + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return 0; + } + } + + // Wait for the operation to complete. + DWORD bytes_transferred = 0; + ok = ::GetOverlappedResult(impl.handle_, + &overlapped, &bytes_transferred, TRUE); + if (!ok) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return 0; + } + + ec = boost::system::error_code(); + return bytes_transferred; +} + +void win_iocp_handle_service::start_write_op( + win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset, + const boost::asio::const_buffer& buffer, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + { + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + } + else if (boost::asio::buffer_size(buffer) == 0) + { + // A request to write 0 bytes on a handle is a no-op. + iocp_service_.on_completion(op); + } + else + { + DWORD bytes_transferred = 0; + op->Offset = offset & 0xFFFFFFFF; + op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::WriteFile(impl.handle_, + boost::asio::buffer_cast(buffer), + static_cast(boost::asio::buffer_size(buffer)), + &bytes_transferred, op); + DWORD last_error = ::GetLastError(); + if (!ok && last_error != ERROR_IO_PENDING + && last_error != ERROR_MORE_DATA) + { + iocp_service_.on_completion(op, last_error, bytes_transferred); + } + else + { + iocp_service_.on_pending(op); + } + } +} + +size_t win_iocp_handle_service::do_read( + win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset, + const boost::asio::mutable_buffer& buffer, boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream handle is a no-op. + if (boost::asio::buffer_size(buffer) == 0) + { + ec = boost::system::error_code(); + return 0; + } + + overlapped_wrapper overlapped(ec); + if (ec) + { + return 0; + } + + // Read some data. + overlapped.Offset = offset & 0xFFFFFFFF; + overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::ReadFile(impl.handle_, + boost::asio::buffer_cast(buffer), + static_cast(boost::asio::buffer_size(buffer)), 0, &overlapped); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA) + { + if (last_error == ERROR_HANDLE_EOF) + { + ec = boost::asio::error::eof; + } + else + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + return 0; + } + } + + // Wait for the operation to complete. + DWORD bytes_transferred = 0; + ok = ::GetOverlappedResult(impl.handle_, + &overlapped, &bytes_transferred, TRUE); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_HANDLE_EOF) + { + ec = boost::asio::error::eof; + } + else + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + return 0; + } + + ec = boost::system::error_code(); + return bytes_transferred; +} + +void win_iocp_handle_service::start_read_op( + win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset, + const boost::asio::mutable_buffer& buffer, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + { + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + } + else if (boost::asio::buffer_size(buffer) == 0) + { + // A request to read 0 bytes on a handle is a no-op. + iocp_service_.on_completion(op); + } + else + { + DWORD bytes_transferred = 0; + op->Offset = offset & 0xFFFFFFFF; + op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::ReadFile(impl.handle_, + boost::asio::buffer_cast(buffer), + static_cast(boost::asio::buffer_size(buffer)), + &bytes_transferred, op); + DWORD last_error = ::GetLastError(); + if (!ok && last_error != ERROR_IO_PENDING + && last_error != ERROR_MORE_DATA) + { + iocp_service_.on_completion(op, last_error, bytes_transferred); + } + else + { + iocp_service_.on_pending(op); + } + } +} + +void win_iocp_handle_service::update_cancellation_thread_id( + win_iocp_handle_service::implementation_type& impl) +{ + if (impl.safe_cancellation_thread_id_ == 0) + impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) + impl.safe_cancellation_thread_id_ = ~DWORD(0); +} + +void win_iocp_handle_service::close_for_destruction(implementation_type& impl) +{ + if (is_open(impl)) + { + ::CloseHandle(impl.handle_); + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP diff --git a/include/boost/asio/detail/impl/win_iocp_io_service.hpp b/include/boost/asio/detail/impl/win_iocp_io_service.hpp new file mode 100644 index 00000000..9ff23426 --- /dev/null +++ b/include/boost/asio/detail/impl/win_iocp_io_service.hpp @@ -0,0 +1,113 @@ +// +// detail/impl/win_iocp_io_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_WIN_IOCP_IO_SERVICE_HPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void win_iocp_io_service::dispatch(Handler handler) +{ + if (call_stack::contains(this)) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } + else + post(handler); +} + +template +void win_iocp_io_service::post(Handler handler) +{ + // Allocate and construct an operation to wrap the handler. + typedef completion_handler op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + post_immediate_completion(p.p); + p.v = p.p = 0; +} + +template +void win_iocp_io_service::add_timer_queue( + timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +template +void win_iocp_io_service::remove_timer_queue( + timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void win_iocp_io_service::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token) +{ + // If the service has been shut down we silently discard the timer. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + return; + + mutex::scoped_lock lock(dispatch_mutex_); + + bool earliest = queue.enqueue_timer(time, op, token); + work_started(); + if (earliest) + update_timeout(); +} + +template +std::size_t win_iocp_io_service::cancel_timer( + timer_queue& queue, void* token) +{ + // If the service has been shut down we silently ignore the cancellation. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + return 0; + + mutex::scoped_lock lock(dispatch_mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(token, ops); + post_deferred_completions(ops); + return n; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP diff --git a/include/boost/asio/detail/impl/win_iocp_io_service.ipp b/include/boost/asio/detail/impl/win_iocp_io_service.ipp new file mode 100644 index 00000000..0219ccdb --- /dev/null +++ b/include/boost/asio/detail/impl/win_iocp_io_service.ipp @@ -0,0 +1,493 @@ +// +// detail/impl/win_iocp_io_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_WIN_IOCP_IO_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct win_iocp_io_service::work_finished_on_block_exit +{ + ~work_finished_on_block_exit() + { + io_service_->work_finished(); + } + + win_iocp_io_service* io_service_; +}; + +struct win_iocp_io_service::timer_thread_function +{ + void operator()() + { + while (::InterlockedExchangeAdd(&io_service_->shutdown_, 0) == 0) + { + if (::WaitForSingleObject(io_service_->waitable_timer_.handle, + INFINITE) == WAIT_OBJECT_0) + { + ::InterlockedExchange(&io_service_->dispatch_required_, 1); + ::PostQueuedCompletionStatus(io_service_->iocp_.handle, + 0, wake_for_dispatch, 0); + } + } + } + + win_iocp_io_service* io_service_; +}; + +win_iocp_io_service::win_iocp_io_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + iocp_(), + outstanding_work_(0), + stopped_(0), + shutdown_(0), + dispatch_required_(0) +{ +} + +void win_iocp_io_service::init(size_t concurrency_hint) +{ + iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, + static_cast((std::min)(concurrency_hint, DWORD(~0)))); + if (!iocp_.handle) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "iocp"); + } +} + +void win_iocp_io_service::shutdown_service() +{ + ::InterlockedExchange(&shutdown_, 1); + + if (timer_thread_) + { + LARGE_INTEGER timeout; + timeout.QuadPart = 1; + ::SetWaitableTimer(waitable_timer_.handle, &timeout, 1, 0, 0, FALSE); + } + + while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0) + { + op_queue ops; + timer_queues_.get_all_timers(ops); + ops.push(completed_ops_); + if (!ops.empty()) + { + while (win_iocp_operation* op = ops.front()) + { + ops.pop(); + ::InterlockedDecrement(&outstanding_work_); + op->destroy(); + } + } + else + { + DWORD bytes_transferred = 0; + dword_ptr_t completion_key = 0; + LPOVERLAPPED overlapped = 0; + ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, + &completion_key, &overlapped, gqcs_timeout); + if (overlapped) + { + ::InterlockedDecrement(&outstanding_work_); + static_cast(overlapped)->destroy(); + } + } + } + + if (timer_thread_) + timer_thread_->join(); +} + +boost::system::error_code win_iocp_io_service::register_handle( + HANDLE handle, boost::system::error_code& ec) +{ + if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + else + { + ec = boost::system::error_code(); + } + return ec; +} + +size_t win_iocp_io_service::run(boost::system::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + call_stack::context ctx(this); + + size_t n = 0; + while (do_one(true, ec)) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +size_t win_iocp_io_service::run_one(boost::system::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + call_stack::context ctx(this); + + return do_one(true, ec); +} + +size_t win_iocp_io_service::poll(boost::system::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + call_stack::context ctx(this); + + size_t n = 0; + while (do_one(false, ec)) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +size_t win_iocp_io_service::poll_one(boost::system::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + call_stack::context ctx(this); + + return do_one(false, ec); +} + +void win_iocp_io_service::stop() +{ + if (::InterlockedExchange(&stopped_, 1) == 0) + { + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "pqcs"); + } + } +} + +void win_iocp_io_service::post_deferred_completion(win_iocp_operation* op) +{ + // Flag the operation as ready. + op->ready_ = 1; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +void win_iocp_io_service::post_deferred_completions( + op_queue& ops) +{ + while (win_iocp_operation* op = ops.front()) + { + ops.pop(); + + // Flag the operation as ready. + op->ready_ = 1; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + completed_ops_.push(ops); + ::InterlockedExchange(&dispatch_required_, 1); + } + } +} + +void win_iocp_io_service::on_pending(win_iocp_operation* op) +{ + if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) + { + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } + } +} + +void win_iocp_io_service::on_completion(win_iocp_operation* op, + DWORD last_error, DWORD bytes_transferred) +{ + // Flag that the operation is ready for invocation. + op->ready_ = 1; + + // Store results in the OVERLAPPED structure. + op->Internal = reinterpret_cast( + &boost::asio::error::get_system_category()); + op->Offset = last_error; + op->OffsetHigh = bytes_transferred; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +void win_iocp_io_service::on_completion(win_iocp_operation* op, + const boost::system::error_code& ec, DWORD bytes_transferred) +{ + // Flag that the operation is ready for invocation. + op->ready_ = 1; + + // Store results in the OVERLAPPED structure. + op->Internal = reinterpret_cast(&ec.category()); + op->Offset = ec.value(); + op->OffsetHigh = bytes_transferred; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +size_t win_iocp_io_service::do_one(bool block, boost::system::error_code& ec) +{ + for (;;) + { + // Try to acquire responsibility for dispatching timers and completed ops. + if (::InterlockedCompareExchange(&dispatch_required_, 0, 1) == 1) + { + mutex::scoped_lock lock(dispatch_mutex_); + + // Dispatch pending timers and operations. + op_queue ops; + ops.push(completed_ops_); + timer_queues_.get_ready_timers(ops); + post_deferred_completions(ops); + update_timeout(); + } + + // Get the next operation from the queue. + DWORD bytes_transferred = 0; + 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); + DWORD last_error = ::GetLastError(); + + if (overlapped) + { + win_iocp_operation* op = static_cast(overlapped); + boost::system::error_code result_ec(last_error, + boost::asio::error::get_system_category()); + + // We may have been passed the last_error and bytes_transferred in the + // OVERLAPPED structure itself. + if (completion_key == overlapped_contains_result) + { + result_ec = boost::system::error_code(static_cast(op->Offset), + *reinterpret_cast(op->Internal)); + bytes_transferred = op->OffsetHigh; + } + + // Otherwise ensure any result has been saved into the OVERLAPPED + // structure. + else + { + op->Internal = reinterpret_cast(&result_ec.category()); + op->Offset = result_ec.value(); + op->OffsetHigh = bytes_transferred; + } + + // Dispatch the operation only if ready. The operation may not be ready + // if the initiating function (e.g. a call to WSARecv) has not yet + // returned. This is because the initiating function still wants access + // to the operation's OVERLAPPED structure. + if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) + { + // Ensure the count of outstanding work is decremented on block exit. + work_finished_on_block_exit on_exit = { this }; + (void)on_exit; + + op->complete(*this, result_ec, bytes_transferred); + ec = boost::system::error_code(); + return 1; + } + } + else if (!ok) + { + if (last_error != WAIT_TIMEOUT) + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return 0; + } + + // If we're not polling we need to keep going until we get a real handler. + if (block) + continue; + + ec = boost::system::error_code(); + return 0; + } + else if (completion_key == wake_for_dispatch) + { + // We have been woken up to try to acquire responsibility for dispatching + // timers and completed operations. + } + else + { + // The stopped_ flag is always checked to ensure that any leftover + // interrupts from a previous run invocation are ignored. + if (::InterlockedExchangeAdd(&stopped_, 0) != 0) + { + // Wake up next thread that is blocked on GetQueuedCompletionStatus. + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) + { + last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return 0; + } + + ec = boost::system::error_code(); + return 0; + } + } + } +} + +void win_iocp_io_service::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(dispatch_mutex_); + + timer_queues_.insert(&queue); + + if (!waitable_timer_.handle) + { + waitable_timer_.handle = ::CreateWaitableTimer(0, FALSE, 0); + if (waitable_timer_.handle == 0) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "timer"); + } + } + + if (!timer_thread_) + { + timer_thread_function thread_function = { this }; + timer_thread_.reset(new thread(thread_function, 65536)); + } +} + +void win_iocp_io_service::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() +{ + if (timer_thread_) + { + // There's no point updating the waitable timer if the new timeout period + // exceeds the maximum timeout. In that case, we might as well wait for the + // existing period of the timer to expire. + long timeout_usec = timer_queues_.wait_duration_usec(max_timeout_usec); + if (timeout_usec < max_timeout_usec) + { + LARGE_INTEGER timeout; + timeout.QuadPart = -timeout_usec; + timeout.QuadPart *= 10; + ::SetWaitableTimer(waitable_timer_.handle, + &timeout, max_timeout_msec, 0, 0, FALSE); + } + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP diff --git a/include/boost/asio/detail/impl/win_iocp_serial_port_service.ipp b/include/boost/asio/detail/impl/win_iocp_serial_port_service.ipp new file mode 100644 index 00000000..bd2310c7 --- /dev/null +++ b/include/boost/asio/detail/impl/win_iocp_serial_port_service.ipp @@ -0,0 +1,182 @@ +// +// detail/impl/win_iocp_serial_port_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_WIN_IOCP_SERIAL_PORT_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) && defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +win_iocp_serial_port_service::win_iocp_serial_port_service( + boost::asio::io_service& io_service) + : handle_service_(io_service) +{ +} + +void win_iocp_serial_port_service::shutdown_service() +{ +} + +boost::system::error_code win_iocp_serial_port_service::open( + win_iocp_serial_port_service::implementation_type& impl, + const std::string& device, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + // For convenience, add a leading \\.\ sequence if not already present. + std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device; + + // Open a handle to the serial port. + ::HANDLE handle = ::CreateFileA(name.c_str(), + GENERIC_READ | GENERIC_WRITE, 0, 0, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + if (handle == INVALID_HANDLE_VALUE) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + // Determine the initial serial port parameters. + using namespace std; // For memset. + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle, &dcb)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + // Set some default serial port parameters. This implementation does not + // support changing these, so they might as well be in a known state. + dcb.fBinary = TRUE; // Win32 only supports binary mode. + dcb.fDsrSensitivity = FALSE; + dcb.fNull = FALSE; // Do not ignore NULL characters. + dcb.fAbortOnError = FALSE; // Ignore serial framing errors. + if (!::SetCommState(handle, &dcb)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + // Set up timeouts so that the serial port will behave similarly to a + // network socket. Reads wait for at least one byte, then return with + // whatever they have. Writes return once everything is out the door. + ::COMMTIMEOUTS timeouts; + timeouts.ReadIntervalTimeout = 1; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.ReadTotalTimeoutConstant = 0; + timeouts.WriteTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = 0; + if (!::SetCommTimeouts(handle, &timeouts)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + // We're done. Take ownership of the serial port handle. + if (handle_service_.assign(impl, handle, ec)) + ::CloseHandle(handle); + return ec; +} + +boost::system::error_code win_iocp_serial_port_service::do_set_option( + win_iocp_serial_port_service::implementation_type& impl, + win_iocp_serial_port_service::store_function_type store, + const void* option, boost::system::error_code& ec) +{ + using namespace std; // For memcpy. + + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle_service_.native(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + if (store(option, dcb, ec)) + return ec; + + if (!::SetCommState(handle_service_.native(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code win_iocp_serial_port_service::do_get_option( + const win_iocp_serial_port_service::implementation_type& impl, + win_iocp_serial_port_service::load_function_type load, + void* option, boost::system::error_code& ec) const +{ + using namespace std; // For memset. + + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle_service_.native(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + return load(option, dcb, ec); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) && defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP diff --git a/include/boost/asio/detail/impl/win_iocp_socket_service_base.ipp b/include/boost/asio/detail/impl/win_iocp_socket_service_base.ipp new file mode 100644 index 00000000..59fc0ef9 --- /dev/null +++ b/include/boost/asio/detail/impl/win_iocp_socket_service_base.ipp @@ -0,0 +1,567 @@ +// +// detail/impl/win_iocp_socket_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_WIN_IOCP_SOCKET_SERVICE_BASE_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include + +#include + +namespace boost { +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(io_service)), + reactor_(0), + mutex_(), + impl_list_(0) +{ +} + +void win_iocp_socket_service_base::shutdown_service() +{ + // 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_; + } +} + +void win_iocp_socket_service_base::construct( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + + // Insert implementation into linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_socket_service_base::destroy( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + close_for_destruction(impl); + + // Remove implementation from linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; +} + +boost::system::error_code win_iocp_socket_service_base::close( + win_iocp_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (is_open(impl)) + { + // 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( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (r) + r->close_descriptor(impl.socket_, impl.reactor_data_); + } + + if (socket_ops::close(impl.socket_, impl.state_, false, ec) == 0) + { + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + } + + return ec; +} + +boost::system::error_code win_iocp_socket_service_base::cancel( + win_iocp_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( + ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) + { + // The version of Windows supports cancellation from any thread. + typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); + cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; + socket_type sock = impl.socket_; + HANDLE sock_as_handle = reinterpret_cast(sock); + if (!cancel_io_ex(sock_as_handle, 0)) + { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_NOT_FOUND) + { + // ERROR_NOT_FOUND means that there were no operations to be + // cancelled. We swallow this error to match the behaviour on other + // platforms. + ec = boost::system::error_code(); + } + else + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + } + else + { + ec = boost::system::error_code(); + } + } +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + else if (impl.safe_cancellation_thread_id_ == 0) + { + // No operations have been started, so there's nothing to cancel. + ec = boost::system::error_code(); + } + else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) + { + // Asynchronous operations have been started from the current thread only, + // so it is safe to try to cancel them using CancelIo. + socket_type sock = impl.socket_; + HANDLE sock_as_handle = reinterpret_cast(sock); + if (!::CancelIo(sock_as_handle)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + else + { + ec = boost::system::error_code(); + } + } + else + { + // Asynchronous operations have been started from more than one thread, + // so cancellation is not safe. + ec = boost::asio::error::operation_not_supported; + } +#else // defined(BOOST_ASIO_ENABLE_CANCELIO) + else + { + // Cancellation is not supported as CancelIo may not be used. + ec = boost::asio::error::operation_not_supported; + } +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + + return ec; +} + +boost::system::error_code win_iocp_socket_service_base::do_open( + win_iocp_socket_service_base::base_implementation_type& impl, + int family, int type, int protocol, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + socket_holder sock(socket_ops::socket(family, type, protocol, ec)); + if (sock.get() == invalid_socket) + return ec; + + HANDLE sock_as_handle = reinterpret_cast(sock.get()); + if (iocp_service_.register_handle(sock_as_handle, ec)) + return ec; + + impl.socket_ = sock.release(); + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + impl.cancel_token_.reset(static_cast(0), socket_ops::noop_deleter()); + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code win_iocp_socket_service_base::do_assign( + win_iocp_socket_service_base::base_implementation_type& impl, + int type, socket_type native_socket, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + HANDLE sock_as_handle = reinterpret_cast(native_socket); + if (iocp_service_.register_handle(sock_as_handle, ec)) + return ec; + + impl.socket_ = native_socket; + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + impl.cancel_token_.reset(static_cast(0), socket_ops::noop_deleter()); + ec = boost::system::error_code(); + return ec; +} + +void win_iocp_socket_service_base::start_send_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (noop) + iocp_service_.on_completion(op); + else if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + int result = ::WSASend(impl.socket_, buffers, + static_cast(buffer_count), &bytes_transferred, flags, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_send_to_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + const socket_addr_type* addr, int addrlen, + socket_base::message_flags flags, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + int result = ::WSASendTo(impl.socket_, buffers, + static_cast(buffer_count), + &bytes_transferred, flags, addr, addrlen, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_receive_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (noop) + iocp_service_.on_completion(op); + else if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecv(impl.socket_, buffers, + static_cast(buffer_count), + &bytes_transferred, &recv_flags, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_NETNAME_DELETED) + last_error = WSAECONNRESET; + else if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_null_buffers_receive_op( + win_iocp_socket_service_base::base_implementation_type& impl, + socket_base::message_flags flags, reactor_op* op) +{ + if ((impl.state_ & socket_ops::stream_oriented) != 0) + { + // For stream sockets on Windows, we may issue a 0-byte overlapped + // WSARecv to wait until there is data available on the socket. + ::WSABUF buf = { 0, 0 }; + start_receive_op(impl, &buf, 1, flags, false, op); + } + else + { + start_reactor_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + op); + } +} + +void win_iocp_socket_service_base::start_receive_from_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr, + socket_base::message_flags flags, int* addrlen, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecvFrom(impl.socket_, buffers, + static_cast(buffer_count), + &bytes_transferred, &recv_flags, addr, addrlen, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_accept_op( + win_iocp_socket_service_base::base_implementation_type& impl, + bool peer_is_open, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else if (peer_is_open) + iocp_service_.on_completion(op, boost::asio::error::already_open); + else + { + boost::system::error_code ec; + new_socket.reset(socket_ops::socket(family, type, protocol, ec)); + if (new_socket.get() == invalid_socket) + iocp_service_.on_completion(op, ec); + else + { + DWORD bytes_read = 0; + BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer, + 0, address_length, address_length, &bytes_read, op); + DWORD last_error = ::WSAGetLastError(); + if (!result && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error); + else + iocp_service_.on_pending(op); + } + } +} + +void win_iocp_socket_service_base::restart_accept_op( + socket_type s, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op) +{ + new_socket.reset(); + iocp_service_.work_started(); + + boost::system::error_code ec; + new_socket.reset(socket_ops::socket(family, type, protocol, ec)); + if (new_socket.get() == invalid_socket) + iocp_service_.on_completion(op, ec); + else + { + DWORD bytes_read = 0; + BOOL result = ::AcceptEx(s, new_socket.get(), output_buffer, + 0, address_length, address_length, &bytes_read, op); + DWORD last_error = ::WSAGetLastError(); + if (!result && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error); + else + iocp_service_.on_pending(op); + } +} + +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(); + update_cancellation_thread_id(impl); + + if (is_open(impl)) + { + r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false); + return; + } + else + op->ec_ = boost::asio::error::bad_descriptor; + + iocp_service_.post_immediate_completion(op); +} + +void win_iocp_socket_service_base::start_connect_op( + win_iocp_socket_service_base::base_implementation_type& impl, + reactor_op* op, const socket_addr_type* addr, std::size_t addrlen) +{ + reactor& r = get_reactor(); + update_cancellation_thread_id(impl); + + if ((impl.state_ & socket_ops::non_blocking) != 0 + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, op->ec_)) + { + if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0) + { + if (op->ec_ == boost::asio::error::in_progress + || op->ec_ == boost::asio::error::would_block) + { + op->ec_ = boost::system::error_code(); + r.start_op(reactor::connect_op, impl.socket_, + impl.reactor_data_, op, false); + return; + } + } + } + + r.post_immediate_completion(op); +} + +void win_iocp_socket_service_base::close_for_destruction( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + if (is_open(impl)) + { + // 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( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (r) + r->close_descriptor(impl.socket_, impl.reactor_data_); + } + + boost::system::error_code ignored_ec; + socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) +} + +void win_iocp_socket_service_base::update_cancellation_thread_id( + win_iocp_socket_service_base::base_implementation_type& impl) +{ +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + if (impl.safe_cancellation_thread_id_ == 0) + impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) + impl.safe_cancellation_thread_id_ = ~DWORD(0); +#else // defined(BOOST_ASIO_ENABLE_CANCELIO) + (void)impl; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) +} + +reactor& win_iocp_socket_service_base::get_reactor() +{ + reactor* r = static_cast( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (!r) + { + r = &(use_service(io_service_)); + interlocked_exchange_pointer(reinterpret_cast(&reactor_), r); + } + return *r; +} + +void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer( + void** dest, void* exch, void* cmp) +{ +#if defined(_M_IX86) + return reinterpret_cast(InterlockedCompareExchange( + reinterpret_cast(dest), reinterpret_cast(exch), + reinterpret_cast(cmp))); +#else + return InterlockedCompareExchangePointer(dest, exch, cmp); +#endif +} + +void* win_iocp_socket_service_base::interlocked_exchange_pointer( + void** dest, void* val) +{ +#if defined(_M_IX86) + return reinterpret_cast(InterlockedExchange( + reinterpret_cast(dest), reinterpret_cast(val))); +#else + return InterlockedExchangePointer(dest, val); +#endif +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP diff --git a/include/boost/asio/detail/impl/win_mutex.ipp b/include/boost/asio/detail/impl/win_mutex.ipp new file mode 100644 index 00000000..3cceda13 --- /dev/null +++ b/include/boost/asio/detail/impl/win_mutex.ipp @@ -0,0 +1,78 @@ +// +// detail/impl/win_mutex.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_WIN_MUTEX_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_MUTEX_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_WINDOWS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +win_mutex::win_mutex() +{ + int error = do_init(); + boost::system::error_code ec(error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "mutex"); +} + +int win_mutex::do_init() +{ +#if defined(__MINGW32__) + // Not sure if MinGW supports structured exception handling, so for now + // we'll just call the Windows API and hope. +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# else + ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000); +# endif + return 0; +#else + __try + { +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# else + ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000); +# endif + } + __except(GetExceptionCode() == STATUS_NO_MEMORY + ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + return ERROR_OUTOFMEMORY; + } + + return 0; +#endif +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_WINDOWS) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_MUTEX_IPP diff --git a/include/boost/asio/detail/impl/win_thread.ipp b/include/boost/asio/detail/impl/win_thread.ipp new file mode 100644 index 00000000..22d23007 --- /dev/null +++ b/include/boost/asio/detail/impl/win_thread.ipp @@ -0,0 +1,140 @@ +// +// detail/impl/win_thread.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_WIN_THREAD_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_THREAD_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_WINDOWS) && !defined(UNDER_CE) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +win_thread::~win_thread() +{ + ::CloseHandle(thread_); + + // The exit_event_ handle is deliberately allowed to leak here since it + // is an error for the owner of an internal thread not to join() it. +} + +void win_thread::join() +{ + HANDLE handles[2] = { exit_event_, thread_ }; + ::WaitForMultipleObjects(2, handles, FALSE, INFINITE); + ::CloseHandle(exit_event_); + if (terminate_threads()) + { + ::TerminateThread(thread_, 0); + } + else + { + ::QueueUserAPC(apc_function, thread_, 0); + ::WaitForSingleObject(thread_, INFINITE); + } +} + +void win_thread::start_thread(func_base* arg, unsigned int stack_size) +{ + ::HANDLE entry_event = 0; + arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0); + if (!entry_event) + { + DWORD last_error = ::GetLastError(); + delete arg; + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread.entry_event"); + } + + arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0); + if (!exit_event_) + { + DWORD last_error = ::GetLastError(); + delete arg; + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread.exit_event"); + } + + unsigned int thread_id = 0; + thread_ = reinterpret_cast(::_beginthreadex(0, + stack_size, win_thread_function, arg, 0, &thread_id)); + if (!thread_) + { + DWORD last_error = ::GetLastError(); + delete arg; + if (entry_event) + ::CloseHandle(entry_event); + if (exit_event_) + ::CloseHandle(exit_event_); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread"); + } + + if (entry_event) + { + ::WaitForSingleObject(entry_event, INFINITE); + ::CloseHandle(entry_event); + } +} + +unsigned int __stdcall win_thread_function(void* arg) +{ + std::auto_ptr func( + static_cast(arg)); + + ::SetEvent(func->entry_event_); + + func->run(); + + // Signal that the thread has finished its work, but rather than returning go + // to sleep to put the thread into a well known state. If the thread is being + // joined during global object destruction then it may be killed using + // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx + // call will be interrupted using QueueUserAPC and the thread will shut down + // cleanly. + HANDLE exit_event = func->exit_event_; + func.reset(); + ::SetEvent(exit_event); + ::SleepEx(INFINITE, TRUE); + + return 0; +} + +#if defined(WINVER) && (WINVER < 0x0500) +void __stdcall apc_function(ULONG) {} +#else +void __stdcall apc_function(ULONG_PTR) {} +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_THREAD_IPP diff --git a/include/boost/asio/detail/impl/win_tss_ptr.ipp b/include/boost/asio/detail/impl/win_tss_ptr.ipp new file mode 100644 index 00000000..7da9be34 --- /dev/null +++ b/include/boost/asio/detail/impl/win_tss_ptr.ipp @@ -0,0 +1,59 @@ +// +// detail/impl/win_tss_ptr.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_WIN_TSS_PTR_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_WINDOWS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +DWORD win_tss_ptr_create() +{ +#if defined(UNDER_CE) + enum { out_of_indexes = 0xFFFFFFFF }; +#else + enum { out_of_indexes = TLS_OUT_OF_INDEXES }; +#endif + + DWORD tss_key = ::TlsAlloc(); + if (tss_key == out_of_indexes) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "tss"); + } + return tss_key; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_WINDOWS) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP diff --git a/include/boost/asio/detail/impl/winsock_init.ipp b/include/boost/asio/detail/impl/winsock_init.ipp new file mode 100644 index 00000000..082ea844 --- /dev/null +++ b/include/boost/asio/detail/impl/winsock_init.ipp @@ -0,0 +1,71 @@ +// +// detail/impl/winsock_init.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_WINSOCK_INIT_IPP +#define BOOST_ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +void winsock_init_base::startup(data& d, + unsigned char major, unsigned char minor) +{ + if (::InterlockedIncrement(&d.init_count_) == 1) + { + WSADATA wsa_data; + long result = ::WSAStartup(MAKEWORD(major, minor), &wsa_data); + ::InterlockedExchange(&d.result_, result); + } +} + +void winsock_init_base::cleanup(data& d) +{ + if (::InterlockedDecrement(&d.init_count_) == 0) + { + ::WSACleanup(); + } +} + +void winsock_init_base::throw_on_error(data& d) +{ + long result = ::InterlockedExchangeAdd(&d.result_, 0); + if (result != 0) + { + boost::system::error_code ec(result, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "winsock"); + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP diff --git a/include/boost/asio/detail/io_control.hpp b/include/boost/asio/detail/io_control.hpp index 5021c2e8..cb02fee6 100644 --- a/include/boost/asio/detail/io_control.hpp +++ b/include/boost/asio/detail/io_control.hpp @@ -1,6 +1,6 @@ // -// io_control.hpp -// ~~~~~~~~~~~~~~ +// detail/io_control.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include - #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/kqueue_reactor.hpp b/include/boost/asio/detail/kqueue_reactor.hpp index c1a67058..db5cb887 100644 --- a/include/boost/asio/detail/kqueue_reactor.hpp +++ b/include/boost/asio/detail/kqueue_reactor.hpp @@ -1,6 +1,6 @@ // -// kqueue_reactor.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/kqueue_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) @@ -16,41 +16,35 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_KQUEUE) -#include #include #include #include #include -#include -#include -#include -#include - -#include -#include #include +#include #include #include #include #include -#include #include #include #include #include #include +#include +#include // Older versions of Mac OS X may not define EV_OOBAND. #if !defined(EV_OOBAND) # define EV_OOBAND EV_FLAG1 #endif // !defined(EV_OOBAND) +#include + namespace boost { namespace asio { namespace detail { @@ -78,371 +72,83 @@ public: typedef descriptor_state* per_descriptor_data; // Constructor. - kqueue_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base(io_service), - io_service_(use_service(io_service)), - mutex_(), - kqueue_fd_(do_kqueue_create()), - interrupter_(), - shutdown_(false) - { - // The interrupter is put into a permanently readable state. Whenever we - // want to interrupt the blocked kevent call we register a one-shot read - // operation against the descriptor. - interrupter_.interrupt(); - } + BOOST_ASIO_DECL kqueue_reactor(boost::asio::io_service& io_service); // Destructor. - ~kqueue_reactor() - { - close(kqueue_fd_); - } + BOOST_ASIO_DECL ~kqueue_reactor(); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - mutex::scoped_lock lock(mutex_); - shutdown_ = true; - lock.unlock(); - - op_queue ops; - - descriptor_map::iterator iter = registered_descriptors_.begin(); - descriptor_map::iterator end = registered_descriptors_.end(); - while (iter != end) - { - for (int i = 0; i < max_ops; ++i) - ops.push(iter->second.op_queue_[i]); - iter->second.shutdown_ = true; - ++iter; - } - - timer_queues_.get_all_timers(ops); - } + BOOST_ASIO_DECL void shutdown_service(); // Initialise the task. - void init_task() - { - io_service_.init_task(); - } + BOOST_ASIO_DECL void init_task(); // Register a socket with the reactor. Returns 0 on success, system error // code on failure. - int register_descriptor(socket_type descriptor, - per_descriptor_data& descriptor_data) + BOOST_ASIO_DECL int register_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op) { - mutex::scoped_lock lock(registered_descriptors_mutex_); - - descriptor_map::iterator new_entry = registered_descriptors_.insert( - std::make_pair(descriptor, descriptor_state())).first; - descriptor_data = &new_entry->second; - - descriptor_data->shutdown_ = false; - - return 0; + io_service_.post_immediate_completion(op); } // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. - void start_op(int op_type, socket_type descriptor, + BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, per_descriptor_data& descriptor_data, - reactor_op* op, bool allow_speculative) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - if (descriptor_data->shutdown_) - return; - - bool first = descriptor_data->op_queue_[op_type].empty(); - if (first) - { - if (allow_speculative) - { - if (op_type != read_op || descriptor_data->op_queue_[except_op].empty()) - { - if (op->perform()) - { - descriptor_lock.unlock(); - io_service_.post_immediate_completion(op); - return; - } - } - } - } - - descriptor_data->op_queue_[op_type].push(op); - io_service_.work_started(); - - if (first) - { - struct kevent event; - switch (op_type) - { - case read_op: - EV_SET(&event, descriptor, EVFILT_READ, - EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); - break; - case write_op: - EV_SET(&event, descriptor, EVFILT_WRITE, - EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); - break; - case except_op: - if (!descriptor_data->op_queue_[read_op].empty()) - return; // Already registered for read events. - EV_SET(&event, descriptor, EVFILT_READ, - EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); - break; - } - - if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) - { - op->ec_ = boost::system::error_code(errno, - boost::asio::error::get_system_category()); - descriptor_data->op_queue_[op_type].pop(); - io_service_.post_deferred_completion(op); - } - } - } + reactor_op* op, bool allow_speculative); // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the // operation_aborted error. - void cancel_ops(socket_type descriptor, per_descriptor_data& descriptor_data) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - - op_queue ops; - for (int i = 0; i < max_ops; ++i) - { - while (reactor_op* op = descriptor_data->op_queue_[i].front()) - { - op->ec_ = boost::asio::error::operation_aborted; - descriptor_data->op_queue_[i].pop(); - ops.push(op); - } - } - - descriptor_lock.unlock(); - - io_service_.post_deferred_completions(ops); - } + BOOST_ASIO_DECL void cancel_ops(socket_type descriptor, + per_descriptor_data& descriptor_data); // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. - void close_descriptor(socket_type descriptor, - per_descriptor_data& descriptor_data) - { - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); - - // Remove the descriptor from the set of known descriptors. The descriptor - // will be automatically removed from the kqueue set when it is closed. - descriptor_data->shutdown_ = true; - - op_queue ops; - for (int i = 0; i < max_ops; ++i) - { - while (reactor_op* op = descriptor_data->op_queue_[i].front()) - { - op->ec_ = boost::asio::error::operation_aborted; - descriptor_data->op_queue_[i].pop(); - ops.push(op); - } - } - - descriptor_lock.unlock(); - - registered_descriptors_.erase(descriptor); - - descriptors_lock.unlock(); - - io_service_.post_deferred_completions(ops); - } + BOOST_ASIO_DECL void close_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); // Add a new timer queue to the reactor. template - void add_timer_queue(timer_queue& timer_queue) - { - mutex::scoped_lock lock(mutex_); - timer_queues_.insert(&timer_queue); - } + void add_timer_queue(timer_queue& queue); // Remove a timer queue from the reactor. template - void remove_timer_queue(timer_queue& timer_queue) - { - mutex::scoped_lock lock(mutex_); - timer_queues_.erase(&timer_queue); - } + void remove_timer_queue(timer_queue& queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template - void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, timer_op* op, void* token) - { - mutex::scoped_lock lock(mutex_); - if (!shutdown_) - { - bool earliest = timer_queue.enqueue_timer(time, op, token); - io_service_.work_started(); - if (earliest) - interrupt(); - } - } + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token); // Cancel the timer operations associated with the given token. Returns the // number of operations that have been posted or dispatched. template - std::size_t cancel_timer(timer_queue& timer_queue, void* token) - { - mutex::scoped_lock lock(mutex_); - op_queue ops; - std::size_t n = timer_queue.cancel_timer(token, ops); - lock.unlock(); - io_service_.post_deferred_completions(ops); - return n; - } + std::size_t cancel_timer(timer_queue& queue, void* token); // Run the kqueue loop. - void run(bool block, op_queue& 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; - - lock.unlock(); - - // Block on the kqueue descriptor. - struct kevent events[128]; - int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout); - - // Dispatch the waiting events. - for (int i = 0; i < num_events; ++i) - { - int descriptor = events[i].ident; - void* ptr = events[i].udata; - if (ptr == &interrupter_) - { - // No need to reset the interrupter since we're leaving the descriptor - // in a ready-to-read state and relying on one-shot notifications. - } - else - { - descriptor_state* descriptor_data = static_cast(ptr); - mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); - - // Exception operations must be processed first to ensure that any - // out-of-band data is read before normal data. - static const int filter[max_ops] = - { EVFILT_READ, EVFILT_WRITE, EVFILT_READ }; - for (int j = max_ops - 1; j >= 0; --j) - { - if (events[i].filter == filter[j]) - { - if (j != except_op || events[i].flags & EV_OOBAND) - { - while (reactor_op* op = descriptor_data->op_queue_[j].front()) - { - if (events[i].flags & EV_ERROR) - { - op->ec_ = boost::system::error_code(events[i].data, - boost::asio::error::get_system_category()); - descriptor_data->op_queue_[j].pop(); - ops.push(op); - } - if (op->perform()) - { - descriptor_data->op_queue_[j].pop(); - ops.push(op); - } - else - break; - } - } - } - } - - // Renew registration for event notifications. - struct kevent event; - switch (events[i].filter) - { - case EVFILT_READ: - if (!descriptor_data->op_queue_[read_op].empty()) - EV_SET(&event, descriptor, EVFILT_READ, - EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); - else if (!descriptor_data->op_queue_[except_op].empty()) - EV_SET(&event, descriptor, EVFILT_READ, - EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); - else - continue; - case EVFILT_WRITE: - if (!descriptor_data->op_queue_[write_op].empty()) - EV_SET(&event, descriptor, EVFILT_WRITE, - EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); - else - continue; - default: - break; - } - if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) - { - boost::system::error_code error(errno, - boost::asio::error::get_system_category()); - for (int j = 0; j < max_ops; ++j) - { - while (reactor_op* op = descriptor_data->op_queue_[j].front()) - { - op->ec_ = error; - descriptor_data->op_queue_[j].pop(); - ops.push(op); - } - } - } - } - } - - lock.lock(); - timer_queues_.get_ready_timers(ops); - } + BOOST_ASIO_DECL void run(bool block, op_queue& ops); // Interrupt the kqueue loop. - void interrupt() - { - struct kevent event; - EV_SET(&event, interrupter_.read_descriptor(), - EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &interrupter_); - ::kevent(kqueue_fd_, &event, 1, 0, 0, 0); - } + BOOST_ASIO_DECL void interrupt(); private: // Create the kqueue file descriptor. Throws an exception if the descriptor // cannot be created. - static int do_kqueue_create() - { - int fd = kqueue(); - if (fd == -1) - { - boost::throw_exception( - boost::system::system_error( - boost::system::error_code(errno, - boost::asio::error::get_system_category()), - "kqueue")); - } - return fd; - } + BOOST_ASIO_DECL static int do_kqueue_create(); + + // Helper function to add a new timer queue. + BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); // Get the timeout value for the kevent call. - timespec* get_timeout(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); - ts.tv_sec = usec / 1000000; - ts.tv_nsec = (usec % 1000000) * 1000; - return &ts; - } + BOOST_ASIO_DECL timespec* get_timeout(timespec& ts); // The io_service implementation used to post completions. io_service_impl& io_service_; @@ -480,8 +186,13 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_KQUEUE) - #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_KQUEUE) + #endif // BOOST_ASIO_DETAIL_KQUEUE_REACTOR_HPP diff --git a/include/boost/asio/detail/kqueue_reactor_fwd.hpp b/include/boost/asio/detail/kqueue_reactor_fwd.hpp index 0471c391..97f8c96a 100644 --- a/include/boost/asio/detail/kqueue_reactor_fwd.hpp +++ b/include/boost/asio/detail/kqueue_reactor_fwd.hpp @@ -1,6 +1,6 @@ // -// kqueue_reactor_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/kqueue_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) @@ -16,15 +16,9 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#if !defined(BOOST_ASIO_DISABLE_KQUEUE) - -#if (defined(__MACH__) && defined(__APPLE__)) \ - || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) - -// Define this to indicate that kqueue is supported on the target platform. -#define BOOST_ASIO_HAS_KQUEUE 1 +#if defined(BOOST_ASIO_HAS_KQUEUE) namespace boost { namespace asio { @@ -36,11 +30,6 @@ class kqueue_reactor; } // namespace asio } // namespace boost -#endif // (defined(__MACH__) && defined(__APPLE__)) - // || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) - -#endif // !defined(BOOST_ASIO_DISABLE_KQUEUE) - -#include +#endif // defined(BOOST_ASIO_HAS_KQUEUE) #endif // BOOST_ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP diff --git a/include/boost/asio/detail/local_free_on_block_exit.hpp b/include/boost/asio/detail/local_free_on_block_exit.hpp index 6a60173e..6c8e0380 100644 --- a/include/boost/asio/detail/local_free_on_block_exit.hpp +++ b/include/boost/asio/detail/local_free_on_block_exit.hpp @@ -1,6 +1,6 @@ // -// local_free_on_block_exit.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/local_free_on_block_exit.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include #include +#include + namespace boost { namespace asio { namespace detail { @@ -54,8 +52,8 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - #include +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP diff --git a/include/boost/asio/detail/macos_fenced_block.hpp b/include/boost/asio/detail/macos_fenced_block.hpp index 496d7f0c..a653aee5 100644 --- a/include/boost/asio/detail/macos_fenced_block.hpp +++ b/include/boost/asio/detail/macos_fenced_block.hpp @@ -1,6 +1,6 @@ // -// macos_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/macos_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(__MACH__) && defined(__APPLE__) -#include #include -#include + +#include namespace boost { namespace asio { @@ -52,8 +48,8 @@ public: } // namespace asio } // namespace boost -#endif // defined(__MACH__) && defined(__APPLE__) - #include +#endif // defined(__MACH__) && defined(__APPLE__) + #endif // BOOST_ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/mutex.hpp b/include/boost/asio/detail/mutex.hpp index e804ec25..f6019965 100644 --- a/include/boost/asio/detail/mutex.hpp +++ b/include/boost/asio/detail/mutex.hpp @@ -1,6 +1,6 @@ // -// mutex.hpp -// ~~~~~~~~~ +// detail/mutex.hpp +// ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include @@ -47,6 +43,4 @@ typedef posix_mutex mutex; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_MUTEX_HPP diff --git a/include/boost/asio/detail/noncopyable.hpp b/include/boost/asio/detail/noncopyable.hpp index b3a6e7cc..65ae9a26 100644 --- a/include/boost/asio/detail/noncopyable.hpp +++ b/include/boost/asio/detail/noncopyable.hpp @@ -1,6 +1,6 @@ // -// noncopyable.hpp -// ~~~~~~~~~~~~~~~ +// detail/noncopyable.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/detail/null_buffers_op.hpp b/include/boost/asio/detail/null_buffers_op.hpp deleted file mode 100644 index 02160af5..00000000 --- a/include/boost/asio/detail/null_buffers_op.hpp +++ /dev/null @@ -1,79 +0,0 @@ -// -// null_buffers_op.hpp -// ~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2010 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_BUFFERS_OP_HPP -#define BOOST_ASIO_DETAIL_NULL_BUFFERS_OP_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#include -#include -#include -#include - -namespace boost { -namespace asio { -namespace detail { - -template -class null_buffers_op : public reactor_op -{ -public: - null_buffers_op(Handler handler) - : reactor_op(&null_buffers_op::do_perform, &null_buffers_op::do_complete), - handler_(handler) - { - } - - static bool do_perform(reactor_op*) - { - return true; - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - null_buffers_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // 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(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - -private: - Handler handler_; -}; - -} // namespace detail -} // namespace asio -} // namespace boost - -#include - -#endif // BOOST_ASIO_DETAIL_NULL_BUFFERS_OP_HPP diff --git a/include/boost/asio/detail/null_event.hpp b/include/boost/asio/detail/null_event.hpp index 2dc0bf6d..3acc26c7 100644 --- a/include/boost/asio/detail/null_event.hpp +++ b/include/boost/asio/detail/null_event.hpp @@ -1,6 +1,6 @@ // -// null_event.hpp -// ~~~~~~~~~~~~~~ +// detail/null_event.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include +#include + namespace boost { namespace asio { namespace detail { @@ -72,8 +70,8 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) - #include +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_NULL_EVENT_HPP diff --git a/include/boost/asio/detail/null_fenced_block.hpp b/include/boost/asio/detail/null_fenced_block.hpp index ea8e0fce..ead4c876 100644 --- a/include/boost/asio/detail/null_fenced_block.hpp +++ b/include/boost/asio/detail/null_fenced_block.hpp @@ -1,6 +1,6 @@ // -// null_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// detail/null_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // diff --git a/include/boost/asio/detail/null_mutex.hpp b/include/boost/asio/detail/null_mutex.hpp index edc13584..8fca31cb 100644 --- a/include/boost/asio/detail/null_mutex.hpp +++ b/include/boost/asio/detail/null_mutex.hpp @@ -1,6 +1,6 @@ // -// null_mutex.hpp -// ~~~~~~~~~~~~~~ +// detail/null_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include #include +#include + namespace boost { namespace asio { namespace detail { @@ -61,8 +59,8 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) - #include +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_NULL_MUTEX_HPP diff --git a/include/boost/asio/detail/null_signal_blocker.hpp b/include/boost/asio/detail/null_signal_blocker.hpp index 65b55e96..67713a7b 100644 --- a/include/boost/asio/detail/null_signal_blocker.hpp +++ b/include/boost/asio/detail/null_signal_blocker.hpp @@ -1,6 +1,6 @@ // -// null_signal_blocker.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// detail/null_signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include +#include + namespace boost { namespace asio { namespace detail { @@ -58,8 +56,8 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) - #include +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP diff --git a/include/boost/asio/detail/null_thread.hpp b/include/boost/asio/detail/null_thread.hpp index ba163114..93fd7154 100644 --- a/include/boost/asio/detail/null_thread.hpp +++ b/include/boost/asio/detail/null_thread.hpp @@ -1,6 +1,6 @@ // -// null_thread.hpp -// ~~~~~~~~~~~~~~~ +// detail/null_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,21 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) -#include -#include -#include - -#include #include +#include +#include + +#include namespace boost { namespace asio { @@ -41,11 +35,10 @@ class null_thread public: // Constructor. template - null_thread(Function f) + null_thread(Function) { - boost::system::system_error e( + boost::asio::detail::throw_error( boost::asio::error::operation_not_supported, "thread"); - boost::throw_exception(e); } // Destructor. @@ -63,8 +56,8 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) - #include +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_NULL_THREAD_HPP diff --git a/include/boost/asio/detail/null_tss_ptr.hpp b/include/boost/asio/detail/null_tss_ptr.hpp index bd83e7ee..3eff2dcf 100644 --- a/include/boost/asio/detail/null_tss_ptr.hpp +++ b/include/boost/asio/detail/null_tss_ptr.hpp @@ -1,6 +1,6 @@ // -// null_tss_ptr.hpp -// ~~~~~~~~~~~~~~~~ +// detail/null_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) #include +#include + namespace boost { namespace asio { namespace detail { @@ -65,8 +63,8 @@ private: } // namespace asio } // namespace boost -#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) - #include +#endif // !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_NULL_TSS_PTR_HPP diff --git a/include/boost/asio/detail/old_win_sdk_compat.hpp b/include/boost/asio/detail/old_win_sdk_compat.hpp index 5f841820..10cd8985 100644 --- a/include/boost/asio/detail/old_win_sdk_compat.hpp +++ b/include/boost/asio/detail/old_win_sdk_compat.hpp @@ -1,6 +1,6 @@ // -// old_win_sdk_compat.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/old_win_sdk_compat.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -36,6 +32,8 @@ // a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support // in that case. +#include + namespace boost { namespace asio { namespace detail { @@ -323,6 +321,8 @@ inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a) } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_OLD_WIN_SDK) // Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY. @@ -337,6 +337,4 @@ inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a) #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -#include - #endif // BOOST_ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP diff --git a/include/boost/asio/detail/op_queue.hpp b/include/boost/asio/detail/op_queue.hpp index ddf3e187..e35e82d3 100644 --- a/include/boost/asio/detail/op_queue.hpp +++ b/include/boost/asio/detail/op_queue.hpp @@ -1,6 +1,6 @@ // -// op_queue.hpp -// ~~~~~~~~~~~~ +// detail/op_queue.hpp +// ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,10 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/operation.hpp b/include/boost/asio/detail/operation.hpp index 579b6b5a..e42455cb 100644 --- a/include/boost/asio/detail/operation.hpp +++ b/include/boost/asio/detail/operation.hpp @@ -1,6 +1,6 @@ // -// operation.hpp -// ~~~~~~~~~~~~~ +// detail/operation.hpp +// ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,14 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_IOCP) # include #else -# include # include #endif @@ -33,13 +30,11 @@ namespace detail { #if defined(BOOST_ASIO_HAS_IOCP) typedef win_iocp_operation operation; #else -typedef task_io_service_operation operation; +typedef task_io_service_operation operation; #endif } // namespace detail } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_OPERATION_HPP diff --git a/include/boost/asio/detail/pipe_select_interrupter.hpp b/include/boost/asio/detail/pipe_select_interrupter.hpp index 7f9e122e..e6314765 100644 --- a/include/boost/asio/detail/pipe_select_interrupter.hpp +++ b/include/boost/asio/detail/pipe_select_interrupter.hpp @@ -1,6 +1,6 @@ // -// pipe_select_interrupter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/pipe_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,22 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include +#include #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#if !defined(BOOST_ASIO_HAS_EVENTFD) #include -#include -#include - -#include -#include namespace boost { namespace asio { @@ -40,57 +30,16 @@ class pipe_select_interrupter { public: // Constructor. - pipe_select_interrupter() - { - int pipe_fds[2]; - if (pipe(pipe_fds) == 0) - { - read_descriptor_ = pipe_fds[0]; - ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); - write_descriptor_ = pipe_fds[1]; - ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); - } - else - { - boost::system::error_code ec(errno, - boost::asio::error::get_system_category()); - boost::system::system_error e(ec, "pipe_select_interrupter"); - boost::throw_exception(e); - } - } + BOOST_ASIO_DECL pipe_select_interrupter(); // Destructor. - ~pipe_select_interrupter() - { - if (read_descriptor_ != -1) - ::close(read_descriptor_); - if (write_descriptor_ != -1) - ::close(write_descriptor_); - } + BOOST_ASIO_DECL ~pipe_select_interrupter(); // Interrupt the select call. - void interrupt() - { - char byte = 0; - int result = ::write(write_descriptor_, &byte, 1); - (void)result; - } + BOOST_ASIO_DECL void interrupt(); // Reset the select interrupt. Returns true if the call was interrupted. - bool reset() - { - for (;;) - { - char data[1024]; - int bytes_read = ::read(read_descriptor_, data, sizeof(data)); - if (bytes_read < 0 && errno == EINTR) - continue; - bool was_interrupted = (bytes_read > 0); - while (bytes_read == sizeof(data)) - bytes_read = ::read(read_descriptor_, data, sizeof(data)); - return was_interrupted; - } - } + BOOST_ASIO_DECL bool reset(); // Get the read descriptor to be passed to select. int read_descriptor() const @@ -115,8 +64,13 @@ private: } // namespace asio } // namespace boost -#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_ASIO_HAS_EVENTFD) +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP diff --git a/include/boost/asio/detail/pop_options.hpp b/include/boost/asio/detail/pop_options.hpp index a26b2039..8653f1a0 100644 --- a/include/boost/asio/detail/pop_options.hpp +++ b/include/boost/asio/detail/pop_options.hpp @@ -1,6 +1,6 @@ // -// pop_options.hpp -// ~~~~~~~~~~~~~~~ +// detail/pop_options.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // diff --git a/include/boost/asio/detail/posix_event.hpp b/include/boost/asio/detail/posix_event.hpp index b2938cfa..13fa3d47 100644 --- a/include/boost/asio/detail/posix_event.hpp +++ b/include/boost/asio/detail/posix_event.hpp @@ -1,6 +1,6 @@ // -// posix_event.hpp -// ~~~~~~~~~~~~~~~ +// detail/posix_event.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,24 +15,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) -#if defined(BOOST_HAS_PTHREADS) - -#include #include -#include #include -#include - -#include #include +#include + namespace boost { namespace asio { namespace detail { @@ -42,19 +34,7 @@ class posix_event { public: // Constructor. - posix_event() - : signalled_(false) - { - int error = ::pthread_cond_init(&cond_, 0); - if (error != 0) - { - boost::system::system_error e( - boost::system::error_code(error, - boost::asio::error::get_system_category()), - "event"); - boost::throw_exception(e); - } - } + BOOST_ASIO_DECL posix_event(); // Destructor. ~posix_event() @@ -109,8 +89,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_HAS_PTHREADS) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_POSIX_EVENT_HPP diff --git a/include/boost/asio/detail/posix_fd_set_adapter.hpp b/include/boost/asio/detail/posix_fd_set_adapter.hpp index 09fc28d0..5395eb99 100644 --- a/include/boost/asio/detail/posix_fd_set_adapter.hpp +++ b/include/boost/asio/detail/posix_fd_set_adapter.hpp @@ -1,6 +1,6 @@ // -// posix_fd_set_adapter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/posix_fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include - -#include +#include #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#include +#include + +#include + namespace boost { namespace asio { namespace detail { @@ -76,8 +75,8 @@ private: } // namespace asio } // namespace boost -#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP diff --git a/include/boost/asio/detail/posix_mutex.hpp b/include/boost/asio/detail/posix_mutex.hpp index 6d9a44f5..4fcd8ace 100644 --- a/include/boost/asio/detail/posix_mutex.hpp +++ b/include/boost/asio/detail/posix_mutex.hpp @@ -1,6 +1,6 @@ // -// posix_mutex.hpp -// ~~~~~~~~~~~~~~~ +// detail/posix_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,24 +15,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) -#if defined(BOOST_HAS_PTHREADS) - -#include -#include #include -#include - -#include #include #include +#include + namespace boost { namespace asio { namespace detail { @@ -46,18 +38,7 @@ public: typedef boost::asio::detail::scoped_lock scoped_lock; // Constructor. - posix_mutex() - { - int error = ::pthread_mutex_init(&mutex_, 0); - if (error != 0) - { - boost::system::system_error e( - boost::system::error_code(error, - boost::asio::error::get_system_category()), - "mutex"); - boost::throw_exception(e); - } - } + BOOST_ASIO_DECL posix_mutex(); // Destructor. ~posix_mutex() @@ -86,8 +67,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_HAS_PTHREADS) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_POSIX_MUTEX_HPP diff --git a/include/boost/asio/detail/posix_signal_blocker.hpp b/include/boost/asio/detail/posix_signal_blocker.hpp index aebe39ba..247a7a8a 100644 --- a/include/boost/asio/detail/posix_signal_blocker.hpp +++ b/include/boost/asio/detail/posix_signal_blocker.hpp @@ -1,6 +1,6 @@ // -// posix_signal_blocker.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/posix_signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,22 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) -#if defined(BOOST_HAS_PTHREADS) - -#include #include #include #include -#include - #include +#include + namespace boost { namespace asio { namespace detail { @@ -85,8 +80,8 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_HAS_PTHREADS) - #include +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP diff --git a/include/boost/asio/detail/posix_thread.hpp b/include/boost/asio/detail/posix_thread.hpp index 41d8bc94..a87e3967 100644 --- a/include/boost/asio/detail/posix_thread.hpp +++ b/include/boost/asio/detail/posix_thread.hpp @@ -1,6 +1,6 @@ // -// posix_thread.hpp -// ~~~~~~~~~~~~~~~~ +// detail/posix_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,29 +15,23 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) -#if defined(BOOST_HAS_PTHREADS) - -#include -#include -#include #include -#include - -#include #include +#include + namespace boost { namespace asio { namespace detail { -extern "C" void* boost_asio_detail_posix_thread_function(void* arg); +extern "C" +{ + BOOST_ASIO_DECL void* boost_asio_detail_posix_thread_function(void* arg); +} class posix_thread : private noncopyable @@ -48,36 +42,14 @@ public: posix_thread(Function f) : joined_(false) { - std::auto_ptr arg(new func(f)); - int error = ::pthread_create(&thread_, 0, - boost_asio_detail_posix_thread_function, arg.get()); - if (error != 0) - { - boost::system::system_error e( - boost::system::error_code(error, - boost::asio::error::get_system_category()), - "thread"); - boost::throw_exception(e); - } - arg.release(); + start_thread(new func(f)); } // Destructor. - ~posix_thread() - { - if (!joined_) - ::pthread_detach(thread_); - } + BOOST_ASIO_DECL ~posix_thread(); // Wait for the thread to exit. - void join() - { - if (!joined_) - { - ::pthread_join(thread_, 0); - joined_ = true; - } - } + BOOST_ASIO_DECL void join(); private: friend void* boost_asio_detail_posix_thread_function(void* arg); @@ -89,6 +61,12 @@ private: virtual void run() = 0; }; + struct auto_func_base_ptr + { + func_base* ptr; + ~auto_func_base_ptr() { delete ptr; } + }; + template class func : public func_base @@ -108,24 +86,22 @@ private: Function f_; }; + BOOST_ASIO_DECL void start_thread(func_base* arg); + ::pthread_t thread_; bool joined_; }; -inline void* boost_asio_detail_posix_thread_function(void* arg) -{ - std::auto_ptr f( - static_cast(arg)); - f->run(); - return 0; -} - } // namespace detail } // namespace asio } // namespace boost -#endif // defined(BOOST_HAS_PTHREADS) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_POSIX_THREAD_HPP diff --git a/include/boost/asio/detail/posix_tss_ptr.hpp b/include/boost/asio/detail/posix_tss_ptr.hpp index c83df96e..dfe83696 100644 --- a/include/boost/asio/detail/posix_tss_ptr.hpp +++ b/include/boost/asio/detail/posix_tss_ptr.hpp @@ -1,6 +1,6 @@ // -// posix_tss_ptr.hpp -// ~~~~~~~~~~~~~~~~~ +// detail/posix_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,27 +15,22 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include +#if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) -#if defined(BOOST_HAS_PTHREADS) - -#include -#include #include -#include - -#include #include +#include + namespace boost { namespace asio { namespace detail { +// Helper function to create thread-specific storage. +BOOST_ASIO_DECL void posix_tss_ptr_create(pthread_key_t& key); + template class posix_tss_ptr : private noncopyable @@ -44,15 +39,7 @@ public: // Constructor. posix_tss_ptr() { - int error = ::pthread_key_create(&tss_key_, 0); - if (error != 0) - { - boost::system::system_error e( - boost::system::error_code(error, - boost::asio::error::get_system_category()), - "tss"); - boost::throw_exception(e); - } + posix_tss_ptr_create(tss_key_); } // Destructor. @@ -77,14 +64,19 @@ private: // Thread-specific storage to allow unlocked access to determine whether a // thread is a member of the pool. pthread_key_t tss_key_; + }; } // namespace detail } // namespace asio } // namespace boost -#endif // defined(BOOST_HAS_PTHREADS) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_HAS_PTHREADS) && !defined(BOOST_ASIO_DISABLE_THREADS) + #endif // BOOST_ASIO_DETAIL_POSIX_TSS_PTR_HPP diff --git a/include/boost/asio/detail/push_options.hpp b/include/boost/asio/detail/push_options.hpp index cb0e9024..00a9b7ee 100644 --- a/include/boost/asio/detail/push_options.hpp +++ b/include/boost/asio/detail/push_options.hpp @@ -1,6 +1,6 @@ // -// push_options.hpp -// ~~~~~~~~~~~~~~~~ +// detail/push_options.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // diff --git a/include/boost/asio/detail/reactive_descriptor_service.hpp b/include/boost/asio/detail/reactive_descriptor_service.hpp index 536b96a5..993211a7 100644 --- a/include/boost/asio/detail/reactive_descriptor_service.hpp +++ b/include/boost/asio/detail/reactive_descriptor_service.hpp @@ -1,6 +1,6 @@ // -// reactive_descriptor_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/reactive_descriptor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,21 +15,24 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include #include -#include #include #include #include #include +#include +#include #include #include -#include +#include #include -#include -#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#include namespace boost { namespace asio { @@ -49,7 +52,7 @@ public: // Default constructor. implementation_type() : descriptor_(-1), - flags_(0) + state_(0) { } @@ -60,94 +63,29 @@ public: // The native descriptor representation. int descriptor_; - enum - { - // The user wants a non-blocking descriptor. - user_set_non_blocking = 1, - - // The descriptor has been set non-blocking. - internal_non_blocking = 2, - - // Helper "flag" used to determine whether the descriptor is non-blocking. - non_blocking = user_set_non_blocking | internal_non_blocking - }; - - // Flags indicating the current state of the descriptor. - unsigned char flags_; + // The current state of the descriptor. + descriptor_ops::state_type state_; // Per-descriptor data used by the reactor. reactor::per_descriptor_data reactor_data_; }; - // The maximum number of buffers to support in a single operation. - enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; - // Constructor. - reactive_descriptor_service(boost::asio::io_service& io_service) - : io_service_impl_(boost::asio::use_service(io_service)), - reactor_(boost::asio::use_service(io_service)) - { - reactor_.init_task(); - } + BOOST_ASIO_DECL reactive_descriptor_service( + boost::asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - } + BOOST_ASIO_DECL void shutdown_service(); // Construct a new descriptor implementation. - void construct(implementation_type& impl) - { - impl.descriptor_ = -1; - impl.flags_ = 0; - } + BOOST_ASIO_DECL void construct(implementation_type& impl); // Destroy a descriptor implementation. - void destroy(implementation_type& impl) - { - if (impl.descriptor_ != -1) - { - reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_); - - if (impl.flags_ & implementation_type::internal_non_blocking) - { - ioctl_arg_type non_blocking = 0; - boost::system::error_code ignored_ec; - descriptor_ops::ioctl(impl.descriptor_, - FIONBIO, &non_blocking, ignored_ec); - impl.flags_ &= ~implementation_type::internal_non_blocking; - } - - boost::system::error_code ignored_ec; - descriptor_ops::close(impl.descriptor_, ignored_ec); - - impl.descriptor_ = -1; - } - } + BOOST_ASIO_DECL void destroy(implementation_type& impl); // Assign a native descriptor to a descriptor implementation. - boost::system::error_code assign(implementation_type& impl, - const native_type& native_descriptor, boost::system::error_code& ec) - { - if (is_open(impl)) - { - ec = boost::asio::error::already_open; - return ec; - } - - if (int err = reactor_.register_descriptor( - native_descriptor, impl.reactor_data_)) - { - ec = boost::system::error_code(err, - boost::asio::error::get_system_category()); - return ec; - } - - impl.descriptor_ = native_descriptor; - impl.flags_ = 0; - ec = boost::system::error_code(); - return ec; - } + BOOST_ASIO_DECL boost::system::error_code assign(implementation_type& impl, + const native_type& native_descriptor, boost::system::error_code& ec); // Determine whether the descriptor is open. bool is_open(const implementation_type& impl) const @@ -156,31 +94,8 @@ public: } // Destroy a descriptor implementation. - boost::system::error_code close(implementation_type& impl, - boost::system::error_code& ec) - { - if (is_open(impl)) - { - reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_); - - if (impl.flags_ & implementation_type::internal_non_blocking) - { - ioctl_arg_type non_blocking = 0; - boost::system::error_code ignored_ec; - descriptor_ops::ioctl(impl.descriptor_, - FIONBIO, &non_blocking, ignored_ec); - impl.flags_ &= ~implementation_type::internal_non_blocking; - } - - if (descriptor_ops::close(impl.descriptor_, ec) == -1) - return ec; - - impl.descriptor_ = -1; - } - - ec = boost::system::error_code(); - return ec; - } + BOOST_ASIO_DECL boost::system::error_code close(implementation_type& impl, + boost::system::error_code& ec); // Get the native descriptor representation. native_type native(const implementation_type& impl) const @@ -189,56 +104,16 @@ public: } // Cancel all operations associated with the descriptor. - boost::system::error_code cancel(implementation_type& impl, - boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_); - ec = boost::system::error_code(); - return ec; - } + BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl, + boost::system::error_code& ec); // Perform an IO control command on the descriptor. template boost::system::error_code io_control(implementation_type& impl, IO_Control_Command& command, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - descriptor_ops::ioctl(impl.descriptor_, command.name(), - static_cast(command.data()), ec); - - // When updating the non-blocking mode we always perform the ioctl syscall, - // even if the flags would otherwise indicate that the descriptor is - // already in the correct state. This ensures that the underlying - // descriptor is put into the state that has been requested by the user. If - // the ioctl syscall was successful then we need to update the flags to - // match. - if (!ec && command.name() == static_cast(FIONBIO)) - { - if (*static_cast(command.data())) - { - impl.flags_ |= implementation_type::user_set_non_blocking; - } - else - { - // Clearing the non-blocking mode always overrides any internally-set - // non-blocking flag. Any subsequent asynchronous operations will need - // to re-enable non-blocking I/O. - impl.flags_ &= ~(implementation_type::user_set_non_blocking - | implementation_type::internal_non_blocking); - } - } - + descriptor_ops::ioctl(impl.descriptor_, impl.state_, + command.name(), static_cast(command.data()), ec); return ec; } @@ -247,148 +122,23 @@ public: size_t write_some(implementation_type& impl, const ConstBufferSequence& buffers, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter bufs(buffers); - // A request to read_some 0 bytes on a stream is a no-op. - if (bufs.all_empty()) - { - ec = boost::system::error_code(); - return 0; - } - - // Send the data. - for (;;) - { - // Try to complete the operation without blocking. - int bytes_sent = descriptor_ops::gather_write( - impl.descriptor_, bufs.buffers(), bufs.count(), ec); - - // Check if operation succeeded. - if (bytes_sent >= 0) - return bytes_sent; - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != boost::asio::error::would_block - && ec != boost::asio::error::try_again)) - return 0; - - // Wait for descriptor to become ready. - if (descriptor_ops::poll_write(impl.descriptor_, ec) < 0) - return 0; - } + return descriptor_ops::sync_write(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); } // Wait until data can be written without blocking. size_t write_some(implementation_type& impl, const null_buffers&, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - // Wait for descriptor to become ready. descriptor_ops::poll_write(impl.descriptor_, ec); return 0; } - template - class write_op_base : public reactor_op - { - public: - write_op_base(int descriptor, - const ConstBufferSequence& buffers, func_type complete_func) - : reactor_op(&write_op_base::do_perform, complete_func), - descriptor_(descriptor), - buffers_(buffers) - { - } - - static bool do_perform(reactor_op* base) - { - write_op_base* o(static_cast(base)); - - buffer_sequence_adapter bufs(o->buffers_); - - for (;;) - { - // Write the data. - boost::system::error_code ec; - int bytes = descriptor_ops::gather_write( - o->descriptor_, bufs.buffers(), bufs.count(), ec); - - // Retry operation if interrupted by signal. - if (ec == boost::asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == boost::asio::error::would_block - || ec == boost::asio::error::try_again) - return false; - - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - int descriptor_; - ConstBufferSequence buffers_; - }; - - template - class write_op : public write_op_base - { - public: - write_op(int descriptor, - const ConstBufferSequence& buffers, Handler handler) - : write_op_base( - descriptor, buffers, &write_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - write_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // 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(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous write. The data being sent must be valid for the // lifetime of the asynchronous operation. template @@ -396,15 +146,16 @@ public: const ConstBufferSequence& buffers, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef write_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, impl.descriptor_, buffers, handler); + typedef descriptor_write_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.descriptor_, buffers, handler); - start_op(impl, reactor::write_op, ptr.get(), true, + start_op(impl, reactor::write_op, p.p, true, buffer_sequence_adapter::all_empty(buffers)); - ptr.release(); + p.v = p.p = 0; } // Start an asynchronous wait until data can be written without blocking. @@ -413,13 +164,14 @@ public: const null_buffers&, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); - start_op(impl, reactor::write_op, ptr.get(), false, false); - ptr.release(); + start_op(impl, reactor::write_op, p.p, false, false); + p.v = p.p = 0; } // Read some data from the stream. Returns the number of bytes read. @@ -427,157 +179,23 @@ public: size_t read_some(implementation_type& impl, const MutableBufferSequence& buffers, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter bufs(buffers); - // A request to read_some 0 bytes on a stream is a no-op. - if (bufs.all_empty()) - { - ec = boost::system::error_code(); - return 0; - } - - // Read some data. - for (;;) - { - // Try to complete the operation without blocking. - int bytes_read = descriptor_ops::scatter_read( - impl.descriptor_, bufs.buffers(), bufs.count(), ec); - - // Check if operation succeeded. - if (bytes_read > 0) - return bytes_read; - - // Check for EOF. - if (bytes_read == 0) - { - ec = boost::asio::error::eof; - return 0; - } - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != boost::asio::error::would_block - && ec != boost::asio::error::try_again)) - return 0; - - // Wait for descriptor to become ready. - if (descriptor_ops::poll_read(impl.descriptor_, ec) < 0) - return 0; - } + return descriptor_ops::sync_read(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); } // Wait until data can be read without blocking. size_t read_some(implementation_type& impl, const null_buffers&, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - // Wait for descriptor to become ready. descriptor_ops::poll_read(impl.descriptor_, ec); return 0; } - template - class read_op_base : public reactor_op - { - public: - read_op_base(int descriptor, - const MutableBufferSequence& buffers, func_type complete_func) - : reactor_op(&read_op_base::do_perform, complete_func), - descriptor_(descriptor), - buffers_(buffers) - { - } - - static bool do_perform(reactor_op* base) - { - read_op_base* o(static_cast(base)); - - buffer_sequence_adapter bufs(o->buffers_); - - for (;;) - { - // Read some data. - boost::system::error_code ec; - int bytes = descriptor_ops::scatter_read( - o->descriptor_, bufs.buffers(), bufs.count(), ec); - if (bytes == 0) - ec = boost::asio::error::eof; - - // Retry operation if interrupted by signal. - if (ec == boost::asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == boost::asio::error::would_block - || ec == boost::asio::error::try_again) - return false; - - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - int descriptor_; - MutableBufferSequence buffers_; - }; - - template - class read_op : public read_op_base - { - public: - read_op(int descriptor, - const MutableBufferSequence& buffers, Handler handler) - : read_op_base( - descriptor, buffers, &read_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - read_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // 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(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous read. The buffer for the data being read must be // valid for the lifetime of the asynchronous operation. template @@ -585,16 +203,16 @@ public: const MutableBufferSequence& buffers, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef read_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, - impl.descriptor_, buffers, handler); + typedef descriptor_read_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.descriptor_, buffers, handler); - start_op(impl, reactor::read_op, ptr.get(), true, + start_op(impl, reactor::read_op, p.p, true, buffer_sequence_adapter::all_empty(buffers)); - ptr.release(); + p.v = p.p = 0; } // Wait until data can be read without blocking. @@ -603,57 +221,20 @@ public: const null_buffers&, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); - start_op(impl, reactor::read_op, ptr.get(), false, false); - ptr.release(); + start_op(impl, reactor::read_op, p.p, false, false); + p.v = p.p = 0; } private: // Start the asynchronous operation. - void start_op(implementation_type& impl, int op_type, - reactor_op* op, bool non_blocking, bool noop) - { - if (!noop) - { - if (is_open(impl)) - { - if (is_non_blocking(impl) || set_non_blocking(impl, op->ec_)) - { - reactor_.start_op(op_type, impl.descriptor_, - impl.reactor_data_, op, non_blocking); - return; - } - } - else - op->ec_ = boost::asio::error::bad_descriptor; - } - - io_service_impl_.post_immediate_completion(op); - } - - // Determine whether the descriptor has been set non-blocking. - bool is_non_blocking(implementation_type& impl) const - { - return (impl.flags_ & implementation_type::non_blocking); - } - - // Set the internal non-blocking flag. - bool set_non_blocking(implementation_type& impl, - boost::system::error_code& ec) - { - ioctl_arg_type non_blocking = 1; - if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) - return false; - impl.flags_ |= implementation_type::internal_non_blocking; - return true; - } - - // The io_service implementation used to post completions. - io_service_impl& io_service_impl_; + BOOST_ASIO_DECL void start_op(implementation_type& impl, int op_type, + reactor_op* op, bool non_blocking, bool noop); // The selector that performs event demultiplexing for the service. reactor& reactor_; @@ -663,8 +244,12 @@ private: } // namespace asio } // namespace boost -#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP diff --git a/include/boost/asio/detail/reactive_null_buffers_op.hpp b/include/boost/asio/detail/reactive_null_buffers_op.hpp new file mode 100644 index 00000000..a2a69112 --- /dev/null +++ b/include/boost/asio/detail/reactive_null_buffers_op.hpp @@ -0,0 +1,85 @@ +// +// detail/reactive_null_buffers_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_NULL_BUFFERS_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_null_buffers_op : public reactor_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op); + + reactive_null_buffers_op(Handler handler) + : reactor_op(&reactive_null_buffers_op::do_perform, + &reactive_null_buffers_op::do_complete), + handler_(handler) + { + } + + static bool do_perform(reactor_op*) + { + return true; + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_null_buffers_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, 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(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP diff --git a/include/boost/asio/detail/reactive_serial_port_service.hpp b/include/boost/asio/detail/reactive_serial_port_service.hpp index faa2149e..0955f1d4 100644 --- a/include/boost/asio/detail/reactive_serial_port_service.hpp +++ b/include/boost/asio/detail/reactive_serial_port_service.hpp @@ -1,6 +1,6 @@ // -// reactive_serial_port_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/reactive_serial_port_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) @@ -16,23 +16,20 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include + +#if defined(BOOST_ASIO_HAS_SERIAL_PORT) +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -#include -#include #include -#include - -#include - -#if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ - && !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include #include +#include #include #include +#include + namespace boost { namespace asio { namespace detail { @@ -47,119 +44,55 @@ public: // The implementation type of the serial port. typedef reactive_descriptor_service::implementation_type implementation_type; - reactive_serial_port_service(boost::asio::io_service& io_service) - : descriptor_service_(io_service) - { - } + BOOST_ASIO_DECL reactive_serial_port_service( + boost::asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - descriptor_service_.shutdown_service(); - } + BOOST_ASIO_DECL void shutdown_service(); - // Construct a new handle implementation. + // Construct a new serial port implementation. void construct(implementation_type& impl) { descriptor_service_.construct(impl); } - // Destroy a handle implementation. + // Destroy a serial port implementation. void destroy(implementation_type& impl) { descriptor_service_.destroy(impl); } // Open the serial port using the specified device name. - boost::system::error_code open(implementation_type& impl, - const std::string& device, boost::system::error_code& ec) - { - if (is_open(impl)) - { - ec = boost::asio::error::already_open; - return ec; - } + BOOST_ASIO_DECL boost::system::error_code open(implementation_type& impl, + const std::string& device, boost::system::error_code& ec); - int fd = descriptor_ops::open(device.c_str(), - O_RDWR | O_NONBLOCK | O_NOCTTY, ec); - if (fd < 0) - return ec; - - int s = descriptor_ops::fcntl(fd, F_GETFL, ec); - if (s >= 0) - s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec); - if (s < 0) - { - boost::system::error_code ignored_ec; - descriptor_ops::close(fd, ignored_ec); - return ec; - } - - // Set up default serial port options. - termios ios; - descriptor_ops::clear_error(ec); - s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec); - if (s >= 0) - { -#if defined(_BSD_SOURCE) - ::cfmakeraw(&ios); -#else - ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK - | ISTRIP | INLCR | IGNCR | ICRNL | IXON); - ios.c_oflag &= ~OPOST; - ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - ios.c_cflag &= ~(CSIZE | PARENB); - ios.c_cflag |= CS8; -#endif - ios.c_iflag |= IGNPAR; - ios.c_cflag |= CREAD | CLOCAL; - descriptor_ops::clear_error(ec); - s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec); - } - if (s < 0) - { - boost::system::error_code ignored_ec; - descriptor_ops::close(fd, ignored_ec); - return ec; - } - - // We're done. Take ownership of the serial port descriptor. - if (descriptor_service_.assign(impl, fd, ec)) - { - boost::system::error_code ignored_ec; - descriptor_ops::close(fd, ignored_ec); - } - - return ec; - } - - // Assign a native handle to a handle implementation. + // Assign a native descriptor to a serial port implementation. boost::system::error_code assign(implementation_type& impl, const native_type& native_descriptor, boost::system::error_code& ec) { return descriptor_service_.assign(impl, native_descriptor, ec); } - // Determine whether the handle is open. + // Determine whether the serial port is open. bool is_open(const implementation_type& impl) const { return descriptor_service_.is_open(impl); } - // Destroy a handle implementation. + // Destroy a serial port implementation. boost::system::error_code close(implementation_type& impl, boost::system::error_code& ec) { return descriptor_service_.close(impl, ec); } - // Get the native handle representation. + // Get the native serial port representation. native_type native(implementation_type& impl) { return descriptor_service_.native(impl); } - // Cancel all operations associated with the handle. + // Cancel all operations associated with the serial port. boost::system::error_code cancel(implementation_type& impl, boost::system::error_code& ec) { @@ -171,20 +104,9 @@ public: boost::system::error_code set_option(implementation_type& impl, const SettableSerialPortOption& option, boost::system::error_code& ec) { - termios ios; - descriptor_ops::clear_error(ec); - descriptor_ops::error_wrapper(::tcgetattr( - descriptor_service_.native(impl), &ios), ec); - if (ec) - return ec; - - if (option.store(ios, ec)) - return ec; - - descriptor_ops::clear_error(ec); - descriptor_ops::error_wrapper(::tcsetattr( - descriptor_service_.native(impl), TCSANOW, &ios), ec); - return ec; + return do_set_option(impl, + &reactive_serial_port_service::store_option, + &option, ec); } // Get an option from the serial port. @@ -192,21 +114,16 @@ public: boost::system::error_code get_option(const implementation_type& impl, GettableSerialPortOption& option, boost::system::error_code& ec) const { - termios ios; - descriptor_ops::clear_error(ec); - descriptor_ops::error_wrapper(::tcgetattr( - descriptor_service_.native(impl), &ios), ec); - if (ec) - return ec; - - return option.load(ios, ec); + return do_get_option(impl, + &reactive_serial_port_service::load_option, + &option, ec); } // Send a break sequence to the serial port. boost::system::error_code send_break(implementation_type& impl, boost::system::error_code& ec) { - descriptor_ops::clear_error(ec); + errno = 0; descriptor_ops::error_wrapper(::tcsendbreak( descriptor_service_.native(impl), 0), ec); return ec; @@ -247,6 +164,41 @@ public: } private: + // Function pointer type for storing a serial port option. + typedef boost::system::error_code (*store_function_type)( + const void*, termios&, boost::system::error_code&); + + // Helper function template to store a serial port option. + template + static boost::system::error_code store_option(const void* option, + termios& storage, boost::system::error_code& ec) + { + return static_cast(option)->store( + storage, ec); + } + + // Helper function to set a serial port option. + BOOST_ASIO_DECL boost::system::error_code do_set_option( + implementation_type& impl, store_function_type store, + const void* option, boost::system::error_code& ec); + + // Function pointer type for loading a serial port option. + typedef boost::system::error_code (*load_function_type)( + void*, const termios&, boost::system::error_code&); + + // Helper function template to load a serial port option. + template + static boost::system::error_code load_option(void* option, + const termios& storage, boost::system::error_code& ec) + { + return static_cast(option)->load(storage, ec); + } + + // Helper function to get a serial port option. + BOOST_ASIO_DECL boost::system::error_code do_get_option( + const implementation_type& impl, load_function_type load, + void* option, boost::system::error_code& ec) const; + // The implementation used for initiating asynchronous operations. reactive_descriptor_service descriptor_service_; }; @@ -255,9 +207,13 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) - // && !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) + #endif // BOOST_ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP diff --git a/include/boost/asio/detail/reactive_socket_accept_op.hpp b/include/boost/asio/detail/reactive_socket_accept_op.hpp new file mode 100644 index 00000000..3b2413f5 --- /dev/null +++ b/include/boost/asio/detail/reactive_socket_accept_op.hpp @@ -0,0 +1,133 @@ +// +// detail/reactive_socket_accept_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SOCKET_ACCEPT_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_accept_op_base : public reactor_op +{ +public: + reactive_socket_accept_op_base(socket_type socket, + socket_ops::state_type state, Socket& peer, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, func_type complete_func) + : reactor_op(&reactive_socket_accept_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + peer_(peer), + protocol_(protocol), + peer_endpoint_(peer_endpoint) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_accept_op_base* o( + static_cast(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); + + // On success, assign new connection to peer socket object. + if (new_socket >= 0) + { + 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(); + } + + return result; + } + +private: + socket_type socket_; + socket_ops::state_type state_; + Socket& peer_; + Protocol protocol_; + typename Protocol::endpoint* peer_endpoint_; +}; + +template +class reactive_socket_accept_op : + public reactive_socket_accept_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op); + + reactive_socket_accept_op(socket_type socket, + socket_ops::state_type state, Socket& peer, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, Handler handler) + : reactive_socket_accept_op_base(socket, state, peer, + protocol, peer_endpoint, &reactive_socket_accept_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_accept_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, 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(o->handler_, o->ec_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP diff --git a/include/boost/asio/detail/reactive_socket_connect_op.hpp b/include/boost/asio/detail/reactive_socket_connect_op.hpp new file mode 100644 index 00000000..2bfb55d8 --- /dev/null +++ b/include/boost/asio/detail/reactive_socket_connect_op.hpp @@ -0,0 +1,103 @@ +// +// detail/reactive_socket_connect_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SOCKET_CONNECT_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class reactive_socket_connect_op_base : public reactor_op +{ +public: + reactive_socket_connect_op_base(socket_type socket, func_type complete_func) + : reactor_op(&reactive_socket_connect_op_base::do_perform, complete_func), + socket_(socket) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_connect_op_base* o( + static_cast(base)); + + return socket_ops::non_blocking_connect(o->socket_, o->ec_); + } + +private: + socket_type socket_; +}; + +template +class reactive_socket_connect_op : public reactive_socket_connect_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op); + + reactive_socket_connect_op(socket_type socket, Handler handler) + : reactive_socket_connect_op_base(socket, + &reactive_socket_connect_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_connect_op* o + (static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, 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(o->handler_, o->ec_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP diff --git a/include/boost/asio/detail/reactive_socket_recv_op.hpp b/include/boost/asio/detail/reactive_socket_recv_op.hpp new file mode 100644 index 00000000..d58aa3f0 --- /dev/null +++ b/include/boost/asio/detail/reactive_socket_recv_op.hpp @@ -0,0 +1,120 @@ +// +// detail/reactive_socket_recv_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SOCKET_RECV_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_recv_op_base : public reactor_op +{ +public: + reactive_socket_recv_op_base(socket_type socket, + socket_ops::state_type state, const MutableBufferSequence& buffers, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_recv_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + buffers_(buffers), + flags_(flags) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_recv_op_base* o( + static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + return socket_ops::non_blocking_recv(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + (o->state_ & socket_ops::stream_oriented), + o->ec_, o->bytes_transferred_); + } + +private: + socket_type socket_; + socket_ops::state_type state_; + MutableBufferSequence buffers_; + socket_base::message_flags flags_; +}; + +template +class reactive_socket_recv_op : + public reactive_socket_recv_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op); + + reactive_socket_recv_op(socket_type socket, + socket_ops::state_type state, const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + : reactive_socket_recv_op_base(socket, state, + buffers, flags, &reactive_socket_recv_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_recv_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, 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(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP diff --git a/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp b/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp new file mode 100644 index 00000000..469b6a5d --- /dev/null +++ b/include/boost/asio/detail/reactive_socket_recvfrom_op.hpp @@ -0,0 +1,130 @@ +// +// detail/reactive_socket_recvfrom_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SOCKET_RECVFROM_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_recvfrom_op_base : public reactor_op +{ +public: + reactive_socket_recvfrom_op_base(socket_type socket, int protocol_type, + const MutableBufferSequence& buffers, Endpoint& endpoint, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_recvfrom_op_base::do_perform, complete_func), + socket_(socket), + protocol_type_(protocol_type), + buffers_(buffers), + sender_endpoint_(endpoint), + flags_(flags) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_recvfrom_op_base* o( + static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + std::size_t addr_len = o->sender_endpoint_.capacity(); + bool 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_); + + if (result && !o->ec_) + o->sender_endpoint_.resize(addr_len); + + return result; + } + +private: + socket_type socket_; + int protocol_type_; + MutableBufferSequence buffers_; + Endpoint& sender_endpoint_; + socket_base::message_flags flags_; +}; + +template +class reactive_socket_recvfrom_op : + public reactive_socket_recvfrom_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op); + + reactive_socket_recvfrom_op(socket_type socket, int protocol_type, + const MutableBufferSequence& buffers, Endpoint& endpoint, + socket_base::message_flags flags, Handler handler) + : reactive_socket_recvfrom_op_base( + socket, protocol_type, buffers, endpoint, flags, + &reactive_socket_recvfrom_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_recvfrom_op* o( + static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, 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(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP diff --git a/include/boost/asio/detail/reactive_socket_send_op.hpp b/include/boost/asio/detail/reactive_socket_send_op.hpp new file mode 100644 index 00000000..157d0750 --- /dev/null +++ b/include/boost/asio/detail/reactive_socket_send_op.hpp @@ -0,0 +1,117 @@ +// +// detail/reactive_socket_send_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SOCKET_SEND_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_send_op_base : public reactor_op +{ +public: + reactive_socket_send_op_base(socket_type socket, + 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), + buffers_(buffers), + flags_(flags) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_send_op_base* o( + static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + return socket_ops::non_blocking_send(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->ec_, o->bytes_transferred_); + } + +private: + socket_type socket_; + ConstBufferSequence buffers_; + socket_base::message_flags flags_; +}; + +template +class reactive_socket_send_op : + public reactive_socket_send_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op); + + reactive_socket_send_op(socket_type socket, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + : reactive_socket_send_op_base(socket, + buffers, flags, &reactive_socket_send_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_send_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, 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(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP diff --git a/include/boost/asio/detail/reactive_socket_sendto_op.hpp b/include/boost/asio/detail/reactive_socket_sendto_op.hpp new file mode 100644 index 00000000..6199ec29 --- /dev/null +++ b/include/boost/asio/detail/reactive_socket_sendto_op.hpp @@ -0,0 +1,120 @@ +// +// detail/reactive_socket_sendto_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SOCKET_SENDTO_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_sendto_op_base : public reactor_op +{ +public: + reactive_socket_sendto_op_base(socket_type socket, + const ConstBufferSequence& buffers, const Endpoint& endpoint, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_sendto_op_base::do_perform, complete_func), + socket_(socket), + buffers_(buffers), + destination_(endpoint), + flags_(flags) + { + } + + static bool do_perform(reactor_op* base) + { + reactive_socket_sendto_op_base* o( + static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + return socket_ops::non_blocking_sendto(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->destination_.data(), o->destination_.size(), + o->ec_, o->bytes_transferred_); + } + +private: + socket_type socket_; + ConstBufferSequence buffers_; + Endpoint destination_; + socket_base::message_flags flags_; +}; + +template +class reactive_socket_sendto_op : + public reactive_socket_sendto_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_sendto_op); + + reactive_socket_sendto_op(socket_type socket, + const ConstBufferSequence& buffers, const Endpoint& endpoint, + socket_base::message_flags flags, Handler handler) + : reactive_socket_sendto_op_base(socket, + buffers, endpoint, flags, &reactive_socket_sendto_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_sendto_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, 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(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP diff --git a/include/boost/asio/detail/reactive_socket_service.hpp b/include/boost/asio/detail/reactive_socket_service.hpp index 5f7bbf5c..73aa0246 100644 --- a/include/boost/asio/detail/reactive_socket_service.hpp +++ b/include/boost/asio/detail/reactive_socket_service.hpp @@ -1,6 +1,6 @@ // -// reactive_socket_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/reactive_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,29 +15,38 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#if !defined(BOOST_ASIO_HAS_IOCP) + +#include #include #include #include #include -#include #include -#include #include -#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include +#include + namespace boost { namespace asio { namespace detail { template -class reactive_socket_service +class reactive_socket_service : + public reactive_socket_service_base { public: // The protocol type. @@ -50,132 +59,32 @@ public: typedef socket_type native_type; // The implementation type of the socket. - class implementation_type - : private boost::asio::detail::noncopyable + struct implementation_type : + reactive_socket_service_base::base_implementation_type { - public: // Default constructor. implementation_type() - : socket_(invalid_socket), - flags_(0), - protocol_(endpoint_type().protocol()) + : protocol_(endpoint_type().protocol()) { } - private: - // Only this service will have access to the internal values. - friend class reactive_socket_service; - - // The native socket representation. - socket_type socket_; - - enum - { - // The user wants a non-blocking socket. - user_set_non_blocking = 1, - - // The implementation wants a non-blocking socket (in order to be able to - // perform asynchronous read and write operations). - internal_non_blocking = 2, - - // Helper "flag" used to determine whether the socket is non-blocking. - non_blocking = user_set_non_blocking | internal_non_blocking, - - // User wants connection_aborted errors, which are disabled by default. - enable_connection_aborted = 4, - - // The user set the linger option. Needs to be checked when closing. - user_set_linger = 8 - }; - - // Flags indicating the current state of the socket. - unsigned char flags_; - // The protocol associated with the socket. protocol_type protocol_; - - // Per-descriptor data used by the reactor. - reactor::per_descriptor_data reactor_data_; }; // Constructor. reactive_socket_service(boost::asio::io_service& io_service) - : io_service_impl_(use_service(io_service)), - reactor_(use_service(io_service)) + : reactive_socket_service_base(io_service) { - reactor_.init_task(); - } - - // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - } - - // Construct a new socket implementation. - void construct(implementation_type& impl) - { - impl.socket_ = invalid_socket; - impl.flags_ = 0; - } - - // Destroy a socket implementation. - void destroy(implementation_type& impl) - { - if (impl.socket_ != invalid_socket) - { - reactor_.close_descriptor(impl.socket_, impl.reactor_data_); - - if (impl.flags_ & implementation_type::non_blocking) - { - ioctl_arg_type non_blocking = 0; - boost::system::error_code ignored_ec; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); - impl.flags_ &= ~implementation_type::non_blocking; - } - - if (impl.flags_ & implementation_type::user_set_linger) - { - ::linger opt; - opt.l_onoff = 0; - opt.l_linger = 0; - boost::system::error_code ignored_ec; - socket_ops::setsockopt(impl.socket_, - SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec); - } - - boost::system::error_code ignored_ec; - socket_ops::close(impl.socket_, ignored_ec); - - impl.socket_ = invalid_socket; - } } // Open a new socket implementation. boost::system::error_code open(implementation_type& impl, const protocol_type& protocol, boost::system::error_code& ec) { - if (is_open(impl)) - { - ec = boost::asio::error::already_open; - return ec; - } - - socket_holder sock(socket_ops::socket(protocol.family(), - protocol.type(), protocol.protocol(), ec)); - if (sock.get() == invalid_socket) - return ec; - - if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_)) - { - ec = boost::system::error_code(err, - boost::asio::error::get_system_category()); - return ec; - } - - impl.socket_ = sock.release(); - impl.flags_ = 0; - impl.protocol_ = protocol; - ec = boost::system::error_code(); + if (!do_open(impl, protocol.family(), + protocol.type(), protocol.protocol(), ec)) + impl.protocol_ = protocol; return ec; } @@ -184,56 +93,8 @@ public: const protocol_type& protocol, const native_type& native_socket, boost::system::error_code& ec) { - if (is_open(impl)) - { - ec = boost::asio::error::already_open; - return ec; - } - - if (int err = reactor_.register_descriptor( - native_socket, impl.reactor_data_)) - { - ec = boost::system::error_code(err, - boost::asio::error::get_system_category()); - return ec; - } - - impl.socket_ = native_socket; - impl.flags_ = 0; - impl.protocol_ = protocol; - ec = boost::system::error_code(); - return ec; - } - - // Determine whether the socket is open. - bool is_open(const implementation_type& impl) const - { - return impl.socket_ != invalid_socket; - } - - // Destroy a socket implementation. - boost::system::error_code close(implementation_type& impl, - boost::system::error_code& ec) - { - if (is_open(impl)) - { - reactor_.close_descriptor(impl.socket_, impl.reactor_data_); - - if (impl.flags_ & implementation_type::non_blocking) - { - ioctl_arg_type non_blocking = 0; - boost::system::error_code ignored_ec; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); - impl.flags_ &= ~implementation_type::non_blocking; - } - - if (socket_ops::close(impl.socket_, ec) == socket_error_retval) - return ec; - - impl.socket_ = invalid_socket; - } - - ec = boost::system::error_code(); + if (!do_assign(impl, protocol.type(), native_socket, ec)) + impl.protocol_ = protocol; return ec; } @@ -243,153 +104,23 @@ public: return impl.socket_; } - // Cancel all operations associated with the socket. - boost::system::error_code cancel(implementation_type& impl, - boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - reactor_.cancel_ops(impl.socket_, impl.reactor_data_); - ec = boost::system::error_code(); - return ec; - } - - // Determine whether the socket is at the out-of-band data mark. - bool at_mark(const implementation_type& impl, - boost::system::error_code& ec) const - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return false; - } - -#if defined(SIOCATMARK) - boost::asio::detail::ioctl_arg_type value = 0; - socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec); -# if defined(ENOTTY) - if (ec.value() == ENOTTY) - ec = boost::asio::error::not_socket; -# endif // defined(ENOTTY) -#else // defined(SIOCATMARK) - int value = sockatmark(impl.socket_); - if (value == -1) - ec = boost::system::error_code(errno, - boost::asio::error::get_system_category()); - else - ec = boost::system::error_code(); -#endif // defined(SIOCATMARK) - return ec ? false : value != 0; - } - - // Determine the number of bytes available for reading. - std::size_t available(const implementation_type& impl, - boost::system::error_code& ec) const - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - boost::asio::detail::ioctl_arg_type value = 0; - socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec); -#if defined(ENOTTY) - if (ec.value() == ENOTTY) - ec = boost::asio::error::not_socket; -#endif // defined(ENOTTY) - return ec ? static_cast(0) : static_cast(value); - } - // Bind the socket to the specified local endpoint. boost::system::error_code bind(implementation_type& impl, const endpoint_type& endpoint, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); return ec; } - // Place the socket into the state where it will listen for new connections. - boost::system::error_code listen(implementation_type& impl, int backlog, - boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - socket_ops::listen(impl.socket_, backlog, ec); - return ec; - } - // Set a socket option. template boost::system::error_code set_option(implementation_type& impl, const Option& option, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - if (option.level(impl.protocol_) == custom_socket_option_level - && option.name(impl.protocol_) == enable_connection_aborted_option) - { - if (option.size(impl.protocol_) != sizeof(int)) - { - ec = boost::asio::error::invalid_argument; - } - else - { - if (*reinterpret_cast(option.data(impl.protocol_))) - impl.flags_ |= implementation_type::enable_connection_aborted; - else - impl.flags_ &= ~implementation_type::enable_connection_aborted; - ec = boost::system::error_code(); - } - return ec; - } - else - { - if (option.level(impl.protocol_) == SOL_SOCKET - && option.name(impl.protocol_) == SO_LINGER) - { - impl.flags_ |= implementation_type::user_set_linger; - } - - socket_ops::setsockopt(impl.socket_, - option.level(impl.protocol_), option.name(impl.protocol_), - option.data(impl.protocol_), option.size(impl.protocol_), ec); - -#if defined(__MACH__) && defined(__APPLE__) \ -|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) - // To implement portable behaviour for SO_REUSEADDR with UDP sockets we - // need to also set SO_REUSEPORT on BSD-based platforms. - if (!ec && impl.protocol_.type() == SOCK_DGRAM - && option.level(impl.protocol_) == SOL_SOCKET - && option.name(impl.protocol_) == SO_REUSEADDR) - { - boost::system::error_code ignored_ec; - socket_ops::setsockopt(impl.socket_, SOL_SOCKET, SO_REUSEPORT, - option.data(impl.protocol_), option.size(impl.protocol_), - ignored_ec); - } -#endif - - return ec; - } + socket_ops::setsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), option.size(impl.protocol_), ec); + return ec; } // Set a socket option. @@ -397,78 +128,12 @@ public: boost::system::error_code get_option(const implementation_type& impl, Option& option, boost::system::error_code& ec) const { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - if (option.level(impl.protocol_) == custom_socket_option_level - && option.name(impl.protocol_) == enable_connection_aborted_option) - { - if (option.size(impl.protocol_) != sizeof(int)) - { - ec = boost::asio::error::invalid_argument; - } - else - { - int* target = reinterpret_cast(option.data(impl.protocol_)); - if (impl.flags_ & implementation_type::enable_connection_aborted) - *target = 1; - else - *target = 0; - option.resize(impl.protocol_, sizeof(int)); - ec = boost::system::error_code(); - } - return ec; - } - else - { - size_t size = option.size(impl.protocol_); - socket_ops::getsockopt(impl.socket_, - option.level(impl.protocol_), option.name(impl.protocol_), - option.data(impl.protocol_), &size, ec); - if (!ec) - option.resize(impl.protocol_, size); - return ec; - } - } - - // Perform an IO control command on the socket. - template - boost::system::error_code io_control(implementation_type& impl, - IO_Control_Command& command, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - socket_ops::ioctl(impl.socket_, command.name(), - static_cast(command.data()), ec); - - // When updating the non-blocking mode we always perform the ioctl - // syscall, even if the flags would otherwise indicate that the socket is - // already in the correct state. This ensures that the underlying socket - // is put into the state that has been requested by the user. If the ioctl - // syscall was successful then we need to update the flags to match. - if (!ec && command.name() == static_cast(FIONBIO)) - { - if (*static_cast(command.data())) - { - impl.flags_ |= implementation_type::user_set_non_blocking; - } - else - { - // Clearing the non-blocking mode always overrides any internally-set - // non-blocking flag. Any subsequent asynchronous operations will need - // to re-enable non-blocking I/O. - impl.flags_ &= ~(implementation_type::user_set_non_blocking - | implementation_type::internal_non_blocking); - } - } - + std::size_t size = option.size(impl.protocol_); + socket_ops::getsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); return ec; } @@ -476,12 +141,6 @@ public: endpoint_type local_endpoint(const implementation_type& impl, boost::system::error_code& ec) const { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return endpoint_type(); - } - endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) @@ -494,218 +153,15 @@ public: endpoint_type remote_endpoint(const implementation_type& impl, boost::system::error_code& ec) const { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return endpoint_type(); - } - endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); - if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec)) + if (socket_ops::getpeername(impl.socket_, + endpoint.data(), &addr_len, false, ec)) return endpoint_type(); endpoint.resize(addr_len); return endpoint; } - /// Disable sends or receives on the socket. - boost::system::error_code shutdown(implementation_type& impl, - socket_base::shutdown_type what, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - socket_ops::shutdown(impl.socket_, what, ec); - return ec; - } - - // Send the given data to the peer. - template - size_t send(implementation_type& impl, const ConstBufferSequence& buffers, - socket_base::message_flags flags, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - buffer_sequence_adapter bufs(buffers); - - // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) - { - ec = boost::system::error_code(); - return 0; - } - - // Send the data. - for (;;) - { - // Try to complete the operation without blocking. - int bytes_sent = socket_ops::send(impl.socket_, - bufs.buffers(), bufs.count(), flags, ec); - - // Check if operation succeeded. - if (bytes_sent >= 0) - return bytes_sent; - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != boost::asio::error::would_block - && ec != boost::asio::error::try_again)) - return 0; - - // Wait for socket to become ready. - if (socket_ops::poll_write(impl.socket_, ec) < 0) - return 0; - } - } - - // Wait until data can be sent without blocking. - size_t send(implementation_type& impl, const null_buffers&, - socket_base::message_flags, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - // Wait for socket to become ready. - socket_ops::poll_write(impl.socket_, ec); - - return 0; - } - - template - class send_op_base : public reactor_op - { - public: - send_op_base(socket_type socket, const ConstBufferSequence& buffers, - socket_base::message_flags flags, func_type complete_func) - : reactor_op(&send_op_base::do_perform, complete_func), - socket_(socket), - buffers_(buffers), - flags_(flags) - { - } - - static bool do_perform(reactor_op* base) - { - send_op_base* o(static_cast(base)); - - buffer_sequence_adapter bufs(o->buffers_); - - for (;;) - { - // Send the data. - boost::system::error_code ec; - int bytes = socket_ops::send(o->socket_, - bufs.buffers(), bufs.count(), o->flags_, ec); - - // Retry operation if interrupted by signal. - if (ec == boost::asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == boost::asio::error::would_block - || ec == boost::asio::error::try_again) - return false; - - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - socket_type socket_; - ConstBufferSequence buffers_; - socket_base::message_flags flags_; - }; - - template - class send_op : public send_op_base - { - public: - send_op(socket_type socket, const ConstBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - : send_op_base(socket, - buffers, flags, &send_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - send_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // 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(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - - // Start an asynchronous send. The data being sent must be valid for the - // lifetime of the asynchronous operation. - template - void async_send(implementation_type& impl, const ConstBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef send_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, - impl.socket_, buffers, flags, handler); - - start_op(impl, reactor::write_op, ptr.get(), true, - (impl.protocol_.type() == SOCK_STREAM - && buffer_sequence_adapter::all_empty(buffers))); - ptr.release(); - } - - // Start an asynchronous wait until data can be sent without blocking. - template - void async_send(implementation_type& impl, const null_buffers&, - socket_base::message_flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); - - start_op(impl, reactor::write_op, ptr.get(), false, false); - ptr.release(); - } - // Send a datagram to the specified endpoint. Returns the number of bytes // sent. template @@ -713,148 +169,25 @@ public: const endpoint_type& destination, socket_base::message_flags flags, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter bufs(buffers); - // Send the data. - for (;;) - { - // Try to complete the operation without blocking. - int bytes_sent = socket_ops::sendto(impl.socket_, bufs.buffers(), - bufs.count(), flags, destination.data(), destination.size(), ec); - - // Check if operation succeeded. - if (bytes_sent >= 0) - return bytes_sent; - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != boost::asio::error::would_block - && ec != boost::asio::error::try_again)) - return 0; - - // Wait for socket to become ready. - if (socket_ops::poll_write(impl.socket_, ec) < 0) - return 0; - } + return socket_ops::sync_sendto(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, + destination.data(), destination.size(), ec); } // Wait until data can be sent without blocking. size_t send_to(implementation_type& impl, const null_buffers&, - socket_base::message_flags, const endpoint_type&, + const endpoint_type&, socket_base::message_flags, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - // Wait for socket to become ready. socket_ops::poll_write(impl.socket_, ec); return 0; } - template - class send_to_op_base : public reactor_op - { - public: - send_to_op_base(socket_type socket, const ConstBufferSequence& buffers, - const endpoint_type& endpoint, socket_base::message_flags flags, - func_type complete_func) - : reactor_op(&send_to_op_base::do_perform, complete_func), - socket_(socket), - buffers_(buffers), - destination_(endpoint), - flags_(flags) - { - } - - static bool do_perform(reactor_op* base) - { - send_to_op_base* o(static_cast(base)); - - buffer_sequence_adapter bufs(o->buffers_); - - for (;;) - { - // Send the data. - boost::system::error_code ec; - int bytes = socket_ops::sendto(o->socket_, bufs.buffers(), bufs.count(), - o->flags_, o->destination_.data(), o->destination_.size(), ec); - - // Retry operation if interrupted by signal. - if (ec == boost::asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == boost::asio::error::would_block - || ec == boost::asio::error::try_again) - return false; - - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - socket_type socket_; - ConstBufferSequence buffers_; - endpoint_type destination_; - socket_base::message_flags flags_; - }; - - template - class send_to_op : public send_to_op_base - { - public: - send_to_op(socket_type socket, const ConstBufferSequence& buffers, - const endpoint_type& endpoint, socket_base::message_flags flags, - Handler handler) - : send_to_op_base(socket, - buffers, endpoint, flags, &send_to_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - send_to_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // 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(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. template @@ -864,235 +197,31 @@ public: Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef send_to_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, impl.socket_, - buffers, destination, flags, handler); + typedef reactive_socket_sendto_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, buffers, destination, flags, handler); - start_op(impl, reactor::write_op, ptr.get(), true, false); - ptr.release(); + start_op(impl, reactor::write_op, p.p, true, false); + p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. template void async_send_to(implementation_type& impl, const null_buffers&, - socket_base::message_flags, const endpoint_type&, Handler handler) + const endpoint_type&, socket_base::message_flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); - start_op(impl, reactor::write_op, ptr.get(), false, false); - ptr.release(); - } - - // Receive some data from the peer. Returns the number of bytes received. - template - size_t receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - buffer_sequence_adapter bufs(buffers); - - // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) - { - ec = boost::system::error_code(); - return 0; - } - - // Receive some data. - for (;;) - { - // Try to complete the operation without blocking. - int bytes_recvd = socket_ops::recv(impl.socket_, - bufs.buffers(), bufs.count(), flags, ec); - - // Check if operation succeeded. - if (bytes_recvd > 0) - return bytes_recvd; - - // Check for EOF. - if (bytes_recvd == 0 && impl.protocol_.type() == SOCK_STREAM) - { - ec = boost::asio::error::eof; - return 0; - } - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != boost::asio::error::would_block - && ec != boost::asio::error::try_again)) - return 0; - - // Wait for socket to become ready. - if (socket_ops::poll_read(impl.socket_, ec) < 0) - return 0; - } - } - - // Wait until data can be received without blocking. - size_t receive(implementation_type& impl, const null_buffers&, - socket_base::message_flags, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - // Wait for socket to become ready. - socket_ops::poll_read(impl.socket_, ec); - - return 0; - } - - template - class receive_op_base : public reactor_op - { - public: - receive_op_base(socket_type socket, int protocol_type, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, func_type complete_func) - : reactor_op(&receive_op_base::do_perform, complete_func), - socket_(socket), - protocol_type_(protocol_type), - buffers_(buffers), - flags_(flags) - { - } - - static bool do_perform(reactor_op* base) - { - receive_op_base* o(static_cast(base)); - - buffer_sequence_adapter bufs(o->buffers_); - - for (;;) - { - // Receive some data. - boost::system::error_code ec; - int bytes = socket_ops::recv(o->socket_, - bufs.buffers(), bufs.count(), o->flags_, ec); - if (bytes == 0 && o->protocol_type_ == SOCK_STREAM) - ec = boost::asio::error::eof; - - // Retry operation if interrupted by signal. - if (ec == boost::asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == boost::asio::error::would_block - || ec == boost::asio::error::try_again) - return false; - - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - socket_type socket_; - int protocol_type_; - MutableBufferSequence buffers_; - socket_base::message_flags flags_; - }; - - template - class receive_op : public receive_op_base - { - public: - receive_op(socket_type socket, int protocol_type, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - : receive_op_base(socket, - protocol_type, buffers, flags, &receive_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - receive_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // 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(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - - // Start an asynchronous receive. The buffer for the data being received - // must be valid for the lifetime of the asynchronous operation. - template - void async_receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef receive_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - int protocol_type = impl.protocol_.type(); - handler_ptr ptr(raw_ptr, impl.socket_, - protocol_type, buffers, flags, handler); - - start_op(impl, - (flags & socket_base::message_out_of_band) - ? reactor::except_op : reactor::read_op, - ptr.get(), (flags & socket_base::message_out_of_band) == 0, - (impl.protocol_.type() == SOCK_STREAM - && buffer_sequence_adapter::all_empty(buffers))); - ptr.release(); - } - - // Wait until data can be received without blocking. - template - void async_receive(implementation_type& impl, const null_buffers&, - socket_base::message_flags flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); - - start_op(impl, - (flags & socket_base::message_out_of_band) - ? reactor::except_op : reactor::read_op, - ptr.get(), false, false); - ptr.release(); + start_op(impl, reactor::write_op, p.p, false, false); + p.v = p.p = 0; } // Receive a datagram with the endpoint of the sender. Returns the number of @@ -1103,47 +232,18 @@ public: endpoint_type& sender_endpoint, socket_base::message_flags flags, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter bufs(buffers); - // Receive some data. - for (;;) - { - // Try to complete the operation without blocking. - std::size_t addr_len = sender_endpoint.capacity(); - int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs.buffers(), - bufs.count(), flags, sender_endpoint.data(), &addr_len, ec); + std::size_t addr_len = sender_endpoint.capacity(); + std::size_t bytes_recvd = socket_ops::sync_recvfrom( + impl.socket_, impl.state_, bufs.buffers(), bufs.count(), + flags, sender_endpoint.data(), &addr_len, ec); - // Check if operation succeeded. - if (bytes_recvd > 0) - { - sender_endpoint.resize(addr_len); - return bytes_recvd; - } + if (!ec) + sender_endpoint.resize(addr_len); - // Check for EOF. - if (bytes_recvd == 0 && impl.protocol_.type() == SOCK_STREAM) - { - ec = boost::asio::error::eof; - return 0; - } - - // Operation failed. - if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (ec != boost::asio::error::would_block - && ec != boost::asio::error::try_again)) - return 0; - - // Wait for socket to become ready. - if (socket_ops::poll_read(impl.socket_, ec) < 0) - return 0; - } + return bytes_recvd; } // Wait until data can be received without blocking. @@ -1151,12 +251,6 @@ public: endpoint_type& sender_endpoint, socket_base::message_flags, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - // Wait for socket to become ready. socket_ops::poll_read(impl.socket_, ec); @@ -1166,105 +260,6 @@ public: return 0; } - template - class receive_from_op_base : public reactor_op - { - public: - receive_from_op_base(socket_type socket, int protocol_type, - const MutableBufferSequence& buffers, endpoint_type& endpoint, - socket_base::message_flags flags, func_type complete_func) - : reactor_op(&receive_from_op_base::do_perform, complete_func), - socket_(socket), - protocol_type_(protocol_type), - buffers_(buffers), - sender_endpoint_(endpoint), - flags_(flags) - { - } - - static bool do_perform(reactor_op* base) - { - receive_from_op_base* o(static_cast(base)); - - buffer_sequence_adapter bufs(o->buffers_); - - for (;;) - { - // Receive some data. - boost::system::error_code ec; - std::size_t addr_len = o->sender_endpoint_.capacity(); - int bytes = socket_ops::recvfrom(o->socket_, bufs.buffers(), - bufs.count(), o->flags_, o->sender_endpoint_.data(), &addr_len, ec); - if (bytes == 0 && o->protocol_type_ == SOCK_STREAM) - ec = boost::asio::error::eof; - - // Retry operation if interrupted by signal. - if (ec == boost::asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == boost::asio::error::would_block - || ec == boost::asio::error::try_again) - return false; - - o->sender_endpoint_.resize(addr_len); - o->ec_ = ec; - o->bytes_transferred_ = (bytes < 0 ? 0 : bytes); - return true; - } - } - - private: - socket_type socket_; - int protocol_type_; - MutableBufferSequence buffers_; - endpoint_type& sender_endpoint_; - socket_base::message_flags flags_; - }; - - template - class receive_from_op : public receive_from_op_base - { - public: - receive_from_op(socket_type socket, int protocol_type, - const MutableBufferSequence& buffers, endpoint_type& endpoint, - socket_base::message_flags flags, Handler handler) - : receive_from_op_base(socket, protocol_type, - buffers, endpoint, flags, &receive_from_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - receive_from_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // 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(o->handler_, o->ec_, o->bytes_transferred_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous receive. The buffer for the data being received and // the sender_endpoint object must both be valid for the lifetime of the // asynchronous operation. @@ -1274,18 +269,20 @@ public: socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef receive_from_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); + typedef reactive_socket_recvfrom_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; int protocol_type = impl.protocol_.type(); - handler_ptr ptr(raw_ptr, impl.socket_, - protocol_type, buffers, sender_endpoint, flags, handler); + p.p = new (p.v) op(impl.socket_, protocol_type, + buffers, sender_endpoint, flags, handler); start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, - ptr.get(), true, false); - ptr.release(); + p.p, true, false); + p.v = p.p = 0; } // Wait until data can be received without blocking. @@ -1295,10 +292,11 @@ public: socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); @@ -1306,8 +304,8 @@ public: start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, - ptr.get(), false, false); - ptr.release(); + p.p, false, false); + p.v = p.p = 0; } // Accept a new connection. @@ -1315,12 +313,6 @@ public: boost::system::error_code accept(implementation_type& impl, Socket& peer, endpoint_type* peer_endpoint, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - // We cannot accept a socket that is already open. if (peer.is_open()) { @@ -1328,182 +320,23 @@ public: return ec; } - // Accept a socket. - for (;;) + 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() >= 0) { - // Try to complete the operation without blocking. - socket_holder new_socket; - std::size_t addr_len = 0; if (peer_endpoint) - { - addr_len = peer_endpoint->capacity(); - new_socket.reset(socket_ops::accept(impl.socket_, - peer_endpoint->data(), &addr_len, ec)); - } - else - { - new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec)); - } - - // Check if operation succeeded. - if (new_socket.get() >= 0) - { - if (peer_endpoint) - peer_endpoint->resize(addr_len); - peer.assign(impl.protocol_, new_socket.get(), ec); - if (!ec) - new_socket.release(); - return ec; - } - - // Operation failed. - if (ec == boost::asio::error::would_block - || ec == boost::asio::error::try_again) - { - if (impl.flags_ & implementation_type::user_set_non_blocking) - return ec; - // Fall through to retry operation. - } - else if (ec == boost::asio::error::connection_aborted) - { - if (impl.flags_ & implementation_type::enable_connection_aborted) - return ec; - // Fall through to retry operation. - } -#if defined(EPROTO) - else if (ec.value() == EPROTO) - { - if (impl.flags_ & implementation_type::enable_connection_aborted) - return ec; - // Fall through to retry operation. - } -#endif // defined(EPROTO) - else - return ec; - - // Wait for socket to become ready. - if (socket_ops::poll_read(impl.socket_, ec) < 0) - return ec; + peer_endpoint->resize(addr_len); + if (!peer.assign(impl.protocol_, new_socket.get(), ec)) + new_socket.release(); } + + return ec; } - template - class accept_op_base : public reactor_op - { - public: - accept_op_base(socket_type socket, Socket& peer, - const protocol_type& protocol, endpoint_type* peer_endpoint, - bool enable_connection_aborted, func_type complete_func) - : reactor_op(&accept_op_base::do_perform, complete_func), - socket_(socket), - peer_(peer), - protocol_(protocol), - peer_endpoint_(peer_endpoint), - enable_connection_aborted_(enable_connection_aborted) - { - } - - static bool do_perform(reactor_op* base) - { - accept_op_base* o(static_cast(base)); - - for (;;) - { - // Accept the waiting connection. - boost::system::error_code ec; - socket_holder new_socket; - std::size_t addr_len = 0; - std::size_t* addr_len_p = 0; - socket_addr_type* addr = 0; - if (o->peer_endpoint_) - { - addr_len = o->peer_endpoint_->capacity(); - addr_len_p = &addr_len; - addr = o->peer_endpoint_->data(); - } - new_socket.reset(socket_ops::accept(o->socket_, addr, addr_len_p, ec)); - - // Retry operation if interrupted by signal. - if (ec == boost::asio::error::interrupted) - continue; - - // Check if we need to run the operation again. - if (ec == boost::asio::error::would_block - || ec == boost::asio::error::try_again) - return false; - if (ec == boost::asio::error::connection_aborted - && !o->enable_connection_aborted_) - return false; -#if defined(EPROTO) - if (ec.value() == EPROTO && !o->enable_connection_aborted_) - return false; -#endif // defined(EPROTO) - - // Transfer ownership of the new socket to the peer object. - if (!ec) - { - if (o->peer_endpoint_) - o->peer_endpoint_->resize(addr_len); - o->peer_.assign(o->protocol_, new_socket.get(), ec); - if (!ec) - new_socket.release(); - } - - o->ec_ = ec; - return true; - } - } - - private: - socket_type socket_; - Socket& peer_; - protocol_type protocol_; - endpoint_type* peer_endpoint_; - bool enable_connection_aborted_; - }; - - template - class accept_op : public accept_op_base - { - public: - accept_op(socket_type socket, Socket& peer, const protocol_type& protocol, - endpoint_type* peer_endpoint, bool enable_connection_aborted, - Handler handler) - : accept_op_base(socket, peer, protocol, peer_endpoint, - enable_connection_aborted, &accept_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - accept_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // 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(o->handler_, o->ec_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. template @@ -1511,230 +344,41 @@ public: endpoint_type* peer_endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef accept_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - bool enable_connection_aborted = - (impl.flags_ & implementation_type::enable_connection_aborted) != 0; - handler_ptr ptr(raw_ptr, impl.socket_, peer, - impl.protocol_, peer_endpoint, enable_connection_aborted, handler); + typedef reactive_socket_accept_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, impl.state_, peer, + impl.protocol_, peer_endpoint, handler); - start_accept_op(impl, ptr.get(), peer.is_open()); - ptr.release(); + start_accept_op(impl, p.p, peer.is_open()); + p.v = p.p = 0; } // 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) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - // Perform the connect operation. - socket_ops::connect(impl.socket_, + socket_ops::sync_connect(impl.socket_, peer_endpoint.data(), peer_endpoint.size(), ec); - if (ec != boost::asio::error::in_progress - && ec != boost::asio::error::would_block) - { - // The connect operation finished immediately. - return ec; - } - - // Wait for socket to become ready. - if (socket_ops::poll_connect(impl.socket_, ec) < 0) - return ec; - - // Get the error code from the connect operation. - int connect_error = 0; - size_t connect_error_len = sizeof(connect_error); - if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_ERROR, - &connect_error, &connect_error_len, ec) == socket_error_retval) - return ec; - - // Return the result of the connect operation. - ec = boost::system::error_code(connect_error, - boost::asio::error::get_system_category()); return ec; } - class connect_op_base : public reactor_op - { - public: - connect_op_base(socket_type socket, func_type complete_func) - : reactor_op(&connect_op_base::do_perform, complete_func), - socket_(socket) - { - } - - static bool do_perform(reactor_op* base) - { - connect_op_base* o(static_cast(base)); - - // Get the error code from the connect operation. - int connect_error = 0; - size_t connect_error_len = sizeof(connect_error); - if (socket_ops::getsockopt(o->socket_, SOL_SOCKET, SO_ERROR, - &connect_error, &connect_error_len, o->ec_) == socket_error_retval) - return true; - - // The connection failed so the handler will be posted with an error code. - if (connect_error) - { - o->ec_ = boost::system::error_code(connect_error, - boost::asio::error::get_system_category()); - } - - return true; - } - - private: - socket_type socket_; - }; - - template - class connect_op : public connect_op_base - { - public: - connect_op(socket_type socket, Handler handler) - : connect_op_base(socket, &connect_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - connect_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // 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(o->handler_, o->ec_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous connect. template void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef connect_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, impl.socket_, handler); + typedef reactive_socket_connect_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, handler); - start_connect_op(impl, ptr.get(), peer_endpoint); - ptr.release(); + start_connect_op(impl, p.p, peer_endpoint.data(), peer_endpoint.size()); + p.v = p.p = 0; } - -private: - // Start the asynchronous read or write operation. - void start_op(implementation_type& impl, int op_type, - reactor_op* op, bool non_blocking, bool noop) - { - if (!noop) - { - if (is_open(impl)) - { - if (!non_blocking || is_non_blocking(impl) - || set_non_blocking(impl, op->ec_)) - { - reactor_.start_op(op_type, impl.socket_, - impl.reactor_data_, op, non_blocking); - return; - } - } - else - op->ec_ = boost::asio::error::bad_descriptor; - } - - io_service_impl_.post_immediate_completion(op); - } - - // Start the asynchronous accept operation. - void start_accept_op(implementation_type& impl, - reactor_op* op, bool peer_is_open) - { - if (!peer_is_open) - start_op(impl, reactor::read_op, op, true, false); - else - { - op->ec_ = boost::asio::error::already_open; - io_service_impl_.post_immediate_completion(op); - } - } - - // Start the asynchronous connect operation. - void start_connect_op(implementation_type& impl, - reactor_op* op, const endpoint_type& peer_endpoint) - { - if (is_open(impl)) - { - if (is_non_blocking(impl) || set_non_blocking(impl, op->ec_)) - { - if (socket_ops::connect(impl.socket_, peer_endpoint.data(), - peer_endpoint.size(), op->ec_) != 0) - { - if (op->ec_ == boost::asio::error::in_progress - || op->ec_ == boost::asio::error::would_block) - { - op->ec_ = boost::system::error_code(); - reactor_.start_op(reactor::connect_op, - impl.socket_, impl.reactor_data_, op, false); - return; - } - } - } - } - else - op->ec_ = boost::asio::error::bad_descriptor; - - io_service_impl_.post_immediate_completion(op); - } - - // Determine whether the socket has been set non-blocking. - bool is_non_blocking(implementation_type& impl) const - { - return (impl.flags_ & implementation_type::non_blocking); - } - - // Set the internal non-blocking flag. - bool set_non_blocking(implementation_type& impl, - boost::system::error_code& ec) - { - ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - return false; - impl.flags_ |= implementation_type::internal_non_blocking; - return true; - } - - // The io_service implementation used to post completions. - io_service_impl& io_service_impl_; - - // The selector that performs event demultiplexing for the service. - reactor& reactor_; }; } // namespace detail @@ -1743,4 +387,6 @@ private: #include +#endif // !defined(BOOST_ASIO_HAS_IOCP) + #endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP diff --git a/include/boost/asio/detail/reactive_socket_service_base.hpp b/include/boost/asio/detail/reactive_socket_service_base.hpp new file mode 100644 index 00000000..1733ce10 --- /dev/null +++ b/include/boost/asio/detail/reactive_socket_service_base.hpp @@ -0,0 +1,300 @@ +// +// detail/reactive_socket_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SOCKET_SERVICE_BASE_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class reactive_socket_service_base +{ +public: + // The native type of a socket. + typedef socket_type native_type; + + // The implementation type of the socket. + struct base_implementation_type + { + // The native socket representation. + socket_type socket_; + + // The current state of the socket. + socket_ops::state_type state_; + + // Per-descriptor data used by the reactor. + reactor::per_descriptor_data reactor_data_; + }; + + // Constructor. + BOOST_ASIO_DECL reactive_socket_service_base( + boost::asio::io_service& io_service); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown_service(); + + // Construct a new socket implementation. + BOOST_ASIO_DECL void construct(base_implementation_type& impl); + + // Destroy a socket implementation. + BOOST_ASIO_DECL void destroy(base_implementation_type& impl); + + // Determine whether the socket is open. + bool is_open(const base_implementation_type& impl) const + { + return impl.socket_ != invalid_socket; + } + + // Destroy a socket implementation. + BOOST_ASIO_DECL boost::system::error_code close( + base_implementation_type& impl, boost::system::error_code& ec); + + // Get the native socket representation. + native_type native(base_implementation_type& impl) + { + return impl.socket_; + } + + // Cancel all operations associated with the socket. + BOOST_ASIO_DECL boost::system::error_code cancel( + base_implementation_type& impl, boost::system::error_code& ec); + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const base_implementation_type& impl, + boost::system::error_code& ec) const + { + return socket_ops::sockatmark(impl.socket_, ec); + } + + // Determine the number of bytes available for reading. + std::size_t available(const base_implementation_type& impl, + boost::system::error_code& ec) const + { + return socket_ops::available(impl.socket_, ec); + } + + // Place the socket into the state where it will listen for new connections. + boost::system::error_code listen(base_implementation_type& impl, + int backlog, boost::system::error_code& ec) + { + socket_ops::listen(impl.socket_, backlog, ec); + return ec; + } + + // Perform an IO control command on the socket. + template + boost::system::error_code io_control(base_implementation_type& impl, + IO_Control_Command& command, boost::system::error_code& ec) + { + socket_ops::ioctl(impl.socket_, impl.state_, command.name(), + static_cast(command.data()), ec); + 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) + { + socket_ops::shutdown(impl.socket_, what, ec); + return ec; + } + + // Send the given data to the peer. + template + size_t send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_send(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be sent without blocking. + size_t send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_send_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, buffers, flags, handler); + + start_op(impl, reactor::write_op, p.p, true, + ((impl.state_ & socket_ops::stream_oriented) + && buffer_sequence_adapter::all_empty(buffers))); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + start_op(impl, reactor::write_op, p.p, false, false); + p.v = p.p = 0; + } + + // Receive some data from the peer. Returns the number of bytes received. + template + size_t receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_recv(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be received without blocking. + size_t receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, ec); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_recv_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, (flags & socket_base::message_out_of_band) == 0, + ((impl.state_ & socket_ops::stream_oriented) + && buffer_sequence_adapter::all_empty(buffers))); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, false, false); + p.v = p.p = 0; + } + +protected: + // Open a new socket implementation. + BOOST_ASIO_DECL boost::system::error_code do_open( + base_implementation_type& impl, int af, + int type, int protocol, boost::system::error_code& ec); + + // Assign a native socket to a socket implementation. + BOOST_ASIO_DECL boost::system::error_code do_assign( + base_implementation_type& impl, int type, + const native_type& native_socket, boost::system::error_code& ec); + + // Start the asynchronous read or write operation. + BOOST_ASIO_DECL void start_op(base_implementation_type& impl, int op_type, + reactor_op* op, bool non_blocking, bool noop); + + // Start the asynchronous accept operation. + BOOST_ASIO_DECL void start_accept_op(base_implementation_type& impl, + reactor_op* op, bool peer_is_open); + + // Start the asynchronous connect operation. + BOOST_ASIO_DECL void start_connect_op(base_implementation_type& impl, + reactor_op* op, const socket_addr_type* addr, size_t addrlen); + + // The selector that performs event demultiplexing for the service. + reactor& reactor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP diff --git a/include/boost/asio/detail/reactor.hpp b/include/boost/asio/detail/reactor.hpp index 43e432b8..468276d7 100644 --- a/include/boost/asio/detail/reactor.hpp +++ b/include/boost/asio/detail/reactor.hpp @@ -1,6 +1,6 @@ // -// reactor.hpp -// ~~~~~~~~~~~ +// detail/reactor.hpp +// ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - #include #if defined(BOOST_ASIO_HAS_EPOLL) @@ -29,6 +27,4 @@ # include #endif -#include - #endif // BOOST_ASIO_DETAIL_REACTOR_HPP diff --git a/include/boost/asio/detail/reactor_fwd.hpp b/include/boost/asio/detail/reactor_fwd.hpp index 9ff05eb5..3fae83c7 100644 --- a/include/boost/asio/detail/reactor_fwd.hpp +++ b/include/boost/asio/detail/reactor_fwd.hpp @@ -1,6 +1,6 @@ // -// reactor_fwd.hpp -// ~~~~~~~~~~~~~~~ +// detail/reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,20 +15,26 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include -#include +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#elif defined(BOOST_ASIO_HAS_EPOLL) +# include +#elif defined(BOOST_ASIO_HAS_KQUEUE) +# include +#elif defined(BOOST_ASIO_HAS_DEV_POLL) +# include +#else +# include +#endif namespace boost { namespace asio { namespace detail { #if defined(BOOST_ASIO_HAS_IOCP) -typedef select_reactor reactor; +typedef select_reactor reactor; #elif defined(BOOST_ASIO_HAS_EPOLL) typedef epoll_reactor reactor; #elif defined(BOOST_ASIO_HAS_KQUEUE) @@ -36,13 +42,11 @@ typedef kqueue_reactor reactor; #elif defined(BOOST_ASIO_HAS_DEV_POLL) typedef dev_poll_reactor reactor; #else -typedef select_reactor reactor; +typedef select_reactor reactor; #endif } // namespace detail } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_REACTOR_FWD_HPP diff --git a/include/boost/asio/detail/reactor_op.hpp b/include/boost/asio/detail/reactor_op.hpp index 40647ec8..ed4a33d9 100644 --- a/include/boost/asio/detail/reactor_op.hpp +++ b/include/boost/asio/detail/reactor_op.hpp @@ -1,6 +1,6 @@ // -// reactor_op.hpp -// ~~~~~~~~~~~~ +// detail/reactor_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/reactor_op_queue.hpp b/include/boost/asio/detail/reactor_op_queue.hpp index 0dd56540..830e9b35 100644 --- a/include/boost/asio/detail/reactor_op_queue.hpp +++ b/include/boost/asio/detail/reactor_op_queue.hpp @@ -1,6 +1,6 @@ // -// reactor_op_queue.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/reactor_op_queue.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include #include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/detail/regex_fwd.hpp b/include/boost/asio/detail/regex_fwd.hpp new file mode 100644 index 00000000..7847b8d8 --- /dev/null +++ b/include/boost/asio/detail/regex_fwd.hpp @@ -0,0 +1,31 @@ +// +// detail/regex_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_REGEX_FWD_HPP +#define BOOST_ASIO_DETAIL_REGEX_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +namespace boost { + +template +class sub_match; + +template +class match_results; + +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_REGEX_FWD_HPP diff --git a/include/boost/asio/detail/resolve_endpoint_op.hpp b/include/boost/asio/detail/resolve_endpoint_op.hpp new file mode 100644 index 00000000..ccf5f532 --- /dev/null +++ b/include/boost/asio/detail/resolve_endpoint_op.hpp @@ -0,0 +1,118 @@ +// +// detail/resolve_endpoint_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_RESOLVER_ENDPOINT_OP_HPP +#define BOOST_ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class resolve_endpoint_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(resolve_endpoint_op); + + typedef typename Protocol::endpoint endpoint_type; + typedef boost::asio::ip::basic_resolver_iterator iterator_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), + cancel_token_(cancel_token), + endpoint_(endpoint), + io_service_impl_(ios), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the operation object. + resolve_endpoint_op* o(static_cast(base)); + ptr p = { boost::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 endpoint resolution operation. + char host_name[NI_MAXHOST]; + char service_name[NI_MAXSERV]; + 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); + + // 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. + + // 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(o->handler_, o->ec_, o->iter_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + endpoint_type endpoint_; + io_service_impl& io_service_impl_; + Handler handler_; + boost::system::error_code ec_; + iterator_type iter_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP diff --git a/include/boost/asio/detail/resolve_op.hpp b/include/boost/asio/detail/resolve_op.hpp new file mode 100644 index 00000000..aff61040 --- /dev/null +++ b/include/boost/asio/detail/resolve_op.hpp @@ -0,0 +1,128 @@ +// +// detail/resolve_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_OP_HPP +#define BOOST_ASIO_DETAIL_RESOLVE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class resolve_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(resolve_op); + + typedef boost::asio::ip::basic_resolver_query query_type; + typedef boost::asio::ip::basic_resolver_iterator 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_(handler), + addrinfo_(0) + { + } + + ~resolve_op() + { + if (addrinfo_) + socket_ops::freeaddrinfo(addrinfo_); + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the operation object. + resolve_op* o(static_cast(base)); + ptr p = { boost::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. + + // 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(o->handler_, o->ec_, iterator_type()); + p.h = boost::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) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + } + +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 +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_RESOLVE_OP_HPP diff --git a/include/boost/asio/detail/resolver_service.hpp b/include/boost/asio/detail/resolver_service.hpp index f9b7a98a..1b734a0e 100644 --- a/include/boost/asio/detail/resolver_service.hpp +++ b/include/boost/asio/detail/resolver_service.hpp @@ -1,6 +1,6 @@ // -// resolver_service.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/resolver_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,69 +15,26 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include -#include - -#include -#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include + +#include namespace boost { namespace asio { namespace detail { template -class resolver_service - : public boost::asio::detail::service_base > +class resolver_service : public resolver_service_base { -private: - // Helper class to perform exception-safe cleanup of addrinfo objects. - class auto_addrinfo - : private boost::asio::detail::noncopyable - { - public: - explicit auto_addrinfo(boost::asio::detail::addrinfo_type* ai) - : ai_(ai) - { - } - - ~auto_addrinfo() - { - if (ai_) - socket_ops::freeaddrinfo(ai_); - } - - operator boost::asio::detail::addrinfo_type*() - { - return ai_; - } - - private: - boost::asio::detail::addrinfo_type* ai_; - }; - public: - // The implementation type of the resolver. The shared pointer is used as a - // cancellation token to indicate to the background thread that the operation - // has been cancelled. - typedef boost::shared_ptr implementation_type; - struct noop_deleter { void operator()(void*) {} }; + // The implementation type of the resolver. A cancellation token is used to + // indicate to the background thread that the operation has been cancelled. + typedef socket_ops::shared_cancel_token_type implementation_type; // The endpoint type. typedef typename Protocol::endpoint endpoint_type; @@ -90,349 +47,69 @@ public: // Constructor. resolver_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - resolver_service >(io_service), - mutex_(), - io_service_impl_(boost::asio::use_service(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_)), - work_thread_(0) + : resolver_service_base(io_service) { } - // Destructor. - ~resolver_service() - { - shutdown_service(); - } - - // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - work_.reset(); - if (work_io_service_) - { - work_io_service_->stop(); - if (work_thread_) - { - work_thread_->join(); - work_thread_.reset(); - } - work_io_service_.reset(); - } - } - - // Construct a new resolver implementation. - void construct(implementation_type& impl) - { - impl.reset(static_cast(0), noop_deleter()); - } - - // Destroy a resolver implementation. - void destroy(implementation_type&) - { - } - - // Cancel pending asynchronous operations. - void cancel(implementation_type& impl) - { - impl.reset(static_cast(0), noop_deleter()); - } - // Resolve a query to a list of entries. iterator_type resolve(implementation_type&, const query_type& query, boost::system::error_code& ec) { boost::asio::detail::addrinfo_type* address_info = 0; - std::string host_name = query.host_name(); - std::string service_name = query.service_name(); - boost::asio::detail::addrinfo_type hints = query.hints(); - socket_ops::getaddrinfo(!host_name.empty() ? host_name.c_str() : 0, - service_name.c_str(), &hints, &address_info, ec); + socket_ops::getaddrinfo(query.host_name().c_str(), + query.service_name().c_str(), query.hints(), &address_info, ec); auto_addrinfo auto_address_info(address_info); - if (ec) - return iterator_type(); - - return iterator_type::create(address_info, host_name, service_name); + return ec ? iterator_type() : iterator_type::create( + address_info, query.host_name(), query.service_name()); } - template - class resolve_op - : public operation - { - public: - resolve_op(implementation_type impl, const query_type& query, - io_service_impl& io_service_impl, Handler handler) - : operation(&resolve_op::do_complete), - impl_(impl), - query_(query), - io_service_impl_(io_service_impl), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the operation object. - resolve_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - if (owner) - { - if (owner != &o->io_service_impl_) - { - // The operation is being run on the worker io_service. Time to - // perform the resolver operation. - - if (o->impl_.expired()) - { - // THe operation has been cancelled. - o->ec_ = boost::asio::error::operation_aborted; - } - else - { - // Perform the blocking host resolution operation. - boost::asio::detail::addrinfo_type* address_info = 0; - std::string host_name = o->query_.host_name(); - std::string service_name = o->query_.service_name(); - boost::asio::detail::addrinfo_type hints = o->query_.hints(); - socket_ops::getaddrinfo(!host_name.empty() ? host_name.c_str() : 0, - service_name.c_str(), &hints, &address_info, o->ec_); - auto_addrinfo auto_address_info(address_info); - o->iter_ = iterator_type::create( - address_info, host_name, service_name); - } - - o->io_service_impl_.post_deferred_completion(o); - ptr.release(); - } - else - { - // The operation has been returned to the main io_serice. The - // completion handler is ready to be delivered. - - // 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(o->handler_, o->ec_, o->iter_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - } - - private: - boost::weak_ptr impl_; - query_type query_; - io_service_impl& io_service_impl_; - Handler handler_; - boost::system::error_code ec_; - iterator_type iter_; - }; - // Asynchronously resolve a query to a list of entries. template void async_resolve(implementation_type& impl, const query_type& query, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef resolve_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, - impl, query, io_service_impl_, handler); + typedef resolve_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl, query, io_service_impl_, handler); - if (work_io_service_) - { - start_work_thread(); - io_service_impl_.work_started(); - work_io_service_impl_.post_immediate_completion(ptr.get()); - ptr.release(); - } + start_resolve_op(p.p); + p.v = p.p = 0; } // Resolve an endpoint to a list of entries. iterator_type resolve(implementation_type&, const endpoint_type& endpoint, boost::system::error_code& ec) { - // First try resolving with the service name. If that fails try resolving - // but allow the service to be returned as a number. char host_name[NI_MAXHOST]; char service_name[NI_MAXSERV]; - int flags = endpoint.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0; - socket_ops::getnameinfo(endpoint.data(), endpoint.size(), - host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); - if (ec) - { - flags |= NI_NUMERICSERV; - socket_ops::getnameinfo(endpoint.data(), endpoint.size(), - host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); - } + socket_ops::sync_getnameinfo(endpoint.data(), endpoint.size(), + host_name, NI_MAXHOST, service_name, NI_MAXSERV, + endpoint.protocol().type(), ec); - if (ec) - return iterator_type(); - - return iterator_type::create(endpoint, host_name, service_name); + return ec ? iterator_type() : iterator_type::create( + endpoint, host_name, service_name); } - template - class resolve_endpoint_op - : public operation - { - public: - resolve_endpoint_op(implementation_type impl, const endpoint_type& ep, - io_service_impl& io_service_impl, Handler handler) - : operation(&resolve_endpoint_op::do_complete), - impl_(impl), - ep_(ep), - io_service_impl_(io_service_impl), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the operation object. - resolve_endpoint_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - if (owner) - { - if (owner != &o->io_service_impl_) - { - // The operation is being run on the worker io_service. Time to - // perform the resolver operation. - - if (o->impl_.expired()) - { - // THe operation has been cancelled. - o->ec_ = boost::asio::error::operation_aborted; - } - else - { - // Perform the blocking endoint resolution operation. - char host_name[NI_MAXHOST]; - char service_name[NI_MAXSERV]; - int flags = o->ep_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0; - socket_ops::getnameinfo(o->ep_.data(), o->ep_.size(), - host_name, NI_MAXHOST, service_name, - NI_MAXSERV, flags, o->ec_); - if (o->ec_) - { - flags |= NI_NUMERICSERV; - socket_ops::getnameinfo(o->ep_.data(), o->ep_.size(), - host_name, NI_MAXHOST, service_name, - NI_MAXSERV, flags, o->ec_); - } - o->iter_ = iterator_type::create(o->ep_, host_name, service_name); - } - - o->io_service_impl_.post_deferred_completion(o); - ptr.release(); - } - else - { - // The operation has been returned to the main io_serice. The - // completion handler is ready to be delivered. - - // 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(o->handler_, o->ec_, o->iter_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - } - - private: - boost::weak_ptr impl_; - endpoint_type ep_; - io_service_impl& io_service_impl_; - Handler handler_; - boost::system::error_code ec_; - iterator_type iter_; - }; - // Asynchronously resolve an endpoint to a list of entries. template void async_resolve(implementation_type& impl, const endpoint_type& endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef resolve_endpoint_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, - impl, endpoint, io_service_impl_, handler); + typedef resolve_endpoint_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl, endpoint, io_service_impl_, handler); - if (work_io_service_) - { - start_work_thread(); - io_service_impl_.work_started(); - work_io_service_impl_.post_immediate_completion(ptr.get()); - ptr.release(); - } + start_resolve_op(p.p); + p.v = p.p = 0; } - -private: - // Helper class to run the work io_service in a thread. - class work_io_service_runner - { - public: - work_io_service_runner(boost::asio::io_service& io_service) - : io_service_(io_service) {} - void operator()() { io_service_.run(); } - private: - boost::asio::io_service& io_service_; - }; - - // Start the work thread if it's not already running. - void start_work_thread() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!work_thread_) - { - work_thread_.reset(new boost::asio::detail::thread( - work_io_service_runner(*work_io_service_))); - } - } - - // Mutex to protect access to internal data. - boost::asio::detail::mutex mutex_; - - // The io_service implementation used to post completions. - io_service_impl& io_service_impl_; - - // Private io_service used for performing asynchronous host resolution. - boost::scoped_ptr work_io_service_; - - // The work io_service implementation used to post completions. - io_service_impl& work_io_service_impl_; - - // Work for the private io_service to perform. - boost::scoped_ptr work_; - - // Thread used for running the work io_service's run loop. - boost::scoped_ptr work_thread_; }; } // namespace detail diff --git a/include/boost/asio/detail/resolver_service_base.hpp b/include/boost/asio/detail/resolver_service_base.hpp new file mode 100644 index 00000000..cc6ede6d --- /dev/null +++ b/include/boost/asio/detail/resolver_service_base.hpp @@ -0,0 +1,125 @@ +// +// detail/resolver_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_RESOLVER_SERVICE_BASE_HPP +#define BOOST_ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class resolver_service_base +{ +public: + // The implementation type of the resolver. A cancellation token is used to + // indicate to the background thread that the operation has been cancelled. + typedef socket_ops::shared_cancel_token_type implementation_type; + + // Constructor. + BOOST_ASIO_DECL resolver_service_base(boost::asio::io_service& io_service); + + // Destructor. + BOOST_ASIO_DECL ~resolver_service_base(); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown_service(); + + // Construct a new resolver implementation. + BOOST_ASIO_DECL void construct(implementation_type& impl); + + // Destroy a resolver implementation. + BOOST_ASIO_DECL void destroy(implementation_type&); + + // 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); + + // Helper class to perform exception-safe cleanup of addrinfo objects. + class auto_addrinfo + : private boost::asio::detail::noncopyable + { + public: + explicit auto_addrinfo(boost::asio::detail::addrinfo_type* ai) + : ai_(ai) + { + } + + ~auto_addrinfo() + { + if (ai_) + socket_ops::freeaddrinfo(ai_); + } + + operator boost::asio::detail::addrinfo_type*() + { + return ai_; + } + + private: + boost::asio::detail::addrinfo_type* ai_; + }; + + // Helper class to run the work io_service in a thread. + class work_io_service_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_; + +private: + // Mutex to protect access to internal data. + boost::asio::detail::mutex mutex_; + + // Private io_service used for performing asynchronous host resolution. + boost::scoped_ptr work_io_service_; + + // The work io_service implementation used to post completions. + io_service_impl& work_io_service_impl_; + + // Work for the private io_service to perform. + boost::scoped_ptr work_; + + // Thread used for running the work io_service's run loop. + boost::scoped_ptr work_thread_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP diff --git a/include/boost/asio/detail/scoped_lock.hpp b/include/boost/asio/detail/scoped_lock.hpp index c3192631..247411e1 100644 --- a/include/boost/asio/detail/scoped_lock.hpp +++ b/include/boost/asio/detail/scoped_lock.hpp @@ -1,6 +1,6 @@ // -// scoped_lock.hpp -// ~~~~~~~~~~~~~~~ +// detail/scoped_lock.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,10 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/select_interrupter.hpp b/include/boost/asio/detail/select_interrupter.hpp index f8448815..3c3fb35f 100644 --- a/include/boost/asio/detail/select_interrupter.hpp +++ b/include/boost/asio/detail/select_interrupter.hpp @@ -1,6 +1,6 @@ // -// select_interrupter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # include -#else +#elif defined(BOOST_ASIO_HAS_EVENTFD) # include +#else # include #endif @@ -44,6 +41,4 @@ typedef pipe_select_interrupter select_interrupter; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_SELECT_INTERRUPTER_HPP diff --git a/include/boost/asio/detail/select_reactor.hpp b/include/boost/asio/detail/select_reactor.hpp index 91030e91..c453c598 100644 --- a/include/boost/asio/detail/select_reactor.hpp +++ b/include/boost/asio/detail/select_reactor.hpp @@ -1,6 +1,6 @@ // -// select_reactor.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/select_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,42 +15,39 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include // Must come before posix_time. +#if defined(BOOST_ASIO_HAS_IOCP) \ + || (!defined(BOOST_ASIO_HAS_DEV_POLL) \ + && !defined(BOOST_ASIO_HAS_EPOLL) \ + && !defined(BOOST_ASIO_HAS_KQUEUE)) -#include #include -#include -#include - -#include -#include -#include #include -#include #include #include #include #include #include -#include -#include -#include #include -#include #include #include #include #include +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#include namespace boost { namespace asio { namespace detail { -template class select_reactor - : public boost::asio::detail::service_base > + : public boost::asio::detail::service_base { public: #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -67,280 +64,89 @@ public: }; // Constructor. - select_reactor(boost::asio::io_service& io_service) - : boost::asio::detail::service_base< - select_reactor >(io_service), - io_service_(use_service(io_service)), - mutex_(), - interrupter_(), - stop_thread_(false), - thread_(0), - shutdown_(false) - { - if (Own_Thread) - { - boost::asio::detail::signal_blocker sb; - thread_ = new boost::asio::detail::thread( - bind_handler(&select_reactor::call_run_thread, this)); - } - } + BOOST_ASIO_DECL select_reactor(boost::asio::io_service& io_service); // Destructor. - ~select_reactor() - { - shutdown_service(); - } + BOOST_ASIO_DECL ~select_reactor(); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - shutdown_ = true; - stop_thread_ = true; - lock.unlock(); - - if (Own_Thread) - { - if (thread_) - { - interrupter_.interrupt(); - thread_->join(); - delete thread_; - thread_ = 0; - } - } - - op_queue ops; - - for (int i = 0; i < max_ops; ++i) - op_queue_[i].get_all_operations(ops); - - timer_queues_.get_all_timers(ops); - } + BOOST_ASIO_DECL void shutdown_service(); // Initialise the task, but only if the reactor is not in its own thread. - void init_task() - { - io_service_.init_task(); - } + BOOST_ASIO_DECL void init_task(); // Register a socket with the reactor. Returns 0 on success, system error // code on failure. - int register_descriptor(socket_type, per_descriptor_data&) + BOOST_ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op) { - return 0; + io_service_.post_immediate_completion(op); } // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. - void start_op(int op_type, socket_type descriptor, - per_descriptor_data&, reactor_op* op, bool) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_) - { - bool first = op_queue_[op_type].enqueue_operation(descriptor, op); - io_service_.work_started(); - if (first) - interrupter_.interrupt(); - } - } + BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data&, reactor_op* op, bool); // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the // operation_aborted error. - void cancel_ops(socket_type descriptor, per_descriptor_data&) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); - } + BOOST_ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. - void close_descriptor(socket_type descriptor, per_descriptor_data&) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); - } + BOOST_ASIO_DECL void close_descriptor(socket_type descriptor, + per_descriptor_data&); // Add a new timer queue to the reactor. template - void add_timer_queue(timer_queue& timer_queue) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.insert(&timer_queue); - } + void add_timer_queue(timer_queue& queue); // Remove a timer queue from the reactor. template - void remove_timer_queue(timer_queue& timer_queue) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - timer_queues_.erase(&timer_queue); - } + void remove_timer_queue(timer_queue& queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template - void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, timer_op* op, void* token) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_) - { - bool earliest = timer_queue.enqueue_timer(time, op, token); - io_service_.work_started(); - if (earliest) - interrupter_.interrupt(); - } - } + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, timer_op* op, void* token); // Cancel the timer operations associated with the given token. Returns the // number of operations that have been posted or dispatched. template - std::size_t cancel_timer(timer_queue& timer_queue, void* token) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - op_queue ops; - std::size_t n = timer_queue.cancel_timer(token, ops); - lock.unlock(); - io_service_.post_deferred_completions(ops); - return n; - } + std::size_t cancel_timer(timer_queue& queue, void* token); // Run select once until interrupted or events are ready to be dispatched. - void run(bool block, op_queue& ops) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - // Check if the thread is supposed to stop. - if (Own_Thread) - if (stop_thread_) - return; - - // Set up the descriptor sets. - fd_set_adapter fds[max_select_ops]; - fds[read_op].set(interrupter_.read_descriptor()); - socket_type max_fd = 0; - bool have_work_to_do = !timer_queues_.all_empty(); - for (int i = 0; i < max_select_ops; ++i) - { - have_work_to_do = have_work_to_do || !op_queue_[i].empty(); - op_queue_[i].get_descriptors(fds[i], ops); - if (fds[i].max_descriptor() > max_fd) - max_fd = fds[i].max_descriptor(); - } - -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Connection operations on Windows use both except and write fd_sets. - have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty(); - op_queue_[connect_op].get_descriptors(fds[write_op], ops); - if (fds[write_op].max_descriptor() > max_fd) - max_fd = fds[write_op].max_descriptor(); - op_queue_[connect_op].get_descriptors(fds[except_op], ops); - if (fds[except_op].max_descriptor() > max_fd) - max_fd = fds[except_op].max_descriptor(); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - - // 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) - return; - - // Determine how long to block while waiting for events. - timeval tv_buf = { 0, 0 }; - timeval* tv = block ? get_timeout(tv_buf) : &tv_buf; - - lock.unlock(); - - // Block on the select call until descriptors become ready. - boost::system::error_code ec; - int retval = socket_ops::select(static_cast(max_fd + 1), - fds[read_op], fds[write_op], fds[except_op], tv, ec); - - // Reset the interrupter. - if (retval > 0 && fds[read_op].is_set(interrupter_.read_descriptor())) - interrupter_.reset(); - - lock.lock(); - - // Dispatch all ready operations. - if (retval > 0) - { -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Connection operations on Windows use both except and write fd_sets. - op_queue_[connect_op].perform_operations_for_descriptors( - fds[except_op], ops); - op_queue_[connect_op].perform_operations_for_descriptors( - fds[write_op], ops); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - - // Exception operations must be processed first to ensure that any - // out-of-band data is read before normal data. - for (int i = max_select_ops - 1; i >= 0; --i) - op_queue_[i].perform_operations_for_descriptors(fds[i], ops); - } - timer_queues_.get_ready_timers(ops); - } + BOOST_ASIO_DECL void run(bool block, op_queue& ops); // Interrupt the select loop. - void interrupt() - { - interrupter_.interrupt(); - } + BOOST_ASIO_DECL void interrupt(); private: +#if defined(BOOST_ASIO_HAS_IOCP) // Run the select loop in the thread. - void run_thread() - { - if (Own_Thread) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - while (!stop_thread_) - { - lock.unlock(); - op_queue ops; - run(true, ops); - io_service_.post_deferred_completions(ops); - lock.lock(); - } - } - } + BOOST_ASIO_DECL void run_thread(); // Entry point for the select loop thread. - static void call_run_thread(select_reactor* reactor) - { - if (Own_Thread) - { - reactor->run_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. + BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); // Get the timeout value for the select call. - timeval* get_timeout(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); - tv.tv_sec = usec / 1000000; - tv.tv_usec = usec % 1000000; - return &tv; - } + BOOST_ASIO_DECL timeval* get_timeout(timeval& tv); // Cancel all operations associated with the given descriptor. This function // does not acquire the select_reactor's mutex. - void cancel_ops_unlocked(socket_type descriptor, - const boost::system::error_code& ec) - { - bool need_interrupt = false; - op_queue ops; - 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); - if (need_interrupt) - interrupter_.interrupt(); - } + 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_; @@ -357,11 +163,13 @@ private: // The timer queues. timer_queue_set timer_queues_; +#if defined(BOOST_ASIO_HAS_IOCP) // Does the reactor loop thread need to stop. bool stop_thread_; // The thread that is running the reactor loop. boost::asio::detail::thread* thread_; +#endif // defined(BOOST_ASIO_HAS_IOCP) // Whether the service has been shut down. bool shutdown_; @@ -373,4 +181,14 @@ private: #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_IOCP) + // || (!defined(BOOST_ASIO_HAS_DEV_POLL) + // && !defined(BOOST_ASIO_HAS_EPOLL) + // && !defined(BOOST_ASIO_HAS_KQUEUE)) + #endif // BOOST_ASIO_DETAIL_SELECT_REACTOR_HPP diff --git a/include/boost/asio/detail/select_reactor_fwd.hpp b/include/boost/asio/detail/select_reactor_fwd.hpp index b48e0f01..f4f9f65a 100644 --- a/include/boost/asio/detail/select_reactor_fwd.hpp +++ b/include/boost/asio/detail/select_reactor_fwd.hpp @@ -1,6 +1,6 @@ // -// select_reactor_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/select_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,19 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - namespace boost { namespace asio { namespace detail { -template class select_reactor; } // namespace detail } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_SELECT_REACTOR_FWD_HPP diff --git a/include/boost/asio/detail/service_base.hpp b/include/boost/asio/detail/service_base.hpp deleted file mode 100644 index 66c2af38..00000000 --- a/include/boost/asio/detail/service_base.hpp +++ /dev/null @@ -1,51 +0,0 @@ -// -// service_base.hpp -// ~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2010 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_SERVICE_BASE_HPP -#define BOOST_ASIO_DETAIL_SERVICE_BASE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#include -#include - -namespace boost { -namespace asio { -namespace detail { - -// Special service base class to keep classes header-file only. -template -class service_base - : public boost::asio::io_service::service -{ -public: - static boost::asio::detail::service_id id; - - // Constructor. - service_base(boost::asio::io_service& io_service) - : boost::asio::io_service::service(io_service) - { - } -}; - -template -boost::asio::detail::service_id service_base::id; - -} // namespace detail -} // namespace asio -} // namespace boost - -#include - -#endif // BOOST_ASIO_DETAIL_SERVICE_BASE_HPP diff --git a/include/boost/asio/detail/service_registry.hpp b/include/boost/asio/detail/service_registry.hpp index e640ec86..d40e3b00 100644 --- a/include/boost/asio/detail/service_registry.hpp +++ b/include/boost/asio/detail/service_registry.hpp @@ -1,6 +1,6 @@ // -// service_registry.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/service_registry.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include - -#include #include #include -#include +#include #if defined(BOOST_NO_TYPEID) # if !defined(BOOST_ASIO_NO_TYPEID) @@ -32,6 +27,8 @@ # endif // !defined(BOOST_ASIO_NO_TYPEID) #endif // defined(BOOST_NO_TYPEID) +#include + namespace boost { namespace asio { namespace detail { @@ -56,98 +53,42 @@ class service_registry { public: // Constructor. - service_registry(boost::asio::io_service& o) - : owner_(o), - first_service_(0) - { - } + BOOST_ASIO_DECL service_registry(boost::asio::io_service& o); // Destructor. - ~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_; - while (service) - { - service->shutdown_service(); - service = service->next_; - } - - // Destroy all services. - while (first_service_) - { - boost::asio::io_service::service* next_service = first_service_->next_; - destroy(first_service_); - first_service_ = next_service; - } - } + BOOST_ASIO_DECL ~service_registry(); // 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 - Service& use_service() - { - boost::asio::io_service::service::key key; - init_key(key, Service::id); - factory_type factory = &service_registry::create; - return *static_cast(do_use_service(key, factory)); - } + Service& use_service(); - // Add a service object. Returns false on error, in which case ownership of - // the object is retained by the caller. + // Add a service object. Throws on error, in which case ownership of the + // object is retained by the caller. template - bool add_service(Service* new_service) - { - boost::asio::io_service::service::key key; - init_key(key, Service::id); - return do_add_service(key, new_service); - } + void add_service(Service* new_service); // Check whether a service object of the specified type already exists. template - bool has_service() const - { - boost::asio::io_service::service::key key; - init_key(key, Service::id); - return do_has_service(key); - } + bool has_service() const; private: // Initialise a service's key based on its id. - void init_key(boost::asio::io_service::service::key& key, - const boost::asio::io_service::id& id) - { - key.type_info_ = 0; - key.id_ = &id; - } + BOOST_ASIO_DECL void init_key(boost::asio::io_service::service::key& key, + const boost::asio::io_service::id& id); #if !defined(BOOST_ASIO_NO_TYPEID) // Initialise a service's key based on its id. template void init_key(boost::asio::io_service::service::key& key, - const boost::asio::detail::service_id& /*id*/) - { - key.type_info_ = &typeid(typeid_wrapper); - key.id_ = 0; - } + const boost::asio::detail::service_id& /*id*/); #endif // !defined(BOOST_ASIO_NO_TYPEID) // Check if a service matches the given id. - static bool keys_match( + BOOST_ASIO_DECL static bool keys_match( const boost::asio::io_service::service::key& key1, - const boost::asio::io_service::service::key& key2) - { - if (key1.id_ && key2.id_) - if (key1.id_ == key2.id_) - return true; - if (key1.type_info_ && key2.type_info_) - if (*key1.type_info_ == *key2.type_info_) - return true; - return false; - } + const boost::asio::io_service::service::key& key2); // The type of a factory function used for creating a service instance. typedef boost::asio::io_service::service* @@ -156,16 +97,11 @@ private: // Factory function for creating a service instance. template static boost::asio::io_service::service* create( - boost::asio::io_service& owner) - { - return new Service(owner); - } + boost::asio::io_service& owner); // Destroy a service instance. - static void destroy(boost::asio::io_service::service* service) - { - delete service; - } + BOOST_ASIO_DECL static void destroy( + boost::asio::io_service::service* service); // Helper class to manage service pointers. struct auto_service_ptr @@ -177,86 +113,19 @@ private: // 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::io_service::service* do_use_service( + BOOST_ASIO_DECL boost::asio::io_service::service* do_use_service( const boost::asio::io_service::service::key& key, - factory_type factory) - { - 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_; - while (service) - { - if (keys_match(service->key_, key)) - return service; - service = service->next_; - } - - // Create a new service object. The service registry's mutex is not locked - // 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_) }; - new_service.ptr_->key_ = key; - lock.lock(); - - // Check that nobody else created another service object of the same type - // while the lock was released. - service = first_service_; - while (service) - { - if (keys_match(service->key_, key)) - return service; - service = service->next_; - } - - // Service was successfully initialised, pass ownership to registry. - new_service.ptr_->next_ = first_service_; - first_service_ = new_service.ptr_; - new_service.ptr_ = 0; - return first_service_; - } + factory_type factory); // Add a service object. Returns false on error, in which case ownership of // the object is retained by the caller. - bool do_add_service( + BOOST_ASIO_DECL void do_add_service( const boost::asio::io_service::service::key& key, - boost::asio::io_service::service* new_service) - { - 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_; - while (service) - { - if (keys_match(service->key_, key)) - return false; - service = service->next_; - } - - // Take ownership of the service object. - new_service->key_ = key; - new_service->next_ = first_service_; - first_service_ = new_service; - - return true; - } + boost::asio::io_service::service* new_service); // Check whether a service object with the specified key already exists. - bool do_has_service(const boost::asio::io_service::service::key& key) const - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - boost::asio::io_service::service* service = first_service_; - while (service) - { - if (keys_match(service->key_, key)) - return true; - service = service->next_; - } - - return false; - } + BOOST_ASIO_DECL bool do_has_service( + const boost::asio::io_service::service::key& key) const; // Mutex to protect access to internal data. mutable boost::asio::detail::mutex mutex_; @@ -274,4 +143,9 @@ private: #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP diff --git a/include/boost/asio/detail/service_registry_fwd.hpp b/include/boost/asio/detail/service_registry_fwd.hpp index 4031b1a1..8713a30b 100644 --- a/include/boost/asio/detail/service_registry_fwd.hpp +++ b/include/boost/asio/detail/service_registry_fwd.hpp @@ -1,6 +1,6 @@ // -// service_registry_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/service_registry_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - namespace boost { namespace asio { namespace detail { @@ -27,6 +25,4 @@ class service_registry; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP diff --git a/include/boost/asio/detail/service_id.hpp b/include/boost/asio/detail/shared_ptr.hpp similarity index 51% rename from include/boost/asio/detail/service_id.hpp rename to include/boost/asio/detail/shared_ptr.hpp index ac0f4d13..0c5586e2 100644 --- a/include/boost/asio/detail/service_id.hpp +++ b/include/boost/asio/detail/shared_ptr.hpp @@ -1,6 +1,6 @@ // -// service_id.hpp -// ~~~~~~~~~~~~~~ +// detail/shared_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,32 +8,33 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_DETAIL_SERVICE_ID_HPP -#define BOOST_ASIO_DETAIL_SERVICE_ID_HPP +#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 +#include -#include +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +# include +#else +# include +#endif namespace boost { namespace asio { namespace detail { -// Special derived service id type to keep classes header-file only. -template -class service_id - : public boost::asio::io_service::id -{ -}; +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +using std::shared_ptr; +#else +using boost::shared_ptr; +#endif } // namespace detail } // namespace asio } // namespace boost -#include - -#endif // BOOST_ASIO_DETAIL_SERVICE_ID_HPP +#endif // BOOST_ASIO_DETAIL_SHARED_PTR_HPP diff --git a/include/boost/asio/detail/signal_blocker.hpp b/include/boost/asio/detail/signal_blocker.hpp index 0197e04d..84923e56 100644 --- a/include/boost/asio/detail/signal_blocker.hpp +++ b/include/boost/asio/detail/signal_blocker.hpp @@ -1,6 +1,6 @@ // -// signal_blocker.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include @@ -47,6 +43,4 @@ typedef posix_signal_blocker signal_blocker; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_SIGNAL_BLOCKER_HPP diff --git a/include/boost/asio/detail/signal_init.hpp b/include/boost/asio/detail/signal_init.hpp index 50e06b85..76d21bff 100644 --- a/include/boost/asio/detail/signal_init.hpp +++ b/include/boost/asio/detail/signal_init.hpp @@ -1,6 +1,6 @@ // -// signal_init.hpp -// ~~~~~~~~~~~~~~~ +// detail/signal_init.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -#include #include -#include + +#include namespace boost { namespace asio { @@ -46,8 +42,8 @@ public: } // namespace asio } // namespace boost -#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) - #include +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_SIGNAL_INIT_HPP diff --git a/include/boost/asio/detail/socket_holder.hpp b/include/boost/asio/detail/socket_holder.hpp index 5d6012b0..7815accc 100644 --- a/include/boost/asio/detail/socket_holder.hpp +++ b/include/boost/asio/detail/socket_holder.hpp @@ -1,6 +1,6 @@ // -// socket_holder.hpp -// ~~~~~~~~~~~~~~~~~ +// detail/socket_holder.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include +#include + namespace boost { namespace asio { namespace detail { @@ -47,7 +48,8 @@ public: if (socket_ != invalid_socket) { boost::system::error_code ec; - socket_ops::close(socket_, ec); + socket_ops::state_type state = 0; + socket_ops::close(socket_, state, true, ec); } } @@ -63,7 +65,8 @@ public: if (socket_ != invalid_socket) { boost::system::error_code ec; - socket_ops::close(socket_, ec); + socket_ops::state_type state = 0; + socket_ops::close(socket_, state, true, ec); socket_ = invalid_socket; } } diff --git a/include/boost/asio/detail/socket_ops.hpp b/include/boost/asio/detail/socket_ops.hpp index 475162a3..bbdba385 100644 --- a/include/boost/asio/detail/socket_ops.hpp +++ b/include/boost/asio/detail/socket_ops.hpp @@ -1,6 +1,6 @@ // -// socket_ops.hpp -// ~~~~~~~~~~~~~~ +// detail/socket_ops.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,194 +15,103 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include +#include +#include #include +#include + +#include namespace boost { namespace asio { namespace detail { namespace socket_ops { -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -struct msghdr { int msg_namelen; }; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - -#if defined(__hpux) -// HP-UX doesn't declare these functions extern "C", so they are declared again -// here to avoid linker errors about undefined symbols. -extern "C" char* if_indextoname(unsigned int, char*); -extern "C" unsigned int if_nametoindex(const char*); -#endif // defined(__hpux) - -inline void clear_error(boost::system::error_code& ec) +// Socket state bits. +enum { -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - WSASetLastError(0); -#else - errno = 0; -#endif - ec = boost::system::error_code(); -} + // The user wants a non-blocking socket. + user_set_non_blocking = 1, -template -inline ReturnType error_wrapper(ReturnType return_value, - boost::system::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - ec = boost::system::error_code(WSAGetLastError(), - boost::asio::error::get_system_category()); -#else - ec = boost::system::error_code(errno, - boost::asio::error::get_system_category()); -#endif - return return_value; -} + // The socket has been set non-blocking. + internal_non_blocking = 2, -template -inline socket_type call_accept(SockLenType msghdr::*, - socket_type s, socket_addr_type* addr, std::size_t* addrlen) -{ - SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; - socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0); - if (addrlen) - *addrlen = (std::size_t)tmp_addrlen; - return result; -} + // Helper "state" used to determine whether the socket is non-blocking. + non_blocking = user_set_non_blocking | internal_non_blocking, -inline socket_type accept(socket_type s, socket_addr_type* addr, - std::size_t* addrlen, boost::system::error_code& ec) -{ - clear_error(ec); + // User wants connection_aborted errors, which are disabled by default. + enable_connection_aborted = 4, - socket_type new_s = error_wrapper(call_accept( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (new_s == invalid_socket) - return new_s; + // The user set the linger option. Needs to be checked when closing. + user_set_linger = 8, -#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) - int optval = 1; - int result = error_wrapper(::setsockopt(new_s, - SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); - if (result != 0) - { - ::close(new_s); - return invalid_socket; - } -#endif + // The socket is stream-oriented. + stream_oriented = 16, - clear_error(ec); - return new_s; -} + // The socket is datagram-oriented. + datagram_oriented = 32 +}; -template -inline int call_bind(SockLenType msghdr::*, - socket_type s, const socket_addr_type* addr, std::size_t addrlen) -{ - return ::bind(s, addr, (SockLenType)addrlen); -} +typedef unsigned char state_type; -inline int bind(socket_type s, const socket_addr_type* addr, - std::size_t addrlen, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(call_bind( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - clear_error(ec); - return result; -} +struct noop_deleter { void operator()(void*) {} }; +typedef shared_ptr shared_cancel_token_type; +typedef weak_ptr weak_cancel_token_type; -inline int close(socket_type s, boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::closesocket(s), ec); -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::close(s), ec); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - if (result == 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL socket_type accept(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec); -inline int shutdown(socket_type s, int what, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::shutdown(s, what), ec); - if (result == 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL socket_type sync_accept(socket_type s, + state_type state, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec); -template -inline int call_connect(SockLenType msghdr::*, - socket_type s, const socket_addr_type* addr, std::size_t addrlen) -{ - return ::connect(s, addr, (SockLenType)addrlen); -} +#if defined(BOOST_ASIO_HAS_IOCP) -inline int connect(socket_type s, const socket_addr_type* addr, - std::size_t addrlen, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(call_connect( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL void complete_iocp_accept(socket_type s, + void* output_buffer, DWORD address_length, + socket_addr_type* addr, std::size_t* addrlen, + socket_type new_socket, boost::system::error_code& ec); -inline int socketpair(int af, int type, int protocol, - socket_type sv[2], boost::system::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - (void)(af); - (void)(type); - (void)(protocol); - (void)(sv); - ec = boost::asio::error::operation_not_supported; - return -1; -#else - clear_error(ec); - int result = error_wrapper(::socketpair(af, type, protocol, sv), ec); - if (result == 0) - clear_error(ec); - return result; -#endif -} +#else // defined(BOOST_ASIO_HAS_IOCP) -inline int listen(socket_type s, int backlog, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::listen(s, backlog), ec); - if (result == 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL bool non_blocking_accept(socket_type s, + state_type state, socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec, socket_type& new_socket); -inline void init_buf_iov_base(void*& base, void* addr) -{ - base = addr; -} +#endif // defined(BOOST_ASIO_HAS_IOCP) -template -inline void init_buf_iov_base(T& base, void* addr) -{ - base = static_cast(addr); -} +BOOST_ASIO_DECL int bind(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec); + +BOOST_ASIO_DECL int close(socket_type s, state_type& state, + bool destruction, boost::system::error_code& ec); + +BOOST_ASIO_DECL bool set_internal_non_blocking(socket_type s, + state_type& state, boost::system::error_code& ec); + +BOOST_ASIO_DECL int shutdown(socket_type s, + int what, boost::system::error_code& ec); + +BOOST_ASIO_DECL int connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec); + +BOOST_ASIO_DECL void sync_connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec); + +BOOST_ASIO_DECL bool non_blocking_connect( + socket_type s, boost::system::error_code& ec); + +BOOST_ASIO_DECL int socketpair(int af, int type, int protocol, + socket_type sv[2], boost::system::error_code& ec); + +BOOST_ASIO_DECL bool sockatmark(socket_type s, boost::system::error_code& ec); + +BOOST_ASIO_DECL size_t available(socket_type s, boost::system::error_code& ec); + +BOOST_ASIO_DECL int listen(socket_type s, + int backlog, boost::system::error_code& ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef WSABUF buf; @@ -210,1699 +119,163 @@ typedef WSABUF buf; typedef iovec buf; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -inline void init_buf(buf& b, void* data, size_t size) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - b.buf = static_cast(data); - b.len = static_cast(size); -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - init_buf_iov_base(b.iov_base, data); - b.iov_len = size; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +BOOST_ASIO_DECL void init_buf(buf& b, void* data, size_t size); -inline void init_buf(buf& b, const void* data, size_t size) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - b.buf = static_cast(const_cast(data)); - b.len = static_cast(size); -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - init_buf_iov_base(b.iov_base, const_cast(data)); - b.iov_len = size; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +BOOST_ASIO_DECL void init_buf(buf& b, const void* data, size_t size); -inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr) -{ - name = addr; -} +BOOST_ASIO_DECL int recv(socket_type s, buf* bufs, size_t count, int flags, + boost::system::error_code& ec); -inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr) -{ - name = const_cast(addr); -} +BOOST_ASIO_DECL size_t sync_recv(socket_type s, state_type state, buf* bufs, + size_t count, int flags, bool all_empty, boost::system::error_code& ec); -template -inline void init_msghdr_msg_name(T& name, socket_addr_type* addr) -{ - name = reinterpret_cast(addr); -} +#if defined(BOOST_ASIO_HAS_IOCP) -template -inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) -{ - name = reinterpret_cast(const_cast(addr)); -} +BOOST_ASIO_DECL void complete_iocp_recv(state_type state, + const weak_cancel_token_type& cancel_token, bool all_empty, + boost::system::error_code& ec, size_t bytes_transferred); -inline int recv(socket_type s, buf* bufs, size_t count, int flags, - boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Receive some data. - DWORD recv_buf_count = static_cast(count); - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = error_wrapper(::WSARecv(s, bufs, - recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); - if (result != 0) - return -1; - clear_error(ec); - return bytes_transferred; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg = msghdr(); - msg.msg_iov = bufs; - msg.msg_iovlen = count; - int result = error_wrapper(::recvmsg(s, &msg, flags), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +#else // defined(BOOST_ASIO_HAS_IOCP) -inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags, +BOOST_ASIO_DECL bool non_blocking_recv(socket_type s, + buf* bufs, size_t count, int flags, bool is_stream, + boost::system::error_code& ec, size_t& bytes_transferred); + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL int recvfrom(socket_type s, buf* bufs, size_t count, int flags, socket_addr_type* addr, std::size_t* addrlen, - boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Receive some data. - DWORD recv_buf_count = static_cast(count); - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int tmp_addrlen = (int)*addrlen; - int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, - &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); - *addrlen = (std::size_t)tmp_addrlen; - if (result != 0) - return -1; - clear_error(ec); - return bytes_transferred; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg = msghdr(); - init_msghdr_msg_name(msg.msg_name, addr); - msg.msg_namelen = *addrlen; - msg.msg_iov = bufs; - msg.msg_iovlen = count; - int result = error_wrapper(::recvmsg(s, &msg, flags), ec); - *addrlen = msg.msg_namelen; - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} + boost::system::error_code& ec); -inline int send(socket_type s, const buf* bufs, size_t count, int flags, - boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Send the data. - DWORD send_buf_count = static_cast(count); - DWORD bytes_transferred = 0; - DWORD send_flags = flags; - int result = error_wrapper(::WSASend(s, const_cast(bufs), - send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); - if (result != 0) - return -1; - clear_error(ec); - return bytes_transferred; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg = msghdr(); - msg.msg_iov = const_cast(bufs); - msg.msg_iovlen = count; -#if defined(__linux__) - flags |= MSG_NOSIGNAL; -#endif // defined(__linux__) - int result = error_wrapper(::sendmsg(s, &msg, flags), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +BOOST_ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state, + buf* bufs, size_t count, int flags, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec); -inline int sendto(socket_type s, const buf* bufs, size_t count, int flags, +#if defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL void complete_iocp_recvfrom( + const weak_cancel_token_type& cancel_token, + boost::system::error_code& ec); + +#else // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL bool non_blocking_recvfrom(socket_type s, + buf* bufs, size_t count, int flags, + socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec, size_t& bytes_transferred); + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL int send(socket_type s, const buf* bufs, + size_t count, int flags, boost::system::error_code& ec); + +BOOST_ASIO_DECL size_t sync_send(socket_type s, state_type state, + const buf* bufs, size_t count, int flags, + bool all_empty, boost::system::error_code& ec); + +#if defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL void complete_iocp_send( + const weak_cancel_token_type& cancel_token, + boost::system::error_code& ec); + +#else // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL bool non_blocking_send(socket_type s, + const buf* bufs, size_t count, int flags, + boost::system::error_code& ec, size_t& bytes_transferred); + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL int sendto(socket_type s, const buf* bufs, size_t count, + int flags, const socket_addr_type* addr, std::size_t addrlen, + boost::system::error_code& ec); + +BOOST_ASIO_DECL size_t sync_sendto(socket_type s, state_type state, + const buf* bufs, size_t count, int flags, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec); + +#if !defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL bool non_blocking_sendto(socket_type s, + const buf* bufs, size_t count, int flags, const socket_addr_type* addr, std::size_t addrlen, - boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // Send the data. - DWORD send_buf_count = static_cast(count); - DWORD bytes_transferred = 0; - int result = error_wrapper(::WSASendTo(s, const_cast(bufs), - send_buf_count, &bytes_transferred, flags, addr, - static_cast(addrlen), 0, 0), ec); - if (result != 0) - return -1; - clear_error(ec); - return bytes_transferred; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg = msghdr(); - init_msghdr_msg_name(msg.msg_name, addr); - msg.msg_namelen = addrlen; - msg.msg_iov = const_cast(bufs); - msg.msg_iovlen = count; -#if defined(__linux__) - flags |= MSG_NOSIGNAL; -#endif // defined(__linux__) - int result = error_wrapper(::sendmsg(s, &msg, flags), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} + boost::system::error_code& ec, size_t& bytes_transferred); -inline socket_type socket(int af, int type, int protocol, - boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0, - WSA_FLAG_OVERLAPPED), ec); - if (s == invalid_socket) - return s; +#endif // !defined(BOOST_ASIO_HAS_IOCP) - if (af == AF_INET6) - { - // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to - // false. This will only succeed on Windows Vista and later versions of - // Windows, where a dual-stack IPv4/v6 implementation is available. - DWORD optval = 0; - ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, - reinterpret_cast(&optval), sizeof(optval)); - } +BOOST_ASIO_DECL socket_type socket(int af, int type, int protocol, + boost::system::error_code& ec); - clear_error(ec); +BOOST_ASIO_DECL int setsockopt(socket_type s, state_type& state, + int level, int optname, const void* optval, + std::size_t optlen, boost::system::error_code& ec); - return s; -#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) - socket_type s = error_wrapper(::socket(af, type, protocol), ec); - if (s == invalid_socket) - return s; +BOOST_ASIO_DECL int getsockopt(socket_type s, state_type state, + int level, int optname, void* optval, + size_t* optlen, boost::system::error_code& ec); - int optval = 1; - int result = error_wrapper(::setsockopt(s, - SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); - if (result != 0) - { - ::close(s); - return invalid_socket; - } +BOOST_ASIO_DECL int getpeername(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, bool cached, boost::system::error_code& ec); - return s; -#else - int s = error_wrapper(::socket(af, type, protocol), ec); - if (s >= 0) - clear_error(ec); - return s; -#endif -} +BOOST_ASIO_DECL int getsockname(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec); -template -inline int call_setsockopt(SockLenType msghdr::*, - socket_type s, int level, int optname, - const void* optval, std::size_t optlen) -{ - return ::setsockopt(s, level, optname, - (const char*)optval, (SockLenType)optlen); -} +BOOST_ASIO_DECL int ioctl(socket_type s, state_type& state, + long cmd, ioctl_arg_type* arg, boost::system::error_code& ec); -inline int setsockopt(socket_type s, int level, int optname, - const void* optval, std::size_t optlen, boost::system::error_code& ec) -{ - if (level == custom_socket_option_level && optname == always_fail_option) - { - ec = boost::asio::error::invalid_argument; - return -1; - } +BOOST_ASIO_DECL int select(int nfds, fd_set* readfds, fd_set* writefds, + fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec); -#if defined(__BORLANDC__) - // Mysteriously, using the getsockopt and setsockopt functions directly with - // Borland C++ results in incorrect values being set and read. The bug can be - // worked around by using function addresses resolved with GetProcAddress. - if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) - { - typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int); - if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt")) - { - clear_error(ec); - return error_wrapper(sso(s, level, optname, - reinterpret_cast(optval), - static_cast(optlen)), ec); - } - } - ec = boost::asio::error::fault; - return -1; -#else // defined(__BORLANDC__) - clear_error(ec); - int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); - if (result == 0) - clear_error(ec); - return result; -#endif // defined(__BORLANDC__) -} +BOOST_ASIO_DECL int poll_read(socket_type s, boost::system::error_code& ec); -template -inline int call_getsockopt(SockLenType msghdr::*, - socket_type s, int level, int optname, - void* optval, std::size_t* optlen) -{ - SockLenType tmp_optlen = (SockLenType)*optlen; - int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen); - *optlen = (std::size_t)tmp_optlen; - return result; -} +BOOST_ASIO_DECL int poll_write(socket_type s, boost::system::error_code& ec); -inline int getsockopt(socket_type s, int level, int optname, void* optval, - size_t* optlen, boost::system::error_code& ec) -{ - if (level == custom_socket_option_level && optname == always_fail_option) - { - ec = boost::asio::error::invalid_argument; - return -1; - } +BOOST_ASIO_DECL int poll_connect(socket_type s, boost::system::error_code& ec); -#if defined(__BORLANDC__) - // Mysteriously, using the getsockopt and setsockopt functions directly with - // Borland C++ results in incorrect values being set and read. The bug can be - // worked around by using function addresses resolved with GetProcAddress. - if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) - { - typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*); - if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt")) - { - clear_error(ec); - int tmp_optlen = static_cast(*optlen); - int result = error_wrapper(gso(s, level, optname, - reinterpret_cast(optval), &tmp_optlen), ec); - *optlen = static_cast(tmp_optlen); - if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY - && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) - { - // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are - // only supported on Windows Vista and later. To simplify program logic - // we will fake success of getting this option and specify that the - // value is non-zero (i.e. true). This corresponds to the behavior of - // IPv6 sockets on Windows platforms pre-Vista. - *static_cast(optval) = 1; - clear_error(ec); - } - return result; - } - } - ec = boost::asio::error::fault; - return -1; -#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) - clear_error(ec); - int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); - if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY - && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) - { - // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only - // supported on Windows Vista and later. To simplify program logic we will - // fake success of getting this option and specify that the value is - // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets - // on Windows platforms pre-Vista. - *static_cast(optval) = 1; - clear_error(ec); - } - if (result == 0) - clear_error(ec); - return result; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - clear_error(ec); - int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, - s, level, optname, optval, optlen), ec); -#if defined(__linux__) - if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) - && (optname == SO_SNDBUF || optname == SO_RCVBUF)) - { - // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel - // to set the buffer size to N*2. Linux puts additional stuff into the - // buffers so that only about half is actually available to the application. - // The retrieved value is divided by 2 here to make it appear as though the - // correct value has been set. - *static_cast(optval) /= 2; - } -#endif // defined(__linux__) - if (result == 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +BOOST_ASIO_DECL const char* inet_ntop(int af, const void* src, char* dest, + size_t length, unsigned long scope_id, boost::system::error_code& ec); -template -inline int call_getpeername(SockLenType msghdr::*, - socket_type s, socket_addr_type* addr, std::size_t* addrlen) -{ - SockLenType tmp_addrlen = (SockLenType)*addrlen; - int result = ::getpeername(s, addr, &tmp_addrlen); - *addrlen = (std::size_t)tmp_addrlen; - return result; -} +BOOST_ASIO_DECL int inet_pton(int af, const char* src, void* dest, + unsigned long* scope_id, boost::system::error_code& ec); -inline int getpeername(socket_type s, socket_addr_type* addr, - std::size_t* addrlen, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(call_getpeername( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL int gethostname(char* name, + int namelen, boost::system::error_code& ec); -template -inline int call_getsockname(SockLenType msghdr::*, - socket_type s, socket_addr_type* addr, std::size_t* addrlen) -{ - SockLenType tmp_addrlen = (SockLenType)*addrlen; - int result = ::getsockname(s, addr, &tmp_addrlen); - *addrlen = (std::size_t)tmp_addrlen; - return result; -} +BOOST_ASIO_DECL boost::system::error_code getaddrinfo(const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, boost::system::error_code& ec); -inline int getsockname(socket_type s, socket_addr_type* addr, - std::size_t* addrlen, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(call_getsockname( - &msghdr::msg_namelen, s, addr, addrlen), ec); - if (result == 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL boost::system::error_code background_getaddrinfo( + const weak_cancel_token_type& cancel_token, const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, boost::system::error_code& ec); -inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg, - boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::ioctl(s, cmd, arg), ec); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - if (result >= 0) - clear_error(ec); - return result; -} +BOOST_ASIO_DECL void freeaddrinfo(addrinfo_type* ai); -inline int select(int nfds, fd_set* readfds, fd_set* writefds, - fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - if (!readfds && !writefds && !exceptfds && timeout) - { - DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; - if (milliseconds == 0) - milliseconds = 1; // Force context switch. - ::Sleep(milliseconds); - ec = boost::system::error_code(); - return 0; - } +BOOST_ASIO_DECL boost::system::error_code getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int flags, boost::system::error_code& ec); - // The select() call allows timeout values measured in microseconds, but the - // system clock (as wrapped by boost::posix_time::microsec_clock) typically - // has a resolution of 10 milliseconds. This can lead to a spinning select - // reactor, meaning increased CPU usage, when waiting for the earliest - // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight - // spin we'll use a minimum timeout of 1 millisecond. - if (timeout && timeout->tv_sec == 0 - && timeout->tv_usec > 0 && timeout->tv_usec < 1000) - timeout->tv_usec = 1000; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +BOOST_ASIO_DECL boost::system::error_code sync_getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, boost::system::error_code& ec); -#if defined(__hpux) && defined(__HP_aCC) - timespec ts; - ts.tv_sec = timeout ? timeout->tv_sec : 0; - ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0; - return error_wrapper(::pselect(nfds, readfds, - writefds, exceptfds, timeout ? &ts : 0, 0), ec); -#else - int result = error_wrapper(::select(nfds, readfds, - writefds, exceptfds, timeout), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif -} +BOOST_ASIO_DECL boost::system::error_code background_getnameinfo( + const weak_cancel_token_type& cancel_token, + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, boost::system::error_code& ec); -inline int poll_read(socket_type s, boost::system::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - FD_SET fds; - FD_ZERO(&fds); - FD_SET(s, &fds); - clear_error(ec); - int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec); - if (result >= 0) - clear_error(ec); - return result; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - pollfd fds; - fds.fd = s; - fds.events = POLLIN; - fds.revents = 0; - clear_error(ec); - int result = error_wrapper(::poll(&fds, 1, -1), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +BOOST_ASIO_DECL u_long_type network_to_host_long(u_long_type value); -inline int poll_write(socket_type s, boost::system::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - FD_SET fds; - FD_ZERO(&fds); - FD_SET(s, &fds); - clear_error(ec); - int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec); - if (result >= 0) - clear_error(ec); - return result; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - pollfd fds; - fds.fd = s; - fds.events = POLLOUT; - fds.revents = 0; - clear_error(ec); - int result = error_wrapper(::poll(&fds, 1, -1), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +BOOST_ASIO_DECL u_long_type host_to_network_long(u_long_type value); -inline int poll_connect(socket_type s, boost::system::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - FD_SET write_fds; - FD_ZERO(&write_fds); - FD_SET(s, &write_fds); - FD_SET except_fds; - FD_ZERO(&except_fds); - FD_SET(s, &except_fds); - clear_error(ec); - int result = error_wrapper(::select(s, 0, &write_fds, &except_fds, 0), ec); - if (result >= 0) - clear_error(ec); - return result; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - pollfd fds; - fds.fd = s; - fds.events = POLLOUT; - fds.revents = 0; - clear_error(ec); - int result = error_wrapper(::poll(&fds, 1, -1), ec); - if (result >= 0) - clear_error(ec); - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} +BOOST_ASIO_DECL u_short_type network_to_host_short(u_short_type value); -inline const char* inet_ntop(int af, const void* src, char* dest, size_t length, - unsigned long scope_id, boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - using namespace std; // For memcpy. - - if (af != AF_INET && af != AF_INET6) - { - ec = boost::asio::error::address_family_not_supported; - return 0; - } - - union - { - socket_addr_type base; - sockaddr_storage_type storage; - sockaddr_in4_type v4; - sockaddr_in6_type v6; - } address; - DWORD address_length; - if (af == AF_INET) - { - address_length = sizeof(sockaddr_in4_type); - address.v4.sin_family = AF_INET; - address.v4.sin_port = 0; - memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type)); - } - else // AF_INET6 - { - address_length = sizeof(sockaddr_in6_type); - address.v6.sin6_family = AF_INET6; - address.v6.sin6_port = 0; - address.v6.sin6_flowinfo = 0; - address.v6.sin6_scope_id = scope_id; - memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type)); - } - - DWORD string_length = static_cast(length); -#if defined(BOOST_NO_ANSI_APIS) - LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); - int result = error_wrapper(::WSAAddressToStringW(&address.base, - address_length, 0, string_buffer, &string_length), ec); - ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0); -#else - int result = error_wrapper(::WSAAddressToStringA( - &address.base, address_length, 0, dest, &string_length), ec); -#endif - - // Windows may set error code on success. - if (result != socket_error_retval) - clear_error(ec); - - // Windows may not set an error code on failure. - else if (result == socket_error_retval && !ec) - ec = boost::asio::error::invalid_argument; - - return result == socket_error_retval ? 0 : dest; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec); - if (result == 0 && !ec) - ec = boost::asio::error::invalid_argument; - if (result != 0 && af == AF_INET6 && scope_id != 0) - { - using namespace std; // For strcat and sprintf. - char if_name[IF_NAMESIZE + 1] = "%"; - const in6_addr_type* ipv6_address = static_cast(src); - bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); - if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0) - sprintf(if_name + 1, "%lu", scope_id); - strcat(dest, if_name); - } - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} - -inline int inet_pton(int af, const char* src, void* dest, - unsigned long* scope_id, boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - using namespace std; // For memcpy and strcmp. - - if (af != AF_INET && af != AF_INET6) - { - ec = boost::asio::error::address_family_not_supported; - return -1; - } - - union - { - socket_addr_type base; - sockaddr_storage_type storage; - sockaddr_in4_type v4; - sockaddr_in6_type v6; - } address; - int address_length = sizeof(sockaddr_storage_type); -#if defined(BOOST_NO_ANSI_APIS) - int num_wide_chars = strlen(src) + 1; - LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); - ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); - int result = error_wrapper(::WSAStringToAddressW( - wide_buffer, af, 0, &address.base, &address_length), ec); -#else - int result = error_wrapper(::WSAStringToAddressA( - const_cast(src), af, 0, &address.base, &address_length), ec); -#endif - - if (af == AF_INET) - { - if (result != socket_error_retval) - { - memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); - clear_error(ec); - } - else if (strcmp(src, "255.255.255.255") == 0) - { - static_cast(dest)->s_addr = INADDR_NONE; - clear_error(ec); - } - } - else // AF_INET6 - { - if (result != socket_error_retval) - { - memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); - if (scope_id) - *scope_id = address.v6.sin6_scope_id; - clear_error(ec); - } - } - - // Windows may not set an error code on failure. - if (result == socket_error_retval && !ec) - ec = boost::asio::error::invalid_argument; - - if (result != socket_error_retval) - clear_error(ec); - - return result == socket_error_retval ? -1 : 1; -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::inet_pton(af, src, dest), ec); - if (result <= 0 && !ec) - ec = boost::asio::error::invalid_argument; - if (result > 0 && af == AF_INET6 && scope_id) - { - using namespace std; // For strchr and atoi. - *scope_id = 0; - if (const char* if_name = strchr(src, '%')) - { - in6_addr_type* ipv6_address = static_cast(dest); - bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); - if (is_link_local) - *scope_id = if_nametoindex(if_name + 1); - if (*scope_id == 0) - *scope_id = atoi(if_name + 1); - } - } - return result; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} - -inline int gethostname(char* name, int namelen, boost::system::error_code& ec) -{ - clear_error(ec); - int result = error_wrapper(::gethostname(name, namelen), ec); -#if defined(BOOST_WINDOWS) - if (result == 0) - clear_error(ec); -#endif - return result; -} - -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \ - || defined(__MACH__) && defined(__APPLE__) - -// The following functions are only needed for emulation of getaddrinfo and -// getnameinfo. - -inline boost::system::error_code translate_netdb_error(int error) -{ - switch (error) - { - case 0: - return boost::system::error_code(); - case HOST_NOT_FOUND: - return boost::asio::error::host_not_found; - case TRY_AGAIN: - return boost::asio::error::host_not_found_try_again; - case NO_RECOVERY: - return boost::asio::error::no_recovery; - case NO_DATA: - return boost::asio::error::no_data; - default: - BOOST_ASSERT(false); - return boost::asio::error::invalid_argument; - } -} - -inline hostent* gethostbyaddr(const char* addr, int length, int af, - hostent* result, char* buffer, int buflength, boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - (void)(buffer); - (void)(buflength); - hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); - if (!retval) - return 0; - clear_error(ec); - *result = *retval; - return retval; -#elif defined(__sun) || defined(__QNX__) - int error = 0; - hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result, - buffer, buflength, &error), ec); - if (error) - ec = translate_netdb_error(error); - return retval; -#elif defined(__MACH__) && defined(__APPLE__) - (void)(buffer); - (void)(buflength); - int error = 0; - hostent* retval = error_wrapper(::getipnodebyaddr( - addr, length, af, &error), ec); - if (error) - ec = translate_netdb_error(error); - if (!retval) - return 0; - *result = *retval; - return retval; -#else - hostent* retval = 0; - int error = 0; - error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, - buflength, &retval, &error), ec); - if (error) - ec = translate_netdb_error(error); - return retval; -#endif -} - -inline hostent* gethostbyname(const char* name, int af, struct hostent* result, - char* buffer, int buflength, int ai_flags, boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - (void)(buffer); - (void)(buflength); - (void)(ai_flags); - if (af != AF_INET) - { - ec = boost::asio::error::address_family_not_supported; - return 0; - } - hostent* retval = error_wrapper(::gethostbyname(name), ec); - if (!retval) - return 0; - clear_error(ec); - *result = *retval; - return result; -#elif defined(__sun) || defined(__QNX__) - (void)(ai_flags); - if (af != AF_INET) - { - ec = boost::asio::error::address_family_not_supported; - return 0; - } - int error = 0; - hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer, - buflength, &error), ec); - if (error) - ec = translate_netdb_error(error); - return retval; -#elif defined(__MACH__) && defined(__APPLE__) - (void)(buffer); - (void)(buflength); - int error = 0; - hostent* retval = error_wrapper(::getipnodebyname( - name, af, ai_flags, &error), ec); - if (error) - ec = translate_netdb_error(error); - if (!retval) - return 0; - *result = *retval; - return retval; -#else - (void)(ai_flags); - if (af != AF_INET) - { - ec = boost::asio::error::address_family_not_supported; - return 0; - } - hostent* retval = 0; - int error = 0; - error_wrapper(::gethostbyname_r(name, result, - buffer, buflength, &retval, &error), ec); - if (error) - ec = translate_netdb_error(error); - return retval; -#endif -} - -inline void freehostent(hostent* h) -{ -#if defined(__MACH__) && defined(__APPLE__) - if (h) - ::freehostent(h); -#else - (void)(h); -#endif -} - -// Emulation of getaddrinfo based on implementation in: -// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998. - -struct gai_search -{ - const char* host; - int family; -}; - -inline int gai_nsearch(const char* host, - const addrinfo_type* hints, gai_search (&search)[2]) -{ - int search_count = 0; - if (host == 0 || host[0] == '\0') - { - if (hints->ai_flags & AI_PASSIVE) - { - // No host and AI_PASSIVE implies wildcard bind. - switch (hints->ai_family) - { - case AF_INET: - search[search_count].host = "0.0.0.0"; - search[search_count].family = AF_INET; - ++search_count; - break; - case AF_INET6: - search[search_count].host = "0::0"; - search[search_count].family = AF_INET6; - ++search_count; - break; - case AF_UNSPEC: - search[search_count].host = "0::0"; - search[search_count].family = AF_INET6; - ++search_count; - search[search_count].host = "0.0.0.0"; - search[search_count].family = AF_INET; - ++search_count; - break; - default: - break; - } - } - else - { - // No host and not AI_PASSIVE means connect to local host. - switch (hints->ai_family) - { - case AF_INET: - search[search_count].host = "localhost"; - search[search_count].family = AF_INET; - ++search_count; - break; - case AF_INET6: - search[search_count].host = "localhost"; - search[search_count].family = AF_INET6; - ++search_count; - break; - case AF_UNSPEC: - search[search_count].host = "localhost"; - search[search_count].family = AF_INET6; - ++search_count; - search[search_count].host = "localhost"; - search[search_count].family = AF_INET; - ++search_count; - break; - default: - break; - } - } - } - else - { - // Host is specified. - switch (hints->ai_family) - { - case AF_INET: - search[search_count].host = host; - search[search_count].family = AF_INET; - ++search_count; - break; - case AF_INET6: - search[search_count].host = host; - search[search_count].family = AF_INET6; - ++search_count; - break; - case AF_UNSPEC: - search[search_count].host = host; - search[search_count].family = AF_INET6; - ++search_count; - search[search_count].host = host; - search[search_count].family = AF_INET; - ++search_count; - break; - default: - break; - } - } - return search_count; -} - -template -inline T* gai_alloc(std::size_t size = sizeof(T)) -{ - using namespace std; - T* p = static_cast(::operator new(size, std::nothrow)); - if (p) - memset(p, 0, size); - return p; -} - -inline void gai_free(void* p) -{ - ::operator delete(p); -} - -inline void gai_strcpy(char* target, const char* source, std::size_t max_size) -{ - using namespace std; -#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) - strcpy_s(target, max_size, source); -#else - *target = 0; - strncat(target, source, max_size); -#endif -} - -enum { gai_clone_flag = 1 << 30 }; - -inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints, - const void* addr, int family) -{ - using namespace std; - - addrinfo_type* ai = gai_alloc(); - if (ai == 0) - return EAI_MEMORY; - - ai->ai_next = 0; - **next = ai; - *next = &ai->ai_next; - - ai->ai_canonname = 0; - ai->ai_socktype = hints->ai_socktype; - if (ai->ai_socktype == 0) - ai->ai_flags |= gai_clone_flag; - ai->ai_protocol = hints->ai_protocol; - ai->ai_family = family; - - switch (ai->ai_family) - { - case AF_INET: - { - sockaddr_in4_type* sinptr = gai_alloc(); - if (sinptr == 0) - return EAI_MEMORY; - sinptr->sin_family = AF_INET; - memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type)); - ai->ai_addr = reinterpret_cast(sinptr); - ai->ai_addrlen = sizeof(sockaddr_in4_type); - break; - } - case AF_INET6: - { - sockaddr_in6_type* sin6ptr = gai_alloc(); - if (sin6ptr == 0) - return EAI_MEMORY; - sin6ptr->sin6_family = AF_INET6; - memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type)); - ai->ai_addr = reinterpret_cast(sin6ptr); - ai->ai_addrlen = sizeof(sockaddr_in6_type); - break; - } - default: - break; - } - - return 0; -} - -inline addrinfo_type* gai_clone(addrinfo_type* ai) -{ - using namespace std; - - addrinfo_type* new_ai = gai_alloc(); - if (new_ai == 0) - return new_ai; - - new_ai->ai_next = ai->ai_next; - ai->ai_next = new_ai; - - new_ai->ai_flags = 0; - new_ai->ai_family = ai->ai_family; - new_ai->ai_socktype = ai->ai_socktype; - new_ai->ai_protocol = ai->ai_protocol; - new_ai->ai_canonname = 0; - new_ai->ai_addrlen = ai->ai_addrlen; - new_ai->ai_addr = gai_alloc(ai->ai_addrlen); - memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen); - - return new_ai; -} - -inline int gai_port(addrinfo_type* aihead, int port, int socktype) -{ - int num_found = 0; - - for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next) - { - if (ai->ai_flags & gai_clone_flag) - { - if (ai->ai_socktype != 0) - { - ai = gai_clone(ai); - if (ai == 0) - return -1; - // ai now points to newly cloned entry. - } - } - else if (ai->ai_socktype != socktype) - { - // Ignore if mismatch on socket type. - continue; - } - - ai->ai_socktype = socktype; - - switch (ai->ai_family) - { - case AF_INET: - { - sockaddr_in4_type* sinptr = - reinterpret_cast(ai->ai_addr); - sinptr->sin_port = port; - ++num_found; - break; - } - case AF_INET6: - { - sockaddr_in6_type* sin6ptr = - reinterpret_cast(ai->ai_addr); - sin6ptr->sin6_port = port; - ++num_found; - break; - } - default: - break; - } - } - - return num_found; -} - -inline int gai_serv(addrinfo_type* aihead, - const addrinfo_type* hints, const char* serv) -{ - using namespace std; - - int num_found = 0; - - if ( -#if defined(AI_NUMERICSERV) - (hints->ai_flags & AI_NUMERICSERV) || -#endif - isdigit(serv[0])) - { - int port = htons(atoi(serv)); - if (hints->ai_socktype) - { - // Caller specifies socket type. - int rc = gai_port(aihead, port, hints->ai_socktype); - if (rc < 0) - return EAI_MEMORY; - num_found += rc; - } - else - { - // Caller does not specify socket type. - int rc = gai_port(aihead, port, SOCK_STREAM); - if (rc < 0) - return EAI_MEMORY; - num_found += rc; - rc = gai_port(aihead, port, SOCK_DGRAM); - if (rc < 0) - return EAI_MEMORY; - num_found += rc; - } - } - else - { - // Try service name with TCP first, then UDP. - if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM) - { - servent* sptr = getservbyname(serv, "tcp"); - if (sptr != 0) - { - int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM); - if (rc < 0) - return EAI_MEMORY; - num_found += rc; - } - } - if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM) - { - servent* sptr = getservbyname(serv, "udp"); - if (sptr != 0) - { - int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM); - if (rc < 0) - return EAI_MEMORY; - num_found += rc; - } - } - } - - if (num_found == 0) - { - if (hints->ai_socktype == 0) - { - // All calls to getservbyname() failed. - return EAI_NONAME; - } - else - { - // Service not supported for socket type. - return EAI_SERVICE; - } - } - - return 0; -} - -inline int gai_echeck(const char* host, const char* service, - int flags, int family, int socktype, int protocol) -{ - (void)(flags); - (void)(protocol); - - // Host or service must be specified. - if (host == 0 || host[0] == '\0') - if (service == 0 || service[0] == '\0') - return EAI_NONAME; - - // Check combination of family and socket type. - switch (family) - { - case AF_UNSPEC: - break; - case AF_INET: - case AF_INET6: - if (service != 0 && service[0] != '\0') - if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM) - return EAI_SOCKTYPE; - break; - default: - return EAI_FAMILY; - } - - return 0; -} - -inline void freeaddrinfo_emulation(addrinfo_type* aihead) -{ - addrinfo_type* ai = aihead; - while (ai) - { - gai_free(ai->ai_addr); - gai_free(ai->ai_canonname); - addrinfo_type* ainext = ai->ai_next; - gai_free(ai); - ai = ainext; - } -} - -inline int getaddrinfo_emulation(const char* host, const char* service, - const addrinfo_type* hintsp, addrinfo_type** result) -{ - // Set up linked list of addrinfo structures. - addrinfo_type* aihead = 0; - addrinfo_type** ainext = &aihead; - char* canon = 0; - - // Supply default hints if not specified by caller. - addrinfo_type hints = addrinfo_type(); - hints.ai_family = AF_UNSPEC; - if (hintsp) - hints = *hintsp; - - // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED - // and AI_ALL flags. -#if defined(AI_V4MAPPED) - if (hints.ai_family != AF_INET6) - hints.ai_flags &= ~AI_V4MAPPED; -#endif -#if defined(AI_ALL) - if (hints.ai_family != AF_INET6) - hints.ai_flags &= ~AI_ALL; -#endif - - // Basic error checking. - int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family, - hints.ai_socktype, hints.ai_protocol); - if (rc != 0) - { - freeaddrinfo_emulation(aihead); - return rc; - } - - gai_search search[2]; - int search_count = gai_nsearch(host, &hints, search); - for (gai_search* sptr = search; sptr < search + search_count; ++sptr) - { - // Check for IPv4 dotted decimal string. - in4_addr_type inaddr; - boost::system::error_code ec; - if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1) - { - if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - return EAI_FAMILY; - } - if (sptr->family == AF_INET) - { - rc = gai_aistruct(&ainext, &hints, &inaddr, AF_INET); - if (rc != 0) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - return rc; - } - } - continue; - } - - // Check for IPv6 hex string. - in6_addr_type in6addr; - if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr, 0, ec) == 1) - { - if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - return EAI_FAMILY; - } - if (sptr->family == AF_INET6) - { - rc = gai_aistruct(&ainext, &hints, &in6addr, AF_INET6); - if (rc != 0) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - return rc; - } - } - continue; - } - - // Look up hostname. - hostent hent; - char hbuf[8192] = ""; - hostent* hptr = socket_ops::gethostbyname(sptr->host, - sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec); - if (hptr == 0) - { - if (search_count == 2) - { - // Failure is OK if there are multiple searches. - continue; - } - freeaddrinfo_emulation(aihead); - gai_free(canon); - if (ec == boost::asio::error::host_not_found) - return EAI_NONAME; - if (ec == boost::asio::error::host_not_found_try_again) - return EAI_AGAIN; - if (ec == boost::asio::error::no_recovery) - return EAI_FAIL; - if (ec == boost::asio::error::no_data) - return EAI_NONAME; - return EAI_NONAME; - } - - // Check for address family mismatch if one was specified. - if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - socket_ops::freehostent(hptr); - return EAI_FAMILY; - } - - // Save canonical name first time. - if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0] - && (hints.ai_flags & AI_CANONNAME) && canon == 0) - { - std::size_t canon_len = strlen(hptr->h_name) + 1; - canon = gai_alloc(canon_len); - if (canon == 0) - { - freeaddrinfo_emulation(aihead); - socket_ops::freehostent(hptr); - return EAI_MEMORY; - } - gai_strcpy(canon, hptr->h_name, canon_len); - } - - // Create an addrinfo structure for each returned address. - for (char** ap = hptr->h_addr_list; *ap; ++ap) - { - rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype); - if (rc != 0) - { - freeaddrinfo_emulation(aihead); - gai_free(canon); - socket_ops::freehostent(hptr); - return EAI_FAMILY; - } - } - - socket_ops::freehostent(hptr); - } - - // Check if we found anything. - if (aihead == 0) - { - gai_free(canon); - return EAI_NONAME; - } - - // Return canonical name in first entry. - if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME)) - { - if (canon) - { - aihead->ai_canonname = canon; - canon = 0; - } - else - { - std::size_t canonname_len = strlen(search[0].host) + 1; - aihead->ai_canonname = gai_alloc(canonname_len); - if (aihead->ai_canonname == 0) - { - freeaddrinfo_emulation(aihead); - return EAI_MEMORY; - } - gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len); - } - } - gai_free(canon); - - // Process the service name. - if (service != 0 && service[0] != '\0') - { - rc = gai_serv(aihead, &hints, service); - if (rc != 0) - { - freeaddrinfo_emulation(aihead); - return rc; - } - } - - // Return result to caller. - *result = aihead; - return 0; -} - -inline boost::system::error_code getnameinfo_emulation( - const socket_addr_type* sa, std::size_t salen, char* host, - std::size_t hostlen, char* serv, std::size_t servlen, int flags, - boost::system::error_code& ec) -{ - using namespace std; - - const char* addr; - size_t addr_len; - unsigned short port; - switch (sa->sa_family) - { - case AF_INET: - if (salen != sizeof(sockaddr_in4_type)) - { - return ec = boost::asio::error::invalid_argument; - } - addr = reinterpret_cast( - &reinterpret_cast(sa)->sin_addr); - addr_len = sizeof(in4_addr_type); - port = reinterpret_cast(sa)->sin_port; - break; - case AF_INET6: - if (salen != sizeof(sockaddr_in6_type)) - { - return ec = boost::asio::error::invalid_argument; - } - addr = reinterpret_cast( - &reinterpret_cast(sa)->sin6_addr); - addr_len = sizeof(in6_addr_type); - port = reinterpret_cast(sa)->sin6_port; - break; - default: - return ec = boost::asio::error::address_family_not_supported; - } - - if (host && hostlen > 0) - { - if (flags & NI_NUMERICHOST) - { - if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0) - { - return ec; - } - } - else - { - hostent hent; - char hbuf[8192] = ""; - hostent* hptr = socket_ops::gethostbyaddr(addr, - static_cast(addr_len), sa->sa_family, - &hent, hbuf, sizeof(hbuf), ec); - if (hptr && hptr->h_name && hptr->h_name[0] != '\0') - { - if (flags & NI_NOFQDN) - { - char* dot = strchr(hptr->h_name, '.'); - if (dot) - { - *dot = 0; - } - } - gai_strcpy(host, hptr->h_name, hostlen); - socket_ops::freehostent(hptr); - } - else - { - socket_ops::freehostent(hptr); - if (flags & NI_NAMEREQD) - { - return ec = boost::asio::error::host_not_found; - } - if (socket_ops::inet_ntop(sa->sa_family, - addr, host, hostlen, 0, ec) == 0) - { - return ec; - } - } - } - } - - if (serv && servlen > 0) - { - if (flags & NI_NUMERICSERV) - { - if (servlen < 6) - { - return ec = boost::asio::error::no_buffer_space; - } -#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) - sprintf_s(serv, servlen, "%u", ntohs(port)); -#else - sprintf(serv, "%u", ntohs(port)); -#endif - } - else - { -#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) - static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - ::pthread_mutex_lock(&mutex); -#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) - servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0); - if (sptr && sptr->s_name && sptr->s_name[0] != '\0') - { - gai_strcpy(serv, sptr->s_name, servlen); - } - else - { - if (servlen < 6) - { - return ec = boost::asio::error::no_buffer_space; - } -#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) - sprintf_s(serv, servlen, "%u", ntohs(port)); -#else - sprintf(serv, "%u", ntohs(port)); -#endif - } -#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) - ::pthread_mutex_unlock(&mutex); -#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) - } - } - - clear_error(ec); - return ec; -} - -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - // || defined(__MACH__) && defined(__APPLE__) - -inline boost::system::error_code translate_addrinfo_error(int error) -{ - switch (error) - { - case 0: - return boost::system::error_code(); - case EAI_AGAIN: - return boost::asio::error::host_not_found_try_again; - case EAI_BADFLAGS: - return boost::asio::error::invalid_argument; - case EAI_FAIL: - return boost::asio::error::no_recovery; - case EAI_FAMILY: - return boost::asio::error::address_family_not_supported; - case EAI_MEMORY: - return boost::asio::error::no_memory; - case EAI_NONAME: -#if defined(EAI_ADDRFAMILY) - case EAI_ADDRFAMILY: -#endif -#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) - case EAI_NODATA: -#endif - return boost::asio::error::host_not_found; - case EAI_SERVICE: - return boost::asio::error::service_not_found; - case EAI_SOCKTYPE: - return boost::asio::error::socket_type_not_supported; - default: // Possibly the non-portable EAI_SYSTEM. -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - return boost::system::error_code( - WSAGetLastError(), boost::asio::error::get_system_category()); -#else - return boost::system::error_code( - errno, boost::asio::error::get_system_category()); -#endif - } -} - -inline boost::system::error_code getaddrinfo(const char* host, - const char* service, const addrinfo_type* hints, addrinfo_type** result, - boost::system::error_code& ec) -{ - clear_error(ec); -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) - // Building for Windows XP, Windows Server 2003, or later. - int error = ::getaddrinfo(host, service, hints, result); - return ec = translate_addrinfo_error(error); -# else - // Building for Windows 2000 or earlier. - typedef int (WSAAPI *gai_t)(const char*, - const char*, const addrinfo_type*, addrinfo_type**); - if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) - { - if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo")) - { - int error = gai(host, service, hints, result); - return ec = translate_addrinfo_error(error); - } - } - int error = getaddrinfo_emulation(host, service, hints, result); - return ec = translate_addrinfo_error(error); -# endif -#elif defined(__MACH__) && defined(__APPLE__) - int error = getaddrinfo_emulation(host, service, hints, result); - return ec = translate_addrinfo_error(error); -#else - int error = ::getaddrinfo(host, service, hints, result); - return ec = translate_addrinfo_error(error); -#endif -} - -inline void freeaddrinfo(addrinfo_type* ai) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) - // Building for Windows XP, Windows Server 2003, or later. - ::freeaddrinfo(ai); -# else - // Building for Windows 2000 or earlier. - typedef int (WSAAPI *fai_t)(addrinfo_type*); - if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) - { - if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo")) - { - fai(ai); - return; - } - } - freeaddrinfo_emulation(ai); -# endif -#elif defined(__MACH__) && defined(__APPLE__) - freeaddrinfo_emulation(ai); -#else - ::freeaddrinfo(ai); -#endif -} - -inline boost::system::error_code getnameinfo(const socket_addr_type* addr, - std::size_t addrlen, char* host, std::size_t hostlen, - char* serv, std::size_t servlen, int flags, boost::system::error_code& ec) -{ -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) - // Building for Windows XP, Windows Server 2003, or later. - clear_error(ec); - int error = ::getnameinfo(addr, static_cast(addrlen), - host, static_cast(hostlen), - serv, static_cast(servlen), flags); - return ec = translate_addrinfo_error(error); -# else - // Building for Windows 2000 or earlier. - typedef int (WSAAPI *gni_t)(const socket_addr_type*, - int, char*, DWORD, char*, DWORD, int); - if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) - { - if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo")) - { - clear_error(ec); - int error = gni(addr, static_cast(addrlen), - host, static_cast(hostlen), - serv, static_cast(servlen), flags); - return ec = translate_addrinfo_error(error); - } - } - clear_error(ec); - return getnameinfo_emulation(addr, addrlen, - host, hostlen, serv, servlen, flags, ec); -# endif -#elif defined(__MACH__) && defined(__APPLE__) - using namespace std; // For memcpy. - sockaddr_storage_type tmp_addr; - memcpy(&tmp_addr, addr, addrlen); - tmp_addr.ss_len = addrlen; - addr = reinterpret_cast(&tmp_addr); - clear_error(ec); - return getnameinfo_emulation(addr, addrlen, - host, hostlen, serv, servlen, flags, ec); -#else - clear_error(ec); - int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); - return ec = translate_addrinfo_error(error); -#endif -} - -inline u_long_type network_to_host_long(u_long_type value) -{ - return ntohl(value); -} - -inline u_long_type host_to_network_long(u_long_type value) -{ - return htonl(value); -} - -inline u_short_type network_to_host_short(u_short_type value) -{ - return ntohs(value); -} - -inline u_short_type host_to_network_short(u_short_type value) -{ - return htons(value); -} +BOOST_ASIO_DECL u_short_type host_to_network_short(u_short_type value); } // namespace socket_ops } // namespace detail @@ -1911,4 +284,8 @@ inline u_short_type host_to_network_short(u_short_type value) #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_DETAIL_SOCKET_OPS_HPP diff --git a/include/boost/asio/detail/socket_option.hpp b/include/boost/asio/detail/socket_option.hpp index e31aae40..37efa834 100644 --- a/include/boost/asio/detail/socket_option.hpp +++ b/include/boost/asio/detail/socket_option.hpp @@ -1,6 +1,6 @@ // -// socket_option.hpp -// ~~~~~~~~~~~~~~~~~ +// detail/socket_option.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include #include -#include - #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/socket_select_interrupter.hpp b/include/boost/asio/detail/socket_select_interrupter.hpp index a538ae55..191174d9 100644 --- a/include/boost/asio/detail/socket_select_interrupter.hpp +++ b/include/boost/asio/detail/socket_select_interrupter.hpp @@ -1,6 +1,6 @@ // -// socket_select_interrupter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/socket_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,19 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include -#include +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -#include -#include -#include #include +#include + namespace boost { namespace asio { namespace detail { @@ -36,135 +31,16 @@ class socket_select_interrupter { public: // Constructor. - socket_select_interrupter() - { - boost::system::error_code ec; - socket_holder acceptor(socket_ops::socket( - AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); - if (acceptor.get() == invalid_socket) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - int opt = 1; - socket_ops::setsockopt(acceptor.get(), - SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec); - - using namespace std; // For memset. - sockaddr_in4_type addr; - std::size_t addr_len = sizeof(addr); - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = inet_addr("127.0.0.1"); - addr.sin_port = 0; - if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr, - addr_len, ec) == socket_error_retval) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr, - &addr_len, ec) == socket_error_retval) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - // Some broken firewalls on Windows will intermittently cause getsockname to - // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We - // explicitly specify the target address here to work around this problem. - addr.sin_addr.s_addr = inet_addr("127.0.0.1"); - - if (socket_ops::listen(acceptor.get(), - SOMAXCONN, ec) == socket_error_retval) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - socket_holder client(socket_ops::socket( - AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); - if (client.get() == invalid_socket) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr, - addr_len, ec) == socket_error_retval) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec)); - if (server.get() == invalid_socket) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(client.get(), FIONBIO, &non_blocking, ec)) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - opt = 1; - socket_ops::setsockopt(client.get(), - IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); - - non_blocking = 1; - if (socket_ops::ioctl(server.get(), FIONBIO, &non_blocking, ec)) - { - boost::system::system_error e(ec, "socket_select_interrupter"); - boost::throw_exception(e); - } - - opt = 1; - socket_ops::setsockopt(server.get(), - IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); - - read_descriptor_ = server.release(); - write_descriptor_ = client.release(); - } + BOOST_ASIO_DECL socket_select_interrupter(); // Destructor. - ~socket_select_interrupter() - { - boost::system::error_code ec; - if (read_descriptor_ != invalid_socket) - socket_ops::close(read_descriptor_, ec); - if (write_descriptor_ != invalid_socket) - socket_ops::close(write_descriptor_, ec); - } + BOOST_ASIO_DECL ~socket_select_interrupter(); // Interrupt the select call. - void interrupt() - { - char byte = 0; - socket_ops::buf b; - socket_ops::init_buf(b, &byte, 1); - boost::system::error_code ec; - socket_ops::send(write_descriptor_, &b, 1, 0, ec); - } + BOOST_ASIO_DECL void interrupt(); // Reset the select interrupt. Returns true if the call was interrupted. - bool reset() - { - char data[1024]; - socket_ops::buf b; - socket_ops::init_buf(b, data, sizeof(data)); - boost::system::error_code ec; - int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); - bool was_interrupted = (bytes_read > 0); - while (bytes_read == sizeof(data)) - bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); - return was_interrupted; - } + BOOST_ASIO_DECL bool reset(); // Get the read descriptor to be passed to select. socket_type read_descriptor() const @@ -191,4 +67,10 @@ private: #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP diff --git a/include/boost/asio/detail/socket_types.hpp b/include/boost/asio/detail/socket_types.hpp index 10091649..dcaf625d 100644 --- a/include/boost/asio/detail/socket_types.hpp +++ b/include/boost/asio/detail/socket_types.hpp @@ -1,6 +1,6 @@ // -// socket_types.hpp -// ~~~~~~~~~~~~~~~~ +// detail/socket_types.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,69 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include - -#include #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) # error WinSock.h has already been included # endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) -# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) -# if defined(_MSC_VER) || defined(__BORLANDC__) -# pragma message( \ - "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ - "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\ - "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\ - "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).") -# else // defined(_MSC_VER) || defined(__BORLANDC__) -# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. -# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line. -# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target). -# endif // defined(_MSC_VER) || defined(__BORLANDC__) -# define _WIN32_WINNT 0x0501 -# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) -# if defined(_MSC_VER) -# if defined(_WIN32) && !defined(WIN32) -# if !defined(_WINSOCK2API_) -# define WIN32 // Needed for correct types in winsock2.h -# else // !defined(_WINSOCK2API_) -# error Please define the macro WIN32 in your compiler options -# endif // !defined(_WINSOCK2API_) -# endif // defined(_WIN32) && !defined(WIN32) -# endif // defined(_MSC_VER) # if defined(__BORLANDC__) # include // Needed for __errno -# if defined(__WIN32__) && !defined(WIN32) -# if !defined(_WINSOCK2API_) -# define WIN32 // Needed for correct types in winsock2.h -# else // !defined(_WINSOCK2API_) -# error Please define the macro WIN32 in your compiler options -# endif // !defined(_WINSOCK2API_) -# endif // defined(__WIN32__) && !defined(WIN32) # if !defined(_WSPIAPI_H_) # define _WSPIAPI_H_ # define BOOST_ASIO_WSPIAPI_H_DEFINED # endif // !defined(_WSPIAPI_H_) # endif // defined(__BORLANDC__) -# if !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) -# if !defined(WIN32_LEAN_AND_MEAN) -# define WIN32_LEAN_AND_MEAN -# endif // !defined(WIN32_LEAN_AND_MEAN) -# endif // !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) -# if !defined(BOOST_ASIO_NO_NOMINMAX) -# if !defined(NOMINMAX) -# define NOMINMAX 1 -# endif // !defined(NOMINMAX) -# endif // !defined(BOOST_ASIO_NO_NOMINMAX) -# if defined(__CYGWIN__) -# if !defined(__USE_W32_SOCKETS) -# error You must add -D__USE_W32_SOCKETS to your compiler options. -# endif // !defined(__USE_W32_SOCKETS) -# endif // defined(__CYGWIN__) # include # include # include @@ -98,6 +48,8 @@ # include # include # include +# include +# include # if defined(__hpux) && !defined(__HP_aCC) # include # else @@ -117,7 +69,8 @@ # include # endif #endif -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/detail/solaris_fenced_block.hpp b/include/boost/asio/detail/solaris_fenced_block.hpp index be9803e7..db6cb980 100644 --- a/include/boost/asio/detail/solaris_fenced_block.hpp +++ b/include/boost/asio/detail/solaris_fenced_block.hpp @@ -1,6 +1,6 @@ // -// solaris_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/solaris_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(__sun) -#include #include -#include + +#include namespace boost { namespace asio { @@ -52,8 +48,8 @@ public: } // namespace asio } // namespace boost -#endif // defined(__sun) - #include +#endif // defined(__sun) + #endif // BOOST_ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/strand_service.hpp b/include/boost/asio/detail/strand_service.hpp index d6b45b1a..24bec7c9 100644 --- a/include/boost/asio/detail/strand_service.hpp +++ b/include/boost/asio/detail/strand_service.hpp @@ -1,6 +1,6 @@ // -// strand_service.hpp -// ~~~~~~~~~~~~~~~~~~ +// detail/strand_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,23 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include -#include - #include -#include -#include -#include -#include -#include #include #include #include -#include + +#include namespace boost { namespace asio { @@ -42,7 +33,10 @@ class strand_service : public boost::asio::detail::service_base { private: + // Helper class to re-post the strand on exit. struct on_do_complete_exit; + + // Helper class to re-post the strand on exit. struct on_dispatch_exit; public: @@ -52,11 +46,7 @@ public: : public operation { public: - strand_impl() - : operation(&strand_service::do_complete), - count_(0) - { - } + strand_impl(); private: // Only this service will have access to the internal values. @@ -77,180 +67,29 @@ public: typedef strand_impl* implementation_type; // Construct a new strand service for the specified io_service. - explicit strand_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base(io_service), - io_service_(boost::asio::use_service(io_service)), - mutex_(), - salt_(0) - { - } + BOOST_ASIO_DECL explicit strand_service(boost::asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - op_queue ops; - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - for (std::size_t i = 0; i < num_implementations; ++i) - if (strand_impl* impl = implementations_[i].get()) - ops.push(impl->queue_); - } + BOOST_ASIO_DECL void shutdown_service(); // Construct a new strand implementation. - void construct(implementation_type& impl) - { - std::size_t index = boost::hash_value(&impl); - boost::hash_combine(index, salt_++); - index = index % num_implementations; - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - if (!implementations_[index]) - implementations_[index].reset(new strand_impl); - impl = implementations_[index].get(); - } + BOOST_ASIO_DECL void construct(implementation_type& impl); // Destroy a strand implementation. - void destroy(implementation_type& impl) - { - impl = 0; - } + void destroy(implementation_type& impl); // Request the io_service to invoke the given handler. template - void dispatch(implementation_type& impl, Handler handler) - { - // If we are already in the strand then the handler can run immediately. - if (call_stack::contains(impl)) - { - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - return; - } - - // Allocate and construct an object to wrap the handler. - typedef completion_handler value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); - - // If we are running inside the io_service, and no other handler is queued - // or running, then the handler can run immediately. - bool can_dispatch = call_stack::contains(&io_service_); - impl->mutex_.lock(); - bool first = (++impl->count_ == 1); - if (can_dispatch && first) - { - // Immediate invocation is allowed. - impl->mutex_.unlock(); - - // Memory must be releaesed before any upcall is made. - ptr.reset(); - - // Indicate that this strand is executing on the current thread. - call_stack::context ctx(impl); - - // Ensure the next handler, if any, is scheduled on block exit. - on_dispatch_exit on_exit = { &io_service_, impl }; - (void)on_exit; - - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - return; - } - - // Immediate invocation is not allowed, so enqueue for later. - impl->queue_.push(ptr.get()); - impl->mutex_.unlock(); - ptr.release(); - - // The first handler to be enqueued is responsible for scheduling the - // strand. - if (first) - io_service_.post_immediate_completion(impl); - } + void dispatch(implementation_type& impl, Handler handler); // Request the io_service to invoke the given handler and return immediately. template - void post(implementation_type& impl, Handler handler) - { - // Allocate and construct an object to wrap the handler. - typedef completion_handler value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); - - // Add the handler to the queue. - impl->mutex_.lock(); - bool first = (++impl->count_ == 1); - impl->queue_.push(ptr.get()); - impl->mutex_.unlock(); - ptr.release(); - - // The first handler to be enqueue is responsible for scheduling the strand. - if (first) - io_service_.post_immediate_completion(impl); - } + void post(implementation_type& impl, Handler handler); private: - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - if (owner) - { - strand_impl* impl = static_cast(base); - - // Get the next handler to be executed. - impl->mutex_.lock(); - operation* o = impl->queue_.front(); - impl->queue_.pop(); - impl->mutex_.unlock(); - - // Indicate that this strand is executing on the current thread. - call_stack::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; - - o->complete(*owner); - } - } - - // Helper class to re-post the strand on exit. - struct on_do_complete_exit - { - io_service_impl* owner_; - strand_impl* impl_; - - ~on_do_complete_exit() - { - impl_->mutex_.lock(); - bool more_handlers = (--impl_->count_ > 0); - impl_->mutex_.unlock(); - - if (more_handlers) - owner_->post_immediate_completion(impl_); - } - }; - - // Helper class to re-post the strand on exit. - struct on_dispatch_exit - { - io_service_impl* io_service_; - strand_impl* impl_; - - ~on_dispatch_exit() - { - impl_->mutex_.lock(); - bool more_handlers = (--impl_->count_ > 0); - impl_->mutex_.unlock(); - - if (more_handlers) - io_service_->post_immediate_completion(impl_); - } - }; + BOOST_ASIO_DECL static void do_complete(io_service_impl* owner, + operation* base, boost::system::error_code ec, + std::size_t bytes_transferred); // The io_service implementation used to post completions. io_service_impl& io_service_; @@ -275,4 +114,9 @@ private: #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP diff --git a/include/boost/asio/detail/task_io_service.hpp b/include/boost/asio/detail/task_io_service.hpp index f6de3706..a9a7053b 100644 --- a/include/boost/asio/detail/task_io_service.hpp +++ b/include/boost/asio/detail/task_io_service.hpp @@ -1,6 +1,6 @@ // -// task_io_service.hpp -// ~~~~~~~~~~~~~~~~~~~ +// detail/task_io_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,181 +15,60 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#if !defined(BOOST_ASIO_HAS_IOCP) + +#include +#include #include -#include -#include -#include -#include -#include -#include #include #include -#include +#include #include #include #include -#include -#include -#include namespace boost { namespace asio { namespace detail { -template class task_io_service - : public boost::asio::detail::service_base > + : public boost::asio::detail::service_base { public: - typedef task_io_service_operation operation; + typedef task_io_service_operation operation; // Constructor. - task_io_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base >(io_service), - mutex_(), - task_(0), - task_interrupted_(true), - outstanding_work_(0), - stopped_(false), - shutdown_(false), - first_idle_thread_(0) - { - } + BOOST_ASIO_DECL task_io_service(boost::asio::io_service& io_service); - void init(size_t /*concurrency_hint*/) - { - } + // How many concurrent threads are likely to run the io_service. + BOOST_ASIO_DECL void init(std::size_t concurrency_hint); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - shutdown_ = true; - lock.unlock(); - - // Destroy handler objects. - while (!op_queue_.empty()) - { - operation* o = op_queue_.front(); - op_queue_.pop(); - if (o != &task_operation_) - o->destroy(); - } - - // Reset to initial state. - task_ = 0; - } + BOOST_ASIO_DECL void shutdown_service(); // Initialise the task, if required. - void init_task() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (!shutdown_ && !task_) - { - task_ = &use_service(this->get_io_service()); - op_queue_.push(&task_operation_); - wake_one_thread_and_unlock(lock); - } - } + BOOST_ASIO_DECL void init_task(); // Run the event loop until interrupted or no more work. - size_t run(boost::system::error_code& ec) - { - ec = boost::system::error_code(); - if (outstanding_work_ == 0) - { - stop(); - return 0; - } - - typename call_stack::context ctx(this); - - idle_thread_info this_idle_thread; - this_idle_thread.next = 0; - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - size_t n = 0; - for (; do_one(lock, &this_idle_thread); lock.lock()) - if (n != (std::numeric_limits::max)()) - ++n; - return n; - } + BOOST_ASIO_DECL std::size_t run(boost::system::error_code& ec); // Run until interrupted or one operation is performed. - size_t run_one(boost::system::error_code& ec) - { - ec = boost::system::error_code(); - if (outstanding_work_ == 0) - { - stop(); - return 0; - } - - typename call_stack::context ctx(this); - - idle_thread_info this_idle_thread; - this_idle_thread.next = 0; - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - return do_one(lock, &this_idle_thread); - } + BOOST_ASIO_DECL std::size_t run_one(boost::system::error_code& ec); // Poll for operations without blocking. - size_t poll(boost::system::error_code& ec) - { - if (outstanding_work_ == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - typename call_stack::context ctx(this); - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - size_t n = 0; - for (; do_one(lock, 0); lock.lock()) - if (n != (std::numeric_limits::max)()) - ++n; - return n; - } + BOOST_ASIO_DECL std::size_t poll(boost::system::error_code& ec); // Poll for one operation without blocking. - size_t poll_one(boost::system::error_code& ec) - { - ec = boost::system::error_code(); - if (outstanding_work_ == 0) - { - stop(); - return 0; - } - - typename call_stack::context ctx(this); - - boost::asio::detail::mutex::scoped_lock lock(mutex_); - - return do_one(lock, 0); - } + BOOST_ASIO_DECL std::size_t poll_one(boost::system::error_code& ec); // Interrupt the event processing loop. - void stop() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - stop_all_threads(lock); - } + BOOST_ASIO_DECL void stop(); // Reset in preparation for a subsequent run invocation. - void reset() - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - stopped_ = false; - } + BOOST_ASIO_DECL void reset(); // Notify that some work has started. void work_started() @@ -206,228 +85,60 @@ public: // Request invocation of the given handler. template - void dispatch(Handler handler) - { - if (call_stack::contains(this)) - { - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - else - post(handler); - } + void dispatch(Handler handler); // Request invocation of the given handler and return immediately. template - void post(Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef completion_handler value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); - - post_immediate_completion(ptr.get()); - ptr.release(); - } + 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(operation* op) - { - work_started(); - post_deferred_completion(op); - } + BOOST_ASIO_DECL void post_immediate_completion(operation* op); // Request invocation of the given operation and return immediately. Assumes // that work_started() was previously called for the operation. - void post_deferred_completion(operation* op) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - op_queue_.push(op); - wake_one_thread_and_unlock(lock); - } + BOOST_ASIO_DECL void post_deferred_completion(operation* op); // Request invocation of the given operations and return immediately. Assumes // that work_started() was previously called for each operation. - void post_deferred_completions(op_queue& ops) - { - if (!ops.empty()) - { - boost::asio::detail::mutex::scoped_lock lock(mutex_); - op_queue_.push(ops); - wake_one_thread_and_unlock(lock); - } - } + BOOST_ASIO_DECL void post_deferred_completions(op_queue& ops); private: + // Structure containing information about an idle thread. struct idle_thread_info; - size_t do_one(boost::asio::detail::mutex::scoped_lock& lock, - idle_thread_info* this_idle_thread) - { - bool polling = !this_idle_thread; - bool task_has_run = false; - while (!stopped_) - { - if (!op_queue_.empty()) - { - // Prepare to execute first handler from queue. - operation* o = op_queue_.front(); - op_queue_.pop(); - bool more_handlers = (!op_queue_.empty()); - - if (o == &task_operation_) - { - task_interrupted_ = more_handlers || polling; - - // If the task has already run and we're polling then we're done. - if (task_has_run && polling) - { - task_interrupted_ = true; - op_queue_.push(&task_operation_); - return 0; - } - task_has_run = true; - - if (!more_handlers || !wake_one_idle_thread_and_unlock(lock)) - lock.unlock(); - - op_queue completed_ops; - task_cleanup c = { this, &lock, &completed_ops }; - (void)c; - - // 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 && !polling, completed_ops); - } - else - { - if (more_handlers) - wake_one_thread_and_unlock(lock); - else - lock.unlock(); - - // Ensure the count of outstanding work is decremented on block exit. - work_finished_on_block_exit on_exit = { this }; - (void)on_exit; - - // Complete the operation. May throw an exception. - o->complete(*this); // deletes the operation object - - return 1; - } - } - else if (this_idle_thread) - { - // Nothing to run right now, so just wait for work to do. - this_idle_thread->next = first_idle_thread_; - first_idle_thread_ = this_idle_thread; - this_idle_thread->wakeup_event.clear(lock); - this_idle_thread->wakeup_event.wait(lock); - } - else - { - return 0; - } - } - - return 0; - } + // Run at most one operation. Blocks only if this_idle_thread is non-null. + BOOST_ASIO_DECL std::size_t do_one(mutex::scoped_lock& lock, + idle_thread_info* this_idle_thread); // Stop the task and all idle threads. - void stop_all_threads( - boost::asio::detail::mutex::scoped_lock& lock) - { - stopped_ = true; - - while (first_idle_thread_) - { - idle_thread_info* idle_thread = first_idle_thread_; - first_idle_thread_ = idle_thread->next; - idle_thread->next = 0; - idle_thread->wakeup_event.signal(lock); - } - - if (!task_interrupted_ && task_) - { - task_interrupted_ = true; - task_->interrupt(); - } - } + BOOST_ASIO_DECL void stop_all_threads(mutex::scoped_lock& lock); // Wakes a single idle thread and unlocks the mutex. Returns true if an idle // thread was found. If there is no idle thread, returns false and leaves the // mutex locked. - bool wake_one_idle_thread_and_unlock( - boost::asio::detail::mutex::scoped_lock& lock) - { - if (first_idle_thread_) - { - idle_thread_info* idle_thread = first_idle_thread_; - first_idle_thread_ = idle_thread->next; - idle_thread->next = 0; - idle_thread->wakeup_event.signal_and_unlock(lock); - return true; - } - return false; - } + BOOST_ASIO_DECL bool wake_one_idle_thread_and_unlock( + mutex::scoped_lock& lock); // Wake a single idle thread, or the task, and always unlock the mutex. - void wake_one_thread_and_unlock( - boost::asio::detail::mutex::scoped_lock& lock) - { - if (!wake_one_idle_thread_and_unlock(lock)) - { - if (!task_interrupted_ && task_) - { - task_interrupted_ = true; - task_->interrupt(); - } - lock.unlock(); - } - } + BOOST_ASIO_DECL void wake_one_thread_and_unlock( + mutex::scoped_lock& lock); // Helper class to perform task-related operations on block exit. struct task_cleanup; friend struct task_cleanup; - struct task_cleanup - { - ~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(*ops_); - task_io_service_->op_queue_.push(&task_io_service_->task_operation_); - } - - task_io_service* task_io_service_; - boost::asio::detail::mutex::scoped_lock* lock_; - op_queue* ops_; - }; // Helper class to call work_finished() on block exit. - struct work_finished_on_block_exit - { - ~work_finished_on_block_exit() - { - task_io_service_->work_finished(); - } - - task_io_service* task_io_service_; - }; + struct work_finished_on_block_exit; // Mutex to protect access to internal data. - boost::asio::detail::mutex mutex_; + mutex mutex_; // The task to be run by this service. - Task* task_; + reactor* task_; // Operation object to represent the position of the task in the queue. - struct task_operation : public operation + struct task_operation : operation { task_operation() : operation(0) {} } task_operation_; @@ -447,13 +158,6 @@ private: // Flag to indicate that the dispatcher has been shut down. bool shutdown_; - // Structure containing information about an idle thread. - struct idle_thread_info - { - event wakeup_event; - idle_thread_info* next; - }; - // The threads that are currently idle. idle_thread_info* first_idle_thread_; }; @@ -464,4 +168,11 @@ private: #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_ASIO_HAS_IOCP) + #endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP diff --git a/include/boost/asio/detail/task_io_service_fwd.hpp b/include/boost/asio/detail/task_io_service_fwd.hpp index 60a07900..24dd11bd 100644 --- a/include/boost/asio/detail/task_io_service_fwd.hpp +++ b/include/boost/asio/detail/task_io_service_fwd.hpp @@ -1,6 +1,6 @@ // -// task_io_service_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// detail/task_io_service_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,19 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - namespace boost { namespace asio { namespace detail { -template class task_io_service; } // namespace detail } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP diff --git a/include/boost/asio/detail/task_io_service_operation.hpp b/include/boost/asio/detail/task_io_service_operation.hpp index 557f6732..e234c07d 100644 --- a/include/boost/asio/detail/task_io_service_operation.hpp +++ b/include/boost/asio/detail/task_io_service_operation.hpp @@ -1,6 +1,6 @@ // -// task_io_service_operation.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/task_io_service_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,22 +15,22 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include +#include + namespace boost { namespace asio { namespace detail { // Base class for all operations. A function pointer is used instead of virtual // functions to avoid the associated overhead. -template class task_io_service_operation { public: - void complete(task_io_service& owner) + void complete(task_io_service& owner) { func_(&owner, this, boost::system::error_code(), 0); } @@ -41,8 +41,9 @@ public: } protected: - typedef void (*func_type)(task_io_service*, - task_io_service_operation*, boost::system::error_code, std::size_t); + typedef void (*func_type)(task_io_service*, + task_io_service_operation*, + boost::system::error_code, std::size_t); task_io_service_operation(func_type func) : next_(0), @@ -65,7 +66,6 @@ private: } // namespace asio } // namespace boost -#include #include #endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP diff --git a/include/boost/asio/detail/thread.hpp b/include/boost/asio/detail/thread.hpp index 3e2e2159..8848cd06 100644 --- a/include/boost/asio/detail/thread.hpp +++ b/include/boost/asio/detail/thread.hpp @@ -1,6 +1,6 @@ // -// thread.hpp -// ~~~~~~~~~~ +// detail/thread.hpp +// ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include @@ -55,6 +51,4 @@ typedef posix_thread thread; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_THREAD_HPP diff --git a/include/boost/asio/detail/throw_error.hpp b/include/boost/asio/detail/throw_error.hpp index e9406a72..713a1963 100644 --- a/include/boost/asio/detail/throw_error.hpp +++ b/include/boost/asio/detail/throw_error.hpp @@ -1,6 +1,6 @@ // -// throw_error.hpp -// ~~~~~~~~~~~~~~~ +// detail/throw_error.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,26 +15,31 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include -#include -#include +#include namespace boost { namespace asio { namespace detail { +BOOST_ASIO_DECL void do_throw_error(const boost::system::error_code& err); + +BOOST_ASIO_DECL void do_throw_error(const boost::system::error_code& err, + const char* location); + inline void throw_error(const boost::system::error_code& err) { if (err) - { - boost::system::system_error e(err); - boost::throw_exception(e); - } + do_throw_error(err); +} + +inline void throw_error(const boost::system::error_code& err, + const char* location) +{ + if (err) + do_throw_error(err, location); } } // namespace detail @@ -43,4 +48,8 @@ inline void throw_error(const boost::system::error_code& err) #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_DETAIL_THROW_ERROR_HPP diff --git a/include/boost/asio/detail/timer_op.hpp b/include/boost/asio/detail/timer_op.hpp index 9973d893..8f82339e 100644 --- a/include/boost/asio/detail/timer_op.hpp +++ b/include/boost/asio/detail/timer_op.hpp @@ -1,6 +1,6 @@ // -// timer_op.hpp -// ~~~~~~~~~~~~ +// detail/timer_op.hpp +// ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/timer_queue.hpp b/include/boost/asio/detail/timer_queue.hpp index 56ae0dcd..4e49ae91 100644 --- a/include/boost/asio/detail/timer_queue.hpp +++ b/include/boost/asio/detail/timer_queue.hpp @@ -1,6 +1,6 @@ // -// timer_queue.hpp -// ~~~~~~~~~~~~~~~ +// detail/timer_queue.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,21 +15,24 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include #include #include -#include - -#include #include #include #include #include +#include +#include + +#include +#include +#include + +#include namespace boost { namespace asio { @@ -273,6 +276,59 @@ private: std::vector heap_; }; +#if !defined(BOOST_ASIO_HEADER_ONLY) + +struct forwarding_posix_time_traits : time_traits {}; + +// Template specialisation for the commonly used instantation. +template <> +class timer_queue > + : public timer_queue_base +{ +public: + // The time type. + typedef boost::posix_time::ptime time_type; + + // The duration type. + typedef boost::posix_time::time_duration duration_type; + + // Constructor. + BOOST_ASIO_DECL timer_queue(); + + // Destructor. + BOOST_ASIO_DECL virtual ~timer_queue(); + + // Add a new timer to the queue. Returns true if this is the timer that is + // earliest in the queue, in which case the reactor's event demultiplexing + // function call may need to be interrupted and restarted. + BOOST_ASIO_DECL bool enqueue_timer(const time_type& time, + timer_op* op, void* token); + + // Whether there are no timers in the queue. + BOOST_ASIO_DECL virtual bool empty() const; + + // Get the time for the timer that is earliest in the queue. + BOOST_ASIO_DECL virtual long wait_duration_msec(long max_duration) const; + + // Get the time for the timer that is earliest in the queue. + BOOST_ASIO_DECL virtual long wait_duration_usec(long max_duration) const; + + // Dequeue all timers not later than the current time. + BOOST_ASIO_DECL virtual void get_ready_timers(op_queue& ops); + + // Dequeue all timers. + BOOST_ASIO_DECL virtual void get_all_timers(op_queue& ops); + + // Cancel and dequeue the timers with the given token. + BOOST_ASIO_DECL std::size_t cancel_timer( + void* timer_token, op_queue& ops); + +private: + timer_queue impl_; +}; + +#endif // !defined(BOOST_ASIO_HEADER_ONLY) + } // namespace detail } // namespace asio } // namespace boost diff --git a/include/boost/asio/detail/timer_queue_base.hpp b/include/boost/asio/detail/timer_queue_base.hpp index 074c2e15..02903085 100644 --- a/include/boost/asio/detail/timer_queue_base.hpp +++ b/include/boost/asio/detail/timer_queue_base.hpp @@ -1,6 +1,6 @@ // -// timer_queue_base.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/timer_queue_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,12 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include #include +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/timer_queue_fwd.hpp b/include/boost/asio/detail/timer_queue_fwd.hpp index b8bc5f2e..0a62a44d 100644 --- a/include/boost/asio/detail/timer_queue_fwd.hpp +++ b/include/boost/asio/detail/timer_queue_fwd.hpp @@ -1,6 +1,6 @@ // -// timer_queue_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~ +// detail/timer_queue_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,8 +15,6 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - namespace boost { namespace asio { namespace detail { @@ -28,6 +26,4 @@ class timer_queue; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_FWD_HPP diff --git a/include/boost/asio/detail/timer_queue_set.hpp b/include/boost/asio/detail/timer_queue_set.hpp index a92a6b90..c2cea662 100644 --- a/include/boost/asio/detail/timer_queue_set.hpp +++ b/include/boost/asio/detail/timer_queue_set.hpp @@ -1,6 +1,6 @@ // -// timer_queue_set.hpp -// ~~~~~~~~~~~~~~~~~~~ +// detail/timer_queue_set.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include +#include + namespace boost { namespace asio { namespace detail { @@ -27,82 +28,28 @@ class timer_queue_set { public: // Constructor. - timer_queue_set() - : first_(0) - { - } + BOOST_ASIO_DECL timer_queue_set(); // Add a timer queue to the set. - void insert(timer_queue_base* q) - { - q->next_ = first_; - first_ = q; - } + BOOST_ASIO_DECL void insert(timer_queue_base* q); // Remove a timer queue from the set. - void erase(timer_queue_base* q) - { - if (first_) - { - if (q == first_) - { - first_ = q->next_; - q->next_ = 0; - return; - } - - for (timer_queue_base* p = first_; p->next_; p = p->next_) - { - if (p->next_ == q) - { - p->next_ = q->next_; - q->next_ = 0; - return; - } - } - } - } + BOOST_ASIO_DECL void erase(timer_queue_base* q); // Determine whether all queues are empty. - bool all_empty() const - { - for (timer_queue_base* p = first_; p; p = p->next_) - if (!p->empty()) - return false; - return true; - } + BOOST_ASIO_DECL bool all_empty() const; // Get the wait duration in milliseconds. - long wait_duration_msec(long max_duration) const - { - long min_duration = max_duration; - for (timer_queue_base* p = first_; p; p = p->next_) - min_duration = p->wait_duration_msec(min_duration); - return min_duration; - } + BOOST_ASIO_DECL long wait_duration_msec(long max_duration) const; // Get the wait duration in microseconds. - long wait_duration_usec(long max_duration) const - { - long min_duration = max_duration; - for (timer_queue_base* p = first_; p; p = p->next_) - min_duration = p->wait_duration_usec(min_duration); - return min_duration; - } + BOOST_ASIO_DECL long wait_duration_usec(long max_duration) const; // Dequeue all ready timers. - void get_ready_timers(op_queue& ops) - { - for (timer_queue_base* p = first_; p; p = p->next_) - p->get_ready_timers(ops); - } + BOOST_ASIO_DECL void get_ready_timers(op_queue& ops); // Dequeue all timers. - void get_all_timers(op_queue& ops) - { - for (timer_queue_base* p = first_; p; p = p->next_) - p->get_all_timers(ops); - } + BOOST_ASIO_DECL void get_all_timers(op_queue& ops); private: timer_queue_base* first_; @@ -114,4 +61,8 @@ private: #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_SET_HPP diff --git a/include/boost/asio/detail/timer_scheduler.hpp b/include/boost/asio/detail/timer_scheduler.hpp index bc837ee0..ec80f407 100644 --- a/include/boost/asio/detail/timer_scheduler.hpp +++ b/include/boost/asio/detail/timer_scheduler.hpp @@ -1,6 +1,6 @@ // -// timer_scheduler.hpp -// ~~~~~~~~~~~~~~~~~~~ +// detail/timer_scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,8 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #if defined(BOOST_ASIO_HAS_IOCP) @@ -31,6 +30,4 @@ # include #endif -#include - #endif // BOOST_ASIO_DETAIL_TIMER_SCHEDULER_HPP diff --git a/include/boost/asio/detail/timer_scheduler_fwd.hpp b/include/boost/asio/detail/timer_scheduler_fwd.hpp index 9d0b1e63..77d6c99e 100644 --- a/include/boost/asio/detail/timer_scheduler_fwd.hpp +++ b/include/boost/asio/detail/timer_scheduler_fwd.hpp @@ -1,6 +1,6 @@ // -// timer_scheduler_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// detail/timer_scheduler_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include -#include +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#elif defined(BOOST_ASIO_HAS_EPOLL) +# include +#elif defined(BOOST_ASIO_HAS_KQUEUE) +# include +#elif defined(BOOST_ASIO_HAS_DEV_POLL) +# include +#else +# include +#endif namespace boost { namespace asio { @@ -36,13 +42,11 @@ typedef kqueue_reactor timer_scheduler; #elif defined(BOOST_ASIO_HAS_DEV_POLL) typedef dev_poll_reactor timer_scheduler; #else -typedef select_reactor timer_scheduler; +typedef select_reactor timer_scheduler; #endif } // namespace detail } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP diff --git a/include/boost/asio/detail/tss_ptr.hpp b/include/boost/asio/detail/tss_ptr.hpp index 7ccfcf32..8edf15bb 100644 --- a/include/boost/asio/detail/tss_ptr.hpp +++ b/include/boost/asio/detail/tss_ptr.hpp @@ -1,6 +1,6 @@ // -// tss_ptr.hpp -// ~~~~~~~~~~~ +// detail/tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_HAS_THREADS) || defined(BOOST_ASIO_DISABLE_THREADS) # include @@ -31,6 +27,8 @@ # error Only Windows and POSIX are supported! #endif +#include + namespace boost { namespace asio { namespace detail { diff --git a/include/boost/asio/detail/wait_handler.hpp b/include/boost/asio/detail/wait_handler.hpp new file mode 100644 index 00000000..e451f196 --- /dev/null +++ b/include/boost/asio/detail/wait_handler.hpp @@ -0,0 +1,78 @@ +// +// detail/wait_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_WAIT_HANDLER_HPP +#define BOOST_ASIO_DETAIL_WAIT_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class wait_handler : public timer_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(wait_handler); + + wait_handler(Handler h) + : timer_op(&wait_handler::do_complete), + handler_(h) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + wait_handler* h(static_cast(base)); + ptr p = { boost::addressof(h->handler_), h, 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 + // 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(h->handler_, h->ec_); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_WAIT_HANDLER_HPP diff --git a/include/boost/asio/detail/weak_ptr.hpp b/include/boost/asio/detail/weak_ptr.hpp new file mode 100644 index 00000000..9a14297f --- /dev/null +++ b/include/boost/asio/detail/weak_ptr.hpp @@ -0,0 +1,41 @@ +// +// detail/weak_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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 +#include + +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +# include +#else +# include +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +using std::weak_ptr; +#else +using boost::weak_ptr; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_WEAK_PTR_HPP diff --git a/include/boost/asio/detail/win_event.hpp b/include/boost/asio/detail/win_event.hpp index bddf09d6..736ebb2d 100644 --- a/include/boost/asio/detail/win_event.hpp +++ b/include/boost/asio/detail/win_event.hpp @@ -1,6 +1,6 @@ // -// win_event.hpp -// ~~~~~~~~~~~~~ +// detail/win_event.hpp +// ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,23 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include +#include #if defined(BOOST_WINDOWS) -#include +#include #include #include #include -#include -#include -#include namespace boost { namespace asio { @@ -42,19 +34,7 @@ class win_event { public: // Constructor. - win_event() - : event_(::CreateEvent(0, true, false, 0)) - { - if (!event_) - { - DWORD last_error = ::GetLastError(); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "event"); - boost::throw_exception(e); - } - } + BOOST_ASIO_DECL win_event(); // Destructor. ~win_event() @@ -107,8 +87,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) + #endif // BOOST_ASIO_DETAIL_WIN_EVENT_HPP diff --git a/include/boost/asio/detail/win_fd_set_adapter.hpp b/include/boost/asio/detail/win_fd_set_adapter.hpp index 11c1e153..4a5d7faa 100644 --- a/include/boost/asio/detail/win_fd_set_adapter.hpp +++ b/include/boost/asio/detail/win_fd_set_adapter.hpp @@ -1,6 +1,6 @@ // -// win_fd_set_adapter.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +#include namespace boost { namespace asio { @@ -83,8 +85,8 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - #include +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP diff --git a/include/boost/asio/detail/win_fenced_block.hpp b/include/boost/asio/detail/win_fenced_block.hpp index ff4a21cb..675dddf3 100644 --- a/include/boost/asio/detail/win_fenced_block.hpp +++ b/include/boost/asio/detail/win_fenced_block.hpp @@ -1,6 +1,6 @@ // -// win_fenced_block.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// detail/win_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(BOOST_WINDOWS) && !defined(UNDER_CE) #include +#include + namespace boost { namespace asio { namespace detail { @@ -70,8 +68,8 @@ public: } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) - #include +#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) + #endif // BOOST_ASIO_DETAIL_WIN_FENCED_BLOCK_HPP diff --git a/include/boost/asio/detail/win_iocp_handle_read_op.hpp b/include/boost/asio/detail/win_iocp_handle_read_op.hpp new file mode 100644 index 00000000..f1a9b1f6 --- /dev/null +++ b/include/boost/asio/detail/win_iocp_handle_read_op.hpp @@ -0,0 +1,103 @@ +// +// detail/win_iocp_handle_read_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_HANDLE_READ_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_handle_read_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_read_op); + + win_iocp_handle_read_op(const MutableBufferSequence& buffers, Handler handler) + : operation(&win_iocp_handle_read_op::do_complete), + buffers_(buffers), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_handle_read_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + if (owner) + { + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_HANDLE_EOF) + ec = boost::asio::error::eof; + + // 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(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + MutableBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP diff --git a/include/boost/asio/detail/win_iocp_handle_service.hpp b/include/boost/asio/detail/win_iocp_handle_service.hpp index a6d65990..291a06ff 100644 --- a/include/boost/asio/detail/win_iocp_handle_service.hpp +++ b/include/boost/asio/detail/win_iocp_handle_service.hpp @@ -1,6 +1,6 @@ // -// win_iocp_handle_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_handle_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) @@ -16,26 +16,23 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_IOCP) -#include #include -#include - #include #include -#include #include #include -#include #include #include +#include +#include #include +#include + namespace boost { namespace asio { namespace detail { @@ -77,75 +74,20 @@ public: implementation_type* prev_; }; - win_iocp_handle_service(boost::asio::io_service& io_service) - : iocp_service_(boost::asio::use_service(io_service)), - mutex_(), - impl_list_(0) - { - } + BOOST_ASIO_DECL win_iocp_handle_service(boost::asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - // Close all implementations, causing all operations to complete. - boost::asio::detail::mutex::scoped_lock lock(mutex_); - implementation_type* impl = impl_list_; - while (impl) - { - close_for_destruction(*impl); - impl = impl->next_; - } - } + BOOST_ASIO_DECL void shutdown_service(); // Construct a new handle implementation. - void construct(implementation_type& impl) - { - impl.handle_ = INVALID_HANDLE_VALUE; - impl.safe_cancellation_thread_id_ = 0; - - // Insert implementation into linked list of all implementations. - boost::asio::detail::mutex::scoped_lock lock(mutex_); - impl.next_ = impl_list_; - impl.prev_ = 0; - if (impl_list_) - impl_list_->prev_ = &impl; - impl_list_ = &impl; - } + BOOST_ASIO_DECL void construct(implementation_type& impl); // Destroy a handle implementation. - void destroy(implementation_type& impl) - { - close_for_destruction(impl); - - // Remove implementation from linked list of all implementations. - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (impl_list_ == &impl) - impl_list_ = impl.next_; - if (impl.prev_) - impl.prev_->next_ = impl.next_; - if (impl.next_) - impl.next_->prev_= impl.prev_; - impl.next_ = 0; - impl.prev_ = 0; - } + BOOST_ASIO_DECL void destroy(implementation_type& impl); // Assign a native handle to a handle implementation. - boost::system::error_code assign(implementation_type& impl, - const native_type& native_handle, boost::system::error_code& ec) - { - if (is_open(impl)) - { - ec = boost::asio::error::already_open; - return ec; - } - - if (iocp_service_.register_handle(native_handle, ec)) - return ec; - - impl.handle_ = native_handle; - ec = boost::system::error_code(); - return ec; - } + BOOST_ASIO_DECL boost::system::error_code assign(implementation_type& impl, + const native_type& native_handle, boost::system::error_code& ec); // Determine whether the handle is open. bool is_open(const implementation_type& impl) const @@ -154,26 +96,8 @@ public: } // Destroy a handle implementation. - boost::system::error_code close(implementation_type& impl, - boost::system::error_code& ec) - { - if (is_open(impl)) - { - if (!::CloseHandle(impl.handle_)) - { - DWORD last_error = ::GetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return ec; - } - - impl.handle_ = INVALID_HANDLE_VALUE; - impl.safe_cancellation_thread_id_ = 0; - } - - ec = boost::system::error_code(); - return ec; - } + BOOST_ASIO_DECL boost::system::error_code close(implementation_type& impl, + boost::system::error_code& ec); // Get the native handle representation. native_type native(const implementation_type& impl) const @@ -182,106 +106,8 @@ public: } // Cancel all operations associated with the handle. - boost::system::error_code cancel(implementation_type& impl, - boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - } - else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( - ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) - { - // The version of Windows supports cancellation from any thread. - typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); - cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; - if (!cancel_io_ex(impl.handle_, 0)) - { - DWORD last_error = ::GetLastError(); - if (last_error == ERROR_NOT_FOUND) - { - // ERROR_NOT_FOUND means that there were no operations to be - // cancelled. We swallow this error to match the behaviour on other - // platforms. - ec = boost::system::error_code(); - } - else - { - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - } - } - else - { - ec = boost::system::error_code(); - } - } - else if (impl.safe_cancellation_thread_id_ == 0) - { - // No operations have been started, so there's nothing to cancel. - ec = boost::system::error_code(); - } - else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) - { - // Asynchronous operations have been started from the current thread only, - // so it is safe to try to cancel them using CancelIo. - if (!::CancelIo(impl.handle_)) - { - DWORD last_error = ::GetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - } - else - { - ec = boost::system::error_code(); - } - } - else - { - // Asynchronous operations have been started from more than one thread, - // so cancellation is not safe. - ec = boost::asio::error::operation_not_supported; - } - - return ec; - } - - class overlapped_wrapper - : public OVERLAPPED - { - public: - explicit overlapped_wrapper(boost::system::error_code& ec) - { - Internal = 0; - InternalHigh = 0; - Offset = 0; - OffsetHigh = 0; - - // Create a non-signalled manual-reset event, for GetOverlappedResult. - hEvent = ::CreateEvent(0, TRUE, FALSE, 0); - if (hEvent) - { - // As documented in GetQueuedCompletionStatus, setting the low order - // bit of this event prevents our synchronous writes from being treated - // as completion port events. - *reinterpret_cast(&hEvent) |= 1; - } - else - { - DWORD last_error = ::GetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - } - } - - ~overlapped_wrapper() - { - if (hEvent) - { - ::CloseHandle(hEvent); - } - } - }; + BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl, + boost::system::error_code& ec); // Write the given data. Returns the number of bytes written. template @@ -297,109 +123,13 @@ public: size_t write_some_at(implementation_type& impl, boost::uint64_t offset, const ConstBufferSequence& buffers, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - boost::asio::const_buffer buffer = buffer_sequence_adapter::first(buffers); - // A request to write 0 bytes on a handle is a no-op. - if (boost::asio::buffer_size(buffer) == 0) - { - ec = boost::system::error_code(); - return 0; - } - - overlapped_wrapper overlapped(ec); - if (ec) - { - return 0; - } - - // Write the data. - overlapped.Offset = offset & 0xFFFFFFFF; - overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::WriteFile(impl.handle_, - boost::asio::buffer_cast(buffer), - static_cast(boost::asio::buffer_size(buffer)), 0, &overlapped); - if (!ok) - { - DWORD last_error = ::GetLastError(); - if (last_error != ERROR_IO_PENDING) - { - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return 0; - } - } - - // Wait for the operation to complete. - DWORD bytes_transferred = 0; - ok = ::GetOverlappedResult(impl.handle_, - &overlapped, &bytes_transferred, TRUE); - if (!ok) - { - DWORD last_error = ::GetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return 0; - } - - ec = boost::system::error_code(); - return bytes_transferred; + return do_write(impl, offset, buffer, ec); } - template - class write_op : public operation - { - public: - write_op(const ConstBufferSequence& buffers, Handler handler) - : operation(&write_op::do_complete), - buffers_(buffers), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - write_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter::validate(o->buffers_); -#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - - // 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(o->handler_, ec, bytes_transferred); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - ConstBufferSequence buffers_; - Handler handler_; - }; - // Start an asynchronous write. The data being written must be valid for the // lifetime of the asynchronous operation. template @@ -416,15 +146,16 @@ public: const ConstBufferSequence& buffers, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef write_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, buffers, handler); + typedef win_iocp_handle_write_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(buffers, handler); start_write_op(impl, offset, buffer_sequence_adapter::first(buffers), ptr.get()); - ptr.release(); + ConstBufferSequence>::first(buffers), p.p); + p.v = p.p = 0; } // Read some data. Returns the number of bytes received. @@ -440,129 +171,13 @@ public: size_t read_some_at(implementation_type& impl, boost::uint64_t offset, const MutableBufferSequence& buffers, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - boost::asio::mutable_buffer buffer = buffer_sequence_adapter::first(buffers); - // A request to read 0 bytes on a stream handle is a no-op. - if (boost::asio::buffer_size(buffer) == 0) - { - ec = boost::system::error_code(); - return 0; - } - - overlapped_wrapper overlapped(ec); - if (ec) - { - return 0; - } - - // Read some data. - overlapped.Offset = offset & 0xFFFFFFFF; - overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::ReadFile(impl.handle_, - boost::asio::buffer_cast(buffer), - static_cast(boost::asio::buffer_size(buffer)), 0, &overlapped); - if (!ok) - { - DWORD last_error = ::GetLastError(); - if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA) - { - if (last_error == ERROR_HANDLE_EOF) - { - ec = boost::asio::error::eof; - } - else - { - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - } - return 0; - } - } - - // Wait for the operation to complete. - DWORD bytes_transferred = 0; - ok = ::GetOverlappedResult(impl.handle_, - &overlapped, &bytes_transferred, TRUE); - if (!ok) - { - DWORD last_error = ::GetLastError(); - if (last_error == ERROR_HANDLE_EOF) - { - ec = boost::asio::error::eof; - } - else - { - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - } - return 0; - } - - ec = boost::system::error_code(); - return bytes_transferred; + return do_read(impl, offset, buffer, ec); } - template - class read_op : public operation - { - public: - read_op(const MutableBufferSequence& buffers, Handler handler) - : operation(&read_op::do_complete), - buffers_(buffers), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - read_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter::validate(o->buffers_); -#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - - // Map non-portable errors to their portable counterparts. - if (ec.value() == ERROR_HANDLE_EOF) - { - ec = boost::asio::error::eof; - } - - // 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(o->handler_, ec, bytes_transferred); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - MutableBufferSequence buffers_; - Handler handler_; - }; - // Start an asynchronous read. The buffer for the data being received must be // valid for the lifetime of the asynchronous operation. template @@ -580,15 +195,16 @@ public: const MutableBufferSequence& buffers, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef read_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, buffers, handler); + typedef win_iocp_handle_read_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(buffers, handler); start_read_op(impl, offset, buffer_sequence_adapter::first(buffers), ptr.get()); - ptr.release(); + MutableBufferSequence>::first(buffers), p.p); + p.v = p.p = 0; } private: @@ -614,113 +230,42 @@ private: void async_read_some_at(implementation_type& impl, boost::uint64_t offset, const null_buffers& buffers, Handler handler); - // Helper function to start a write operation. - void start_write_op(implementation_type& impl, boost::uint64_t offset, - const boost::asio::const_buffer& buffer, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); + // Helper class for waiting for synchronous operations to complete. + class overlapped_wrapper; - if (!is_open(impl)) - { - iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); - } - else if (boost::asio::buffer_size(buffer) == 0) - { - // A request to write 0 bytes on a handle is a no-op. - iocp_service_.on_completion(op); - } - else - { - DWORD bytes_transferred = 0; - op->Offset = offset & 0xFFFFFFFF; - op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::WriteFile(impl.handle_, - boost::asio::buffer_cast(buffer), - static_cast(boost::asio::buffer_size(buffer)), - &bytes_transferred, op); - DWORD last_error = ::GetLastError(); - if (!ok && last_error != ERROR_IO_PENDING - && last_error != ERROR_MORE_DATA) - { - iocp_service_.on_completion(op, last_error, bytes_transferred); - } - else - { - iocp_service_.on_pending(op); - } - } - } + // Helper function to perform a synchronous write operation. + BOOST_ASIO_DECL size_t do_write(implementation_type& impl, + boost::uint64_t offset, const boost::asio::const_buffer& buffer, + boost::system::error_code& ec); + + // Helper function to start a write operation. + BOOST_ASIO_DECL void start_write_op(implementation_type& impl, + boost::uint64_t offset, const boost::asio::const_buffer& buffer, + operation* op); + + // Helper function to perform a synchronous write operation. + BOOST_ASIO_DECL size_t do_read(implementation_type& impl, + boost::uint64_t offset, const boost::asio::mutable_buffer& buffer, + boost::system::error_code& ec); // Helper function to start a read operation. - void start_read_op(implementation_type& impl, boost::uint64_t offset, - const boost::asio::mutable_buffer& buffer, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (!is_open(impl)) - { - iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); - } - else if (boost::asio::buffer_size(buffer) == 0) - { - // A request to read 0 bytes on a handle is a no-op. - iocp_service_.on_completion(op); - } - else - { - DWORD bytes_transferred = 0; - op->Offset = offset & 0xFFFFFFFF; - op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; - BOOL ok = ::ReadFile(impl.handle_, - boost::asio::buffer_cast(buffer), - static_cast(boost::asio::buffer_size(buffer)), - &bytes_transferred, op); - DWORD last_error = ::GetLastError(); - if (!ok && last_error != ERROR_IO_PENDING - && last_error != ERROR_MORE_DATA) - { - iocp_service_.on_completion(op, last_error, bytes_transferred); - } - else - { - iocp_service_.on_pending(op); - } - } - } + BOOST_ASIO_DECL void start_read_op(implementation_type& impl, + boost::uint64_t offset, const boost::asio::mutable_buffer& buffer, + operation* op); // Update the ID of the thread from which cancellation is safe. - void update_cancellation_thread_id(implementation_type& impl) - { -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#else // defined(BOOST_ASIO_ENABLE_CANCELIO) - (void)impl; -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - } + BOOST_ASIO_DECL void update_cancellation_thread_id(implementation_type& impl); // Helper function to close a handle when the associated object is being // destroyed. - void close_for_destruction(implementation_type& impl) - { - if (is_open(impl)) - { - ::CloseHandle(impl.handle_); - impl.handle_ = INVALID_HANDLE_VALUE; - impl.safe_cancellation_thread_id_ = 0; - } - } + BOOST_ASIO_DECL void close_for_destruction(implementation_type& impl); // The IOCP service used for running asynchronous operations and dispatching // handlers. win_iocp_io_service& iocp_service_; // Mutex to protect access to the linked list of implementations. - boost::asio::detail::mutex mutex_; + mutex mutex_; // The head of a linked list of all implementations. implementation_type* impl_list_; @@ -730,8 +275,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_IOCP) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_IOCP) + #endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP diff --git a/include/boost/asio/detail/win_iocp_handle_write_op.hpp b/include/boost/asio/detail/win_iocp_handle_write_op.hpp new file mode 100644 index 00000000..971f1746 --- /dev/null +++ b/include/boost/asio/detail/win_iocp_handle_write_op.hpp @@ -0,0 +1,99 @@ +// +// detail/win_iocp_handle_write_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_HANDLE_WRITE_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_handle_write_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_write_op); + + win_iocp_handle_write_op(const ConstBufferSequence& buffers, Handler handler) + : operation(&win_iocp_handle_write_op::do_complete), + buffers_(buffers), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_handle_write_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + if (owner) + { + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + + // 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(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + ConstBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP diff --git a/include/boost/asio/detail/win_iocp_io_service.hpp b/include/boost/asio/detail/win_iocp_io_service.hpp index 83b16bf8..e7420192 100644 --- a/include/boost/asio/detail/win_iocp_io_service.hpp +++ b/include/boost/asio/detail/win_iocp_io_service.hpp @@ -1,6 +1,6 @@ // -// win_iocp_io_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_io_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,33 +15,24 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_IOCP) -#include -#include -#include -#include -#include - +#include #include -#include -#include -#include -#include -#include #include #include -#include #include #include #include #include #include +#include #include +#include + +#include namespace boost { namespace asio { @@ -53,69 +44,13 @@ class win_iocp_io_service : public boost::asio::detail::service_base { public: - typedef win_iocp_operation operation; - // Constructor. - win_iocp_io_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base(io_service), - iocp_(), - outstanding_work_(0), - stopped_(0), - shutdown_(0), - timer_thread_(0), - timer_interrupt_issued_(false) - { - } + BOOST_ASIO_DECL win_iocp_io_service(boost::asio::io_service& io_service); - void init(size_t concurrency_hint) - { - iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, - static_cast((std::min)(concurrency_hint, DWORD(~0)))); - if (!iocp_.handle) - { - DWORD last_error = ::GetLastError(); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "iocp"); - boost::throw_exception(e); - } - } + BOOST_ASIO_DECL void init(size_t concurrency_hint); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - ::InterlockedExchange(&shutdown_, 1); - - while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0) - { - op_queue ops; - timer_queues_.get_all_timers(ops); - ops.push(completed_ops_); - if (!ops.empty()) - { - while (operation* op = ops.front()) - { - ops.pop(); - ::InterlockedDecrement(&outstanding_work_); - op->destroy(); - } - } - else - { - DWORD bytes_transferred = 0; - dword_ptr_t completion_key = 0; - LPOVERLAPPED overlapped = 0; - ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, - &completion_key, &overlapped, max_timeout); - if (overlapped) - { - ::InterlockedDecrement(&outstanding_work_); - static_cast(overlapped)->destroy(); - } - } - } - } + BOOST_ASIO_DECL void shutdown_service(); // Initialise the task. Nothing to do here. void init_task() @@ -123,106 +58,23 @@ public: } // Register a handle with the IO completion port. - boost::system::error_code register_handle( - HANDLE handle, boost::system::error_code& ec) - { - if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0) - { - DWORD last_error = ::GetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - } - else - { - ec = boost::system::error_code(); - } - return ec; - } + BOOST_ASIO_DECL boost::system::error_code register_handle( + HANDLE handle, boost::system::error_code& ec); // Run the event loop until stopped or no more work. - size_t run(boost::system::error_code& ec) - { - if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - call_stack::context ctx(this); - - size_t n = 0; - while (do_one(true, ec)) - if (n != (std::numeric_limits::max)()) - ++n; - return n; - } + BOOST_ASIO_DECL size_t run(boost::system::error_code& ec); // Run until stopped or one operation is performed. - size_t run_one(boost::system::error_code& ec) - { - if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - call_stack::context ctx(this); - - return do_one(true, ec); - } + BOOST_ASIO_DECL size_t run_one(boost::system::error_code& ec); // Poll for operations without blocking. - size_t poll(boost::system::error_code& ec) - { - if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - call_stack::context ctx(this); - - size_t n = 0; - while (do_one(false, ec)) - if (n != (std::numeric_limits::max)()) - ++n; - return n; - } + BOOST_ASIO_DECL size_t poll(boost::system::error_code& ec); // Poll for one operation without blocking. - size_t poll_one(boost::system::error_code& ec) - { - if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) - { - stop(); - ec = boost::system::error_code(); - return 0; - } - - call_stack::context ctx(this); - - return do_one(false, ec); - } + BOOST_ASIO_DECL size_t poll_one(boost::system::error_code& ec); // Stop the event processing loop. - void stop() - { - if (::InterlockedExchange(&stopped_, 1) == 0) - { - if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) - { - DWORD last_error = ::GetLastError(); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "pqcs"); - boost::throw_exception(e); - } - } - } + BOOST_ASIO_DECL void stop(); // Reset in preparation for a subsequent run invocation. void reset() @@ -245,34 +97,15 @@ public: // Request invocation of the given handler. template - void dispatch(Handler handler) - { - if (call_stack::contains(this)) - { - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - else - post(handler); - } + void dispatch(Handler handler); // Request invocation of the given handler and return immediately. template - void post(Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef completion_handler value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); - - post_immediate_completion(ptr.get()); - ptr.release(); - } + 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(operation* op) + void post_immediate_completion(win_iocp_operation* op) { work_started(); post_deferred_completion(op); @@ -280,171 +113,48 @@ public: // Request invocation of the given operation and return immediately. Assumes // that work_started() was previously called for the operation. - void post_deferred_completion(operation* op) - { - // Flag the operation as ready. - op->ready_ = 1; - - // Enqueue the operation on the I/O completion port. - if (!::PostQueuedCompletionStatus(iocp_.handle, - 0, overlapped_contains_result, op)) - { - // Out of resources. Put on completed queue instead. - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - completed_ops_.push(op); - } - } + BOOST_ASIO_DECL void post_deferred_completion(win_iocp_operation* op); // Request invocation of the given operation and return immediately. Assumes // that work_started() was previously called for the operations. - void post_deferred_completions(op_queue& ops) - { - while (operation* op = ops.front()) - { - ops.pop(); - - // Flag the operation as ready. - op->ready_ = 1; - - // Enqueue the operation on the I/O completion port. - if (!::PostQueuedCompletionStatus(iocp_.handle, - 0, overlapped_contains_result, op)) - { - // Out of resources. Put on completed queue instead. - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - completed_ops_.push(op); - completed_ops_.push(ops); - } - } - } + BOOST_ASIO_DECL void post_deferred_completions( + op_queue& ops); // Called after starting an overlapped I/O operation that did not complete // immediately. The caller must have already called work_started() prior to // starting the operation. - void on_pending(operation* op) - { - if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) - { - // Enqueue the operation on the I/O completion port. - if (!::PostQueuedCompletionStatus(iocp_.handle, - 0, overlapped_contains_result, op)) - { - // Out of resources. Put on completed queue instead. - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - completed_ops_.push(op); - } - } - } + BOOST_ASIO_DECL void on_pending(win_iocp_operation* op); // Called after starting an overlapped I/O operation that completed // immediately. The caller must have already called work_started() prior to // starting the operation. - void on_completion(operation* op, - DWORD last_error = 0, DWORD bytes_transferred = 0) - { - // Flag that the operation is ready for invocation. - op->ready_ = 1; - - // Store results in the OVERLAPPED structure. - op->Internal = reinterpret_cast( - &boost::asio::error::get_system_category()); - op->Offset = last_error; - op->OffsetHigh = bytes_transferred; - - // Enqueue the operation on the I/O completion port. - if (!::PostQueuedCompletionStatus(iocp_.handle, - 0, overlapped_contains_result, op)) - { - // Out of resources. Put on completed queue instead. - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - completed_ops_.push(op); - } - } + BOOST_ASIO_DECL void on_completion(win_iocp_operation* op, + DWORD last_error = 0, DWORD bytes_transferred = 0); // Called after starting an overlapped I/O operation that completed // immediately. The caller must have already called work_started() prior to // starting the operation. - void on_completion(operation* op, - const boost::system::error_code& ec, DWORD bytes_transferred = 0) - { - // Flag that the operation is ready for invocation. - op->ready_ = 1; - - // Store results in the OVERLAPPED structure. - op->Internal = reinterpret_cast(&ec.category()); - op->Offset = ec.value(); - op->OffsetHigh = bytes_transferred; - - // Enqueue the operation on the I/O completion port. - if (!::PostQueuedCompletionStatus(iocp_.handle, - 0, overlapped_contains_result, op)) - { - // Out of resources. Put on completed queue instead. - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - completed_ops_.push(op); - } - } + BOOST_ASIO_DECL void on_completion(win_iocp_operation* op, + const boost::system::error_code& ec, DWORD bytes_transferred = 0); // Add a new timer queue to the service. template - void add_timer_queue(timer_queue& timer_queue) - { - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - timer_queues_.insert(&timer_queue); - } + void add_timer_queue(timer_queue& timer_queue); // Remove a timer queue from the service. template - void remove_timer_queue(timer_queue& timer_queue) - { - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - timer_queues_.erase(&timer_queue); - } + void remove_timer_queue(timer_queue& timer_queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template void schedule_timer(timer_queue& timer_queue, - const typename Time_Traits::time_type& time, timer_op* op, void* token) - { - // If the service has been shut down we silently discard the timer. - if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) - return; - - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - bool interrupt = timer_queue.enqueue_timer(time, op, token); - work_started(); - if (interrupt && !timer_interrupt_issued_) - { - timer_interrupt_issued_ = true; - lock.unlock(); - ::PostQueuedCompletionStatus(iocp_.handle, - 0, steal_timer_dispatching, 0); - } - } + const typename Time_Traits::time_type& time, timer_op* op, void* token); // Cancel the timer associated with the given token. Returns the number of // handlers that have been posted or dispatched. template - std::size_t cancel_timer(timer_queue& timer_queue, void* token) - { - // If the service has been shut down we silently ignore the cancellation. - if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) - return 0; - - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - op_queue ops; - std::size_t n = timer_queue.cancel_timer(token, ops); - post_deferred_completions(ops); - if (n > 0 && !timer_interrupt_issued_) - { - timer_interrupt_issued_ = true; - lock.unlock(); - ::PostQueuedCompletionStatus(iocp_.handle, - 0, steal_timer_dispatching, 0); - } - return n; - } + std::size_t cancel_timer(timer_queue& timer_queue, void* token); private: #if defined(WINVER) && (WINVER < 0x0500) @@ -458,181 +168,30 @@ 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). - size_t do_one(bool block, boost::system::error_code& ec) - { - long this_thread_id = static_cast(::GetCurrentThreadId()); + BOOST_ASIO_DECL size_t do_one(bool block, boost::system::error_code& ec); - for (;;) - { - // Try to acquire responsibility for dispatching timers. - bool dispatching_timers = (::InterlockedCompareExchange( - &timer_thread_, this_thread_id, 0) == 0); + // Helper function to add a new timer queue. + BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); - // Calculate timeout for GetQueuedCompletionStatus call. - DWORD timeout = max_timeout; - if (dispatching_timers) - { - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - timer_interrupt_issued_ = false; - timeout = get_timeout(); - } + // Helper function to remove a timer queue. + BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); - // Get the next operation from the queue. - DWORD bytes_transferred = 0; - dword_ptr_t completion_key = 0; - LPOVERLAPPED overlapped = 0; - ::SetLastError(0); - BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, - &completion_key, &overlapped, block ? timeout : 0); - DWORD last_error = ::GetLastError(); - - // Dispatch any pending timers. - if (dispatching_timers) - { - boost::asio::detail::mutex::scoped_lock lock(timer_mutex_); - op_queue ops; - ops.push(completed_ops_); - timer_queues_.get_ready_timers(ops); - post_deferred_completions(ops); - } - - if (!ok && overlapped == 0) - { - if (block && last_error == WAIT_TIMEOUT) - { - // Relinquish responsibility for dispatching timers. - if (dispatching_timers) - { - ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id); - } - - continue; - } - - // Transfer responsibility for dispatching timers to another thread. - if (dispatching_timers && ::InterlockedCompareExchange( - &timer_thread_, 0, this_thread_id) == this_thread_id) - { - ::PostQueuedCompletionStatus(iocp_.handle, - 0, transfer_timer_dispatching, 0); - } - - ec = boost::system::error_code(); - return 0; - } - else if (overlapped) - { - operation* op = static_cast(overlapped); - boost::system::error_code result_ec(last_error, - boost::asio::error::get_system_category()); - - // Transfer responsibility for dispatching timers to another thread. - if (dispatching_timers && ::InterlockedCompareExchange( - &timer_thread_, 0, this_thread_id) == this_thread_id) - { - ::PostQueuedCompletionStatus(iocp_.handle, - 0, transfer_timer_dispatching, 0); - } - - // We may have been passed the last_error and bytes_transferred in the - // OVERLAPPED structure itself. - if (completion_key == overlapped_contains_result) - { - result_ec = boost::system::error_code(static_cast(op->Offset), - *reinterpret_cast(op->Internal)); - bytes_transferred = op->OffsetHigh; - } - - // Otherwise ensure any result has been saved into the OVERLAPPED - // structure. - else - { - op->Internal = reinterpret_cast(&result_ec.category()); - op->Offset = result_ec.value(); - op->OffsetHigh = bytes_transferred; - } - - // Dispatch the operation only if ready. The operation may not be ready - // if the initiating function (e.g. a call to WSARecv) has not yet - // returned. This is because the initiating function still wants access - // to the operation's OVERLAPPED structure. - if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) - { - // Ensure the count of outstanding work is decremented on block exit. - work_finished_on_block_exit on_exit = { this }; - (void)on_exit; - - op->complete(*this, result_ec, bytes_transferred); - ec = boost::system::error_code(); - return 1; - } - } - else if (completion_key == transfer_timer_dispatching) - { - // Woken up to try to acquire responsibility for dispatching timers. - ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id); - } - else if (completion_key == steal_timer_dispatching) - { - // Woken up to steal responsibility for dispatching timers. - ::InterlockedExchange(&timer_thread_, 0); - } - else - { - // Relinquish responsibility for dispatching timers. If the io_service - // is not being stopped then the thread will get an opportunity to - // reacquire timer responsibility on the next loop iteration. - if (dispatching_timers) - { - ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id); - } - - // The stopped_ flag is always checked to ensure that any leftover - // interrupts from a previous run invocation are ignored. - if (::InterlockedExchangeAdd(&stopped_, 0) != 0) - { - // Wake up next thread that is blocked on GetQueuedCompletionStatus. - if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) - { - last_error = ::GetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return 0; - } - - ec = boost::system::error_code(); - return 0; - } - } - } - } - - // Get the timeout value for the GetQueuedCompletionStatus call. The timeout - // value is returned as a number of milliseconds. We will wait no longer than - // 1000 milliseconds. - DWORD get_timeout() - { - return timer_queues_.wait_duration_msec(max_timeout); - } + // Called to recalculate and update the timeout. + BOOST_ASIO_DECL void update_timeout(); // Helper class to call work_finished() on block exit. - struct work_finished_on_block_exit - { - ~work_finished_on_block_exit() - { - io_service_->work_finished(); - } + struct work_finished_on_block_exit; - win_iocp_io_service* io_service_; + // Helper class for managing a HANDLE. + struct auto_handle + { + HANDLE handle; + auto_handle() : handle(0) {} + ~auto_handle() { if (handle) ::CloseHandle(handle); } }; // The IO completion port used for queueing operations. - struct iocp_holder - { - HANDLE handle; - iocp_holder() : handle(0) {} - ~iocp_holder() { if (handle) ::CloseHandle(handle); } - } iocp_; + auto_handle iocp_; // The count of unfinished work. long outstanding_work_; @@ -645,45 +204,62 @@ private: enum { - // Maximum GetQueuedCompletionStatus timeout, in milliseconds. - max_timeout = 500, + // Timeout to use with GetQueuedCompletionStatus. Some versions of windows + // have a "bug" where a call to GetQueuedCompletionStatus can appear stuck + // even though there are events waiting on the queue. Using a timeout helps + // to work around the issue. + gqcs_timeout = 500, - // Completion key value to indicate that responsibility for dispatching - // timers is being cooperatively transferred from one thread to another. - transfer_timer_dispatching = 1, + // Maximum waitable timer timeout, in milliseconds. + max_timeout_msec = 5 * 60 * 1000, - // Completion key value to indicate that responsibility for dispatching - // timers should be stolen from another thread. - steal_timer_dispatching = 2, + // Maximum waitable timer timeout, in microseconds. + max_timeout_usec = max_timeout_msec * 1000, + + // Completion key value used to wake up a thread to dispatch timers or + // completed operations. + wake_for_dispatch = 1, // Completion key value to indicate that an operation has posted with the // original last_error and bytes_transferred values stored in the fields of // the OVERLAPPED structure. - overlapped_contains_result = 3 + overlapped_contains_result = 2 }; - // The thread that's currently in charge of dispatching timers. - long timer_thread_; + // Function object for processing timeouts in a background thread. + struct timer_thread_function; + friend struct timer_thread_function; - // Mutex for protecting access to the timer queues. - mutex timer_mutex_; + // Background thread used for processing timeouts. + boost::scoped_ptr timer_thread_; - // Whether a thread has been interrupted to process a new timeout. - bool timer_interrupt_issued_; + // A waitable timer object used for waiting for timeouts. + auto_handle waitable_timer_; + + // Non-zero if timers or completed operations need to be dispatched. + long dispatch_required_; + + // Mutex for protecting access to the timer queues and completed operations. + mutex dispatch_mutex_; // The timer queues. timer_queue_set timer_queues_; // The operations that are ready to dispatch. - op_queue completed_ops_; + op_queue completed_ops_; }; } // namespace detail } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_IOCP) - #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_IOCP) + #endif // BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP diff --git a/include/boost/asio/detail/win_iocp_io_service_fwd.hpp b/include/boost/asio/detail/win_iocp_io_service_fwd.hpp index be413ec9..1357603b 100644 --- a/include/boost/asio/detail/win_iocp_io_service_fwd.hpp +++ b/include/boost/asio/detail/win_iocp_io_service_fwd.hpp @@ -1,6 +1,6 @@ // -// win_iocp_io_service_fwd.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_io_service_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,22 +15,9 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include - -#include - -// This service is only supported on Win32 (NT4 and later). -#if !defined(BOOST_ASIO_DISABLE_IOCP) -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) -#if !defined(UNDER_CE) - -// Define this to indicate that IOCP is supported on the target platform. -#define BOOST_ASIO_HAS_IOCP 1 +#if defined(BOOST_ASIO_HAS_IOCP) namespace boost { namespace asio { @@ -43,11 +30,6 @@ class win_iocp_overlapped_ptr; } // namespace asio } // namespace boost -#endif // !defined(UNDER_CE) -#endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -#endif // !defined(BOOST_ASIO_DISABLE_IOCP) - -#include +#endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP diff --git a/include/boost/asio/detail/win_iocp_null_buffers_op.hpp b/include/boost/asio/detail/win_iocp_null_buffers_op.hpp new file mode 100644 index 00000000..ed1c28f8 --- /dev/null +++ b/include/boost/asio/detail/win_iocp_null_buffers_op.hpp @@ -0,0 +1,114 @@ +// +// detail/win_iocp_null_buffers_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_NULL_BUFFERS_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_null_buffers_op : public reactor_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_null_buffers_op); + + win_iocp_null_buffers_op(socket_ops::weak_cancel_token_type cancel_token, + Handler handler) + : reactor_op(&win_iocp_null_buffers_op::do_perform, + &win_iocp_null_buffers_op::do_complete), + cancel_token_(cancel_token), + handler_(handler) + { + } + + static bool do_perform(reactor_op*) + { + return true; + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_null_buffers_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, 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::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP diff --git a/include/boost/asio/detail/win_iocp_operation.hpp b/include/boost/asio/detail/win_iocp_operation.hpp index d7d5723b..c9b30412 100644 --- a/include/boost/asio/detail/win_iocp_operation.hpp +++ b/include/boost/asio/detail/win_iocp_operation.hpp @@ -1,6 +1,6 @@ // -// win_iocp_operation.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_IOCP) #include +#include +#include + +#include namespace boost { namespace asio { @@ -83,9 +85,8 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_IOCP) - -#include #include +#endif // defined(BOOST_ASIO_HAS_IOCP) + #endif // BOOST_ASIO_DETAIL_WIN_IOCP_OPERATION_HPP diff --git a/include/boost/asio/detail/win_iocp_overlapped_op.hpp b/include/boost/asio/detail/win_iocp_overlapped_op.hpp new file mode 100644 index 00000000..911449d3 --- /dev/null +++ b/include/boost/asio/detail/win_iocp_overlapped_op.hpp @@ -0,0 +1,86 @@ +// +// detail/win_iocp_overlapped_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_OVERLAPPED_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_overlapped_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_overlapped_op); + + win_iocp_overlapped_op(Handler handler) + : operation(&win_iocp_overlapped_op::do_complete), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_overlapped_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, 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(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP diff --git a/include/boost/asio/detail/win_iocp_overlapped_ptr.hpp b/include/boost/asio/detail/win_iocp_overlapped_ptr.hpp index 082a5b1b..5589c110 100644 --- a/include/boost/asio/detail/win_iocp_overlapped_ptr.hpp +++ b/include/boost/asio/detail/win_iocp_overlapped_ptr.hpp @@ -1,6 +1,6 @@ // -// win_iocp_overlapped_ptr.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_overlapped_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_IOCP) -#include +#include +#include +#include #include +#include #include -#include + +#include namespace boost { namespace asio { @@ -75,13 +77,15 @@ public: template void reset(boost::asio::io_service& io_service, Handler handler) { - typedef overlapped_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + typedef win_iocp_overlapped_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(handler); io_service.impl_.work_started(); reset(); - ptr_ = ptr.release(); + ptr_ = p.p; + p.v = p.p = 0; iocp_service_ = &io_service.impl_; } @@ -123,44 +127,6 @@ public: } private: - template - struct overlapped_op : public win_iocp_operation - { - overlapped_op(Handler handler) - : win_iocp_operation(&overlapped_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - overlapped_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // 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(o->handler_, ec, bytes_transferred); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - win_iocp_operation* ptr_; win_iocp_io_service* iocp_service_; }; @@ -169,8 +135,8 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_IOCP) - #include +#endif // defined(BOOST_ASIO_HAS_IOCP) + #endif // BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP diff --git a/include/boost/asio/detail/win_iocp_serial_port_service.hpp b/include/boost/asio/detail/win_iocp_serial_port_service.hpp index 288287c2..a0caa691 100644 --- a/include/boost/asio/detail/win_iocp_serial_port_service.hpp +++ b/include/boost/asio/detail/win_iocp_serial_port_service.hpp @@ -1,6 +1,6 @@ // -// win_iocp_serial_port_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_serial_port_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) @@ -16,21 +16,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include + +#if defined(BOOST_ASIO_HAS_IOCP) && defined(BOOST_ASIO_HAS_SERIAL_PORT) -#include -#include #include -#include - -#include - -#if defined(BOOST_ASIO_HAS_IOCP) - #include #include #include +#include + namespace boost { namespace asio { namespace detail { @@ -39,133 +35,56 @@ namespace detail { class win_iocp_serial_port_service { public: - // The native type of a stream handle. + // The native type of a serial port. typedef win_iocp_handle_service::native_type native_type; - // The implementation type of the stream handle. + // The implementation type of the serial port. typedef win_iocp_handle_service::implementation_type implementation_type; - win_iocp_serial_port_service(boost::asio::io_service& io_service) - : handle_service_(io_service) - { - } + // Constructor. + BOOST_ASIO_DECL win_iocp_serial_port_service( + boost::asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - } + BOOST_ASIO_DECL void shutdown_service(); - // Construct a new handle implementation. + // Construct a new serial port implementation. void construct(implementation_type& impl) { handle_service_.construct(impl); } - // Destroy a handle implementation. + // Destroy a serial port implementation. void destroy(implementation_type& impl) { handle_service_.destroy(impl); } // Open the serial port using the specified device name. - boost::system::error_code open(implementation_type& impl, - const std::string& device, boost::system::error_code& ec) - { - if (is_open(impl)) - { - ec = boost::asio::error::already_open; - return ec; - } + BOOST_ASIO_DECL boost::system::error_code open(implementation_type& impl, + const std::string& device, boost::system::error_code& ec); - // For convenience, add a leading \\.\ sequence if not already present. - std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device; - - // Open a handle to the serial port. - ::HANDLE handle = ::CreateFileA(name.c_str(), - GENERIC_READ | GENERIC_WRITE, 0, 0, - OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); - if (handle == INVALID_HANDLE_VALUE) - { - DWORD last_error = ::GetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return ec; - } - - // Determine the initial serial port parameters. - using namespace std; // For memcpy. - ::DCB dcb; - memset(&dcb, 0, sizeof(DCB)); - dcb.DCBlength = sizeof(DCB); - if (!::GetCommState(handle, &dcb)) - { - DWORD last_error = ::GetLastError(); - ::CloseHandle(handle); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return ec; - } - - // Set some default serial port parameters. This implementation does not - // support changing these, so they might as well be in a known state. - dcb.fBinary = TRUE; // Win32 only supports binary mode. - dcb.fDsrSensitivity = FALSE; - dcb.fNull = FALSE; // Do not ignore NULL characters. - dcb.fAbortOnError = FALSE; // Ignore serial framing errors. - if (!::SetCommState(handle, &dcb)) - { - DWORD last_error = ::GetLastError(); - ::CloseHandle(handle); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return ec; - } - - // Set up timeouts so that the serial port will behave similarly to a - // network socket. Reads wait for at least one byte, then return with - // whatever they have. Writes return once everything is out the door. - ::COMMTIMEOUTS timeouts; - timeouts.ReadIntervalTimeout = 1; - timeouts.ReadTotalTimeoutMultiplier = 0; - timeouts.ReadTotalTimeoutConstant = 0; - timeouts.WriteTotalTimeoutMultiplier = 0; - timeouts.WriteTotalTimeoutConstant = 0; - if (!::SetCommTimeouts(handle, &timeouts)) - { - DWORD last_error = ::GetLastError(); - ::CloseHandle(handle); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return ec; - } - - // We're done. Take ownership of the serial port handle. - if (handle_service_.assign(impl, handle, ec)) - ::CloseHandle(handle); - return ec; - } - - // Assign a native handle to a handle implementation. + // Assign a native handle to a serial port implementation. boost::system::error_code assign(implementation_type& impl, const native_type& native_handle, boost::system::error_code& ec) { return handle_service_.assign(impl, native_handle, ec); } - // Determine whether the handle is open. + // Determine whether the serial port is open. bool is_open(const implementation_type& impl) const { return handle_service_.is_open(impl); } - // Destroy a handle implementation. + // Destroy a serial port implementation. boost::system::error_code close(implementation_type& impl, boost::system::error_code& ec) { return handle_service_.close(impl, ec); } - // Get the native handle representation. + // Get the native serial port representation. native_type native(implementation_type& impl) { return handle_service_.native(impl); @@ -183,32 +102,9 @@ public: boost::system::error_code set_option(implementation_type& impl, const SettableSerialPortOption& option, boost::system::error_code& ec) { - using namespace std; // For memcpy. - - ::DCB dcb; - memset(&dcb, 0, sizeof(DCB)); - dcb.DCBlength = sizeof(DCB); - if (!::GetCommState(handle_service_.native(impl), &dcb)) - { - DWORD last_error = ::GetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return ec; - } - - if (option.store(dcb, ec)) - return ec; - - if (!::SetCommState(handle_service_.native(impl), &dcb)) - { - DWORD last_error = ::GetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return ec; - } - - ec = boost::system::error_code(); - return ec; + return do_set_option(impl, + &win_iocp_serial_port_service::store_option, + &option, ec); } // Get an option from the serial port. @@ -216,20 +112,9 @@ public: boost::system::error_code get_option(const implementation_type& impl, GettableSerialPortOption& option, boost::system::error_code& ec) const { - using namespace std; // For memcpy. - - ::DCB dcb; - memset(&dcb, 0, sizeof(DCB)); - dcb.DCBlength = sizeof(DCB); - if (!::GetCommState(handle_service_.native(impl), &dcb)) - { - DWORD last_error = ::GetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return ec; - } - - return option.load(dcb, ec); + return do_get_option(impl, + &win_iocp_serial_port_service::load_option, + &option, ec); } // Send a break sequence to the serial port. @@ -275,6 +160,41 @@ public: } private: + // Function pointer type for storing a serial port option. + typedef boost::system::error_code (*store_function_type)( + const void*, ::DCB&, boost::system::error_code&); + + // Helper function template to store a serial port option. + template + static boost::system::error_code store_option(const void* option, + ::DCB& storage, boost::system::error_code& ec) + { + return static_cast(option)->store( + storage, ec); + } + + // Helper function to set a serial port option. + BOOST_ASIO_DECL boost::system::error_code do_set_option( + implementation_type& impl, store_function_type store, + const void* option, boost::system::error_code& ec); + + // Function pointer type for loading a serial port option. + typedef boost::system::error_code (*load_function_type)( + void*, const ::DCB&, boost::system::error_code&); + + // Helper function template to load a serial port option. + template + static boost::system::error_code load_option(void* option, + const ::DCB& storage, boost::system::error_code& ec) + { + return static_cast(option)->load(storage, ec); + } + + // Helper function to get a serial port option. + BOOST_ASIO_DECL boost::system::error_code do_get_option( + const implementation_type& impl, load_function_type load, + void* option, boost::system::error_code& ec) const; + // The implementation used for initiating asynchronous operations. win_iocp_handle_service handle_service_; }; @@ -283,8 +203,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_IOCP) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_IOCP) && defined(BOOST_ASIO_HAS_SERIAL_PORT) + #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP diff --git a/include/boost/asio/detail/win_iocp_socket_accept_op.hpp b/include/boost/asio/detail/win_iocp_socket_accept_op.hpp new file mode 100644 index 00000000..89dff0c6 --- /dev/null +++ b/include/boost/asio/detail/win_iocp_socket_accept_op.hpp @@ -0,0 +1,160 @@ +// +// detail/win_iocp_socket_accept_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SOCKET_ACCEPT_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_socket_accept_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_accept_op); + + win_iocp_socket_accept_op(win_iocp_socket_service_base& socket_service, + socket_type socket, Socket& peer, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, + bool enable_connection_aborted, Handler handler) + : operation(&win_iocp_socket_accept_op::do_complete), + socket_service_(socket_service), + socket_(socket), + peer_(peer), + protocol_(protocol), + peer_endpoint_(peer_endpoint), + enable_connection_aborted_(enable_connection_aborted), + handler_(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(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t /*bytes_transferred*/) + { + // Take ownership of the operation object. + win_iocp_socket_accept_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + + 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 Socket::native_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; + } + + // 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(o->handler_, ec); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + win_iocp_socket_service_base& socket_service_; + socket_type socket_; + socket_holder new_socket_; + 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_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP diff --git a/include/boost/asio/detail/win_iocp_socket_recv_op.hpp b/include/boost/asio/detail/win_iocp_socket_recv_op.hpp new file mode 100644 index 00000000..98d7e99e --- /dev/null +++ b/include/boost/asio/detail/win_iocp_socket_recv_op.hpp @@ -0,0 +1,110 @@ +// +// detail/win_iocp_socket_recv_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SOCKET_RECV_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_socket_recv_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recv_op); + + win_iocp_socket_recv_op(socket_ops::state_type state, + socket_ops::weak_cancel_token_type cancel_token, + const MutableBufferSequence& buffers, Handler handler) + : operation(&win_iocp_socket_recv_op::do_complete), + state_(state), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_socket_recv_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_recv(o->state_, o->cancel_token_, + buffer_sequence_adapter::all_empty(o->buffers_), + ec, bytes_transferred); + + // 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(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + socket_ops::state_type state_; + socket_ops::weak_cancel_token_type cancel_token_; + MutableBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP diff --git a/include/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp b/include/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp new file mode 100644 index 00000000..eca34df7 --- /dev/null +++ b/include/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp @@ -0,0 +1,118 @@ +// +// detail/win_iocp_socket_recvfrom_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SOCKET_RECVFROM_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_socket_recvfrom_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvfrom_op); + + win_iocp_socket_recvfrom_op(Endpoint& endpoint, + socket_ops::weak_cancel_token_type cancel_token, + const MutableBufferSequence& buffers, Handler handler) + : operation(&win_iocp_socket_recvfrom_op::do_complete), + endpoint_(endpoint), + endpoint_size_(static_cast(endpoint.capacity())), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(handler) + { + } + + int& endpoint_size() + { + return endpoint_size_; + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_socket_recvfrom_op* o( + static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_recvfrom(o->cancel_token_, ec); + + // Record the size of the endpoint returned by the operation. + o->endpoint_.resize(o->endpoint_size_); + + // 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(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + Endpoint& endpoint_; + int endpoint_size_; + socket_ops::weak_cancel_token_type cancel_token_; + MutableBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP diff --git a/include/boost/asio/detail/win_iocp_socket_send_op.hpp b/include/boost/asio/detail/win_iocp_socket_send_op.hpp new file mode 100644 index 00000000..2dcb4af4 --- /dev/null +++ b/include/boost/asio/detail/win_iocp_socket_send_op.hpp @@ -0,0 +1,104 @@ +// +// detail/win_iocp_socket_send_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SOCKET_SEND_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_socket_send_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_send_op); + + win_iocp_socket_send_op(socket_ops::weak_cancel_token_type cancel_token, + const ConstBufferSequence& buffers, Handler handler) + : operation(&win_iocp_socket_send_op::do_complete), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(handler) + { + } + + static void do_complete(io_service_impl* owner, operation* base, + boost::system::error_code ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_socket_send_op* o(static_cast(base)); + ptr p = { boost::addressof(o->handler_), o, o }; + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_send(o->cancel_token_, ec); + + // 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(o->handler_, ec, bytes_transferred); + p.h = boost::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + boost::asio::detail::fenced_block b; + boost_asio_handler_invoke_helpers::invoke(handler, handler.handler_); + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + ConstBufferSequence buffers_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP diff --git a/include/boost/asio/detail/win_iocp_socket_service.hpp b/include/boost/asio/detail/win_iocp_socket_service.hpp index 5d545a87..6f1f2bd4 100644 --- a/include/boost/asio/detail/win_iocp_socket_service.hpp +++ b/include/boost/asio/detail/win_iocp_socket_service.hpp @@ -1,6 +1,6 @@ // -// win_iocp_socket_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_iocp_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,19 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_IOCP) -#include #include -#include -#include -#include -#include - +#include #include #include #include @@ -37,21 +30,28 @@ #include #include #include -#include #include +#include #include #include #include #include #include #include +#include +#include +#include +#include +#include + +#include namespace boost { namespace asio { namespace detail { template -class win_iocp_socket_service +class win_iocp_socket_service : public win_iocp_socket_service_base { public: // The protocol type. @@ -60,10 +60,6 @@ public: // The endpoint type. typedef typename Protocol::endpoint endpoint_type; - struct noop_deleter { void operator()(void*) {} }; - typedef boost::shared_ptr shared_cancel_token_type; - typedef boost::weak_ptr weak_cancel_token_type; - // The native type of a socket. class native_type { @@ -93,11 +89,6 @@ public: return socket_; } - HANDLE as_handle() const - { - return reinterpret_cast(socket_); - } - bool have_remote_endpoint() const { return have_remote_endpoint_; @@ -115,148 +106,44 @@ public: }; // The implementation type of the socket. - class implementation_type + struct implementation_type : + win_iocp_socket_service_base::base_implementation_type { - public: // Default constructor. implementation_type() - : socket_(invalid_socket), - flags_(0), - cancel_token_(), - protocol_(endpoint_type().protocol()), - next_(0), - prev_(0) + : protocol_(endpoint_type().protocol()), + have_remote_endpoint_(false), + remote_endpoint_() { } - private: - // Only this service will have access to the internal values. - friend class win_iocp_socket_service; - - // The native socket representation. - native_type socket_; - - enum - { - enable_connection_aborted = 1, // User wants connection_aborted errors. - close_might_block = 2, // User set linger option for blocking close. - user_set_non_blocking = 4 // The user wants a non-blocking socket. - }; - - // Flags indicating the current state of the socket. - unsigned char flags_; - - // We use a shared pointer as a cancellation token here to work around the - // broken Windows support for cancellation. MSDN says that when you call - // closesocket any outstanding WSARecv or WSASend operations will complete - // with the error ERROR_OPERATION_ABORTED. In practice they complete with - // ERROR_NETNAME_DELETED, which means you can't tell the difference between - // a local cancellation and the socket being hard-closed by the peer. - shared_cancel_token_type cancel_token_; - // The protocol associated with the socket. protocol_type protocol_; - // Per-descriptor data used by the reactor. - reactor::per_descriptor_data reactor_data_; + // Whether we have a cached remote endpoint. + bool have_remote_endpoint_; -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - // The ID of the thread from which it is safe to cancel asynchronous - // operations. 0 means no asynchronous operations have been started yet. - // ~0 means asynchronous operations have been started from more than one - // thread, and cancellation is not supported for the socket. - DWORD safe_cancellation_thread_id_; -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - - // Pointers to adjacent socket implementations in linked list. - implementation_type* next_; - implementation_type* prev_; + // A cached remote endpoint. + endpoint_type remote_endpoint_; }; // Constructor. win_iocp_socket_service(boost::asio::io_service& io_service) - : io_service_(io_service), - iocp_service_(use_service(io_service)), - reactor_(0), - mutex_(), - impl_list_(0) + : win_iocp_socket_service_base(io_service) { } - // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - // Close all implementations, causing all operations to complete. - boost::asio::detail::mutex::scoped_lock lock(mutex_); - implementation_type* impl = impl_list_; - while (impl) - { - boost::system::error_code ignored_ec; - close_for_destruction(*impl); - impl = impl->next_; - } - } - - // Construct a new socket implementation. - void construct(implementation_type& impl) - { - impl.socket_ = invalid_socket; - impl.flags_ = 0; - impl.cancel_token_.reset(); -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - impl.safe_cancellation_thread_id_ = 0; -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - - // Insert implementation into linked list of all implementations. - boost::asio::detail::mutex::scoped_lock lock(mutex_); - impl.next_ = impl_list_; - impl.prev_ = 0; - if (impl_list_) - impl_list_->prev_ = &impl; - impl_list_ = &impl; - } - - // Destroy a socket implementation. - void destroy(implementation_type& impl) - { - close_for_destruction(impl); - - // Remove implementation from linked list of all implementations. - boost::asio::detail::mutex::scoped_lock lock(mutex_); - if (impl_list_ == &impl) - impl_list_ = impl.next_; - if (impl.prev_) - impl.prev_->next_ = impl.next_; - if (impl.next_) - impl.next_->prev_= impl.prev_; - impl.next_ = 0; - impl.prev_ = 0; - } - // Open a new socket implementation. boost::system::error_code open(implementation_type& impl, const protocol_type& protocol, boost::system::error_code& ec) { - if (is_open(impl)) + if (!do_open(impl, protocol.family(), + protocol.type(), protocol.protocol(), ec)) { - ec = boost::asio::error::already_open; - return ec; + impl.protocol_ = protocol; + impl.have_remote_endpoint_ = false; + impl.remote_endpoint_ = endpoint_type(); } - - socket_holder sock(socket_ops::socket(protocol.family(), protocol.type(), - protocol.protocol(), ec)); - if (sock.get() == invalid_socket) - return ec; - - HANDLE sock_as_handle = reinterpret_cast(sock.get()); - if (iocp_service_.register_handle(sock_as_handle, ec)) - return ec; - - impl.socket_ = sock.release(); - impl.flags_ = 0; - impl.cancel_token_.reset(static_cast(0), noop_deleter()); - impl.protocol_ = protocol; - ec = boost::system::error_code(); return ec; } @@ -265,247 +152,40 @@ public: const protocol_type& protocol, const native_type& native_socket, boost::system::error_code& ec) { - if (is_open(impl)) + if (!do_assign(impl, protocol.type(), native_socket, ec)) { - ec = boost::asio::error::already_open; - return ec; + impl.protocol_ = protocol; + impl.have_remote_endpoint_ = native_socket.have_remote_endpoint(); + impl.remote_endpoint_ = native_socket.remote_endpoint(); } - - if (iocp_service_.register_handle(native_socket.as_handle(), ec)) - return ec; - - impl.socket_ = native_socket; - impl.flags_ = 0; - impl.cancel_token_.reset(static_cast(0), noop_deleter()); - impl.protocol_ = protocol; - ec = boost::system::error_code(); - return ec; - } - - // Determine whether the socket is open. - bool is_open(const implementation_type& impl) const - { - return impl.socket_ != invalid_socket; - } - - // Destroy a socket implementation. - boost::system::error_code close(implementation_type& impl, - boost::system::error_code& ec) - { - if (is_open(impl)) - { - // 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( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (r) - r->close_descriptor(impl.socket_, impl.reactor_data_); - - if (socket_ops::close(impl.socket_, ec) == socket_error_retval) - return ec; - - impl.socket_ = invalid_socket; - impl.flags_ = 0; - impl.cancel_token_.reset(); -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - impl.safe_cancellation_thread_id_ = 0; -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - } - - ec = boost::system::error_code(); return ec; } // Get the native socket representation. native_type native(implementation_type& impl) { - return impl.socket_; - } - - // Cancel all operations associated with the socket. - boost::system::error_code cancel(implementation_type& impl, - boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( - ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) - { - // The version of Windows supports cancellation from any thread. - typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); - cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; - socket_type sock = impl.socket_; - HANDLE sock_as_handle = reinterpret_cast(sock); - if (!cancel_io_ex(sock_as_handle, 0)) - { - DWORD last_error = ::GetLastError(); - if (last_error == ERROR_NOT_FOUND) - { - // ERROR_NOT_FOUND means that there were no operations to be - // cancelled. We swallow this error to match the behaviour on other - // platforms. - ec = boost::system::error_code(); - } - else - { - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - } - } - else - { - ec = boost::system::error_code(); - } - } -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - else if (impl.safe_cancellation_thread_id_ == 0) - { - // No operations have been started, so there's nothing to cancel. - ec = boost::system::error_code(); - } - else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) - { - // Asynchronous operations have been started from the current thread only, - // so it is safe to try to cancel them using CancelIo. - socket_type sock = impl.socket_; - HANDLE sock_as_handle = reinterpret_cast(sock); - if (!::CancelIo(sock_as_handle)) - { - DWORD last_error = ::GetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - } - else - { - ec = boost::system::error_code(); - } - } - else - { - // Asynchronous operations have been started from more than one thread, - // so cancellation is not safe. - ec = boost::asio::error::operation_not_supported; - } -#else // defined(BOOST_ASIO_ENABLE_CANCELIO) - else - { - // Cancellation is not supported as CancelIo may not be used. - ec = boost::asio::error::operation_not_supported; - } -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - - return ec; - } - - // Determine whether the socket is at the out-of-band data mark. - bool at_mark(const implementation_type& impl, - boost::system::error_code& ec) const - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return false; - } - - boost::asio::detail::ioctl_arg_type value = 0; - socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec); - return ec ? false : value != 0; - } - - // Determine the number of bytes available for reading. - std::size_t available(const implementation_type& impl, - boost::system::error_code& ec) const - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - boost::asio::detail::ioctl_arg_type value = 0; - socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec); - return ec ? static_cast(0) : static_cast(value); + if (impl.have_remote_endpoint_) + return native_type(impl.socket_, impl.remote_endpoint_); + return native_type(impl.socket_); } // Bind the socket to the specified local endpoint. boost::system::error_code bind(implementation_type& impl, const endpoint_type& endpoint, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); return ec; } - // Place the socket into the state where it will listen for new connections. - boost::system::error_code listen(implementation_type& impl, int backlog, - boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - socket_ops::listen(impl.socket_, backlog, ec); - return ec; - } - // Set a socket option. template boost::system::error_code set_option(implementation_type& impl, const Option& option, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - if (option.level(impl.protocol_) == custom_socket_option_level - && option.name(impl.protocol_) == enable_connection_aborted_option) - { - if (option.size(impl.protocol_) != sizeof(int)) - { - ec = boost::asio::error::invalid_argument; - } - else - { - if (*reinterpret_cast(option.data(impl.protocol_))) - impl.flags_ |= implementation_type::enable_connection_aborted; - else - impl.flags_ &= ~implementation_type::enable_connection_aborted; - ec = boost::system::error_code(); - } - return ec; - } - else - { - if (option.level(impl.protocol_) == SOL_SOCKET - && option.name(impl.protocol_) == SO_LINGER) - { - const ::linger* linger_option = - reinterpret_cast(option.data(impl.protocol_)); - if (linger_option->l_onoff != 0 && linger_option->l_linger != 0) - impl.flags_ |= implementation_type::close_might_block; - else - impl.flags_ &= ~implementation_type::close_might_block; - } - - socket_ops::setsockopt(impl.socket_, - option.level(impl.protocol_), option.name(impl.protocol_), - option.data(impl.protocol_), option.size(impl.protocol_), ec); - return ec; - } + socket_ops::setsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), option.size(impl.protocol_), ec); + return ec; } // Set a socket option. @@ -513,65 +193,12 @@ public: boost::system::error_code get_option(const implementation_type& impl, Option& option, boost::system::error_code& ec) const { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - if (option.level(impl.protocol_) == custom_socket_option_level - && option.name(impl.protocol_) == enable_connection_aborted_option) - { - if (option.size(impl.protocol_) != sizeof(int)) - { - ec = boost::asio::error::invalid_argument; - } - else - { - int* target = reinterpret_cast(option.data(impl.protocol_)); - if (impl.flags_ & implementation_type::enable_connection_aborted) - *target = 1; - else - *target = 0; - option.resize(impl.protocol_, sizeof(int)); - ec = boost::system::error_code(); - } - return ec; - } - else - { - size_t size = option.size(impl.protocol_); - socket_ops::getsockopt(impl.socket_, - option.level(impl.protocol_), option.name(impl.protocol_), - option.data(impl.protocol_), &size, ec); - if (!ec) - option.resize(impl.protocol_, size); - return ec; - } - } - - // Perform an IO control command on the socket. - template - boost::system::error_code io_control(implementation_type& impl, - IO_Control_Command& command, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - socket_ops::ioctl(impl.socket_, command.name(), - static_cast(command.data()), ec); - - if (!ec && command.name() == static_cast(FIONBIO)) - { - if (*static_cast(command.data())) - impl.flags_ |= implementation_type::user_set_non_blocking; - else - impl.flags_ &= ~implementation_type::user_set_non_blocking; - } - + std::size_t size = option.size(impl.protocol_); + socket_ops::getsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); return ec; } @@ -579,12 +206,6 @@ public: endpoint_type local_endpoint(const implementation_type& impl, boost::system::error_code& ec) const { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return endpoint_type(); - } - endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) @@ -597,210 +218,13 @@ public: endpoint_type remote_endpoint(const implementation_type& impl, boost::system::error_code& ec) const { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; + endpoint_type endpoint = impl.remote_endpoint_; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getpeername(impl.socket_, endpoint.data(), + &addr_len, impl.have_remote_endpoint_, ec)) return endpoint_type(); - } - - if (impl.socket_.have_remote_endpoint()) - { - // Check if socket is still connected. - DWORD connect_time = 0; - size_t connect_time_len = sizeof(connect_time); - if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_CONNECT_TIME, - &connect_time, &connect_time_len, ec) == socket_error_retval) - { - return endpoint_type(); - } - if (connect_time == 0xFFFFFFFF) - { - ec = boost::asio::error::not_connected; - return endpoint_type(); - } - - ec = boost::system::error_code(); - return impl.socket_.remote_endpoint(); - } - else - { - endpoint_type endpoint; - std::size_t addr_len = endpoint.capacity(); - if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec)) - return endpoint_type(); - endpoint.resize(addr_len); - return endpoint; - } - } - - /// Disable sends or receives on the socket. - boost::system::error_code shutdown(implementation_type& impl, - socket_base::shutdown_type what, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - socket_ops::shutdown(impl.socket_, what, ec); - return ec; - } - - // Send the given data to the peer. Returns the number of bytes sent. - template - size_t send(implementation_type& impl, const ConstBufferSequence& buffers, - socket_base::message_flags flags, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - buffer_sequence_adapter bufs(buffers); - - // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) - { - ec = boost::system::error_code(); - return 0; - } - - // Send the data. - DWORD bytes_transferred = 0; - int result = ::WSASend(impl.socket_, bufs.buffers(), - bufs.count(), &bytes_transferred, flags, 0, 0); - if (result != 0) - { - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_NETNAME_DELETED) - last_error = WSAECONNRESET; - else if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return 0; - } - - ec = boost::system::error_code(); - return bytes_transferred; - } - - // Wait until data can be sent without blocking. - size_t send(implementation_type& impl, const null_buffers&, - socket_base::message_flags, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - // Wait for socket to become ready. - socket_ops::poll_write(impl.socket_, ec); - - return 0; - } - - template - class send_op : public operation - { - public: - send_op(weak_cancel_token_type cancel_token, - const ConstBufferSequence& buffers, Handler handler) - : operation(&send_op::do_complete), - cancel_token_(cancel_token), - buffers_(buffers), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - send_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter::validate(o->buffers_); -#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - - // 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::binder2 - handler(o->handler_, ec, bytes_transferred); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - weak_cancel_token_type cancel_token_; - ConstBufferSequence buffers_; - Handler handler_; - }; - - // Start an asynchronous send. The data being sent must be valid for the - // lifetime of the asynchronous operation. - template - void async_send(implementation_type& impl, const ConstBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef send_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, - impl.cancel_token_, buffers, handler); - - buffer_sequence_adapter bufs(buffers); - - start_send_op(impl, bufs.buffers(), bufs.count(), flags, - impl.protocol_.type() == SOCK_STREAM && bufs.all_empty(), ptr.get()); - ptr.release(); - } - - // Start an asynchronous wait until data can be sent without blocking. - template - void async_send(implementation_type& impl, const null_buffers&, - socket_base::message_flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); - - start_reactor_op(impl, reactor::write_op, ptr.get()); - ptr.release(); + endpoint.resize(addr_len); + return endpoint; } // Send a datagram to the specified endpoint. Returns the number of bytes @@ -810,107 +234,25 @@ public: const endpoint_type& destination, socket_base::message_flags flags, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter bufs(buffers); - // Send the data. - DWORD bytes_transferred = 0; - int result = ::WSASendTo(impl.socket_, bufs.buffers(), bufs.count(), - &bytes_transferred, flags, destination.data(), - static_cast(destination.size()), 0, 0); - if (result != 0) - { - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return 0; - } - - ec = boost::system::error_code(); - return bytes_transferred; + return socket_ops::sync_sendto(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, + destination.data(), destination.size(), ec); } // Wait until data can be sent without blocking. size_t send_to(implementation_type& impl, const null_buffers&, - socket_base::message_flags, const endpoint_type&, + const endpoint_type&, socket_base::message_flags, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - // Wait for socket to become ready. socket_ops::poll_write(impl.socket_, ec); return 0; } - template - class send_to_op : public operation - { - public: - send_to_op(weak_cancel_token_type cancel_token, - const ConstBufferSequence& buffers, Handler handler) - : operation(&send_to_op::do_complete), - cancel_token_(cancel_token), - buffers_(buffers), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - send_to_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter::validate(o->buffers_); -#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - - // Map non-portable errors to their portable counterparts. - 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::binder2 - handler(o->handler_, ec, bytes_transferred); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - weak_cancel_token_type cancel_token_; - ConstBufferSequence buffers_; - Handler handler_; - }; - // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. template @@ -919,233 +261,35 @@ public: socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef send_to_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, - impl.cancel_token_, buffers, handler); + typedef win_iocp_socket_send_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, buffers, handler); buffer_sequence_adapter bufs(buffers); - start_send_to_op(impl, bufs.buffers(), - bufs.count(), destination, flags, ptr.get()); - ptr.release(); + start_send_to_op(impl, bufs.buffers(), bufs.count(), + destination.data(), static_cast(destination.size()), + flags, p.p); + p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. template void async_send_to(implementation_type& impl, const null_buffers&, - socket_base::message_flags, const endpoint_type&, Handler handler) + const endpoint_type&, socket_base::message_flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); - start_reactor_op(impl, reactor::write_op, ptr.get()); - ptr.release(); - } - - // Receive some data from the peer. Returns the number of bytes received. - template - size_t receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - buffer_sequence_adapter bufs(buffers); - - // A request to receive 0 bytes on a stream socket is a no-op. - if (impl.protocol_.type() == SOCK_STREAM && bufs.all_empty()) - { - ec = boost::system::error_code(); - return 0; - } - - // Receive some data. - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = ::WSARecv(impl.socket_, bufs.buffers(), - bufs.count(), &bytes_transferred, &recv_flags, 0, 0); - if (result != 0) - { - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_NETNAME_DELETED) - last_error = WSAECONNRESET; - else if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return 0; - } - if (bytes_transferred == 0 && impl.protocol_.type() == SOCK_STREAM) - { - ec = boost::asio::error::eof; - return 0; - } - - ec = boost::system::error_code(); - return bytes_transferred; - } - - // Wait until data can be received without blocking. - size_t receive(implementation_type& impl, const null_buffers&, - socket_base::message_flags, boost::system::error_code& ec) - { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - - // Wait for socket to become ready. - socket_ops::poll_read(impl.socket_, ec); - - return 0; - } - - template - class receive_op : public operation - { - public: - receive_op(int protocol_type, weak_cancel_token_type cancel_token, - const MutableBufferSequence& buffers, Handler handler) - : operation(&receive_op::do_complete), - protocol_type_(protocol_type), - cancel_token_(cancel_token), - buffers_(buffers), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - receive_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter::validate(o->buffers_); -#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - - // 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; - } - - // Check for connection closed. - else if (!ec && bytes_transferred == 0 - && o->protocol_type_ == SOCK_STREAM - && !buffer_sequence_adapter::all_empty(o->buffers_) - && !boost::is_same::value) - { - ec = boost::asio::error::eof; - } - - // 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(o->handler_, ec, bytes_transferred); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - int protocol_type_; - weak_cancel_token_type cancel_token_; - MutableBufferSequence buffers_; - Handler handler_; - }; - - // Start an asynchronous receive. The buffer for the data being received - // must be valid for the lifetime of the asynchronous operation. - template - void async_receive(implementation_type& impl, - const MutableBufferSequence& buffers, - socket_base::message_flags flags, Handler handler) - { - // Allocate and construct an operation to wrap the handler. - typedef receive_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - int protocol_type = impl.protocol_.type(); - handler_ptr ptr(raw_ptr, protocol_type, - impl.cancel_token_, buffers, handler); - - buffer_sequence_adapter bufs(buffers); - - start_receive_op(impl, bufs.buffers(), bufs.count(), flags, - protocol_type == SOCK_STREAM && bufs.all_empty(), ptr.get()); - ptr.release(); - } - - // Wait until data can be received without blocking. - template - void async_receive(implementation_type& impl, const null_buffers& buffers, - socket_base::message_flags flags, Handler handler) - { - if (impl.protocol_.type() == SOCK_STREAM) - { - // For stream sockets on Windows, we may issue a 0-byte overlapped - // WSARecv to wait until there is data available on the socket. - - // Allocate and construct an operation to wrap the handler. - typedef receive_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - int protocol_type = impl.protocol_.type(); - handler_ptr ptr(raw_ptr, protocol_type, - impl.cancel_token_, buffers, handler); - - ::WSABUF buf = { 0, 0 }; - start_receive_op(impl, &buf, 1, flags, false, ptr.get()); - ptr.release(); - } - else - { - // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); - - start_reactor_op(impl, - (flags & socket_base::message_out_of_band) - ? reactor::except_op : reactor::read_op, - ptr.get()); - ptr.release(); - } + start_reactor_op(impl, reactor::write_op, p.p); + p.v = p.p = 0; } // Receive a datagram with the endpoint of the sender. Returns the number of @@ -1156,41 +300,18 @@ public: endpoint_type& sender_endpoint, socket_base::message_flags flags, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - buffer_sequence_adapter bufs(buffers); - // Receive some data. - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int endpoint_size = static_cast(sender_endpoint.capacity()); - int result = ::WSARecvFrom(impl.socket_, bufs.buffers(), - bufs.count(), &bytes_transferred, &recv_flags, - sender_endpoint.data(), &endpoint_size, 0, 0); - if (result != 0) - { - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - return 0; - } - if (bytes_transferred == 0 && impl.protocol_.type() == SOCK_STREAM) - { - ec = boost::asio::error::eof; - return 0; - } + std::size_t addr_len = sender_endpoint.capacity(); + std::size_t bytes_recvd = socket_ops::sync_recvfrom( + impl.socket_, impl.state_, bufs.buffers(), bufs.count(), + flags, sender_endpoint.data(), &addr_len, ec); - sender_endpoint.resize(static_cast(endpoint_size)); + if (!ec) + sender_endpoint.resize(addr_len); - ec = boost::system::error_code(); - return bytes_transferred; + return bytes_recvd; } // Wait until data can be received without blocking. @@ -1198,12 +319,6 @@ public: const null_buffers&, endpoint_type& sender_endpoint, socket_base::message_flags, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return 0; - } - // Wait for socket to become ready. socket_ops::poll_read(impl.socket_, ec); @@ -1213,75 +328,6 @@ public: return 0; } - template - class receive_from_op : public operation - { - public: - receive_from_op(int protocol_type, endpoint_type& endpoint, - const MutableBufferSequence& buffers, Handler handler) - : operation(&receive_from_op::do_complete), - protocol_type_(protocol_type), - endpoint_(endpoint), - endpoint_size_(static_cast(endpoint.capacity())), - buffers_(buffers), - handler_(handler) - { - } - - int& endpoint_size() - { - return endpoint_size_; - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code ec, std::size_t bytes_transferred) - { - // Take ownership of the operation object. - receive_from_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { -#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - // Check whether buffers are still valid. - buffer_sequence_adapter::validate(o->buffers_); -#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) - - // Map non-portable errors to their portable counterparts. - if (ec.value() == ERROR_PORT_UNREACHABLE) - { - ec = boost::asio::error::connection_refused; - } - - // Record the size of the endpoint returned by the operation. - o->endpoint_.resize(o->endpoint_size_); - - // 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(o->handler_, ec, bytes_transferred); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - int protocol_type_; - endpoint_type& endpoint_; - int endpoint_size_; - weak_cancel_token_type cancel_token_; - MutableBufferSequence buffers_; - Handler handler_; - }; - // Start an asynchronous receive. The buffer for the data being received and // the sender_endpoint object must both be valid for the lifetime of the // asynchronous operation. @@ -1291,19 +337,19 @@ public: socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef receive_from_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - int protocol_type = impl.protocol_.type(); - handler_ptr ptr(raw_ptr, - protocol_type, sender_endp, buffers, handler); + typedef win_iocp_socket_recvfrom_op< + MutableBufferSequence, endpoint_type, Handler> op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(sender_endp, impl.cancel_token_, buffers, handler); buffer_sequence_adapter bufs(buffers); start_receive_from_op(impl, bufs.buffers(), bufs.count(), - sender_endp, flags, &ptr.get()->endpoint_size(), ptr.get()); - ptr.release(); + sender_endp.data(), flags, &p.p->endpoint_size(), p.p); + p.v = p.p = 0; } // Wait until data can be received without blocking. @@ -1313,19 +359,17 @@ public: socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef null_buffers_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); - start_reactor_op(impl, - (flags & socket_base::message_out_of_band) - ? reactor::except_op : reactor::read_op, - ptr.get()); - ptr.release(); + start_null_buffers_receive_op(impl, flags, p.p); + p.v = p.p = 0; } // Accept a new connection. @@ -1333,12 +377,6 @@ public: boost::system::error_code accept(implementation_type& impl, Socket& peer, endpoint_type* peer_endpoint, boost::system::error_code& ec) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - // We cannot accept a socket that is already open. if (peer.is_open()) { @@ -1346,223 +384,23 @@ public: return ec; } - for (;;) + 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() >= 0) { - socket_holder new_socket; - std::size_t addr_len = 0; - if (peer_endpoint) - { - addr_len = peer_endpoint->capacity(); - new_socket.reset(socket_ops::accept(impl.socket_, - peer_endpoint->data(), &addr_len, ec)); - } - else - { - new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec)); - } - - if (ec) - { - if (ec == boost::asio::error::connection_aborted - && !(impl.flags_ & implementation_type::enable_connection_aborted)) - { - // Retry accept operation. - continue; - } - else - { - return ec; - } - } - if (peer_endpoint) peer_endpoint->resize(addr_len); - - peer.assign(impl.protocol_, new_socket.get(), ec); - if (!ec) + if (!peer.assign(impl.protocol_, new_socket.get(), ec)) new_socket.release(); - return ec; } + + return ec; } - template - class accept_op : public operation - { - public: - accept_op(win_iocp_io_service& iocp_service, socket_type socket, - Socket& peer, const protocol_type& protocol, - endpoint_type* peer_endpoint, bool enable_connection_aborted, - Handler handler) - : operation(&accept_op::do_complete), - iocp_service_(iocp_service), - socket_(socket), - peer_(peer), - protocol_(protocol), - peer_endpoint_(peer_endpoint), - enable_connection_aborted_(enable_connection_aborted), - handler_(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(io_service_impl* owner, operation* base, - boost::system::error_code ec, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - accept_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // Map Windows error ERROR_NETNAME_DELETED to connection_aborted. - if (ec.value() == ERROR_NETNAME_DELETED) - { - ec = boost::asio::error::connection_aborted; - } - - // 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_) - { - // Reset OVERLAPPED structure. - o->reset(); - - // Create a new socket for the next connection, since the AcceptEx - // call fails with WSAEINVAL if we try to reuse the same socket. - o->new_socket_.reset(); - o->new_socket_.reset(socket_ops::socket(o->protocol_.family(), - o->protocol_.type(), o->protocol_.protocol(), ec)); - if (o->new_socket_.get() != invalid_socket) - { - // Accept a connection. - DWORD bytes_read = 0; - BOOL result = ::AcceptEx(o->socket_, o->new_socket_.get(), - o->output_buffer(), 0, o->address_length(), - o->address_length(), &bytes_read, o); - DWORD last_error = ::WSAGetLastError(); - ec = boost::system::error_code(last_error, - boost::asio::error::get_system_category()); - - // Check if the operation completed immediately. - if (!result && last_error != WSA_IO_PENDING) - { - if (last_error == ERROR_NETNAME_DELETED - || last_error == WSAECONNABORTED) - { - // Post this handler so that operation will be restarted again. - o->iocp_service_.work_started(); - o->iocp_service_.on_completion(o, ec); - ptr.release(); - return; - } - else - { - // Operation already complete. Continue with rest of this - // handler. - } - } - else - { - // Asynchronous operation has been successfully restarted. - o->iocp_service_.work_started(); - o->iocp_service_.on_pending(o); - ptr.release(); - return; - } - } - } - - // Get the address of the peer. - endpoint_type peer_endpoint; - if (!ec) - { - LPSOCKADDR local_addr = 0; - int local_addr_length = 0; - LPSOCKADDR remote_addr = 0; - int remote_addr_length = 0; - GetAcceptExSockaddrs(o->output_buffer(), 0, o->address_length(), - o->address_length(), &local_addr, &local_addr_length, - &remote_addr, &remote_addr_length); - if (static_cast(remote_addr_length) - > peer_endpoint.capacity()) - { - ec = boost::asio::error::invalid_argument; - } - else - { - using namespace std; // For memcpy. - memcpy(peer_endpoint.data(), remote_addr, remote_addr_length); - peer_endpoint.resize(static_cast(remote_addr_length)); - } - } - - // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname - // and getpeername will work on the accepted socket. - if (!ec) - { - SOCKET update_ctx_param = o->socket_; - socket_ops::setsockopt(o->new_socket_.get(), - SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, - &update_ctx_param, sizeof(SOCKET), ec); - } - - // If the socket was successfully accepted, transfer ownership of the - // socket to the peer object. - if (!ec) - { - o->peer_.assign(o->protocol_, - native_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; - - // 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(o->handler_, ec); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - win_iocp_io_service& iocp_service_; - socket_type socket_; - socket_holder new_socket_; - Socket& peer_; - protocol_type protocol_; - endpoint_type* peer_endpoint_; - unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; - bool enable_connection_aborted_; - Handler handler_; - }; - // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. template @@ -1570,443 +408,55 @@ public: endpoint_type* peer_endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef accept_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); + typedef win_iocp_socket_accept_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; bool enable_connection_aborted = - (impl.flags_ & implementation_type::enable_connection_aborted); - handler_ptr ptr(raw_ptr, iocp_service_, impl.socket_, peer, - impl.protocol_, peer_endpoint, enable_connection_aborted, handler); + (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); - start_accept_op(impl, peer.is_open(), ptr.get()->new_socket(), - ptr.get()->output_buffer(), ptr.get()->address_length(), ptr.get()); - ptr.release(); + start_accept_op(impl, peer.is_open(), 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; } // 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) { - if (!is_open(impl)) - { - ec = boost::asio::error::bad_descriptor; - return ec; - } - - // Perform the connect operation. - socket_ops::connect(impl.socket_, + socket_ops::sync_connect(impl.socket_, peer_endpoint.data(), peer_endpoint.size(), ec); return ec; } - class connect_op_base : public reactor_op - { - public: - connect_op_base(socket_type socket, func_type complete_func) - : reactor_op(&connect_op_base::do_perform, complete_func), - socket_(socket) - { - } - - static bool do_perform(reactor_op* base) - { - connect_op_base* o(static_cast(base)); - - // Get the error code from the connect operation. - int connect_error = 0; - size_t connect_error_len = sizeof(connect_error); - if (socket_ops::getsockopt(o->socket_, SOL_SOCKET, SO_ERROR, - &connect_error, &connect_error_len, o->ec_) == socket_error_retval) - return true; - - // The connection failed so the handler will be posted with an error code. - if (connect_error) - { - o->ec_ = boost::system::error_code(connect_error, - boost::asio::error::get_system_category()); - } - - return true; - } - - private: - socket_type socket_; - }; - - template - class connect_op : public connect_op_base - { - public: - connect_op(socket_type socket, Handler handler) - : connect_op_base(socket, &connect_op::do_complete), - handler_(handler) - { - } - - static void do_complete(io_service_impl* owner, operation* base, - boost::system::error_code /*ec*/, std::size_t /*bytes_transferred*/) - { - // Take ownership of the handler object. - connect_op* o(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(o->handler_, o); - - // Make the upcall if required. - if (owner) - { - // 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(o->handler_, o->ec_); - ptr.reset(); - boost::asio::detail::fenced_block b; - boost_asio_handler_invoke_helpers::invoke(handler, handler); - } - } - - private: - Handler handler_; - }; - // Start an asynchronous connect. template void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef connect_op value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, impl.socket_, handler); + typedef reactive_socket_connect_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.socket_, handler); - start_connect_op(impl, ptr.get(), peer_endpoint); - ptr.release(); + start_connect_op(impl, p.p, peer_endpoint.data(), + static_cast(peer_endpoint.size())); + p.v = p.p = 0; } - -private: - // Helper function to start an asynchronous send operation. - void start_send_op(implementation_type& impl, WSABUF* buffers, - std::size_t buffer_count, socket_base::message_flags flags, - bool noop, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (noop) - iocp_service_.on_completion(op); - else if (!is_open(impl)) - iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); - else - { - DWORD bytes_transferred = 0; - int result = ::WSASend(impl.socket_, buffers, - buffer_count, &bytes_transferred, flags, op, 0); - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - if (result != 0 && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error, bytes_transferred); - else - iocp_service_.on_pending(op); - } - } - - // Helper function to start an asynchronous send_to operation. - void start_send_to_op(implementation_type& impl, WSABUF* buffers, - std::size_t buffer_count, const endpoint_type& destination, - socket_base::message_flags flags, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (!is_open(impl)) - iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); - else - { - DWORD bytes_transferred = 0; - int result = ::WSASendTo(impl.socket_, buffers, buffer_count, - &bytes_transferred, flags, destination.data(), - static_cast(destination.size()), op, 0); - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - if (result != 0 && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error, bytes_transferred); - else - iocp_service_.on_pending(op); - } - } - - // Helper function to start an asynchronous receive operation. - void start_receive_op(implementation_type& impl, WSABUF* buffers, - std::size_t buffer_count, socket_base::message_flags flags, - bool noop, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (noop) - iocp_service_.on_completion(op); - else if (!is_open(impl)) - iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); - else - { - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = ::WSARecv(impl.socket_, buffers, buffer_count, - &bytes_transferred, &recv_flags, op, 0); - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_NETNAME_DELETED) - last_error = WSAECONNRESET; - else if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - if (result != 0 && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error, bytes_transferred); - else - iocp_service_.on_pending(op); - } - } - - // Helper function to start an asynchronous receive_from operation. - void start_receive_from_op(implementation_type& impl, WSABUF* buffers, - std::size_t buffer_count, endpoint_type& sender_endpoint, - socket_base::message_flags flags, int* endpoint_size, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (!is_open(impl)) - iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); - else - { - DWORD bytes_transferred = 0; - DWORD recv_flags = flags; - int result = ::WSARecvFrom(impl.socket_, buffers, - buffer_count, &bytes_transferred, &recv_flags, - sender_endpoint.data(), endpoint_size, op, 0); - DWORD last_error = ::WSAGetLastError(); - if (last_error == ERROR_PORT_UNREACHABLE) - last_error = WSAECONNREFUSED; - if (result != 0 && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error, bytes_transferred); - else - iocp_service_.on_pending(op); - } - } - - // Helper function to start an asynchronous receive_from operation. - void start_accept_op(implementation_type& impl, - bool peer_is_open, socket_holder& new_socket, - void* output_buffer, DWORD address_length, operation* op) - { - update_cancellation_thread_id(impl); - iocp_service_.work_started(); - - if (!is_open(impl)) - iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); - else if (peer_is_open) - iocp_service_.on_completion(op, boost::asio::error::already_open); - else - { - boost::system::error_code ec; - new_socket.reset(socket_ops::socket(impl.protocol_.family(), - impl.protocol_.type(), impl.protocol_.protocol(), ec)); - if (new_socket.get() == invalid_socket) - iocp_service_.on_completion(op, ec); - else - { - DWORD bytes_read = 0; - BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer, - 0, address_length, address_length, &bytes_read, op); - DWORD last_error = ::WSAGetLastError(); - if (!result && last_error != WSA_IO_PENDING) - iocp_service_.on_completion(op, last_error); - else - iocp_service_.on_pending(op); - } - } - } - - // Start an asynchronous read or write operation using the the reactor. - void start_reactor_op(implementation_type& impl, int op_type, reactor_op* op) - { - reactor& r = get_reactor(); - update_cancellation_thread_id(impl); - - if (is_open(impl)) - { - r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false); - return; - } - else - op->ec_ = boost::asio::error::bad_descriptor; - - iocp_service_.post_immediate_completion(op); - } - - // Start the asynchronous connect operation using the reactor. - void start_connect_op(implementation_type& impl, - reactor_op* op, const endpoint_type& peer_endpoint) - { - reactor& r = get_reactor(); - update_cancellation_thread_id(impl); - - if (is_open(impl)) - { - ioctl_arg_type non_blocking = 1; - if (!socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, op->ec_)) - { - if (socket_ops::connect(impl.socket_, peer_endpoint.data(), - peer_endpoint.size(), op->ec_) != 0) - { - if (!op->ec_ - && !(impl.flags_ & implementation_type::user_set_non_blocking)) - { - non_blocking = 0; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, op->ec_); - } - - if (op->ec_ == boost::asio::error::in_progress - || op->ec_ == boost::asio::error::would_block) - { - op->ec_ = boost::system::error_code(); - r.start_op(reactor::connect_op, impl.socket_, - impl.reactor_data_, op, true); - return; - } - } - } - } - else - op->ec_ = boost::asio::error::bad_descriptor; - - iocp_service_.post_immediate_completion(op); - } - - // Helper function to close a socket when the associated object is being - // destroyed. - void close_for_destruction(implementation_type& impl) - { - if (is_open(impl)) - { - // 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( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (r) - r->close_descriptor(impl.socket_, impl.reactor_data_); - - // The socket destructor must not block. If the user has changed the - // linger option to block in the foreground, we will change it back to the - // default so that the closure is performed in the background. - if (impl.flags_ & implementation_type::close_might_block) - { - ::linger opt; - opt.l_onoff = 0; - opt.l_linger = 0; - boost::system::error_code ignored_ec; - socket_ops::setsockopt(impl.socket_, - SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec); - } - - boost::system::error_code ignored_ec; - socket_ops::close(impl.socket_, ignored_ec); - impl.socket_ = invalid_socket; - impl.flags_ = 0; - impl.cancel_token_.reset(); -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - impl.safe_cancellation_thread_id_ = 0; -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - } - } - - // Update the ID of the thread from which cancellation is safe. - void update_cancellation_thread_id(implementation_type& impl) - { -#if defined(BOOST_ASIO_ENABLE_CANCELIO) - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) - impl.safe_cancellation_thread_id_ = ~DWORD(0); -#else // defined(BOOST_ASIO_ENABLE_CANCELIO) - (void)impl; -#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) - } - - // 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 - // this service. - reactor& get_reactor() - { - reactor* r = static_cast( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (!r) - { - r = &(use_service(io_service_)); - interlocked_exchange_pointer(reinterpret_cast(&reactor_), r); - } - return *r; - } - - // Helper function to emulate InterlockedCompareExchangePointer functionality - // for: - // - very old Platform SDKs; and - // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. - void* interlocked_compare_exchange_pointer(void** dest, void* exch, void* cmp) - { -#if defined(_M_IX86) - return reinterpret_cast(InterlockedCompareExchange( - reinterpret_cast(dest), reinterpret_cast(exch), - reinterpret_cast(cmp))); -#else - return InterlockedCompareExchangePointer(dest, exch, cmp); -#endif - } - - // Helper function to emulate InterlockedExchangePointer functionality for: - // - very old Platform SDKs; and - // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. - void* interlocked_exchange_pointer(void** dest, void* val) - { -#if defined(_M_IX86) - return reinterpret_cast(InterlockedExchange( - reinterpret_cast(dest), reinterpret_cast(val))); -#else - return InterlockedExchangePointer(dest, val); -#endif - } - - // The io_service used to obtain the reactor, if required. - boost::asio::io_service& io_service_; - - // The IOCP service used for running asynchronous operations and dispatching - // handlers. - win_iocp_io_service& iocp_service_; - - // The reactor used for performing connect operations. This object is created - // only if needed. - reactor* reactor_; - - // Mutex to protect access to the linked list of implementations. - boost::asio::detail::mutex mutex_; - - // The head of a linked list of all implementations. - implementation_type* impl_list_; }; } // namespace detail } // namespace asio } // namespace boost -#endif // defined(BOOST_ASIO_HAS_IOCP) - #include +#endif // defined(BOOST_ASIO_HAS_IOCP) + #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP diff --git a/include/boost/asio/detail/win_iocp_socket_service_base.hpp b/include/boost/asio/detail/win_iocp_socket_service_base.hpp new file mode 100644 index 00000000..2dd3ba35 --- /dev/null +++ b/include/boost/asio/detail/win_iocp_socket_service_base.hpp @@ -0,0 +1,387 @@ +// +// detail/win_iocp_socket_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_SOCKET_SERVICE_BASE_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_iocp_socket_service_base +{ +public: + // The implementation type of the socket. + struct base_implementation_type + { + // The native socket representation. + socket_type socket_; + + // The current state of the socket. + socket_ops::state_type state_; + + // We use a shared pointer as a cancellation token here to work around the + // broken Windows support for cancellation. MSDN says that when you call + // closesocket any outstanding WSARecv or WSASend operations will complete + // with the error ERROR_OPERATION_ABORTED. In practice they complete with + // ERROR_NETNAME_DELETED, which means you can't tell the difference between + // a local cancellation and the socket being hard-closed by the peer. + socket_ops::shared_cancel_token_type cancel_token_; + + // Per-descriptor data used by the reactor. + 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 + // operations. 0 means no asynchronous operations have been started yet. + // ~0 means asynchronous operations have been started from more than one + // thread, and cancellation is not supported for the socket. + DWORD safe_cancellation_thread_id_; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + + // Pointers to adjacent socket implementations in linked list. + base_implementation_type* next_; + base_implementation_type* prev_; + }; + + // Constructor. + BOOST_ASIO_DECL win_iocp_socket_service_base( + boost::asio::io_service& io_service); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown_service(); + + // Construct a new socket implementation. + BOOST_ASIO_DECL void construct(base_implementation_type& impl); + + // Destroy a socket implementation. + BOOST_ASIO_DECL void destroy(base_implementation_type& impl); + + // Determine whether the socket is open. + bool is_open(const base_implementation_type& impl) const + { + return impl.socket_ != invalid_socket; + } + + // Destroy a socket implementation. + BOOST_ASIO_DECL boost::system::error_code close( + 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); + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const base_implementation_type& impl, + boost::system::error_code& ec) const + { + return socket_ops::sockatmark(impl.socket_, ec); + } + + // Determine the number of bytes available for reading. + std::size_t available(const base_implementation_type& impl, + boost::system::error_code& ec) const + { + return socket_ops::available(impl.socket_, ec); + } + + // Place the socket into the state where it will listen for new connections. + boost::system::error_code listen(base_implementation_type& impl, + int backlog, boost::system::error_code& ec) + { + socket_ops::listen(impl.socket_, backlog, ec); + return ec; + } + + // Perform an IO control command on the socket. + template + boost::system::error_code io_control(base_implementation_type& impl, + IO_Control_Command& command, boost::system::error_code& ec) + { + socket_ops::ioctl(impl.socket_, impl.state_, command.name(), + static_cast(command.data()), ec); + 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) + { + socket_ops::shutdown(impl.socket_, what, ec); + return ec; + } + + // Send the given data to the peer. Returns the number of bytes sent. + template + size_t send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_send(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be sent without blocking. + size_t send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_send_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, buffers, handler); + + buffer_sequence_adapter bufs(buffers); + + start_send_op(impl, bufs.buffers(), bufs.count(), flags, + (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(), + p.p); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); + + start_reactor_op(impl, reactor::write_op, p.p); + p.v = p.p = 0; + } + + // Receive some data from the peer. Returns the number of bytes received. + template + size_t receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_recv(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be received without blocking. + size_t receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, ec); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_recv_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.state_, impl.cancel_token_, buffers, handler); + + buffer_sequence_adapter bufs(buffers); + + start_receive_op(impl, bufs.buffers(), bufs.count(), flags, + (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(), + p.p); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags flags, Handler handler) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { boost::addressof(handler), + boost_asio_handler_alloc_helpers::allocate( + sizeof(op), handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler); + + start_null_buffers_receive_op(impl, flags, p.p); + p.v = p.p = 0; + } + + // Helper function to restart an asynchronous accept operation. + BOOST_ASIO_DECL void restart_accept_op(socket_type s, + socket_holder& new_socket, int family, int type, int protocol, + void* output_buffer, DWORD address_length, operation* op); + +protected: + // Open a new socket implementation. + BOOST_ASIO_DECL boost::system::error_code do_open( + base_implementation_type& impl, int family, int type, + int protocol, boost::system::error_code& ec); + + // Assign a native socket to a socket implementation. + BOOST_ASIO_DECL boost::system::error_code do_assign( + base_implementation_type& impl, int type, + socket_type native_socket, boost::system::error_code& ec); + + // Helper function to start an asynchronous send operation. + BOOST_ASIO_DECL void start_send_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op); + + // Helper function to start an asynchronous send_to operation. + BOOST_ASIO_DECL void start_send_to_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + const socket_addr_type* addr, int addrlen, + socket_base::message_flags flags, operation* op); + + // Helper function to start an asynchronous receive operation. + BOOST_ASIO_DECL void start_receive_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op); + + // Helper function to start an asynchronous null_buffers receive operation. + BOOST_ASIO_DECL void start_null_buffers_receive_op( + base_implementation_type& impl, + socket_base::message_flags flags, reactor_op* op); + + // Helper function to start an asynchronous receive_from operation. + BOOST_ASIO_DECL void start_receive_from_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr, + socket_base::message_flags flags, int* addrlen, operation* op); + + // Helper function to start an asynchronous accept operation. + BOOST_ASIO_DECL void start_accept_op(base_implementation_type& impl, + bool peer_is_open, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op); + + // Start an asynchronous read or write operation using the the reactor. + BOOST_ASIO_DECL void start_reactor_op(base_implementation_type& impl, + int op_type, reactor_op* op); + + // Start the asynchronous connect operation using the reactor. + BOOST_ASIO_DECL void start_connect_op(base_implementation_type& impl, + reactor_op* op, const socket_addr_type* addr, std::size_t addrlen); + + // Helper function to close a socket when the associated object is being + // destroyed. + BOOST_ASIO_DECL void close_for_destruction(base_implementation_type& impl); + + // Update the ID of the thread from which cancellation is safe. + BOOST_ASIO_DECL void update_cancellation_thread_id( + 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 + // this service. + BOOST_ASIO_DECL reactor& get_reactor(); + + // Helper function to emulate InterlockedCompareExchangePointer functionality + // for: + // - very old Platform SDKs; and + // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. + BOOST_ASIO_DECL void* interlocked_compare_exchange_pointer( + void** dest, void* exch, void* cmp); + + // Helper function to emulate InterlockedExchangePointer functionality for: + // - very old Platform SDKs; and + // - 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 IOCP service used for running asynchronous operations and dispatching + // handlers. + win_iocp_io_service& iocp_service_; + + // The reactor used for performing connect operations. This object is created + // only if needed. + reactor* reactor_; + + // Mutex to protect access to the linked list of implementations. + boost::asio::detail::mutex mutex_; + + // The head of a linked list of all implementations. + base_implementation_type* impl_list_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP diff --git a/include/boost/asio/detail/win_mutex.hpp b/include/boost/asio/detail/win_mutex.hpp index 176a5fd9..3f6dadbe 100644 --- a/include/boost/asio/detail/win_mutex.hpp +++ b/include/boost/asio/detail/win_mutex.hpp @@ -1,6 +1,6 @@ // -// win_mutex.hpp -// ~~~~~~~~~~~~~ +// detail/win_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,23 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include +#include #if defined(BOOST_WINDOWS) -#include #include -#include #include +#include #include -#include -#include namespace boost { namespace asio { @@ -44,18 +36,7 @@ public: typedef boost::asio::detail::scoped_lock scoped_lock; // Constructor. - win_mutex() - { - int error = do_init(); - if (error != 0) - { - boost::system::system_error e( - boost::system::error_code(error, - boost::asio::error::get_system_category()), - "mutex"); - boost::throw_exception(e); - } - } + BOOST_ASIO_DECL win_mutex(); // Destructor. ~win_mutex() @@ -79,35 +60,7 @@ private: // Initialisation must be performed in a separate function to the constructor // since the compiler does not support the use of structured exceptions and // C++ exceptions in the same function. - int do_init() - { -#if defined(__MINGW32__) - // Not sure if MinGW supports structured exception handling, so for now - // we'll just call the Windows API and hope. -# if defined(UNDER_CE) - ::InitializeCriticalSection(&crit_section_); -# else - ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000); -# endif - return 0; -#else - __try - { -# if defined(UNDER_CE) - ::InitializeCriticalSection(&crit_section_); -# else - ::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000); -# endif - } - __except(GetExceptionCode() == STATUS_NO_MEMORY - ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) - { - return ERROR_OUTOFMEMORY; - } - - return 0; -#endif - } + BOOST_ASIO_DECL int do_init(); ::CRITICAL_SECTION crit_section_; }; @@ -116,8 +69,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) + #endif // BOOST_ASIO_DETAIL_WIN_MUTEX_HPP diff --git a/include/boost/asio/detail/win_signal_blocker.hpp b/include/boost/asio/detail/win_signal_blocker.hpp index 6d70a16c..70d1b81c 100644 --- a/include/boost/asio/detail/win_signal_blocker.hpp +++ b/include/boost/asio/detail/win_signal_blocker.hpp @@ -1,6 +1,6 @@ // -// win_signal_blocker.hpp -// ~~~~~~~~~~~~~~~~~~~~~~ +// detail/win_signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include +#include + namespace boost { namespace asio { namespace detail { @@ -62,8 +60,8 @@ public: } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - #include +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_WIN_SIGNAL_BLOCKER_HPP diff --git a/include/boost/asio/detail/win_thread.hpp b/include/boost/asio/detail/win_thread.hpp index 61c9b8a9..cba546f6 100644 --- a/include/boost/asio/detail/win_thread.hpp +++ b/include/boost/asio/detail/win_thread.hpp @@ -1,6 +1,6 @@ // -// win_thread.hpp -// ~~~~~~~~~~~~~~ +// detail/win_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,35 +15,25 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include +#include #if defined(BOOST_WINDOWS) && !defined(UNDER_CE) -#include #include #include #include -#include -#include -#include -#include namespace boost { namespace asio { namespace detail { -unsigned int __stdcall win_thread_function(void* arg); +BOOST_ASIO_DECL unsigned int __stdcall win_thread_function(void* arg); #if defined(WINVER) && (WINVER < 0x0500) -void __stdcall apc_function(ULONG data); +BOOST_ASIO_DECL void __stdcall apc_function(ULONG data); #else -void __stdcall apc_function(ULONG_PTR data); +BOOST_ASIO_DECL void __stdcall apc_function(ULONG_PTR data); #endif template @@ -74,92 +64,26 @@ class win_thread public: // Constructor. template - win_thread(Function f) - : exit_event_(0) + win_thread(Function f, unsigned int stack_size = 0) + : thread_(0), + exit_event_(0) { - std::auto_ptr arg(new func(f)); - - ::HANDLE entry_event = 0; - arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0); - if (!entry_event) - { - DWORD last_error = ::GetLastError(); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "thread.entry_event"); - boost::throw_exception(e); - } - - arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0); - if (!exit_event_) - { - DWORD last_error = ::GetLastError(); - ::CloseHandle(entry_event); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "thread.exit_event"); - boost::throw_exception(e); - } - - unsigned int thread_id = 0; - thread_ = reinterpret_cast(::_beginthreadex(0, 0, - win_thread_function, arg.get(), 0, &thread_id)); - if (!thread_) - { - DWORD last_error = ::GetLastError(); - if (entry_event) - ::CloseHandle(entry_event); - if (exit_event_) - ::CloseHandle(exit_event_); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "thread"); - boost::throw_exception(e); - } - arg.release(); - - if (entry_event) - { - ::WaitForSingleObject(entry_event, INFINITE); - ::CloseHandle(entry_event); - } + start_thread(new func(f), stack_size); } // Destructor. - ~win_thread() - { - ::CloseHandle(thread_); - - // The exit_event_ handle is deliberately allowed to leak here since it - // is an error for the owner of an internal thread not to join() it. - } + BOOST_ASIO_DECL ~win_thread(); // Wait for the thread to exit. - void join() - { - ::WaitForSingleObject(exit_event_, INFINITE); - ::CloseHandle(exit_event_); - if (terminate_threads()) - { - ::TerminateThread(thread_, 0); - } - else - { - ::QueueUserAPC(apc_function, thread_, 0); - ::WaitForSingleObject(thread_, INFINITE); - } - } + BOOST_ASIO_DECL void join(); private: - friend unsigned int __stdcall win_thread_function(void* arg); + friend BOOST_ASIO_DECL unsigned int __stdcall win_thread_function(void* arg); #if defined(WINVER) && (WINVER < 0x0500) - friend void __stdcall apc_function(ULONG); + friend BOOST_ASIO_DECL void __stdcall apc_function(ULONG); #else - friend void __stdcall apc_function(ULONG_PTR); + friend BOOST_ASIO_DECL void __stdcall apc_function(ULONG_PTR); #endif class func_base @@ -171,6 +95,12 @@ private: ::HANDLE exit_event_; }; + struct auto_func_base_ptr + { + func_base* ptr; + ~auto_func_base_ptr() { delete ptr; } + }; + template class func : public func_base @@ -190,45 +120,22 @@ private: Function f_; }; + BOOST_ASIO_DECL void start_thread(func_base* arg, unsigned int stack_size); + ::HANDLE thread_; ::HANDLE exit_event_; }; -inline unsigned int __stdcall win_thread_function(void* arg) -{ - std::auto_ptr func( - static_cast(arg)); - - ::SetEvent(func->entry_event_); - - func->run(); - - // Signal that the thread has finished its work, but rather than returning go - // to sleep to put the thread into a well known state. If the thread is being - // joined during global object destruction then it may be killed using - // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx - // call will be interrupted using QueueUserAPC and the thread will shut down - // cleanly. - HANDLE exit_event = func->exit_event_; - func.reset(); - ::SetEvent(exit_event); - ::SleepEx(INFINITE, TRUE); - - return 0; -} - -#if defined(WINVER) && (WINVER < 0x0500) -inline void __stdcall apc_function(ULONG) {} -#else -inline void __stdcall apc_function(ULONG_PTR) {} -#endif - } // namespace detail } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) + #endif // BOOST_ASIO_DETAIL_WIN_THREAD_HPP diff --git a/include/boost/asio/detail/win_tss_ptr.hpp b/include/boost/asio/detail/win_tss_ptr.hpp index fa04613c..2c5ee3bd 100644 --- a/include/boost/asio/detail/win_tss_ptr.hpp +++ b/include/boost/asio/detail/win_tss_ptr.hpp @@ -1,6 +1,6 @@ // -// win_tss_ptr.hpp -// ~~~~~~~~~~~~~~~ +// detail/win_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,51 +15,31 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include +#include #if defined(BOOST_WINDOWS) -#include #include #include #include -#include -#include namespace boost { namespace asio { namespace detail { +// Helper function to create thread-specific storage. +BOOST_ASIO_DECL DWORD win_tss_ptr_create(); + template class win_tss_ptr : private noncopyable { public: -#if defined(UNDER_CE) - enum { out_of_indexes = 0xFFFFFFFF }; -#else - enum { out_of_indexes = TLS_OUT_OF_INDEXES }; -#endif - // Constructor. win_tss_ptr() + : tss_key_(win_tss_ptr_create()) { - tss_key_ = ::TlsAlloc(); - if (tss_key_ == out_of_indexes) - { - DWORD last_error = ::GetLastError(); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "tss"); - boost::throw_exception(e); - } } // Destructor. @@ -90,8 +70,12 @@ private: } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) + #endif // BOOST_ASIO_DETAIL_WIN_TSS_PTR_HPP diff --git a/include/boost/asio/detail/wince_thread.hpp b/include/boost/asio/detail/wince_thread.hpp index 1cb9a7ae..82ca544b 100644 --- a/include/boost/asio/detail/wince_thread.hpp +++ b/include/boost/asio/detail/wince_thread.hpp @@ -1,6 +1,6 @@ // -// wince_thread.hpp -// ~~~~~~~~~~~~~~~~ +// detail/wince_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,23 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include +#include #if defined(BOOST_WINDOWS) && defined(UNDER_CE) -#include +#include #include #include +#include +#include #include -#include -#include -#include namespace boost { namespace asio { @@ -54,11 +48,9 @@ public: if (!thread_) { DWORD last_error = ::GetLastError(); - boost::system::system_error e( - boost::system::error_code(last_error, - boost::asio::error::get_system_category()), - "thread"); - boost::throw_exception(e); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread"); } arg.release(); } @@ -119,8 +111,8 @@ inline DWORD WINAPI wince_thread_function(LPVOID arg) } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) && defined(UNDER_CE) - #include +#endif // defined(BOOST_WINDOWS) && defined(UNDER_CE) + #endif // BOOST_ASIO_DETAIL_WINCE_THREAD_HPP diff --git a/include/boost/asio/detail/winsock_init.hpp b/include/boost/asio/detail/winsock_init.hpp index 186a8b5c..d9e84691 100644 --- a/include/boost/asio/detail/winsock_init.hpp +++ b/include/boost/asio/detail/winsock_init.hpp @@ -1,6 +1,6 @@ // -// winsock_init.hpp -// ~~~~~~~~~~~~~~~~ +// detail/winsock_init.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,108 +15,78 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include +#include #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include -#include -#include -#include - -#include -#include -#include namespace boost { namespace asio { namespace detail { -template -class winsock_init - : private noncopyable +class winsock_init_base { -private: - // Structure to perform the actual initialisation. - struct do_init +protected: + // Structure to track result of initialisation and number of uses. POD is used + // to ensure that the values are zero-initialised prior to any code being run. + struct data { - do_init() - { - WSADATA wsa_data; - result_ = ::WSAStartup(MAKEWORD(Major, Minor), &wsa_data); - } - - ~do_init() - { - ::WSACleanup(); - } - - int result() const - { - return result_; - } - - // Helper function to manage a do_init singleton. The static instance of the - // winsock_init object ensures that this function is always called before - // main, and therefore before any other threads can get started. The do_init - // instance must be static in this function to ensure that it gets - // initialised before any other global objects try to use it. - static boost::shared_ptr instance() - { - static boost::shared_ptr init(new do_init); - return init; - } - - private: - int result_; + long init_count_; + long result_; }; + BOOST_ASIO_DECL static void startup(data& d, + unsigned char major, unsigned char minor); + + BOOST_ASIO_DECL static void cleanup(data& d); + + BOOST_ASIO_DECL static void throw_on_error(data& d); +}; + +template +class winsock_init : private winsock_init_base +{ public: - // Constructor. - winsock_init() - : ref_(do_init::instance()) + winsock_init(bool allow_throw = true) { - // Check whether winsock was successfully initialised. This check is not - // performed for the global instance since there will be nobody around to - // catch the exception. - if (this != &instance_ && ref_->result() != 0) - { - boost::system::system_error e( - boost::system::error_code(ref_->result(), - boost::asio::error::get_system_category()), - "winsock"); - boost::throw_exception(e); - } + startup(data_, Major, Minor); + if (allow_throw) + throw_on_error(data_); + } + + winsock_init(const winsock_init&) + { + startup(data_, Major, Minor); + throw_on_error(data_); } - // Destructor. ~winsock_init() { + cleanup(data_); } private: - // Instance to force initialisation of winsock at global scope. - static winsock_init instance_; - - // Reference to singleton do_init object to ensure that winsock does not get - // cleaned up until the last user has finished with it. - boost::shared_ptr ref_; + static data data_; }; template -winsock_init winsock_init::instance_; +typename winsock_init::data winsock_init::data_; + +// Static variable to ensure that winsock is initialised before main, and +// therefore before any other threads can get started. +static const winsock_init<>& winsock_init_instance = winsock_init<>(false); } // namespace detail } // namespace asio } // namespace boost -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + #endif // BOOST_ASIO_DETAIL_WINSOCK_INIT_HPP diff --git a/include/boost/asio/detail/wrapped_handler.hpp b/include/boost/asio/detail/wrapped_handler.hpp index 8f2f6252..9645b64f 100644 --- a/include/boost/asio/detail/wrapped_handler.hpp +++ b/include/boost/asio/detail/wrapped_handler.hpp @@ -1,6 +1,6 @@ // -// wrapped_handler.hpp -// ~~~~~~~~~~~~~~~~~~~ +// detail/wrapped_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include - #include #include #include +#include + namespace boost { namespace asio { namespace detail { @@ -35,9 +31,7 @@ class wrapped_handler public: typedef void result_type; - wrapped_handler( - typename boost::add_reference::type dispatcher, - Handler handler) + wrapped_handler(Dispatcher dispatcher, Handler handler) : dispatcher_(dispatcher), handler_(handler) { diff --git a/include/boost/asio/error.hpp b/include/boost/asio/error.hpp index 0dcb3dcd..5663b694 100644 --- a/include/boost/asio/error.hpp +++ b/include/boost/asio/error.hpp @@ -15,15 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include #include -#include - -#include +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# include +#else +# include +# include +#endif #if defined(GENERATING_DOCUMENTATION) /// INTERNAL ONLY. @@ -50,6 +50,8 @@ # define BOOST_ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix #endif +#include + namespace boost { namespace asio { namespace error { @@ -220,65 +222,11 @@ inline const boost::system::error_category& get_system_category() #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -namespace detail { +extern BOOST_ASIO_DECL +const boost::system::error_category& get_netdb_category(); -class netdb_category : public boost::system::error_category -{ -public: - const char* name() const - { - return "asio.netdb"; - } - - std::string message(int value) const - { - if (value == error::host_not_found) - return "Host not found (authoritative)"; - if (value == error::host_not_found_try_again) - return "Host not found (non-authoritative), try again later"; - if (value == error::no_data) - return "The query is valid, but it does not have associated data"; - if (value == error::no_recovery) - return "A non-recoverable error occurred during database lookup"; - return "asio.netdb error"; - } -}; - -} // namespace detail - -inline const boost::system::error_category& get_netdb_category() -{ - static detail::netdb_category instance; - return instance; -} - -namespace detail { - -class addrinfo_category : public boost::system::error_category -{ -public: - const char* name() const - { - return "asio.addrinfo"; - } - - std::string message(int value) const - { - if (value == error::service_not_found) - return "Service not found"; - if (value == error::socket_type_not_supported) - return "Socket type not supported"; - return "asio.addrinfo error"; - } -}; - -} // namespace detail - -inline const boost::system::error_category& get_addrinfo_category() -{ - static detail::addrinfo_category instance; - return instance; -} +extern BOOST_ASIO_DECL +const boost::system::error_category& get_addrinfo_category(); #else // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) @@ -294,61 +242,11 @@ inline const boost::system::error_category& get_addrinfo_category() #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -namespace detail { +extern BOOST_ASIO_DECL +const boost::system::error_category& get_misc_category(); -class misc_category : public boost::system::error_category -{ -public: - const char* name() const - { - return "asio.misc"; - } - - std::string message(int value) const - { - if (value == error::already_open) - return "Already open"; - if (value == error::eof) - return "End of file"; - if (value == error::not_found) - return "Element not found"; - if (value == error::fd_set_failure) - return "The descriptor does not fit into the select call's fd_set"; - return "asio.misc error"; - } -}; - -} // namespace detail - -inline const boost::system::error_category& get_misc_category() -{ - static detail::misc_category instance; - return instance; -} - -namespace detail { - -class ssl_category : public boost::system::error_category -{ -public: - const char* name() const - { - return "asio.ssl"; - } - - std::string message(int) const - { - return "asio.ssl error"; - } -}; - -} // namespace detail - -inline const boost::system::error_category& get_ssl_category() -{ - static detail::ssl_category instance; - return instance; -} +extern BOOST_ASIO_DECL +const boost::system::error_category& get_ssl_category(); static const boost::system::error_category& system_category = boost::asio::error::get_system_category(); @@ -430,13 +328,16 @@ inline boost::system::error_code make_error_code(ssl_errors e) } // namespace asio } // namespace boost +#include + #undef BOOST_ASIO_NATIVE_ERROR #undef BOOST_ASIO_SOCKET_ERROR #undef BOOST_ASIO_NETDB_ERROR #undef BOOST_ASIO_GETADDRINFO_ERROR #undef BOOST_ASIO_WIN_OR_POSIX - -#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_ERROR_HPP diff --git a/include/boost/asio/handler_alloc_hook.hpp b/include/boost/asio/handler_alloc_hook.hpp index 5dada4e7..179f75e6 100644 --- a/include/boost/asio/handler_alloc_hook.hpp +++ b/include/boost/asio/handler_alloc_hook.hpp @@ -15,12 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#include #include -#include -#include -#include namespace boost { namespace asio { diff --git a/include/boost/asio/handler_invoke_hook.hpp b/include/boost/asio/handler_invoke_hook.hpp index 184f4495..f997f110 100644 --- a/include/boost/asio/handler_invoke_hook.hpp +++ b/include/boost/asio/handler_invoke_hook.hpp @@ -15,6 +15,8 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +#include + #include namespace boost { diff --git a/include/boost/asio/impl/error.ipp b/include/boost/asio/impl/error.ipp new file mode 100644 index 00000000..708654e4 --- /dev/null +++ b/include/boost/asio/impl/error.ipp @@ -0,0 +1,155 @@ +// +// impl/error.ipp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_ERROR_IPP +#define BOOST_ASIO_IMPL_ERROR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace error { + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +namespace detail { + +class netdb_category : public boost::system::error_category +{ +public: + const char* name() const + { + return "asio.netdb"; + } + + std::string message(int value) const + { + if (value == error::host_not_found) + return "Host not found (authoritative)"; + if (value == error::host_not_found_try_again) + return "Host not found (non-authoritative), try again later"; + if (value == error::no_data) + return "The query is valid, but it does not have associated data"; + if (value == error::no_recovery) + return "A non-recoverable error occurred during database lookup"; + return "asio.netdb error"; + } +}; + +} // namespace detail + +const boost::system::error_category& get_netdb_category() +{ + static detail::netdb_category instance; + return instance; +} + +namespace detail { + +class addrinfo_category : public boost::system::error_category +{ +public: + const char* name() const + { + return "asio.addrinfo"; + } + + std::string message(int value) const + { + if (value == error::service_not_found) + return "Service not found"; + if (value == error::socket_type_not_supported) + return "Socket type not supported"; + return "asio.addrinfo error"; + } +}; + +} // namespace detail + +const boost::system::error_category& get_addrinfo_category() +{ + static detail::addrinfo_category instance; + return instance; +} + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +namespace detail { + +class misc_category : public boost::system::error_category +{ +public: + const char* name() const + { + return "asio.misc"; + } + + std::string message(int value) const + { + if (value == error::already_open) + return "Already open"; + if (value == error::eof) + return "End of file"; + if (value == error::not_found) + return "Element not found"; + if (value == error::fd_set_failure) + return "The descriptor does not fit into the select call's fd_set"; + return "asio.misc error"; + } +}; + +} // namespace detail + +const boost::system::error_category& get_misc_category() +{ + static detail::misc_category instance; + return instance; +} + +namespace detail { + +class ssl_category : public boost::system::error_category +{ +public: + const char* name() const + { + return "asio.ssl"; + } + + std::string message(int) const + { + return "asio.ssl error"; + } +}; + +} // namespace detail + +const boost::system::error_category& get_ssl_category() +{ + static detail::ssl_category instance; + return instance; +} + +} // namespace error +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_ERROR_IPP diff --git a/include/boost/asio/impl/io_service.hpp b/include/boost/asio/impl/io_service.hpp new file mode 100644 index 00000000..011c1c5a --- /dev/null +++ b/include/boost/asio/impl/io_service.hpp @@ -0,0 +1,126 @@ +// +// impl/io_service.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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 + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else +# include +#endif + +#include + +namespace boost { +namespace asio { + +template +inline void io_service::dispatch(Handler handler) +{ + impl_.dispatch(handler); +} + +template +inline void io_service::post(Handler handler) +{ + impl_.post(handler); +} + +template +#if defined(GENERATING_DOCUMENTATION) +unspecified +#else +inline detail::wrapped_handler +#endif +io_service::wrap(Handler handler) +{ + return detail::wrapped_handler(*this, handler); +} + +inline io_service::work::work(boost::asio::io_service& io_service) + : io_service_(io_service) +{ + io_service_.impl_.work_started(); +} + +inline io_service::work::work(const work& other) + : io_service_(other.io_service_) +{ + io_service_.impl_.work_started(); +} + +inline io_service::work::~work() +{ + io_service_.impl_.work_finished(); +} + +inline boost::asio::io_service& io_service::work::io_service() +{ + return io_service_; +} + +inline boost::asio::io_service& io_service::work::get_io_service() +{ + return io_service_; +} + +inline boost::asio::io_service& io_service::service::io_service() +{ + return owner_; +} + +inline boost::asio::io_service& io_service::service::get_io_service() +{ + return owner_; +} + +template +inline Service& use_service(io_service& ios) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast(static_cast(0)); + (void)static_cast(&Service::id); + + return ios.service_registry_->template use_service(); +} + +template +inline void add_service(io_service& ios, Service* svc) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast(static_cast(0)); + (void)static_cast(&Service::id); + + ios.service_registry_->template add_service(svc); +} + +template +inline bool has_service(io_service& ios) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast(static_cast(0)); + (void)static_cast(&Service::id); + + return ios.service_registry_->template has_service(); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_IO_SERVICE_HPP diff --git a/include/boost/asio/impl/io_service.ipp b/include/boost/asio/impl/io_service.ipp index 20f868d2..731adb87 100644 --- a/include/boost/asio/impl/io_service.ipp +++ b/include/boost/asio/impl/io_service.ipp @@ -1,6 +1,6 @@ // -// io_service.ipp -// ~~~~~~~~~~~~~~ +// impl/io_service.ipp +// ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,19 +8,16 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_IO_SERVICE_IPP -#define BOOST_ASIO_IO_SERVICE_IPP +#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 - -#include +#include #include -#include - +#include #include #include @@ -28,32 +25,33 @@ # include #else # include -# include #endif +#include + namespace boost { namespace asio { -inline io_service::io_service() +io_service::io_service() : service_registry_(new boost::asio::detail::service_registry(*this)), impl_(service_registry_->use_service()) { impl_.init((std::numeric_limits::max)()); } -inline io_service::io_service(std::size_t concurrency_hint) +io_service::io_service(std::size_t concurrency_hint) : service_registry_(new boost::asio::detail::service_registry(*this)), impl_(service_registry_->use_service()) { impl_.init(concurrency_hint); } -inline io_service::~io_service() +io_service::~io_service() { delete service_registry_; } -inline std::size_t io_service::run() +std::size_t io_service::run() { boost::system::error_code ec; std::size_t s = impl_.run(ec); @@ -61,12 +59,12 @@ inline std::size_t io_service::run() return s; } -inline std::size_t io_service::run(boost::system::error_code& ec) +std::size_t io_service::run(boost::system::error_code& ec) { return impl_.run(ec); } -inline std::size_t io_service::run_one() +std::size_t io_service::run_one() { boost::system::error_code ec; std::size_t s = impl_.run_one(ec); @@ -74,12 +72,12 @@ inline std::size_t io_service::run_one() return s; } -inline std::size_t io_service::run_one(boost::system::error_code& ec) +std::size_t io_service::run_one(boost::system::error_code& ec) { return impl_.run_one(ec); } -inline std::size_t io_service::poll() +std::size_t io_service::poll() { boost::system::error_code ec; std::size_t s = impl_.poll(ec); @@ -87,12 +85,12 @@ inline std::size_t io_service::poll() return s; } -inline std::size_t io_service::poll(boost::system::error_code& ec) +std::size_t io_service::poll(boost::system::error_code& ec) { return impl_.poll(ec); } -inline std::size_t io_service::poll_one() +std::size_t io_service::poll_one() { boost::system::error_code ec; std::size_t s = impl_.poll_one(ec); @@ -100,122 +98,39 @@ inline std::size_t io_service::poll_one() return s; } -inline std::size_t io_service::poll_one(boost::system::error_code& ec) +std::size_t io_service::poll_one(boost::system::error_code& ec) { return impl_.poll_one(ec); } -inline void io_service::stop() +void io_service::stop() { impl_.stop(); } -inline void io_service::reset() +void io_service::reset() { impl_.reset(); } -template -inline void io_service::dispatch(Handler handler) -{ - impl_.dispatch(handler); -} - -template -inline void io_service::post(Handler handler) -{ - impl_.post(handler); -} - -template -#if defined(GENERATING_DOCUMENTATION) -unspecified -#else -inline detail::wrapped_handler -#endif -io_service::wrap(Handler handler) -{ - return detail::wrapped_handler(*this, handler); -} - -inline io_service::work::work(boost::asio::io_service& io_service) - : io_service_(io_service) -{ - io_service_.impl_.work_started(); -} - -inline io_service::work::work(const work& other) - : io_service_(other.io_service_) -{ - io_service_.impl_.work_started(); -} - -inline io_service::work::~work() -{ - io_service_.impl_.work_finished(); -} - -inline boost::asio::io_service& io_service::work::io_service() -{ - return io_service_; -} - -inline boost::asio::io_service& io_service::work::get_io_service() -{ - return io_service_; -} - -inline io_service::service::service(boost::asio::io_service& owner) +io_service::service::service(boost::asio::io_service& owner) : owner_(owner), next_(0) { } -inline io_service::service::~service() +io_service::service::~service() { } -inline boost::asio::io_service& io_service::service::io_service() +service_already_exists::service_already_exists() + : std::logic_error("Service already exists.") { - return owner_; } -inline boost::asio::io_service& io_service::service::get_io_service() +invalid_service_owner::invalid_service_owner() + : std::logic_error("Invalid service owner.") { - return owner_; -} - -template -inline Service& use_service(io_service& ios) -{ - // Check that Service meets the necessary type requirements. - (void)static_cast(static_cast(0)); - (void)static_cast(&Service::id); - - return ios.service_registry_->template use_service(); -} - -template -void add_service(io_service& ios, Service* svc) -{ - // Check that Service meets the necessary type requirements. - (void)static_cast(static_cast(0)); - (void)static_cast(&Service::id); - - if (&ios != &svc->io_service()) - boost::throw_exception(invalid_service_owner()); - if (!ios.service_registry_->template add_service(svc)) - boost::throw_exception(service_already_exists()); -} - -template -bool has_service(io_service& ios) -{ - // Check that Service meets the necessary type requirements. - (void)static_cast(static_cast(0)); - (void)static_cast(&Service::id); - - return ios.service_registry_->template has_service(); } } // namespace asio @@ -223,4 +138,4 @@ bool has_service(io_service& ios) #include -#endif // BOOST_ASIO_IO_SERVICE_IPP +#endif // BOOST_ASIO_IMPL_IO_SERVICE_IPP diff --git a/include/boost/asio/impl/read.ipp b/include/boost/asio/impl/read.hpp similarity index 87% rename from include/boost/asio/impl/read.ipp rename to include/boost/asio/impl/read.hpp index 772c06bc..e51210ee 100644 --- a/include/boost/asio/impl/read.ipp +++ b/include/boost/asio/impl/read.hpp @@ -1,6 +1,6 @@ // -// read.ipp -// ~~~~~~~~ +// impl/read.hpp +// ~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,28 +8,25 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_READ_IPP -#define BOOST_ASIO_READ_IPP +#ifndef BOOST_ASIO_IMPL_READ_HPP +#define BOOST_ASIO_IMPL_READ_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include #include -#include - #include #include -#include #include #include #include #include #include #include +#include + +#include namespace boost { namespace asio { @@ -88,8 +85,7 @@ std::size_t read(SyncReadStream& s, 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 = std::min(512, - std::min(max_size, b.max_size() - b.size())); + std::size_t bytes_available = read_size_helper(b, max_size); while (bytes_available > 0) { std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec); @@ -97,8 +93,7 @@ std::size_t read(SyncReadStream& s, total_transferred += bytes_transferred; max_size = detail::adapt_completion_condition_result( completion_condition(ec, total_transferred)); - bytes_available = std::min(512, - std::min(max_size, b.max_size() - b.size())); + bytes_available = read_size_helper(b, max_size); } return total_transferred; } @@ -142,25 +137,24 @@ namespace detail stream_(stream), buffers_(buffers), total_transferred_(0), - handler_(handler), - start_(true) + handler_(handler) { } void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred) + std::size_t bytes_transferred, int start = 0) { - switch (start_) + switch (start) { - case true: start_ = false; - buffers_.prepare(this->check(ec, total_transferred_)); + case 1: + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); for (;;) { stream_.async_read_some(buffers_, *this); return; default: total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - buffers_.prepare(this->check(ec, total_transferred_)); + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); if ((!ec && bytes_transferred == 0) || buffers_.begin() == buffers_.end()) break; @@ -176,7 +170,6 @@ namespace detail mutable_buffer, MutableBufferSequence> buffers_; std::size_t total_transferred_; ReadHandler handler_; - bool start_; }; template check(ec, total_transferred_); + case 1: + n = this->check_for_completion(ec, total_transferred_); for (;;) { stream_.async_read_some(boost::asio::buffer( @@ -215,7 +207,7 @@ namespace detail return; default: total_transferred_ += bytes_transferred; if ((!ec && bytes_transferred == 0) - || (n = this->check(ec, total_transferred_)) == 0 + || (n = this->check_for_completion(ec, total_transferred_)) == 0 || total_transferred_ == boost::asio::buffer_size(buffer_)) break; } @@ -229,7 +221,6 @@ namespace detail boost::asio::mutable_buffer buffer_; std::size_t total_transferred_; ReadHandler handler_; - bool start_; }; template ( s, buffers, completion_condition, handler)( - boost::system::error_code(), 0); + boost::system::error_code(), 0, 1); } template check(ec, total_transferred_); - bytes_available = std::min(512, - std::min(max_size, - streambuf_.max_size() - streambuf_.size())); + case 1: + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = read_size_helper(streambuf_, max_size); for (;;) { stream_.async_read_some(streambuf_.prepare(bytes_available), *this); return; default: total_transferred_ += bytes_transferred; streambuf_.commit(bytes_transferred); - max_size = this->check(ec, total_transferred_); - bytes_available = std::min(512, - std::min(max_size, - streambuf_.max_size() - streambuf_.size())); + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = read_size_helper(streambuf_, max_size); if ((!ec && bytes_transferred == 0) || bytes_available == 0) break; } @@ -340,7 +326,6 @@ namespace detail boost::asio::basic_streambuf& streambuf_; std::size_t total_transferred_; ReadHandler handler_; - bool start_; }; template ( s, b, completion_condition, handler)( - boost::system::error_code(), 0); + boost::system::error_code(), 0, 1); } template @@ -400,4 +385,4 @@ inline void async_read(AsyncReadStream& s, #include -#endif // BOOST_ASIO_READ_IPP +#endif // BOOST_ASIO_IMPL_READ_HPP diff --git a/include/boost/asio/impl/read_at.ipp b/include/boost/asio/impl/read_at.hpp similarity index 63% rename from include/boost/asio/impl/read_at.ipp rename to include/boost/asio/impl/read_at.hpp index eb3c3f89..0eb064b5 100644 --- a/include/boost/asio/impl/read_at.ipp +++ b/include/boost/asio/impl/read_at.hpp @@ -1,6 +1,6 @@ // -// read_at.ipp -// ~~~~~~~~~~~ +// impl/read_at.hpp +// ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,27 +8,25 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_READ_AT_IPP -#define BOOST_ASIO_READ_AT_IPP +#ifndef BOOST_ASIO_IMPL_READ_AT_HPP +#define BOOST_ASIO_IMPL_READ_AT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include #include -#include - #include #include -#include +#include #include #include #include #include #include +#include + +#include namespace boost { namespace asio { @@ -89,19 +87,22 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, boost::asio::basic_streambuf& b, CompletionCondition completion_condition, boost::system::error_code& ec) { + ec = boost::system::error_code(); std::size_t total_transferred = 0; - for (;;) + 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); + while (bytes_available > 0) { - std::size_t bytes_available = - std::min(512, b.max_size() - b.size()); std::size_t bytes_transferred = d.read_some_at( offset + total_transferred, b.prepare(bytes_available), ec); b.commit(bytes_transferred); total_transferred += bytes_transferred; - if (b.size() == b.max_size() - || completion_condition(ec, total_transferred)) - return total_transferred; + max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + bytes_available = read_size_helper(b, max_size); } + return total_transferred; } template @@ -135,48 +136,105 @@ namespace detail template - class read_at_handler + class read_at_op + : detail::base_from_completion_cond { public: - typedef boost::asio::detail::consuming_buffers< - mutable_buffer, MutableBufferSequence> buffers_type; - - read_at_handler(AsyncRandomAccessReadDevice& stream, - boost::uint64_t offset, const buffers_type& buffers, + read_at_op(AsyncRandomAccessReadDevice& device, + boost::uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition, ReadHandler handler) - : stream_(stream), + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), offset_(offset), buffers_(buffers), total_transferred_(0), - completion_condition_(completion_condition), handler_(handler) { } void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred) + std::size_t bytes_transferred, int start = 0) { - total_transferred_ += bytes_transferred; - buffers_.consume(bytes_transferred); - buffers_.prepare(detail::adapt_completion_condition_result( - completion_condition_(ec, total_transferred_))); - if (buffers_.begin() == buffers_.end()) + switch (start) { + case 1: + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); + for (;;) + { + device_.async_read_some_at( + offset_ + total_transferred_, buffers_, *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, total_transferred_); } - else - { - stream_.async_read_some_at( - offset_ + total_transferred_, buffers_, *this); - } } //private: - AsyncRandomAccessReadDevice& stream_; + AsyncRandomAccessReadDevice& device_; boost::uint64_t offset_; - buffers_type buffers_; + boost::asio::detail::consuming_buffers< + mutable_buffer, MutableBufferSequence> buffers_; + std::size_t total_transferred_; + ReadHandler handler_; + }; + + template + class read_at_op + : detail::base_from_completion_cond + { + public: + read_at_op(AsyncRandomAccessReadDevice& device, + boost::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), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t n = 0; + switch (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), *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, total_transferred_); + } + } + + //private: + AsyncRandomAccessReadDevice& device_; + boost::uint64_t offset_; + boost::asio::mutable_buffer buffer_; std::size_t total_transferred_; - CompletionCondition completion_condition_; ReadHandler handler_; }; @@ -184,7 +242,7 @@ namespace detail typename MutableBufferSequence, typename CompletionCondition, typename ReadHandler> inline void* asio_handler_allocate(std::size_t size, - read_at_handler* this_handler) { return boost_asio_handler_alloc_helpers::allocate( @@ -195,7 +253,7 @@ namespace detail typename MutableBufferSequence, typename CompletionCondition, typename ReadHandler> inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_at_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( @@ -206,7 +264,7 @@ namespace detail typename MutableBufferSequence, typename CompletionCondition, typename ReadHandler> inline void asio_handler_invoke(const Function& function, - read_at_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -220,24 +278,10 @@ inline void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition, ReadHandler handler) { - boost::asio::detail::consuming_buffers< - mutable_buffer, MutableBufferSequence> tmp(buffers); - - boost::system::error_code ec; - std::size_t total_transferred = 0; - tmp.prepare(detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred))); - if (tmp.begin() == tmp.end()) - { - d.get_io_service().post(detail::bind_handler( - handler, ec, total_transferred)); - return; - } - - d.async_read_some_at(offset, tmp, - detail::read_at_handler( - d, offset, tmp, completion_condition, handler)); + detail::read_at_op( + d, offset, buffers, completion_condition, handler)( + boost::system::error_code(), 0, 1); } template - class read_at_streambuf_handler + class read_at_streambuf_op + : detail::base_from_completion_cond { public: - read_at_streambuf_handler(AsyncRandomAccessReadDevice& stream, + read_at_streambuf_op(AsyncRandomAccessReadDevice& device, boost::uint64_t offset, basic_streambuf& streambuf, CompletionCondition completion_condition, ReadHandler handler) - : stream_(stream), + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), offset_(offset), streambuf_(streambuf), total_transferred_(0), - completion_condition_(completion_condition), handler_(handler) { } void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred) + std::size_t bytes_transferred, int start = 0) { - total_transferred_ += bytes_transferred; - streambuf_.commit(bytes_transferred); - std::size_t max_size = detail::adapt_completion_condition_result( - completion_condition_(ec, total_transferred_)); - std::size_t bytes_available = std::min(512, - std::min(max_size, - streambuf_.max_size() - streambuf_.size())); - if (bytes_available == 0) + std::size_t max_size, bytes_available; + switch (start) { + case 1: + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = read_size_helper(streambuf_, max_size); + for (;;) + { + device_.async_read_some_at(offset_ + total_transferred_, + streambuf_.prepare(bytes_available), *this); + return; default: + total_transferred_ += bytes_transferred; + streambuf_.commit(bytes_transferred); + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = read_size_helper(streambuf_, max_size); + if ((!ec && bytes_transferred == 0) || bytes_available == 0) + break; + } + handler_(ec, total_transferred_); } - else - { - stream_.async_read_some_at(offset_ + total_transferred_, - streambuf_.prepare(bytes_available), *this); - } } //private: - AsyncRandomAccessReadDevice& stream_; + AsyncRandomAccessReadDevice& device_; boost::uint64_t offset_; boost::asio::basic_streambuf& streambuf_; std::size_t total_transferred_; - CompletionCondition completion_condition_; ReadHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, - read_at_streambuf_handler* this_handler) { return boost_asio_handler_alloc_helpers::allocate( @@ -313,7 +363,7 @@ namespace detail template inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_at_streambuf_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( @@ -323,7 +373,7 @@ namespace detail template inline void asio_handler_invoke(const Function& function, - read_at_streambuf_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -337,23 +387,10 @@ inline void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, boost::asio::basic_streambuf& b, CompletionCondition completion_condition, ReadHandler handler) { - boost::system::error_code ec; - 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 = std::min(512, - std::min(max_size, b.max_size() - b.size())); - if (bytes_available == 0) - { - d.get_io_service().post(detail::bind_handler( - handler, ec, total_transferred)); - return; - } - - d.async_read_some_at(offset, b.prepare(bytes_available), - detail::read_at_streambuf_handler( - d, offset, b, completion_condition, handler)); + detail::read_at_streambuf_op( + d, offset, b, completion_condition, handler)( + boost::system::error_code(), 0, 1); } template -#endif // BOOST_ASIO_READ_AT_IPP +#endif // BOOST_ASIO_IMPL_READ_AT_HPP diff --git a/include/boost/asio/impl/read_until.hpp b/include/boost/asio/impl/read_until.hpp new file mode 100644 index 00000000..f3d8819e --- /dev/null +++ b/include/boost/asio/impl/read_until.hpp @@ -0,0 +1,876 @@ +// +// impl/read_until.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_READ_UNTIL_HPP +#define BOOST_ASIO_IMPL_READ_UNTIL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +template +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, char delim) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, b, delim, ec); + boost::asio::detail::throw_error(ec); + return bytes_transferred; +} + +template +std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, char delim, + boost::system::error_code& ec) +{ + 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 iterator; + const_buffers_type buffers = b.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position; + iterator end = iterator::end(buffers); + + // Look for a match. + iterator iter = std::find(start, end, delim); + if (iter != end) + { + // Found a match. We're done. + ec = boost::system::error_code(); + return iter - begin + 1; + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = read_size_helper(b, 65536); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +template +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, const std::string& delim) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, b, delim, ec); + boost::asio::detail::throw_error(ec); + return bytes_transferred; +} + +namespace detail +{ + // Algorithm that finds a subsequence of equal values in a sequence. Returns + // (iterator,true) if a full match was found, in which case the iterator + // points to the beginning of the match. Returns (iterator,false) if a + // partial match was found at the end of the first sequence, in which case + // the iterator points to the beginning of the partial match. Returns + // (last1,false) if no full or partial match was found. + template + std::pair partial_search( + Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) + { + for (Iterator1 iter1 = first1; iter1 != last1; ++iter1) + { + Iterator1 test_iter1 = iter1; + Iterator2 test_iter2 = first2; + for (;; ++test_iter1, ++test_iter2) + { + if (test_iter2 == last2) + return std::make_pair(iter1, true); + if (test_iter1 == last1) + { + if (test_iter2 != first2) + return std::make_pair(iter1, false); + else + break; + } + if (*test_iter1 != *test_iter2) + break; + } + } + return std::make_pair(last1, false); + } +} // namespace detail + +template +std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, const std::string& delim, + boost::system::error_code& ec) +{ + 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 iterator; + const_buffers_type buffers = b.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position; + iterator end = iterator::end(buffers); + + // Look for a match. + std::pair result = detail::partial_search( + start, end, delim.begin(), delim.end()); + if (result.first != end) + { + if (result.second) + { + // Full match. We're done. + ec = boost::system::error_code(); + return result.first - begin + delim.length(); + } + else + { + // Partial match. Next search needs to start from beginning of match. + search_position = result.first - begin; + } + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = read_size_helper(b, 65536); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +template +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, const boost::regex& expr) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, b, expr, ec); + boost::asio::detail::throw_error(ec); + return bytes_transferred; +} + +template +std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, const boost::regex& expr, + boost::system::error_code& ec) +{ + 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 iterator; + const_buffers_type buffers = b.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position; + iterator end = iterator::end(buffers); + + // Look for a match. + boost::match_results >::allocator_type> + match_results; + if (regex_search(start, end, match_results, expr, + boost::match_default | boost::match_partial)) + { + if (match_results[0].matched) + { + // Full match. We're done. + ec = boost::system::error_code(); + return match_results[0].second - begin; + } + else + { + // Partial match. Next search needs to start from beginning of match. + search_position = match_results[0].first - begin; + } + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = read_size_helper(b, 65536); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +template +std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, + MatchCondition match_condition, boost::system::error_code& ec, + typename boost::enable_if >::type*) +{ + 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 iterator; + const_buffers_type buffers = b.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position; + iterator end = iterator::end(buffers); + + // Look for a match. + std::pair result = match_condition(start, end); + if (result.second) + { + // Full match. We're done. + ec = boost::system::error_code(); + return result.first - begin; + } + else if (result.first != end) + { + // Partial match. Next search needs to start from beginning of match. + search_position = result.first - begin; + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = read_size_helper(b, 65536); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +template +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, MatchCondition match_condition, + typename boost::enable_if >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, b, match_condition, ec); + boost::asio::detail::throw_error(ec); + return bytes_transferred; +} + +namespace detail +{ + template + class read_until_delim_op + { + public: + read_until_delim_op(AsyncReadStream& stream, + boost::asio::basic_streambuf& streambuf, + char delim, ReadHandler handler) + : stream_(stream), + streambuf_(streambuf), + delim_(delim), + search_position_(0), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits::max)(); + std::size_t bytes_to_read; + switch (start) + { + case 1: + 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 iterator; + const_buffers_type buffers = streambuf_.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position_; + iterator end = iterator::end(buffers); + + // Look for a match. + iterator iter = std::find(start, end, delim_); + if (iter != end) + { + // Found a match. We're done. + search_position_ = iter - begin + 1; + bytes_to_read = 0; + } + + // No match yet. Check if buffer is full. + else if (streambuf_.size() == streambuf_.max_size()) + { + search_position_ = not_found; + bytes_to_read = 0; + } + + // Need to read some more data. + else + { + // Next search can start with the new data. + search_position_ = end - begin; + bytes_to_read = read_size_helper(streambuf_, 65536); + } + } + + // Check if we're done. + if (!start && bytes_to_read == 0) + break; + + // Start a new asynchronous read operation to obtain more data. + stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this); + return; default: + streambuf_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + handler_(search_position_ == not_found ? error::not_found : ec, + ec || search_position_ == not_found ? 0 : search_position_); + } + } + + //private: + AsyncReadStream& stream_; + boost::asio::basic_streambuf& streambuf_; + char delim_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_until_delim_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_delim_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_until_delim_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template +void async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf& b, char delim, ReadHandler handler) +{ + detail::read_until_delim_op< + AsyncReadStream, Allocator, ReadHandler>( + s, b, delim, handler)( + boost::system::error_code(), 0, 1); +} + +namespace detail +{ + template + class read_until_delim_string_op + { + public: + read_until_delim_string_op(AsyncReadStream& stream, + boost::asio::basic_streambuf& streambuf, + const std::string& delim, ReadHandler handler) + : stream_(stream), + streambuf_(streambuf), + delim_(delim), + search_position_(0), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits::max)(); + std::size_t bytes_to_read; + switch (start) + { + case 1: + 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 iterator; + const_buffers_type buffers = streambuf_.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position_; + iterator end = iterator::end(buffers); + + // Look for a match. + std::pair result = detail::partial_search( + start, end, delim_.begin(), delim_.end()); + if (result.first != end && result.second) + { + // Full match. We're done. + search_position_ = result.first - begin + delim_.length(); + bytes_to_read = 0; + } + + // No match yet. Check if buffer is full. + else if (streambuf_.size() == streambuf_.max_size()) + { + search_position_ = not_found; + bytes_to_read = 0; + } + + // Need to read some more data. + else + { + if (result.first != end) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = result.first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read = read_size_helper(streambuf_, 65536); + } + } + + // Check if we're done. + if (!start && bytes_to_read == 0) + break; + + // Start a new asynchronous read operation to obtain more data. + stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this); + return; default: + streambuf_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + handler_(search_position_ == not_found ? error::not_found : ec, + ec || search_position_ == not_found ? 0 : search_position_); + } + } + + //private: + AsyncReadStream& stream_; + boost::asio::basic_streambuf& streambuf_; + std::string delim_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_until_delim_string_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_delim_string_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_until_delim_string_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template +void async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf& b, const std::string& delim, + ReadHandler handler) +{ + detail::read_until_delim_string_op< + AsyncReadStream, Allocator, ReadHandler>( + s, b, delim, handler)( + boost::system::error_code(), 0, 1); +} + +namespace detail +{ + template + class read_until_expr_op + { + public: + read_until_expr_op(AsyncReadStream& stream, + boost::asio::basic_streambuf& streambuf, + const boost::regex& expr, ReadHandler handler) + : stream_(stream), + streambuf_(streambuf), + expr_(expr), + search_position_(0), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits::max)(); + std::size_t bytes_to_read; + switch (start) + { + case 1: + 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 iterator; + const_buffers_type buffers = streambuf_.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position_; + iterator end = iterator::end(buffers); + + // Look for a match. + boost::match_results >::allocator_type> + match_results; + bool match = regex_search(start, end, match_results, expr_, + boost::match_default | boost::match_partial); + if (match && match_results[0].matched) + { + // Full match. We're done. + search_position_ = match_results[0].second - begin; + bytes_to_read = 0; + } + + // No match yet. Check if buffer is full. + else if (streambuf_.size() == streambuf_.max_size()) + { + search_position_ = not_found; + bytes_to_read = 0; + } + + // Need to read some more data. + else + { + if (match) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = match_results[0].first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read = read_size_helper(streambuf_, 65536); + } + } + + // Check if we're done. + if (!start && bytes_to_read == 0) + break; + + // Start a new asynchronous read operation to obtain more data. + stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this); + return; default: + streambuf_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + handler_(search_position_ == not_found ? error::not_found : ec, + ec || search_position_ == not_found ? 0 : search_position_); + } + } + + //private: + AsyncReadStream& stream_; + boost::asio::basic_streambuf& streambuf_; + RegEx expr_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_until_expr_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_expr_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_until_expr_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template +void async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf& b, const boost::regex& expr, + ReadHandler handler) +{ + detail::read_until_expr_op( + s, b, expr, handler)( + boost::system::error_code(), 0, 1); +} + +namespace detail +{ + template + class read_until_match_op + { + public: + read_until_match_op(AsyncReadStream& stream, + boost::asio::basic_streambuf& streambuf, + MatchCondition match_condition, ReadHandler handler) + : stream_(stream), + streambuf_(streambuf), + match_condition_(match_condition), + search_position_(0), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits::max)(); + std::size_t bytes_to_read; + switch (start) + { + case 1: + 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 iterator; + const_buffers_type buffers = streambuf_.data(); + iterator begin = iterator::begin(buffers); + iterator start = begin + search_position_; + iterator end = iterator::end(buffers); + + // Look for a match. + std::pair result = match_condition_(start, end); + if (result.second) + { + // Full match. We're done. + search_position_ = result.first - begin; + bytes_to_read = 0; + } + + // No match yet. Check if buffer is full. + else if (streambuf_.size() == streambuf_.max_size()) + { + search_position_ = not_found; + bytes_to_read = 0; + } + + // Need to read some more data. + else + { + if (result.first != end) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = result.first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read = read_size_helper(streambuf_, 65536); + } + } + + // Check if we're done. + if (!start && bytes_to_read == 0) + break; + + // Start a new asynchronous read operation to obtain more data. + stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this); + return; default: + streambuf_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + handler_(search_position_ == not_found ? error::not_found : ec, + ec || search_position_ == not_found ? 0 : search_position_); + } + } + + //private: + AsyncReadStream& stream_; + boost::asio::basic_streambuf& streambuf_; + MatchCondition match_condition_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_until_match_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_match_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_until_match_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } +} // namespace detail + +template +void async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf& b, + MatchCondition match_condition, ReadHandler handler, + typename boost::enable_if >::type*) +{ + detail::read_until_match_op< + AsyncReadStream, Allocator, MatchCondition, ReadHandler>( + s, b, match_condition, handler)( + boost::system::error_code(), 0, 1); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_READ_UNTIL_HPP diff --git a/include/boost/asio/impl/read_until.ipp b/include/boost/asio/impl/read_until.ipp deleted file mode 100644 index 0ee0de0d..00000000 --- a/include/boost/asio/impl/read_until.ipp +++ /dev/null @@ -1,989 +0,0 @@ -// -// read_until.ipp -// ~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2010 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_READ_UNTIL_IPP -#define BOOST_ASIO_READ_UNTIL_IPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace asio { - -template -inline std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf& b, char delim) -{ - boost::system::error_code ec; - std::size_t bytes_transferred = read_until(s, b, delim, ec); - boost::asio::detail::throw_error(ec); - return bytes_transferred; -} - -template -std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf& b, char delim, - boost::system::error_code& ec) -{ - std::size_t next_search_start = 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 iterator; - const_buffers_type buffers = b.data(); - iterator begin = iterator::begin(buffers); - iterator start = begin + next_search_start; - iterator end = iterator::end(buffers); - - // Look for a match. - iterator iter = std::find(start, end, delim); - if (iter != end) - { - // Found a match. We're done. - ec = boost::system::error_code(); - return iter - begin + 1; - } - else - { - // No match. Next search can start with the new data. - next_search_start = end - begin; - } - - // Check if buffer is full. - if (b.size() == b.max_size()) - { - ec = error::not_found; - return 0; - } - - // Need more data. - std::size_t bytes_available = - std::min(512, b.max_size() - b.size()); - b.commit(s.read_some(b.prepare(bytes_available), ec)); - if (ec) - return 0; - } -} - -template -inline std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf& b, const std::string& delim) -{ - boost::system::error_code ec; - std::size_t bytes_transferred = read_until(s, b, delim, ec); - boost::asio::detail::throw_error(ec); - return bytes_transferred; -} - -namespace detail -{ - // Algorithm that finds a subsequence of equal values in a sequence. Returns - // (iterator,true) if a full match was found, in which case the iterator - // points to the beginning of the match. Returns (iterator,false) if a - // partial match was found at the end of the first sequence, in which case - // the iterator points to the beginning of the partial match. Returns - // (last1,false) if no full or partial match was found. - template - std::pair partial_search( - Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) - { - for (Iterator1 iter1 = first1; iter1 != last1; ++iter1) - { - Iterator1 test_iter1 = iter1; - Iterator2 test_iter2 = first2; - for (;; ++test_iter1, ++test_iter2) - { - if (test_iter2 == last2) - return std::make_pair(iter1, true); - if (test_iter1 == last1) - { - if (test_iter2 != first2) - return std::make_pair(iter1, false); - else - break; - } - if (*test_iter1 != *test_iter2) - break; - } - } - return std::make_pair(last1, false); - } -} // namespace detail - -template -std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf& b, const std::string& delim, - boost::system::error_code& ec) -{ - std::size_t next_search_start = 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 iterator; - const_buffers_type buffers = b.data(); - iterator begin = iterator::begin(buffers); - iterator start = begin + next_search_start; - iterator end = iterator::end(buffers); - - // Look for a match. - std::pair result = boost::asio::detail::partial_search( - start, end, delim.begin(), delim.end()); - if (result.first != end) - { - if (result.second) - { - // Full match. We're done. - ec = boost::system::error_code(); - return result.first - begin + delim.length(); - } - else - { - // Partial match. Next search needs to start from beginning of match. - next_search_start = result.first - begin; - } - } - else - { - // No match. Next search can start with the new data. - next_search_start = end - begin; - } - - // Check if buffer is full. - if (b.size() == b.max_size()) - { - ec = error::not_found; - return 0; - } - - // Need more data. - std::size_t bytes_available = - std::min(512, b.max_size() - b.size()); - b.commit(s.read_some(b.prepare(bytes_available), ec)); - if (ec) - return 0; - } -} - -template -inline std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf& b, const boost::regex& expr) -{ - boost::system::error_code ec; - std::size_t bytes_transferred = read_until(s, b, expr, ec); - boost::asio::detail::throw_error(ec); - return bytes_transferred; -} - -template -std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf& b, const boost::regex& expr, - boost::system::error_code& ec) -{ - std::size_t next_search_start = 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 iterator; - const_buffers_type buffers = b.data(); - iterator begin = iterator::begin(buffers); - iterator start = begin + next_search_start; - iterator end = iterator::end(buffers); - - // Look for a match. - boost::match_results match_results; - if (boost::regex_search(start, end, match_results, expr, - boost::match_default | boost::match_partial)) - { - if (match_results[0].matched) - { - // Full match. We're done. - ec = boost::system::error_code(); - return match_results[0].second - begin; - } - else - { - // Partial match. Next search needs to start from beginning of match. - next_search_start = match_results[0].first - begin; - } - } - else - { - // No match. Next search can start with the new data. - next_search_start = end - begin; - } - - // Check if buffer is full. - if (b.size() == b.max_size()) - { - ec = error::not_found; - return 0; - } - - // Need more data. - std::size_t bytes_available = - std::min(512, b.max_size() - b.size()); - b.commit(s.read_some(b.prepare(bytes_available), ec)); - if (ec) - return 0; - } -} - -template -std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf& b, - MatchCondition match_condition, boost::system::error_code& ec, - typename boost::enable_if >::type*) -{ - std::size_t next_search_start = 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 iterator; - const_buffers_type buffers = b.data(); - iterator begin = iterator::begin(buffers); - iterator start = begin + next_search_start; - iterator end = iterator::end(buffers); - - // Look for a match. - std::pair result = match_condition(start, end); - if (result.second) - { - // Full match. We're done. - ec = boost::system::error_code(); - return result.first - begin; - } - else if (result.first != end) - { - // Partial match. Next search needs to start from beginning of match. - next_search_start = result.first - begin; - } - else - { - // No match. Next search can start with the new data. - next_search_start = end - begin; - } - - // Check if buffer is full. - if (b.size() == b.max_size()) - { - ec = error::not_found; - return 0; - } - - // Need more data. - std::size_t bytes_available = - std::min(512, b.max_size() - b.size()); - b.commit(s.read_some(b.prepare(bytes_available), ec)); - if (ec) - return 0; - } -} - -template -inline std::size_t read_until(SyncReadStream& s, - boost::asio::basic_streambuf& b, MatchCondition match_condition, - typename boost::enable_if >::type*) -{ - boost::system::error_code ec; - std::size_t bytes_transferred = read_until(s, b, match_condition, ec); - boost::asio::detail::throw_error(ec); - return bytes_transferred; -} - -namespace detail -{ - template - class read_until_delim_handler - { - public: - read_until_delim_handler(AsyncReadStream& stream, - boost::asio::basic_streambuf& streambuf, char delim, - std::size_t next_search_start, ReadHandler handler) - : stream_(stream), - streambuf_(streambuf), - delim_(delim), - next_search_start_(next_search_start), - handler_(handler) - { - } - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - // Check for errors. - if (ec) - { - std::size_t bytes = 0; - handler_(ec, bytes); - return; - } - - // Commit received data to streambuf's get area. - streambuf_.commit(bytes_transferred); - - // 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 iterator; - const_buffers_type buffers = streambuf_.data(); - iterator begin = iterator::begin(buffers); - iterator start = begin + next_search_start_; - iterator end = iterator::end(buffers); - - // Look for a match. - iterator iter = std::find(start, end, delim_); - if (iter != end) - { - // Found a match. We're done. - std::size_t bytes = iter - begin + 1; - handler_(ec, bytes); - return; - } - - // No match. Check if buffer is full. - if (streambuf_.size() == streambuf_.max_size()) - { - std::size_t bytes = 0; - boost::system::error_code ec(error::not_found); - handler_(ec, bytes); - return; - } - - // Next search can start with the new data. - next_search_start_ = end - begin; - - // Start a new asynchronous read operation to obtain more data. - std::size_t bytes_available = - std::min(512, streambuf_.max_size() - streambuf_.size()); - stream_.async_read_some(streambuf_.prepare(bytes_available), *this); - } - - //private: - AsyncReadStream& stream_; - boost::asio::basic_streambuf& streambuf_; - char delim_; - std::size_t next_search_start_; - ReadHandler handler_; - }; - - template - inline void* asio_handler_allocate(std::size_t size, - read_until_delim_handler* this_handler) - { - return boost_asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template - inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_delim_handler* this_handler) - { - boost_asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template - inline void asio_handler_invoke(const Function& function, - read_until_delim_handler* this_handler) - { - boost_asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } -} // namespace detail - -template -void async_read_until(AsyncReadStream& s, - boost::asio::basic_streambuf& b, char delim, ReadHandler handler) -{ - // 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 iterator; - const_buffers_type buffers = b.data(); - iterator begin = iterator::begin(buffers); - iterator end = iterator::end(buffers); - - // Look for a match. - iterator iter = std::find(begin, end, delim); - if (iter != end) - { - // Found a match. We're done. - boost::system::error_code ec; - std::size_t bytes = iter - begin + 1; - s.get_io_service().post(detail::bind_handler(handler, ec, bytes)); - return; - } - - // No match. Check if buffer is full. - if (b.size() == b.max_size()) - { - boost::system::error_code ec(error::not_found); - s.get_io_service().post(detail::bind_handler(handler, ec, 0)); - return; - } - - // Start a new asynchronous read operation to obtain more data. - std::size_t bytes_available = - std::min(512, b.max_size() - b.size()); - s.async_read_some(b.prepare(bytes_available), - detail::read_until_delim_handler( - s, b, delim, end - begin, handler)); -} - -namespace detail -{ - template - class read_until_delim_string_handler - { - public: - read_until_delim_string_handler(AsyncReadStream& stream, - boost::asio::basic_streambuf& streambuf, - const std::string& delim, std::size_t next_search_start, - ReadHandler handler) - : stream_(stream), - streambuf_(streambuf), - delim_(delim), - next_search_start_(next_search_start), - handler_(handler) - { - } - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - // Check for errors. - if (ec) - { - std::size_t bytes = 0; - handler_(ec, bytes); - return; - } - - // Commit received data to streambuf's get area. - streambuf_.commit(bytes_transferred); - - // 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 iterator; - const_buffers_type buffers = streambuf_.data(); - iterator begin = iterator::begin(buffers); - iterator start = begin + next_search_start_; - iterator end = iterator::end(buffers); - - // Look for a match. - std::pair result = boost::asio::detail::partial_search( - start, end, delim_.begin(), delim_.end()); - if (result.first != end) - { - if (result.second) - { - // Full match. We're done. - std::size_t bytes = result.first - begin + delim_.length(); - handler_(ec, bytes); - return; - } - else - { - // Partial match. Next search needs to start from beginning of match. - next_search_start_ = result.first - begin; - } - } - else - { - // No match. Next search can start with the new data. - next_search_start_ = end - begin; - } - - // Check if buffer is full. - if (streambuf_.size() == streambuf_.max_size()) - { - std::size_t bytes = 0; - boost::system::error_code ec2(error::not_found); - handler_(ec2, bytes); - return; - } - - // Start a new asynchronous read operation to obtain more data. - std::size_t bytes_available = - std::min(512, streambuf_.max_size() - streambuf_.size()); - stream_.async_read_some(streambuf_.prepare(bytes_available), *this); - } - - //private: - AsyncReadStream& stream_; - boost::asio::basic_streambuf& streambuf_; - std::string delim_; - std::size_t next_search_start_; - ReadHandler handler_; - }; - - template - inline void* asio_handler_allocate(std::size_t size, - read_until_delim_string_handler* this_handler) - { - return boost_asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template - inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_delim_string_handler* this_handler) - { - boost_asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template - inline void asio_handler_invoke(const Function& function, - read_until_delim_string_handler* this_handler) - { - boost_asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } -} // namespace detail - -template -void async_read_until(AsyncReadStream& s, - boost::asio::basic_streambuf& b, const std::string& delim, - ReadHandler handler) -{ - // 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 iterator; - const_buffers_type buffers = b.data(); - iterator begin = iterator::begin(buffers); - iterator end = iterator::end(buffers); - - // Look for a match. - std::size_t next_search_start; - std::pair result = boost::asio::detail::partial_search( - begin, end, delim.begin(), delim.end()); - if (result.first != end) - { - if (result.second) - { - // Full match. We're done. - boost::system::error_code ec; - std::size_t bytes = result.first - begin + delim.length(); - s.get_io_service().post(detail::bind_handler(handler, ec, bytes)); - return; - } - else - { - // Partial match. Next search needs to start from beginning of match. - next_search_start = result.first - begin; - } - } - else - { - // No match. Next search can start with the new data. - next_search_start = end - begin; - } - - // Check if buffer is full. - if (b.size() == b.max_size()) - { - boost::system::error_code ec(error::not_found); - s.get_io_service().post(detail::bind_handler(handler, ec, 0)); - return; - } - - // Start a new asynchronous read operation to obtain more data. - std::size_t bytes_available = - std::min(512, b.max_size() - b.size()); - s.async_read_some(b.prepare(bytes_available), - detail::read_until_delim_string_handler< - AsyncReadStream, Allocator, ReadHandler>( - s, b, delim, next_search_start, handler)); -} - -namespace detail -{ - template - class read_until_expr_handler - { - public: - read_until_expr_handler(AsyncReadStream& stream, - boost::asio::basic_streambuf& streambuf, - const boost::regex& expr, std::size_t next_search_start, - ReadHandler handler) - : stream_(stream), - streambuf_(streambuf), - expr_(expr), - next_search_start_(next_search_start), - handler_(handler) - { - } - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - // Check for errors. - if (ec) - { - std::size_t bytes = 0; - handler_(ec, bytes); - return; - } - - // Commit received data to streambuf's get area. - streambuf_.commit(bytes_transferred); - - // 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 iterator; - const_buffers_type buffers = streambuf_.data(); - iterator begin = iterator::begin(buffers); - iterator start = begin + next_search_start_; - iterator end = iterator::end(buffers); - - // Look for a match. - boost::match_results match_results; - if (boost::regex_search(start, end, match_results, expr_, - boost::match_default | boost::match_partial)) - { - if (match_results[0].matched) - { - // Full match. We're done. - std::size_t bytes = match_results[0].second - begin; - handler_(ec, bytes); - return; - } - else - { - // Partial match. Next search needs to start from beginning of match. - next_search_start_ = match_results[0].first - begin; - } - } - else - { - // No match. Next search can start with the new data. - next_search_start_ = end - begin; - } - - // Check if buffer is full. - if (streambuf_.size() == streambuf_.max_size()) - { - std::size_t bytes = 0; - boost::system::error_code ec(error::not_found); - handler_(ec, bytes); - return; - } - - // Start a new asynchronous read operation to obtain more data. - std::size_t bytes_available = - std::min(512, streambuf_.max_size() - streambuf_.size()); - stream_.async_read_some(streambuf_.prepare(bytes_available), *this); - } - - //private: - AsyncReadStream& stream_; - boost::asio::basic_streambuf& streambuf_; - boost::regex expr_; - std::size_t next_search_start_; - ReadHandler handler_; - }; - - template - inline void* asio_handler_allocate(std::size_t size, - read_until_expr_handler* this_handler) - { - return boost_asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template - inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_expr_handler* this_handler) - { - boost_asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template - inline void asio_handler_invoke(const Function& function, - read_until_expr_handler* this_handler) - { - boost_asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } -} // namespace detail - -template -void async_read_until(AsyncReadStream& s, - boost::asio::basic_streambuf& b, const boost::regex& expr, - ReadHandler handler) -{ - // 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 iterator; - const_buffers_type buffers = b.data(); - iterator begin = iterator::begin(buffers); - iterator end = iterator::end(buffers); - - // Look for a match. - std::size_t next_search_start; - boost::match_results match_results; - if (boost::regex_search(begin, end, match_results, expr, - boost::match_default | boost::match_partial)) - { - if (match_results[0].matched) - { - // Full match. We're done. - boost::system::error_code ec; - std::size_t bytes = match_results[0].second - begin; - s.get_io_service().post(detail::bind_handler(handler, ec, bytes)); - return; - } - else - { - // Partial match. Next search needs to start from beginning of match. - next_search_start = match_results[0].first - begin; - } - } - else - { - // No match. Next search can start with the new data. - next_search_start = end - begin; - } - - // Check if buffer is full. - if (b.size() == b.max_size()) - { - boost::system::error_code ec(error::not_found); - s.get_io_service().post(detail::bind_handler(handler, ec, 0)); - return; - } - - // Start a new asynchronous read operation to obtain more data. - std::size_t bytes_available = - std::min(512, b.max_size() - b.size()); - s.async_read_some(b.prepare(bytes_available), - detail::read_until_expr_handler( - s, b, expr, next_search_start, handler)); -} - -namespace detail -{ - template - class read_until_match_handler - { - public: - read_until_match_handler(AsyncReadStream& stream, - boost::asio::basic_streambuf& streambuf, - MatchCondition match_condition, std::size_t next_search_start, - ReadHandler handler) - : stream_(stream), - streambuf_(streambuf), - match_condition_(match_condition), - next_search_start_(next_search_start), - handler_(handler) - { - } - - void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred) - { - // Check for errors. - if (ec) - { - std::size_t bytes = 0; - handler_(ec, bytes); - return; - } - - // Commit received data to streambuf's get area. - streambuf_.commit(bytes_transferred); - - // 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 iterator; - const_buffers_type buffers = streambuf_.data(); - iterator begin = iterator::begin(buffers); - iterator start = begin + next_search_start_; - iterator end = iterator::end(buffers); - - // Look for a match. - std::pair result = match_condition_(start, end); - if (result.second) - { - // Full match. We're done. - std::size_t bytes = result.first - begin; - handler_(ec, bytes); - return; - } - else if (result.first != end) - { - // Partial match. Next search needs to start from beginning of match. - next_search_start_ = result.first - begin; - } - else - { - // No match. Next search can start with the new data. - next_search_start_ = end - begin; - } - - // Check if buffer is full. - if (streambuf_.size() == streambuf_.max_size()) - { - std::size_t bytes = 0; - boost::system::error_code ec(error::not_found); - handler_(ec, bytes); - return; - } - - // Start a new asynchronous read operation to obtain more data. - std::size_t bytes_available = - std::min(512, streambuf_.max_size() - streambuf_.size()); - stream_.async_read_some(streambuf_.prepare(bytes_available), *this); - } - - //private: - AsyncReadStream& stream_; - boost::asio::basic_streambuf& streambuf_; - MatchCondition match_condition_; - std::size_t next_search_start_; - ReadHandler handler_; - }; - - template - inline void* asio_handler_allocate(std::size_t size, - read_until_match_handler* this_handler) - { - return boost_asio_handler_alloc_helpers::allocate( - size, this_handler->handler_); - } - - template - inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_match_handler* this_handler) - { - boost_asio_handler_alloc_helpers::deallocate( - pointer, size, this_handler->handler_); - } - - template - inline void asio_handler_invoke(const Function& function, - read_until_match_handler* this_handler) - { - boost_asio_handler_invoke_helpers::invoke( - function, this_handler->handler_); - } -} // namespace detail - -template -void async_read_until(AsyncReadStream& s, - boost::asio::basic_streambuf& b, - MatchCondition match_condition, ReadHandler handler, - typename boost::enable_if >::type*) -{ - // 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 iterator; - const_buffers_type buffers = b.data(); - iterator begin = iterator::begin(buffers); - iterator end = iterator::end(buffers); - - // Look for a match. - std::size_t next_search_start; - std::pair result = match_condition(begin, end); - if (result.second) - { - // Full match. We're done. - boost::system::error_code ec; - std::size_t bytes = result.first - begin; - s.get_io_service().post(detail::bind_handler(handler, ec, bytes)); - return; - } - else if (result.first != end) - { - // Partial match. Next search needs to start from beginning of match. - next_search_start = result.first - begin; - } - else - { - // No match. Next search can start with the new data. - next_search_start = end - begin; - } - - // Check if buffer is full. - if (b.size() == b.max_size()) - { - boost::system::error_code ec(error::not_found); - s.get_io_service().post(detail::bind_handler(handler, ec, 0)); - return; - } - - // Start a new asynchronous read operation to obtain more data. - std::size_t bytes_available = - std::min(512, b.max_size() - b.size()); - s.async_read_some(b.prepare(bytes_available), - detail::read_until_match_handler< - AsyncReadStream, Allocator, MatchCondition, ReadHandler>( - s, b, match_condition, next_search_start, handler)); -} - -} // namespace asio -} // namespace boost - -#include - -#endif // BOOST_ASIO_READ_UNTIL_IPP diff --git a/include/boost/asio/impl/serial_port_base.hpp b/include/boost/asio/impl/serial_port_base.hpp new file mode 100644 index 00000000..2b291f39 --- /dev/null +++ b/include/boost/asio/impl/serial_port_base.hpp @@ -0,0 +1,61 @@ +// +// impl/serial_port_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.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_SERIAL_PORT_BASE_HPP +#define BOOST_ASIO_IMPL_SERIAL_PORT_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace asio { + +inline serial_port_base::baud_rate::baud_rate(unsigned int rate) + : value_(rate) +{ +} + +inline unsigned int serial_port_base::baud_rate::value() const +{ + return value_; +} + +inline serial_port_base::flow_control::type +serial_port_base::flow_control::value() const +{ + return value_; +} + +inline serial_port_base::parity::type serial_port_base::parity::value() const +{ + return value_; +} + +inline serial_port_base::stop_bits::type +serial_port_base::stop_bits::value() const +{ + return value_; +} + +inline unsigned int serial_port_base::character_size::value() const +{ + return value_; +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_SERIAL_PORT_BASE_HPP diff --git a/include/boost/asio/impl/serial_port_base.ipp b/include/boost/asio/impl/serial_port_base.ipp index 2775a02b..1eb96b02 100644 --- a/include/boost/asio/impl/serial_port_base.ipp +++ b/include/boost/asio/impl/serial_port_base.ipp @@ -1,6 +1,6 @@ // -// serial_port_base.ipp -// ~~~~~~~~~~~~~~~~~~~~ +// impl/serial_port_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) @@ -9,33 +9,36 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_SERIAL_PORT_BASE_IPP -#define BOOST_ASIO_SERIAL_PORT_BASE_IPP +#ifndef BOOST_ASIO_IMPL_SERIAL_PORT_BASE_IPP +#define BOOST_ASIO_IMPL_SERIAL_PORT_BASE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include + +#if defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#include +#include +#include +#include + +#if defined(GENERATING_DOCUMENTATION) +# define BOOST_ASIO_OPTION_STORAGE implementation_defined +#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# define BOOST_ASIO_OPTION_STORAGE DCB +#else +# define BOOST_ASIO_OPTION_STORAGE termios +#endif #include -#include -#include namespace boost { namespace asio { -inline serial_port_base::baud_rate::baud_rate(unsigned int rate) - : value_(rate) -{ -} - -inline unsigned int serial_port_base::baud_rate::value() const -{ - return value_; -} - -inline boost::system::error_code serial_port_base::baud_rate::store( +boost::system::error_code serial_port_base::baud_rate::store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -123,7 +126,7 @@ inline boost::system::error_code serial_port_base::baud_rate::store( return ec; } -inline boost::system::error_code serial_port_base::baud_rate::load( +boost::system::error_code serial_port_base::baud_rate::load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -205,7 +208,7 @@ inline boost::system::error_code serial_port_base::baud_rate::load( return ec; } -inline serial_port_base::flow_control::flow_control( +serial_port_base::flow_control::flow_control( serial_port_base::flow_control::type t) : value_(t) { @@ -216,13 +219,7 @@ inline serial_port_base::flow_control::flow_control( } } -inline serial_port_base::flow_control::type -serial_port_base::flow_control::value() const -{ - return value_; -} - -inline boost::system::error_code serial_port_base::flow_control::store( +boost::system::error_code serial_port_base::flow_control::store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -281,7 +278,7 @@ inline boost::system::error_code serial_port_base::flow_control::store( return ec; } -inline boost::system::error_code serial_port_base::flow_control::load( +boost::system::error_code serial_port_base::flow_control::load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -317,7 +314,7 @@ inline boost::system::error_code serial_port_base::flow_control::load( return ec; } -inline serial_port_base::parity::parity(serial_port_base::parity::type t) +serial_port_base::parity::parity(serial_port_base::parity::type t) : value_(t) { if (t != none && t != odd && t != even) @@ -327,12 +324,7 @@ inline serial_port_base::parity::parity(serial_port_base::parity::type t) } } -inline serial_port_base::parity::type serial_port_base::parity::value() const -{ - return value_; -} - -inline boost::system::error_code serial_port_base::parity::store( +boost::system::error_code serial_port_base::parity::store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -379,7 +371,7 @@ inline boost::system::error_code serial_port_base::parity::store( return ec; } -inline boost::system::error_code serial_port_base::parity::load( +boost::system::error_code serial_port_base::parity::load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -416,7 +408,7 @@ inline boost::system::error_code serial_port_base::parity::load( return ec; } -inline serial_port_base::stop_bits::stop_bits( +serial_port_base::stop_bits::stop_bits( serial_port_base::stop_bits::type t) : value_(t) { @@ -427,13 +419,7 @@ inline serial_port_base::stop_bits::stop_bits( } } -inline serial_port_base::stop_bits::type -serial_port_base::stop_bits::value() const -{ - return value_; -} - -inline boost::system::error_code serial_port_base::stop_bits::store( +boost::system::error_code serial_port_base::stop_bits::store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -469,7 +455,7 @@ inline boost::system::error_code serial_port_base::stop_bits::store( return ec; } -inline boost::system::error_code serial_port_base::stop_bits::load( +boost::system::error_code serial_port_base::stop_bits::load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -496,7 +482,7 @@ inline boost::system::error_code serial_port_base::stop_bits::load( return ec; } -inline serial_port_base::character_size::character_size(unsigned int t) +serial_port_base::character_size::character_size(unsigned int t) : value_(t) { if (t < 5 || t > 8) @@ -506,12 +492,7 @@ inline serial_port_base::character_size::character_size(unsigned int t) } } -inline unsigned int serial_port_base::character_size::value() const -{ - return value_; -} - -inline boost::system::error_code serial_port_base::character_size::store( +boost::system::error_code serial_port_base::character_size::store( BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -531,7 +512,7 @@ inline boost::system::error_code serial_port_base::character_size::store( return ec; } -inline boost::system::error_code serial_port_base::character_size::load( +boost::system::error_code serial_port_base::character_size::load( const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -556,4 +537,8 @@ inline boost::system::error_code serial_port_base::character_size::load( #include -#endif // BOOST_ASIO_SERIAL_PORT_BASE_IPP +#undef BOOST_ASIO_OPTION_STORAGE + +#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#endif // BOOST_ASIO_IMPL_SERIAL_PORT_BASE_IPP diff --git a/include/boost/asio/impl/src.cpp b/include/boost/asio/impl/src.cpp new file mode 100644 index 00000000..59a10c95 --- /dev/null +++ b/include/boost/asio/impl/src.cpp @@ -0,0 +1,59 @@ +// +// impl/src.cpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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) +// + +#define BOOST_ASIO_SOURCE + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# error Do not compile Asio library source with BOOST_ASIO_HEADER_ONLY defined +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/include/boost/asio/impl/write.ipp b/include/boost/asio/impl/write.hpp similarity index 92% rename from include/boost/asio/impl/write.ipp rename to include/boost/asio/impl/write.hpp index 28a5273c..0792f2cb 100644 --- a/include/boost/asio/impl/write.ipp +++ b/include/boost/asio/impl/write.hpp @@ -1,6 +1,6 @@ // -// write.ipp -// ~~~~~~~~~ +// impl/write.hpp +// ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,15 +8,13 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_WRITE_IPP -#define BOOST_ASIO_WRITE_IPP +#ifndef BOOST_ASIO_IMPL_WRITE_HPP +#define BOOST_ASIO_IMPL_WRITE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - #include #include #include @@ -26,6 +24,8 @@ #include #include +#include + namespace boost { namespace asio { @@ -123,25 +123,24 @@ namespace detail stream_(stream), buffers_(buffers), total_transferred_(0), - handler_(handler), - start_(true) + handler_(handler) { } void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred) + std::size_t bytes_transferred, int start = 0) { - switch (start_) + switch (start) { - case true: start_ = false; - buffers_.prepare(this->check(ec, total_transferred_)); + case 1: + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); for (;;) { stream_.async_write_some(buffers_, *this); return; default: total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - buffers_.prepare(this->check(ec, total_transferred_)); + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); if ((!ec && bytes_transferred == 0) || buffers_.begin() == buffers_.end()) break; @@ -157,7 +156,6 @@ namespace detail const_buffer, ConstBufferSequence> buffers_; std::size_t total_transferred_; WriteHandler handler_; - bool start_; }; template check(ec, total_transferred_); + case 1: + n = this->check_for_completion(ec, total_transferred_); for (;;) { stream_.async_write_some(boost::asio::buffer( @@ -196,7 +193,7 @@ namespace detail return; default: total_transferred_ += bytes_transferred; if ((!ec && bytes_transferred == 0) - || (n = this->check(ec, total_transferred_)) == 0 + || (n = this->check_for_completion(ec, total_transferred_)) == 0 || total_transferred_ == boost::asio::buffer_size(buffer_)) break; } @@ -210,7 +207,6 @@ namespace detail boost::asio::mutable_buffer buffer_; std::size_t total_transferred_; WriteHandler handler_; - bool start_; }; template check(ec, total_transferred_); + case 1: + n = this->check_for_completion(ec, total_transferred_); for (;;) { stream_.async_write_some(boost::asio::buffer( @@ -249,7 +244,7 @@ namespace detail return; default: total_transferred_ += bytes_transferred; if ((!ec && bytes_transferred == 0) - || (n = this->check(ec, total_transferred_)) == 0 + || (n = this->check_for_completion(ec, total_transferred_)) == 0 || total_transferred_ == boost::asio::buffer_size(buffer_)) break; } @@ -263,7 +258,6 @@ namespace detail boost::asio::const_buffer buffer_; std::size_t total_transferred_; WriteHandler handler_; - bool start_; }; template ( s, buffers, completion_condition, handler)( - boost::system::error_code(), 0); + boost::system::error_code(), 0, 1); } template -#endif // BOOST_ASIO_WRITE_IPP +#endif // BOOST_ASIO_IMPL_WRITE_HPP diff --git a/include/boost/asio/impl/write_at.ipp b/include/boost/asio/impl/write_at.hpp similarity index 61% rename from include/boost/asio/impl/write_at.ipp rename to include/boost/asio/impl/write_at.hpp index 3d1a1128..daa14420 100644 --- a/include/boost/asio/impl/write_at.ipp +++ b/include/boost/asio/impl/write_at.hpp @@ -1,6 +1,6 @@ // -// write_at.ipp -// ~~~~~~~~~~~~ +// impl/write_at.hpp +// ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -8,23 +8,24 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BOOST_ASIO_WRITE_AT_IPP -#define BOOST_ASIO_WRITE_AT_IPP +#ifndef BOOST_ASIO_IMPL_WRITE_AT_HPP +#define BOOST_ASIO_IMPL_WRITE_AT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - #include #include +#include #include #include #include #include #include +#include + namespace boost { namespace asio { @@ -119,55 +120,166 @@ namespace detail { template - class write_at_handler + class write_at_op + : detail::base_from_completion_cond { public: - typedef boost::asio::detail::consuming_buffers< - const_buffer, ConstBufferSequence> buffers_type; - - write_at_handler(AsyncRandomAccessWriteDevice& stream, - boost::uint64_t offset, const buffers_type& buffers, + write_at_op(AsyncRandomAccessWriteDevice& device, + boost::uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition, WriteHandler handler) - : stream_(stream), - buffers_(buffers), + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), offset_(offset), + buffers_(buffers), total_transferred_(0), - completion_condition_(completion_condition), handler_(handler) { } void operator()(const boost::system::error_code& ec, - std::size_t bytes_transferred) + std::size_t bytes_transferred, int start = 0) { - total_transferred_ += bytes_transferred; - buffers_.consume(bytes_transferred); - buffers_.prepare(detail::adapt_completion_condition_result( - completion_condition_(ec, total_transferred_))); - if (buffers_.begin() == buffers_.end()) + switch (start) { + case 1: + buffers_.prepare(this->check_for_completion(ec, total_transferred_)); + for (;;) + { + device_.async_write_some_at( + offset_ + total_transferred_, buffers_, *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, total_transferred_); } - else - { - stream_.async_write_some_at( - offset_ + total_transferred_, buffers_, *this); - } } //private: - AsyncRandomAccessWriteDevice& stream_; - buffers_type buffers_; + AsyncRandomAccessWriteDevice& device_; boost::uint64_t offset_; + boost::asio::detail::consuming_buffers< + const_buffer, ConstBufferSequence> buffers_; + std::size_t total_transferred_; + WriteHandler handler_; + }; + + template + class write_at_op + : detail::base_from_completion_cond + { + public: + write_at_op(AsyncRandomAccessWriteDevice& device, + boost::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), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t n = 0; + switch (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), *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, total_transferred_); + } + } + + //private: + AsyncRandomAccessWriteDevice& device_; + boost::uint64_t offset_; + boost::asio::mutable_buffer buffer_; + std::size_t total_transferred_; + WriteHandler handler_; + }; + + template + class write_at_op + : detail::base_from_completion_cond + { + public: + write_at_op(AsyncRandomAccessWriteDevice& device, + boost::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), + total_transferred_(0), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t n = 0; + switch (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), *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, total_transferred_); + } + } + + //private: + AsyncRandomAccessWriteDevice& device_; + boost::uint64_t offset_; + boost::asio::const_buffer buffer_; std::size_t total_transferred_; - CompletionCondition completion_condition_; WriteHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, - write_at_handler* this_handler) { return boost_asio_handler_alloc_helpers::allocate( @@ -177,7 +289,7 @@ namespace detail template inline void asio_handler_deallocate(void* pointer, std::size_t size, - write_at_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( @@ -188,7 +300,7 @@ namespace detail typename ConstBufferSequence, typename CompletionCondition, typename WriteHandler> inline void asio_handler_invoke(const Function& function, - write_at_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -202,24 +314,10 @@ inline void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition, WriteHandler handler) { - boost::asio::detail::consuming_buffers< - const_buffer, ConstBufferSequence> tmp(buffers); - - boost::system::error_code ec; - std::size_t total_transferred = 0; - tmp.prepare(detail::adapt_completion_condition_result( - completion_condition(ec, total_transferred))); - if (tmp.begin() == tmp.end()) - { - d.get_io_service().post(detail::bind_handler( - handler, ec, total_transferred)); - return; - } - - d.async_write_some_at(offset, tmp, - detail::write_at_handler( - d, offset, tmp, completion_condition, handler)); + detail::write_at_op( + d, offset, buffers, completion_condition, handler)( + boost::system::error_code(), 0, 1); } template - class write_at_streambuf_handler + template + class write_at_streambuf_op { public: - write_at_streambuf_handler( + write_at_streambuf_op( boost::asio::basic_streambuf& streambuf, WriteHandler handler) : streambuf_(streambuf), @@ -263,7 +361,7 @@ namespace detail template inline void* asio_handler_allocate(std::size_t size, - write_at_streambuf_handler* this_handler) { return boost_asio_handler_alloc_helpers::allocate( @@ -273,7 +371,7 @@ namespace detail template inline void asio_handler_deallocate(void* pointer, std::size_t size, - write_at_streambuf_handler* this_handler) { boost_asio_handler_alloc_helpers::deallocate( @@ -283,7 +381,7 @@ namespace detail template inline void asio_handler_invoke(const Function& function, - write_at_streambuf_handler* this_handler) { boost_asio_handler_invoke_helpers::invoke( @@ -298,7 +396,7 @@ inline void async_write_at(AsyncRandomAccessWriteDevice& d, CompletionCondition completion_condition, WriteHandler handler) { async_write_at(d, offset, b.data(), completion_condition, - detail::write_at_streambuf_handler< + detail::write_at_streambuf_op< AsyncRandomAccessWriteDevice, Allocator, WriteHandler>(b, handler)); } @@ -318,4 +416,4 @@ inline void async_write_at(AsyncRandomAccessWriteDevice& d, #include -#endif // BOOST_ASIO_WRITE_AT_IPP +#endif // BOOST_ASIO_IMPL_WRITE_AT_HPP diff --git a/include/boost/asio/io_service.hpp b/include/boost/asio/io_service.hpp index 3863e96f..9350a84a 100644 --- a/include/boost/asio/io_service.hpp +++ b/include/boost/asio/io_service.hpp @@ -15,25 +15,29 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include -#include -#include -#include -#include - #include -#include #include -#include -#include -#include -#include #include +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else +# include +#endif + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# include +#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ + || defined(__osf__) +# include +#endif + +#include namespace boost { namespace asio { @@ -46,7 +50,7 @@ template bool has_service(io_service& ios); #if defined(BOOST_ASIO_HAS_IOCP) namespace detail { typedef win_iocp_io_service io_service_impl; } #else -namespace detail { typedef task_io_service io_service_impl; } +namespace detail { typedef task_io_service io_service_impl; } #endif /// Provides core I/O functionality. @@ -197,7 +201,7 @@ public: class strand; /// Constructor. - io_service(); + BOOST_ASIO_DECL io_service(); /// Constructor. /** @@ -206,7 +210,7 @@ public: * @param concurrency_hint A suggestion to the implementation on how many * threads it should allow to run simultaneously. */ - explicit io_service(std::size_t concurrency_hint); + BOOST_ASIO_DECL explicit io_service(std::size_t concurrency_hint); /// Destructor. /** @@ -240,7 +244,7 @@ public: * destructor defined above destroys all handlers, causing all @c shared_ptr * references to all connection objects to be destroyed. */ - ~io_service(); + BOOST_ASIO_DECL ~io_service(); /// Run the io_service object's event processing loop. /** @@ -266,7 +270,7 @@ public: * The poll() function may also be used to dispatch ready handlers, but * without blocking. */ - std::size_t run(); + BOOST_ASIO_DECL std::size_t run(); /// Run the io_service object's event processing loop. /** @@ -292,7 +296,7 @@ public: * The poll() function may also be used to dispatch ready handlers, but * without blocking. */ - std::size_t run(boost::system::error_code& ec); + 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. @@ -304,7 +308,7 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - std::size_t run_one(); + BOOST_ASIO_DECL std::size_t run_one(); /// Run the io_service object's event processing loop to execute at most one /// handler. @@ -316,7 +320,7 @@ public: * * @return The number of handlers that were executed. */ - std::size_t run_one(boost::system::error_code& ec); + 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. @@ -328,7 +332,7 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - std::size_t poll(); + BOOST_ASIO_DECL std::size_t poll(); /// Run the io_service object's event processing loop to execute ready /// handlers. @@ -340,7 +344,7 @@ public: * * @return The number of handlers that were executed. */ - std::size_t poll(boost::system::error_code& ec); + 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. @@ -352,7 +356,7 @@ public: * * @throws boost::system::system_error Thrown on failure. */ - std::size_t poll_one(); + BOOST_ASIO_DECL std::size_t poll_one(); /// Run the io_service object's event processing loop to execute one ready /// handler. @@ -364,7 +368,7 @@ public: * * @return The number of handlers that were executed. */ - std::size_t poll_one(boost::system::error_code& ec); + BOOST_ASIO_DECL std::size_t poll_one(boost::system::error_code& ec); /// Stop the io_service object's event processing loop. /** @@ -373,7 +377,7 @@ public: * return as soon as possible. Subsequent calls to run(), run_one(), poll() * or poll_one() will return immediately until reset() is called. */ - void stop(); + BOOST_ASIO_DECL void stop(); /// Reset the io_service in preparation for a subsequent run() invocation. /** @@ -386,7 +390,7 @@ public: * This function must not be called while there are any unfinished calls to * the run(), run_one(), poll() or poll_one() functions. */ - void reset(); + BOOST_ASIO_DECL void reset(); /// Request the io_service to invoke the given handler. /** @@ -606,10 +610,10 @@ protected: /** * @param owner The io_service object that owns the service. */ - service(boost::asio::io_service& owner); + BOOST_ASIO_DECL service(boost::asio::io_service& owner); /// Destructor. - virtual ~service(); + BOOST_ASIO_DECL virtual ~service(); private: /// Destroy all user-defined handler objects owned by the service. @@ -632,10 +636,7 @@ class service_already_exists : public std::logic_error { public: - service_already_exists() - : std::logic_error("Service already exists.") - { - } + BOOST_ASIO_DECL service_already_exists(); }; /// Exception thrown when trying to add a service object to an io_service where @@ -644,17 +645,45 @@ class invalid_service_owner : public std::logic_error { public: - invalid_service_owner() - : std::logic_error("Invalid service owner.") + BOOST_ASIO_DECL invalid_service_owner(); +}; + +namespace detail { + +// Special derived service id type to keep classes header-file only. +template +class service_id + : public boost::asio::io_service::id +{ +}; + +// Special service base class to keep classes header-file only. +template +class service_base + : public boost::asio::io_service::service +{ +public: + static boost::asio::detail::service_id id; + + // Constructor. + service_base(boost::asio::io_service& io_service) + : boost::asio::io_service::service(io_service) { } }; +template +boost::asio::detail::service_id service_base::id; + +} // namespace detail } // namespace asio } // namespace boost -#include - #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_IO_SERVICE_HPP diff --git a/include/boost/asio/ip/address.hpp b/include/boost/asio/ip/address.hpp index 16113f00..8cc3a4b4 100644 --- a/include/boost/asio/ip/address.hpp +++ b/include/boost/asio/ip/address.hpp @@ -1,6 +1,6 @@ // -// address.hpp -// ~~~~~~~~~~~ +// ip/address.hpp +// ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,21 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#include +#include +#include +#include -#include -#include #if !defined(BOOST_NO_IOSTREAM) # include #endif // !defined(BOOST_NO_IOSTREAM) -#include -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace asio { @@ -48,63 +44,27 @@ class address { public: /// Default constructor. - address() - : type_(ipv4), - ipv4_address_(), - ipv6_address_() - { - } + BOOST_ASIO_DECL address(); /// Construct an address from an IPv4 address. - address(const boost::asio::ip::address_v4& ipv4_address) - : type_(ipv4), - ipv4_address_(ipv4_address), - ipv6_address_() - { - } + BOOST_ASIO_DECL address(const boost::asio::ip::address_v4& ipv4_address); /// Construct an address from an IPv6 address. - address(const boost::asio::ip::address_v6& ipv6_address) - : type_(ipv6), - ipv4_address_(), - ipv6_address_(ipv6_address) - { - } + BOOST_ASIO_DECL address(const boost::asio::ip::address_v6& ipv6_address); /// Copy constructor. - address(const address& other) - : type_(other.type_), - ipv4_address_(other.ipv4_address_), - ipv6_address_(other.ipv6_address_) - { - } + BOOST_ASIO_DECL address(const address& other); /// Assign from another address. - address& operator=(const address& other) - { - type_ = other.type_; - ipv4_address_ = other.ipv4_address_; - ipv6_address_ = other.ipv6_address_; - return *this; - } + BOOST_ASIO_DECL address& operator=(const address& other); /// Assign from an IPv4 address. - address& operator=(const boost::asio::ip::address_v4& ipv4_address) - { - type_ = ipv4; - ipv4_address_ = ipv4_address; - ipv6_address_ = boost::asio::ip::address_v6(); - return *this; - } + BOOST_ASIO_DECL address& operator=( + const boost::asio::ip::address_v4& ipv4_address); /// Assign from an IPv6 address. - address& operator=(const boost::asio::ip::address_v6& ipv6_address) - { - type_ = ipv6; - ipv4_address_ = boost::asio::ip::address_v4(); - ipv6_address_ = ipv6_address; - return *this; - } + BOOST_ASIO_DECL address& operator=( + const boost::asio::ip::address_v6& ipv6_address); /// Get whether the address is an IP version 4 address. bool is_v4() const @@ -119,127 +79,63 @@ public: } /// Get the address as an IP version 4 address. - boost::asio::ip::address_v4 to_v4() const - { - if (type_ != ipv4) - { - boost::system::system_error e( - boost::asio::error::address_family_not_supported); - boost::throw_exception(e); - } - return ipv4_address_; - } + BOOST_ASIO_DECL boost::asio::ip::address_v4 to_v4() const; /// Get the address as an IP version 6 address. - boost::asio::ip::address_v6 to_v6() const - { - if (type_ != ipv6) - { - boost::system::system_error e( - boost::asio::error::address_family_not_supported); - boost::throw_exception(e); - } - return ipv6_address_; - } + BOOST_ASIO_DECL boost::asio::ip::address_v6 to_v6() const; /// Get the address as a string in dotted decimal format. - std::string to_string() const - { - if (type_ == ipv6) - return ipv6_address_.to_string(); - return ipv4_address_.to_string(); - } + BOOST_ASIO_DECL std::string to_string() const; /// Get the address as a string in dotted decimal format. - std::string to_string(boost::system::error_code& ec) const - { - if (type_ == ipv6) - return ipv6_address_.to_string(ec); - return ipv4_address_.to_string(ec); - } + 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. - static 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; - } + 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. - static 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(); - } + 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. - static address from_string(const std::string& str) - { - return from_string(str.c_str()); - } + 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. - static address from_string(const std::string& str, - boost::system::error_code& ec) - { - return from_string(str.c_str(), ec); - } + BOOST_ASIO_DECL static address from_string( + const std::string& str, boost::system::error_code& ec); /// Compare two addresses for equality. - friend bool operator==(const address& a1, const address& a2) - { - if (a1.type_ != a2.type_) - return false; - if (a1.type_ == ipv6) - return a1.ipv6_address_ == a2.ipv6_address_; - return a1.ipv4_address_ == a2.ipv4_address_; - } + BOOST_ASIO_DECL friend bool operator==(const address& a1, const address& a2); /// Compare two addresses for inequality. friend bool operator!=(const address& a1, const address& a2) { - if (a1.type_ != a2.type_) - return true; - if (a1.type_ == ipv6) - return a1.ipv6_address_ != a2.ipv6_address_; - return a1.ipv4_address_ != a2.ipv4_address_; + return !(a1 == a2); } /// Compare addresses for ordering. - friend bool operator<(const address& a1, const address& a2) + BOOST_ASIO_DECL friend bool operator<(const address& a1, const address& a2); + + /// Compare addresses for ordering. + friend bool operator>(const address& a1, const address& a2) { - if (a1.type_ < a2.type_) - return true; - if (a1.type_ > a2.type_) - return false; - if (a1.type_ == ipv6) - return a1.ipv6_address_ < a2.ipv6_address_; - return a1.ipv4_address_ < a2.ipv4_address_; + return a2 < a1; + } + + /// Compare addresses for ordering. + friend bool operator<=(const address& a1, const address& a2) + { + return !(a2 < a1); + } + + /// Compare addresses for ordering. + friend bool operator>=(const address& a1, const address& a2) + { + return !(a1 < a2); } private: @@ -269,11 +165,7 @@ private: */ template std::basic_ostream& operator<<( - std::basic_ostream& os, const address& addr) -{ - os << addr.to_string(); - return os; -} + std::basic_ostream& os, const address& addr); #endif // !defined(BOOST_NO_IOSTREAM) @@ -283,4 +175,9 @@ std::basic_ostream& operator<<( #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_IP_ADDRESS_HPP diff --git a/include/boost/asio/ip/address_v4.hpp b/include/boost/asio/ip/address_v4.hpp index 47d36b5d..21c1a7ff 100644 --- a/include/boost/asio/ip/address_v4.hpp +++ b/include/boost/asio/ip/address_v4.hpp @@ -1,6 +1,6 @@ // -// address_v4.hpp -// ~~~~~~~~~~~~~~ +// ip/address_v4.hpp +// ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,24 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#include +#include +#include +#include +#include -#include -#include #if !defined(BOOST_NO_IOSTREAM) # include #endif // !defined(BOOST_NO_IOSTREAM) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace asio { @@ -60,34 +54,10 @@ public: } /// Construct an address from raw bytes. - explicit address_v4(const bytes_type& bytes) - { -#if UCHAR_MAX > 0xFF - if (bytes[0] > 0xFF || bytes[1] > 0xFF - || bytes[2] > 0xFF || bytes[3] > 0xFF) - { - std::out_of_range ex("address_v4 from bytes_type"); - boost::throw_exception(ex); - } -#endif // UCHAR_MAX > 0xFF - - using namespace std; // For memcpy. - memcpy(&addr_.s_addr, bytes.elems, 4); - } + BOOST_ASIO_DECL explicit address_v4(const bytes_type& bytes); /// Construct an address from a unsigned long in host byte order. - explicit address_v4(unsigned long addr) - { -#if ULONG_MAX > 0xFFFFFFFF - if (addr > 0xFFFFFFFF) - { - std::out_of_range ex("address_v4 from unsigned long"); - boost::throw_exception(ex); - } -#endif // ULONG_MAX > 0xFFFFFFFF - - addr_.s_addr = boost::asio::detail::socket_ops::host_to_network_long(addr); - } + BOOST_ASIO_DECL explicit address_v4(unsigned long addr); /// Copy constructor. address_v4(const address_v4& other) @@ -103,96 +73,42 @@ public: } /// Get the address in bytes, in network byte order. - bytes_type to_bytes() const - { - using namespace std; // For memcpy. - bytes_type bytes; - memcpy(bytes.elems, &addr_.s_addr, 4); - return bytes; - } + BOOST_ASIO_DECL bytes_type to_bytes() const; /// Get the address as an unsigned long in host byte order - unsigned long to_ulong() const - { - return boost::asio::detail::socket_ops::network_to_host_long(addr_.s_addr); - } + BOOST_ASIO_DECL unsigned long to_ulong() const; /// Get the address as a string in dotted decimal format. - std::string to_string() const - { - boost::system::error_code ec; - std::string addr = to_string(ec); - boost::asio::detail::throw_error(ec); - return addr; - } + BOOST_ASIO_DECL std::string to_string() const; /// Get the address as a string in dotted decimal format. - std::string to_string(boost::system::error_code& ec) const - { - char addr_str[boost::asio::detail::max_addr_v4_str_len]; - const char* addr = - boost::asio::detail::socket_ops::inet_ntop(AF_INET, &addr_, addr_str, - boost::asio::detail::max_addr_v4_str_len, 0, ec); - if (addr == 0) - return std::string(); - return addr; - } + 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. - static 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; - } + BOOST_ASIO_DECL static address_v4 from_string(const char* str); /// 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) - { - address_v4 tmp; - if (boost::asio::detail::socket_ops::inet_pton( - AF_INET, str, &tmp.addr_, 0, ec) <= 0) - return address_v4(); - return tmp; - } + BOOST_ASIO_DECL 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. - static address_v4 from_string(const std::string& str) - { - return from_string(str.c_str()); - } + BOOST_ASIO_DECL static address_v4 from_string(const std::string& str); /// 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) - { - return from_string(str.c_str(), ec); - } + BOOST_ASIO_DECL static address_v4 from_string( + const std::string& str, boost::system::error_code& ec); /// Determine whether the address is a class A address. - bool is_class_a() const - { - return IN_CLASSA(to_ulong()); - } + BOOST_ASIO_DECL bool is_class_a() const; /// Determine whether the address is a class B address. - bool is_class_b() const - { - return IN_CLASSB(to_ulong()); - } + BOOST_ASIO_DECL bool is_class_b() const; /// Determine whether the address is a class C address. - bool is_class_c() const - { - return IN_CLASSC(to_ulong()); - } + BOOST_ASIO_DECL bool is_class_c() const; /// Determine whether the address is a multicast address. - bool is_multicast() const - { - return IN_MULTICAST(to_ulong()); - } + BOOST_ASIO_DECL bool is_multicast() const; /// Compare two addresses for equality. friend bool operator==(const address_v4& a1, const address_v4& a2) @@ -250,23 +166,12 @@ public: /// Obtain an address object that represents the broadcast address that /// corresponds to the specified address and netmask. - static address_v4 broadcast(const address_v4& addr, const address_v4& mask) - { - return address_v4(addr.to_ulong() | ~mask.to_ulong()); - } + 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. - static address_v4 netmask(const address_v4& addr) - { - if (addr.is_class_a()) - return address_v4(0xFF000000); - if (addr.is_class_b()) - return address_v4(0xFFFF0000); - if (addr.is_class_c()) - return address_v4(0xFFFFFF00); - return address_v4(0xFFFFFFFF); - } + BOOST_ASIO_DECL static address_v4 netmask(const address_v4& addr); private: // The underlying IPv4 address. @@ -289,22 +194,7 @@ private: */ template std::basic_ostream& operator<<( - std::basic_ostream& os, const address_v4& addr) -{ - boost::system::error_code ec; - std::string s = addr.to_string(ec); - if (ec) - { - if (os.exceptions() & std::ios::failbit) - boost::asio::detail::throw_error(ec); - else - os.setstate(std::ios_base::failbit); - } - else - for (std::string::iterator i = s.begin(); i != s.end(); ++i) - os << os.widen(*i); - return os; -} + std::basic_ostream& os, const address_v4& addr); #endif // !defined(BOOST_NO_IOSTREAM) @@ -314,4 +204,9 @@ std::basic_ostream& operator<<( #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_IP_ADDRESS_V4_HPP diff --git a/include/boost/asio/ip/address_v6.hpp b/include/boost/asio/ip/address_v6.hpp index 5685f082..7165eac2 100644 --- a/include/boost/asio/ip/address_v6.hpp +++ b/include/boost/asio/ip/address_v6.hpp @@ -1,6 +1,6 @@ // -// address_v6.hpp -// ~~~~~~~~~~~~~~ +// ip/address_v6.hpp +// ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,26 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#include +#include +#include +#include +#include +#include -#include -#include #if !defined(BOOST_NO_IOSTREAM) # include #endif // !defined(BOOST_NO_IOSTREAM) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace boost { namespace asio { @@ -56,46 +49,17 @@ public: typedef boost::array bytes_type; /// Default constructor. - address_v6() - : scope_id_(0) - { - boost::asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; - addr_ = tmp_addr; - } + BOOST_ASIO_DECL address_v6(); /// Construct an address from raw bytes and scope ID. - explicit address_v6(const bytes_type& bytes, unsigned long scope_id = 0) - : scope_id_(scope_id) - { -#if UCHAR_MAX > 0xFF - for (std::size_t i = 0; i < bytes.size(); ++i) - { - if (bytes[i] > 0xFF) - { - std::out_of_range ex("address_v6 from bytes_type"); - boost::throw_exception(ex); - } - } -#endif // UCHAR_MAX > 0xFF - - using namespace std; // For memcpy. - memcpy(addr_.s6_addr, bytes.elems, 16); - } + BOOST_ASIO_DECL explicit address_v6(const bytes_type& bytes, + unsigned long scope_id = 0); /// Copy constructor. - address_v6(const address_v6& other) - : addr_(other.addr_), - scope_id_(other.scope_id_) - { - } + BOOST_ASIO_DECL address_v6(const address_v6& other); /// Assign from another address. - address_v6& operator=(const address_v6& other) - { - addr_ = other.addr_; - scope_id_ = other.scope_id_; - return *this; - } + BOOST_ASIO_DECL address_v6& operator=(const address_v6& other); /// The scope ID of the address. /** @@ -116,217 +80,80 @@ public: } /// Get the address in bytes, in network byte order. - bytes_type to_bytes() const - { - using namespace std; // For memcpy. - bytes_type bytes; - memcpy(bytes.elems, addr_.s6_addr, 16); - return bytes; - } + BOOST_ASIO_DECL bytes_type to_bytes() const; /// Get the address as a string. - std::string to_string() const - { - boost::system::error_code ec; - std::string addr = to_string(ec); - boost::asio::detail::throw_error(ec); - return addr; - } + BOOST_ASIO_DECL std::string to_string() const; /// Get the address as a string. - std::string to_string(boost::system::error_code& ec) const - { - char addr_str[boost::asio::detail::max_addr_v6_str_len]; - const char* addr = - boost::asio::detail::socket_ops::inet_ntop(AF_INET6, &addr_, addr_str, - boost::asio::detail::max_addr_v6_str_len, scope_id_, ec); - if (addr == 0) - return std::string(); - return addr; - } + BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; /// Create an address from an IP address string. - static 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; - } + BOOST_ASIO_DECL static address_v6 from_string(const char* str); /// Create an address from an IP address string. - static address_v6 from_string(const char* str, boost::system::error_code& ec) - { - address_v6 tmp; - if (boost::asio::detail::socket_ops::inet_pton( - AF_INET6, str, &tmp.addr_, &tmp.scope_id_, ec) <= 0) - return address_v6(); - return tmp; - } + BOOST_ASIO_DECL static address_v6 from_string( + const char* str, boost::system::error_code& ec); /// Create an address from an IP address string. - static address_v6 from_string(const std::string& str) - { - return from_string(str.c_str()); - } + BOOST_ASIO_DECL static address_v6 from_string(const std::string& str); /// Create an address from an IP address string. - static address_v6 from_string(const std::string& str, - boost::system::error_code& ec) - { - return from_string(str.c_str(), ec); - } + BOOST_ASIO_DECL 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. - address_v4 to_v4() const - { - if (!is_v4_mapped() && !is_v4_compatible()) - { - std::bad_cast ex; - boost::throw_exception(ex); - } - - address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12], - addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } }; - return address_v4(v4_bytes); - } + BOOST_ASIO_DECL address_v4 to_v4() const; /// Determine whether the address is a loopback address. - bool is_loopback() const - { -#if defined(__BORLANDC__) - return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) - && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) - && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) - && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) - && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) - && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) - && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) - && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1)); -#else - using namespace boost::asio::detail; - return IN6_IS_ADDR_LOOPBACK(&addr_) != 0; -#endif - } + BOOST_ASIO_DECL bool is_loopback() const; /// Determine whether the address is unspecified. - bool is_unspecified() const - { -#if defined(__BORLANDC__) - return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) - && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) - && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) - && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) - && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) - && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) - && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) - && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0)); -#else - using namespace boost::asio::detail; - return IN6_IS_ADDR_UNSPECIFIED(&addr_) != 0; -#endif - } + BOOST_ASIO_DECL bool is_unspecified() const; /// Determine whether the address is link local. - bool is_link_local() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_LINKLOCAL(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_link_local() const; /// Determine whether the address is site local. - bool is_site_local() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_SITELOCAL(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_site_local() const; /// Determine whether the address is a mapped IPv4 address. - bool is_v4_mapped() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_V4MAPPED(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_v4_mapped() const; /// Determine whether the address is an IPv4-compatible address. - bool is_v4_compatible() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_V4COMPAT(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_v4_compatible() const; /// Determine whether the address is a multicast address. - bool is_multicast() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_MULTICAST(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_multicast() const; /// Determine whether the address is a global multicast address. - bool is_multicast_global() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_MC_GLOBAL(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_multicast_global() const; /// Determine whether the address is a link-local multicast address. - bool is_multicast_link_local() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_MC_LINKLOCAL(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_multicast_link_local() const; /// Determine whether the address is a node-local multicast address. - bool is_multicast_node_local() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_MC_NODELOCAL(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_multicast_node_local() const; /// Determine whether the address is a org-local multicast address. - bool is_multicast_org_local() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_MC_ORGLOCAL(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_multicast_org_local() const; /// Determine whether the address is a site-local multicast address. - bool is_multicast_site_local() const - { - using namespace boost::asio::detail; - return IN6_IS_ADDR_MC_SITELOCAL(&addr_) != 0; - } + BOOST_ASIO_DECL bool is_multicast_site_local() const; /// Compare two addresses for equality. - friend bool operator==(const address_v6& a1, const address_v6& a2) - { - using namespace std; // For memcmp. - return memcmp(&a1.addr_, &a2.addr_, - sizeof(boost::asio::detail::in6_addr_type)) == 0 - && a1.scope_id_ == a2.scope_id_; - } + BOOST_ASIO_DECL friend bool operator==( + const address_v6& a1, const address_v6& a2); /// Compare two addresses for inequality. friend bool operator!=(const address_v6& a1, const address_v6& a2) { - using namespace std; // For memcmp. - return memcmp(&a1.addr_, &a2.addr_, - sizeof(boost::asio::detail::in6_addr_type)) != 0 - || a1.scope_id_ != a2.scope_id_; + return !(a1 == a2); } /// Compare addresses for ordering. - friend bool operator<(const address_v6& a1, const address_v6& a2) - { - using namespace std; // For memcmp. - int memcmp_result = memcmp(&a1.addr_, &a2.addr_, - sizeof(boost::asio::detail::in6_addr_type)); - if (memcmp_result < 0) - return true; - if (memcmp_result > 0) - return false; - return a1.scope_id_ < a2.scope_id_; - } + BOOST_ASIO_DECL friend bool operator<( + const address_v6& a1, const address_v6& a2); /// Compare addresses for ordering. friend bool operator>(const address_v6& a1, const address_v6& a2) @@ -353,31 +180,13 @@ public: } /// Obtain an address object that represents the loopback address. - static address_v6 loopback() - { - address_v6 tmp; - boost::asio::detail::in6_addr_type tmp_addr = IN6ADDR_LOOPBACK_INIT; - tmp.addr_ = tmp_addr; - return tmp; - } + BOOST_ASIO_DECL static address_v6 loopback(); /// Create an IPv4-mapped IPv6 address. - static address_v6 v4_mapped(const address_v4& addr) - { - address_v4::bytes_type v4_bytes = addr.to_bytes(); - 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); - } + BOOST_ASIO_DECL static address_v6 v4_mapped(const address_v4& addr); /// Create an IPv4-compatible IPv6 address. - static address_v6 v4_compatible(const address_v4& addr) - { - address_v4::bytes_type v4_bytes = addr.to_bytes(); - bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; - return address_v6(v6_bytes); - } + BOOST_ASIO_DECL static address_v6 v4_compatible(const address_v4& addr); private: // The underlying IPv6 address. @@ -403,22 +212,7 @@ private: */ template std::basic_ostream& operator<<( - std::basic_ostream& os, const address_v6& addr) -{ - boost::system::error_code ec; - std::string s = addr.to_string(ec); - if (ec) - { - if (os.exceptions() & std::ios::failbit) - boost::asio::detail::throw_error(ec); - else - os.setstate(std::ios_base::failbit); - } - else - for (std::string::iterator i = s.begin(); i != s.end(); ++i) - os << os.widen(*i); - return os; -} + std::basic_ostream& os, const address_v6& addr); #endif // !defined(BOOST_NO_IOSTREAM) @@ -428,4 +222,9 @@ std::basic_ostream& operator<<( #include +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_IP_ADDRESS_V6_HPP diff --git a/include/boost/asio/ip/basic_endpoint.hpp b/include/boost/asio/ip/basic_endpoint.hpp index f191a4ca..10459c41 100644 --- a/include/boost/asio/ip/basic_endpoint.hpp +++ b/include/boost/asio/ip/basic_endpoint.hpp @@ -1,6 +1,6 @@ // -// basic_endpoint.hpp -// ~~~~~~~~~~~~~~~~~~ +// ip/basic_endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,25 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include -#if !defined(BOOST_NO_IOSTREAM) -# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -# include -# endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -# include -#endif // !defined(BOOST_NO_IOSTREAM) -#include - -#include +#include #include -#include -#include +#include + +#if !defined(BOOST_NO_IOSTREAM) +# include +#endif // !defined(BOOST_NO_IOSTREAM) + +#include namespace boost { namespace asio { @@ -68,11 +58,8 @@ public: /// Default constructor. basic_endpoint() - : data_() + : impl_() { - data_.v4.sin_family = AF_INET; - data_.v4.sin_port = 0; - data_.v4.sin_addr.s_addr = INADDR_ANY; } /// Construct an endpoint using a port number, specified in the host's byte @@ -92,74 +79,35 @@ public: * @endcode */ basic_endpoint(const InternetProtocol& protocol, unsigned short port_num) - : data_() + : impl_(protocol.family(), port_num) { - using namespace std; // For memcpy. - if (protocol.family() == PF_INET) - { - data_.v4.sin_family = AF_INET; - data_.v4.sin_port = - boost::asio::detail::socket_ops::host_to_network_short(port_num); - data_.v4.sin_addr.s_addr = INADDR_ANY; - } - else - { - data_.v6.sin6_family = AF_INET6; - data_.v6.sin6_port = - boost::asio::detail::socket_ops::host_to_network_short(port_num); - data_.v6.sin6_flowinfo = 0; - boost::asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; - data_.v6.sin6_addr = tmp_addr; - data_.v6.sin6_scope_id = 0; - } } /// Construct an endpoint using a port number and an IP address. This /// constructor may be used for accepting connections on a specific interface /// or for making a connection to a remote endpoint. basic_endpoint(const boost::asio::ip::address& addr, unsigned short port_num) - : data_() + : impl_(addr, port_num) { - using namespace std; // For memcpy. - if (addr.is_v4()) - { - data_.v4.sin_family = AF_INET; - data_.v4.sin_port = - 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( - addr.to_v4().to_ulong()); - } - else - { - data_.v6.sin6_family = AF_INET6; - data_.v6.sin6_port = - boost::asio::detail::socket_ops::host_to_network_short(port_num); - data_.v6.sin6_flowinfo = 0; - boost::asio::ip::address_v6 v6_addr = addr.to_v6(); - boost::asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes(); - memcpy(data_.v6.sin6_addr.s6_addr, bytes.elems, 16); - data_.v6.sin6_scope_id = v6_addr.scope_id(); - } } /// Copy constructor. basic_endpoint(const basic_endpoint& other) - : data_(other.data_) + : impl_(other.impl_) { } /// Assign from another endpoint. basic_endpoint& operator=(const basic_endpoint& other) { - data_ = other.data_; + impl_ = other.impl_; return *this; } /// The protocol associated with the endpoint. protocol_type protocol() const { - if (is_v4()) + if (impl_.is_v4()) return InternetProtocol::v4(); return InternetProtocol::v6(); } @@ -167,137 +115,104 @@ public: /// Get the underlying endpoint in the native type. data_type* data() { - return &data_.base; + return impl_.data(); } /// Get the underlying endpoint in the native type. const data_type* data() const { - return &data_.base; + return impl_.data(); } /// Get the underlying size of the endpoint in the native type. std::size_t size() const { - if (is_v4()) - return sizeof(boost::asio::detail::sockaddr_in4_type); - else - return sizeof(boost::asio::detail::sockaddr_in6_type); + return impl_.size(); } /// Set the underlying size of the endpoint in the native type. void resize(std::size_t size) { - if (size > sizeof(boost::asio::detail::sockaddr_storage_type)) - { - boost::system::system_error e(boost::asio::error::invalid_argument); - boost::throw_exception(e); - } + impl_.resize(size); } /// Get the capacity of the endpoint in the native type. std::size_t capacity() const { - return sizeof(boost::asio::detail::sockaddr_storage_type); + return impl_.capacity(); } /// Get the port associated with the endpoint. The port number is always in /// the host's byte order. unsigned short port() const { - if (is_v4()) - { - return boost::asio::detail::socket_ops::network_to_host_short( - data_.v4.sin_port); - } - else - { - return boost::asio::detail::socket_ops::network_to_host_short( - data_.v6.sin6_port); - } + return impl_.port(); } /// Set the port associated with the endpoint. The port number is always in /// the host's byte order. void port(unsigned short port_num) { - if (is_v4()) - { - data_.v4.sin_port - = boost::asio::detail::socket_ops::host_to_network_short(port_num); - } - else - { - data_.v6.sin6_port - = boost::asio::detail::socket_ops::host_to_network_short(port_num); - } + impl_.port(port_num); } /// Get the IP address associated with the endpoint. boost::asio::ip::address address() const { - using namespace std; // For memcpy. - if (is_v4()) - { - return boost::asio::ip::address_v4( - boost::asio::detail::socket_ops::network_to_host_long( - data_.v4.sin_addr.s_addr)); - } - else - { - boost::asio::ip::address_v6::bytes_type bytes; - memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16); - return boost::asio::ip::address_v6(bytes, data_.v6.sin6_scope_id); - } + return impl_.address(); } /// Set the IP address associated with the endpoint. void address(const boost::asio::ip::address& addr) { - basic_endpoint tmp_endpoint(addr, port()); - data_ = tmp_endpoint.data_; + impl_.address(addr); } /// Compare two endpoints for equality. friend bool operator==(const basic_endpoint& e1, const basic_endpoint& e2) { - return e1.address() == e2.address() && e1.port() == e2.port(); + return e1.impl_ == e2.impl_; } /// Compare two endpoints for inequality. friend bool operator!=(const basic_endpoint& e1, const basic_endpoint& e2) { - return e1.address() != e2.address() || e1.port() != e2.port(); + return !(e1 == e2); } /// Compare endpoints for ordering. friend bool operator<(const basic_endpoint& e1, const basic_endpoint& e2) { - if (e1.address() < e2.address()) - return true; - if (e1.address() != e2.address()) - return false; - return e1.port() < e2.port(); + return e1.impl_ < e2.impl_; + } + + /// Compare endpoints for ordering. + friend bool operator>(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return e2.impl_ < e1.impl_; + } + + /// Compare endpoints for ordering. + friend bool operator<=(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return !(e2 < e1); + } + + /// Compare endpoints for ordering. + friend bool operator>=(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return !(e1 < e2); } private: - // Helper function to determine whether the endpoint is IPv4. - bool is_v4() const - { - return data_.base.sa_family == AF_INET; - } - - // The underlying IP socket address. - union data_union - { - boost::asio::detail::socket_addr_type base; - boost::asio::detail::sockaddr_storage_type storage; - boost::asio::detail::sockaddr_in4_type v4; - boost::asio::detail::sockaddr_in6_type v6; - } data_; + // The underlying IP endpoint. + boost::asio::ip::detail::endpoint impl_; }; #if !defined(BOOST_NO_IOSTREAM) @@ -314,64 +229,10 @@ private: * * @relates boost::asio::ip::basic_endpoint */ -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -template -std::ostream& operator<<(std::ostream& os, - const basic_endpoint& endpoint) -{ - const address& addr = endpoint.address(); - boost::system::error_code ec; - std::string a = addr.to_string(ec); - if (ec) - { - if (os.exceptions() & std::ios::failbit) - boost::asio::detail::throw_error(ec); - else - os.setstate(std::ios_base::failbit); - } - else - { - std::ostringstream tmp_os; - tmp_os.imbue(std::locale::classic()); - if (addr.is_v4()) - tmp_os << a; - else - tmp_os << '[' << a << ']'; - tmp_os << ':' << endpoint.port(); - os << tmp_os.str(); - } - return os; -} -#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) template std::basic_ostream& operator<<( std::basic_ostream& os, - const basic_endpoint& endpoint) -{ - const address& addr = endpoint.address(); - boost::system::error_code ec; - std::string a = addr.to_string(ec); - if (ec) - { - if (os.exceptions() & std::ios::failbit) - boost::asio::detail::throw_error(ec); - else - os.setstate(std::ios_base::failbit); - } - else - { - std::ostringstream tmp_os; - tmp_os.imbue(std::locale::classic()); - if (addr.is_v4()) - tmp_os << a; - else - tmp_os << '[' << a << ']'; - tmp_os << ':' << endpoint.port(); - os << tmp_os.str(); - } - return os; -} -#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + const basic_endpoint& endpoint); #endif // !defined(BOOST_NO_IOSTREAM) @@ -381,4 +242,6 @@ std::basic_ostream& operator<<( #include +#include + #endif // BOOST_ASIO_IP_BASIC_ENDPOINT_HPP diff --git a/include/boost/asio/ip/basic_resolver.hpp b/include/boost/asio/ip/basic_resolver.hpp index 0660ce58..21b83da9 100644 --- a/include/boost/asio/ip/basic_resolver.hpp +++ b/include/boost/asio/ip/basic_resolver.hpp @@ -1,6 +1,6 @@ // -// basic_resolver.hpp -// ~~~~~~~~~~~~~~~~~~ +// ip/basic_resolver.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,14 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include +#include #include #include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/ip/basic_resolver_entry.hpp b/include/boost/asio/ip/basic_resolver_entry.hpp index f2ac5957..84589b5b 100644 --- a/include/boost/asio/ip/basic_resolver_entry.hpp +++ b/include/boost/asio/ip/basic_resolver_entry.hpp @@ -1,6 +1,6 @@ // -// basic_resolver_entry.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// ip/basic_resolver_entry.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#include #include -#include -#include namespace boost { namespace asio { diff --git a/include/boost/asio/ip/basic_resolver_iterator.hpp b/include/boost/asio/ip/basic_resolver_iterator.hpp index 5f4937bf..de426993 100644 --- a/include/boost/asio/ip/basic_resolver_iterator.hpp +++ b/include/boost/asio/ip/basic_resolver_iterator.hpp @@ -1,6 +1,6 @@ // -// basic_resolver_iterator.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ip/basic_resolver_iterator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,20 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include #include #include #include -#include - +#include #include #include #include +#include + namespace boost { namespace asio { namespace ip { @@ -177,7 +175,7 @@ private: } typedef std::vector > values_type; - boost::shared_ptr values_; + boost::asio::detail::shared_ptr values_; std::size_t index_; }; diff --git a/include/boost/asio/ip/basic_resolver_query.hpp b/include/boost/asio/ip/basic_resolver_query.hpp index 75d3c477..38cba015 100644 --- a/include/boost/asio/ip/basic_resolver_query.hpp +++ b/include/boost/asio/ip/basic_resolver_query.hpp @@ -1,6 +1,6 @@ // -// basic_resolver_query.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// ip/basic_resolver_query.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include -#include - #include #include +#include + namespace boost { namespace asio { namespace ip { diff --git a/include/boost/asio/ip/detail/endpoint.hpp b/include/boost/asio/ip/detail/endpoint.hpp new file mode 100644 index 00000000..9823e720 --- /dev/null +++ b/include/boost/asio/ip/detail/endpoint.hpp @@ -0,0 +1,142 @@ +// +// ip/detail/endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_DETAIL_ENDPOINT_HPP +#define BOOST_ASIO_IP_DETAIL_ENDPOINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { +namespace detail { + +// Helper class for implementating an IP endpoint. +class endpoint +{ +public: + // Default constructor. + BOOST_ASIO_DECL endpoint(); + + // Construct an endpoint using a family and port number. + BOOST_ASIO_DECL endpoint(int family, unsigned short port_num); + + // Construct an endpoint using an address and port number. + BOOST_ASIO_DECL endpoint(const boost::asio::ip::address& addr, + unsigned short port_num); + + // Copy constructor. + endpoint(const endpoint& other) + : data_(other.data_) + { + } + + // Assign from another endpoint. + endpoint& operator=(const endpoint& other) + { + data_ = other.data_; + return *this; + } + + // Get the underlying endpoint in the native type. + boost::asio::detail::socket_addr_type* data() + { + return &data_.base; + } + + // Get the underlying endpoint in the native type. + const boost::asio::detail::socket_addr_type* data() const + { + return &data_.base; + } + + // Get the underlying size of the endpoint in the native type. + std::size_t size() const + { + if (is_v4()) + return sizeof(boost::asio::detail::sockaddr_in4_type); + else + return sizeof(boost::asio::detail::sockaddr_in6_type); + } + + // Set the underlying size of the endpoint in the native type. + BOOST_ASIO_DECL void resize(std::size_t size); + + // Get the capacity of the endpoint in the native type. + std::size_t capacity() const + { + return sizeof(boost::asio::detail::sockaddr_storage_type); + } + + // Get the port associated with the endpoint. + BOOST_ASIO_DECL unsigned short port() const; + + // Set the port associated with the endpoint. + BOOST_ASIO_DECL void port(unsigned short port_num); + + // Get the IP address associated with the endpoint. + BOOST_ASIO_DECL boost::asio::ip::address address() const; + + // Set the IP address associated with the endpoint. + BOOST_ASIO_DECL void address(const boost::asio::ip::address& addr); + + // Compare two endpoints for equality. + BOOST_ASIO_DECL friend bool operator==( + const endpoint& e1, const endpoint& e2); + + // Compare endpoints for ordering. + BOOST_ASIO_DECL friend bool operator<( + const endpoint& e1, const endpoint& e2); + + // Determine whether the endpoint is IPv4. + bool is_v4() const + { + return data_.base.sa_family == AF_INET; + } + +#if !defined(BOOST_NO_IOSTREAM) + // Convert to a string. + BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; +#endif // !defined(BOOST_NO_IOSTREAM) + +private: + // The underlying IP socket address. + union data_union + { + boost::asio::detail::socket_addr_type base; + boost::asio::detail::sockaddr_storage_type storage; + boost::asio::detail::sockaddr_in4_type v4; + boost::asio::detail::sockaddr_in6_type v6; + } data_; +}; + +} // namespace detail +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_IP_DETAIL_ENDPOINT_HPP diff --git a/include/boost/asio/ip/detail/impl/endpoint.ipp b/include/boost/asio/ip/detail/impl/endpoint.ipp new file mode 100644 index 00000000..4a6e3954 --- /dev/null +++ b/include/boost/asio/ip/detail/impl/endpoint.ipp @@ -0,0 +1,193 @@ +// +// ip/detail/impl/endpoint.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_DETAIL_IMPL_ENDPOINT_IPP +#define BOOST_ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#if !defined(BOOST_NO_IOSTREAM) +# include +#endif // !defined(BOOST_NO_IOSTREAM) +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { +namespace detail { + +endpoint::endpoint() + : data_() +{ + data_.v4.sin_family = AF_INET; + data_.v4.sin_port = 0; + data_.v4.sin_addr.s_addr = INADDR_ANY; +} + +endpoint::endpoint(int family, unsigned short port_num) + : data_() +{ + using namespace std; // For memcpy. + if (family == PF_INET) + { + data_.v4.sin_family = AF_INET; + data_.v4.sin_port = + boost::asio::detail::socket_ops::host_to_network_short(port_num); + data_.v4.sin_addr.s_addr = INADDR_ANY; + } + else + { + data_.v6.sin6_family = AF_INET6; + data_.v6.sin6_port = + boost::asio::detail::socket_ops::host_to_network_short(port_num); + data_.v6.sin6_flowinfo = 0; + boost::asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; + data_.v6.sin6_addr = tmp_addr; + data_.v6.sin6_scope_id = 0; + } +} + +endpoint::endpoint(const boost::asio::ip::address& addr, + unsigned short port_num) + : data_() +{ + using namespace std; // For memcpy. + if (addr.is_v4()) + { + data_.v4.sin_family = AF_INET; + data_.v4.sin_port = + 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( + addr.to_v4().to_ulong()); + } + else + { + data_.v6.sin6_family = AF_INET6; + data_.v6.sin6_port = + boost::asio::detail::socket_ops::host_to_network_short(port_num); + data_.v6.sin6_flowinfo = 0; + boost::asio::ip::address_v6 v6_addr = addr.to_v6(); + boost::asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes(); + memcpy(data_.v6.sin6_addr.s6_addr, bytes.elems, 16); + data_.v6.sin6_scope_id = v6_addr.scope_id(); + } +} + +void endpoint::resize(std::size_t size) +{ + if (size > sizeof(boost::asio::detail::sockaddr_storage_type)) + { + boost::system::error_code ec(boost::asio::error::invalid_argument); + boost::asio::detail::throw_error(ec); + } +} + +unsigned short endpoint::port() const +{ + if (is_v4()) + { + return boost::asio::detail::socket_ops::network_to_host_short( + data_.v4.sin_port); + } + else + { + return boost::asio::detail::socket_ops::network_to_host_short( + data_.v6.sin6_port); + } +} + +void endpoint::port(unsigned short port_num) +{ + if (is_v4()) + { + data_.v4.sin_port + = boost::asio::detail::socket_ops::host_to_network_short(port_num); + } + else + { + data_.v6.sin6_port + = boost::asio::detail::socket_ops::host_to_network_short(port_num); + } +} + +boost::asio::ip::address endpoint::address() const +{ + using namespace std; // For memcpy. + if (is_v4()) + { + return boost::asio::ip::address_v4( + boost::asio::detail::socket_ops::network_to_host_long( + data_.v4.sin_addr.s_addr)); + } + else + { + boost::asio::ip::address_v6::bytes_type bytes; + memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16); + return boost::asio::ip::address_v6(bytes, data_.v6.sin6_scope_id); + } +} + +void endpoint::address(const boost::asio::ip::address& addr) +{ + endpoint tmp_endpoint(addr, port()); + data_ = tmp_endpoint.data_; +} + +bool operator==(const endpoint& e1, const endpoint& e2) +{ + return e1.address() == e2.address() && e1.port() == e2.port(); +} + +bool operator<(const endpoint& e1, const endpoint& e2) +{ + if (e1.address() < e2.address()) + return true; + if (e1.address() != e2.address()) + return false; + return e1.port() < e2.port(); +} + +#if !defined(BOOST_NO_IOSTREAM) +std::string endpoint::to_string(boost::system::error_code& ec) 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; + else + tmp_os << '[' << a << ']'; + tmp_os << ':' << port(); + + return tmp_os.str(); +} +#endif // !defined(BOOST_NO_IOSTREAM) + +} // namespace detail +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP diff --git a/include/boost/asio/ip/detail/socket_option.hpp b/include/boost/asio/ip/detail/socket_option.hpp index 0c268648..59ce6c37 100644 --- a/include/boost/asio/ip/detail/socket_option.hpp +++ b/include/boost/asio/ip/detail/socket_option.hpp @@ -1,6 +1,6 @@ // -// socket_option.hpp -// ~~~~~~~~~~~~~~~~~ +// detail/socket_option.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,18 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include #include -#include - -#include #include #include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/ip/host_name.hpp b/include/boost/asio/ip/host_name.hpp index fee245b7..f40a9df6 100644 --- a/include/boost/asio/ip/host_name.hpp +++ b/include/boost/asio/ip/host_name.hpp @@ -1,6 +1,6 @@ // -// host_name.hpp -// ~~~~~~~~~~~~~ +// ip/host_name.hpp +// ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,45 +15,21 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include +#include -#include -#include -#include +#include namespace boost { namespace asio { namespace ip { /// Get the current host name. -std::string host_name(); +BOOST_ASIO_DECL std::string host_name(); /// Get the current host name. -std::string host_name(boost::system::error_code& ec); - -inline std::string host_name() -{ - char name[1024]; - boost::system::error_code ec; - if (boost::asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) - { - boost::asio::detail::throw_error(ec); - return std::string(); - } - return std::string(name); -} - -inline std::string host_name(boost::system::error_code& ec) -{ - char name[1024]; - if (boost::asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) - return std::string(); - return std::string(name); -} +BOOST_ASIO_DECL std::string host_name(boost::system::error_code& ec); } // namespace ip } // namespace asio @@ -61,4 +37,8 @@ inline std::string host_name(boost::system::error_code& ec) #include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // BOOST_ASIO_IP_HOST_NAME_HPP diff --git a/include/boost/asio/ip/icmp.hpp b/include/boost/asio/ip/icmp.hpp index 5d2fcabd..ca5d4348 100644 --- a/include/boost/asio/ip/icmp.hpp +++ b/include/boost/asio/ip/icmp.hpp @@ -1,6 +1,6 @@ // -// icmp.hpp -// ~~~~~~~~ +// ip/icmp.hpp +// ~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,14 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include +#include #include #include #include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/ip/impl/address.hpp b/include/boost/asio/ip/impl/address.hpp new file mode 100644 index 00000000..c19d25d8 --- /dev/null +++ b/include/boost/asio/ip/impl/address.hpp @@ -0,0 +1,55 @@ +// +// ip/impl/address.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_ADDRESS_HPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_NO_IOSTREAM) + +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, const address& addr) +{ + boost::system::error_code ec; + std::string s = addr.to_string(ec); + if (ec) + { + if (os.exceptions() & std::basic_ostream::failbit) + boost::asio::detail::throw_error(ec); + else + os.setstate(std::basic_ostream::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 + +#endif // !defined(BOOST_NO_IOSTREAM) + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_HPP diff --git a/include/boost/asio/ip/impl/address.ipp b/include/boost/asio/ip/impl/address.ipp new file mode 100644 index 00000000..70513b78 --- /dev/null +++ b/include/boost/asio/ip/impl/address.ipp @@ -0,0 +1,188 @@ +// +// ip/impl/address.ipp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_ADDRESS_IPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +address::address() + : type_(ipv4), + ipv4_address_(), + ipv6_address_() +{ +} + +address::address(const boost::asio::ip::address_v4& ipv4_address) + : type_(ipv4), + ipv4_address_(ipv4_address), + ipv6_address_() +{ +} + +address::address(const boost::asio::ip::address_v6& ipv6_address) + : type_(ipv6), + ipv4_address_(), + ipv6_address_(ipv6_address) +{ +} + +address::address(const address& other) + : type_(other.type_), + ipv4_address_(other.ipv4_address_), + ipv6_address_(other.ipv6_address_) +{ +} + +address& address::operator=(const address& other) +{ + type_ = other.type_; + ipv4_address_ = other.ipv4_address_; + ipv6_address_ = other.ipv6_address_; + return *this; +} + +address& address::operator=(const boost::asio::ip::address_v4& ipv4_address) +{ + type_ = ipv4; + ipv4_address_ = ipv4_address; + ipv6_address_ = boost::asio::ip::address_v6(); + return *this; +} + +address& address::operator=(const boost::asio::ip::address_v6& ipv6_address) +{ + type_ = ipv6; + ipv4_address_ = boost::asio::ip::address_v4(); + ipv6_address_ = ipv6_address; + return *this; +} + +boost::asio::ip::address_v4 address::to_v4() const +{ + if (type_ != ipv4) + { + std::bad_cast ex; + boost::throw_exception(ex); + } + return ipv4_address_; +} + +boost::asio::ip::address_v6 address::to_v6() const +{ + if (type_ != ipv6) + { + std::bad_cast ex; + boost::throw_exception(ex); + } + return ipv6_address_; +} + +std::string address::to_string() const +{ + if (type_ == ipv6) + return ipv6_address_.to_string(); + return ipv4_address_.to_string(); +} + +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); +} + +bool operator==(const address& a1, const address& a2) +{ + if (a1.type_ != a2.type_) + return false; + if (a1.type_ == address::ipv6) + return a1.ipv6_address_ == a2.ipv6_address_; + return a1.ipv4_address_ == a2.ipv4_address_; +} + +bool operator<(const address& a1, const address& a2) +{ + if (a1.type_ < a2.type_) + return true; + if (a1.type_ > a2.type_) + return false; + if (a1.type_ == address::ipv6) + return a1.ipv6_address_ < a2.ipv6_address_; + return a1.ipv4_address_ < a2.ipv4_address_; +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_IPP diff --git a/include/boost/asio/ip/impl/address_v4.hpp b/include/boost/asio/ip/impl/address_v4.hpp new file mode 100644 index 00000000..7e798e89 --- /dev/null +++ b/include/boost/asio/ip/impl/address_v4.hpp @@ -0,0 +1,55 @@ +// +// ip/impl/address_v4.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_ADDRESS_V4_HPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_V4_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_NO_IOSTREAM) + +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +template +std::basic_ostream& operator<<( + std::basic_ostream& 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::failbit) + boost::asio::detail::throw_error(ec); + else + os.setstate(std::basic_ostream::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 + +#endif // !defined(BOOST_NO_IOSTREAM) + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_V4_HPP diff --git a/include/boost/asio/ip/impl/address_v4.ipp b/include/boost/asio/ip/impl/address_v4.ipp new file mode 100644 index 00000000..3cdcbf1c --- /dev/null +++ b/include/boost/asio/ip/impl/address_v4.ipp @@ -0,0 +1,164 @@ +// +// ip/impl/address_v4.ipp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_ADDRESS_V4_IPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_V4_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +address_v4::address_v4(const address_v4::bytes_type& bytes) +{ +#if UCHAR_MAX > 0xFF + if (bytes[0] > 0xFF || bytes[1] > 0xFF + || bytes[2] > 0xFF || bytes[3] > 0xFF) + { + std::out_of_range ex("address_v4 from bytes_type"); + boost::throw_exception(ex); + } +#endif // UCHAR_MAX > 0xFF + + using namespace std; // For memcpy. + memcpy(&addr_.s_addr, bytes.elems, 4); +} + +address_v4::address_v4(unsigned long addr) +{ +#if ULONG_MAX > 0xFFFFFFFF + if (addr > 0xFFFFFFFF) + { + std::out_of_range ex("address_v4 from unsigned long"); + boost::throw_exception(ex); + } +#endif // ULONG_MAX > 0xFFFFFFFF + + addr_.s_addr = boost::asio::detail::socket_ops::host_to_network_long(addr); +} + +address_v4::bytes_type address_v4::to_bytes() const +{ + using namespace std; // For memcpy. + bytes_type bytes; + memcpy(bytes.elems, &addr_.s_addr, 4); + return bytes; +} + +unsigned long address_v4::to_ulong() const +{ + return boost::asio::detail::socket_ops::network_to_host_long(addr_.s_addr); +} + +std::string address_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 address_v4::to_string(boost::system::error_code& ec) const +{ + char addr_str[boost::asio::detail::max_addr_v4_str_len]; + const char* addr = + boost::asio::detail::socket_ops::inet_ntop(AF_INET, &addr_, addr_str, + boost::asio::detail::max_addr_v4_str_len, 0, ec); + if (addr == 0) + 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( + 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); +} + +bool address_v4::is_class_a() const +{ + return IN_CLASSA(to_ulong()); +} + +bool address_v4::is_class_b() const +{ + return IN_CLASSB(to_ulong()); +} + +bool address_v4::is_class_c() const +{ + return IN_CLASSC(to_ulong()); +} + +bool address_v4::is_multicast() const +{ + return IN_MULTICAST(to_ulong()); +} + +address_v4 address_v4::broadcast(const address_v4& addr, const address_v4& mask) +{ + return address_v4(addr.to_ulong() | ~mask.to_ulong()); +} + +address_v4 address_v4::netmask(const address_v4& addr) +{ + if (addr.is_class_a()) + return address_v4(0xFF000000); + if (addr.is_class_b()) + return address_v4(0xFFFF0000); + if (addr.is_class_c()) + return address_v4(0xFFFFFF00); + return address_v4(0xFFFFFFFF); +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_V4_IPP diff --git a/include/boost/asio/ip/impl/address_v6.hpp b/include/boost/asio/ip/impl/address_v6.hpp new file mode 100644 index 00000000..8b39e3e0 --- /dev/null +++ b/include/boost/asio/ip/impl/address_v6.hpp @@ -0,0 +1,55 @@ +// +// ip/impl/address_v6.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_ADDRESS_V6_HPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_V6_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_NO_IOSTREAM) + +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +template +std::basic_ostream& operator<<( + std::basic_ostream& 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::failbit) + boost::asio::detail::throw_error(ec); + else + os.setstate(std::basic_ostream::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 + +#endif // !defined(BOOST_NO_IOSTREAM) + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_V6_HPP diff --git a/include/boost/asio/ip/impl/address_v6.ipp b/include/boost/asio/ip/impl/address_v6.ipp new file mode 100644 index 00000000..a06dfe5f --- /dev/null +++ b/include/boost/asio/ip/impl/address_v6.ipp @@ -0,0 +1,286 @@ +// +// ip/impl/address_v6.ipp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_ADDRESS_V6_IPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +address_v6::address_v6() + : scope_id_(0) +{ + boost::asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; + addr_ = tmp_addr; +} + +address_v6::address_v6(const address_v6::bytes_type& bytes, + unsigned long scope_id) + : scope_id_(scope_id) +{ +#if UCHAR_MAX > 0xFF + for (std::size_t i = 0; i < bytes.size(); ++i) + { + if (bytes[i] > 0xFF) + { + std::out_of_range ex("address_v6 from bytes_type"); + boost::throw_exception(ex); + } + } +#endif // UCHAR_MAX > 0xFF + + using namespace std; // For memcpy. + memcpy(addr_.s6_addr, bytes.elems, 16); +} + +address_v6::address_v6(const address_v6& other) + : addr_(other.addr_), + scope_id_(other.scope_id_) +{ +} + +address_v6& address_v6::operator=(const address_v6& other) +{ + addr_ = other.addr_; + scope_id_ = other.scope_id_; + return *this; +} + +address_v6::bytes_type address_v6::to_bytes() const +{ + using namespace std; // For memcpy. + bytes_type bytes; + memcpy(bytes.elems, addr_.s6_addr, 16); + return bytes; +} + +std::string address_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 address_v6::to_string(boost::system::error_code& ec) const +{ + char addr_str[boost::asio::detail::max_addr_v6_str_len]; + const char* addr = + boost::asio::detail::socket_ops::inet_ntop(AF_INET6, &addr_, addr_str, + boost::asio::detail::max_addr_v6_str_len, scope_id_, ec); + if (addr == 0) + return std::string(); + 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( + 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; + boost::throw_exception(ex); + } + + address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12], + addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } }; + return address_v4(v4_bytes); +} + +bool address_v6::is_loopback() const +{ +#if defined(__BORLANDC__) + return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) + && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) + && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) + && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) + && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) + && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) + && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) + && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1)); +#else + using namespace boost::asio::detail; + return IN6_IS_ADDR_LOOPBACK(&addr_) != 0; +#endif +} + +bool address_v6::is_unspecified() const +{ +#if defined(__BORLANDC__) + return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) + && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) + && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) + && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) + && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) + && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) + && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) + && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0)); +#else + using namespace boost::asio::detail; + return IN6_IS_ADDR_UNSPECIFIED(&addr_) != 0; +#endif +} + +bool address_v6::is_link_local() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_LINKLOCAL(&addr_) != 0; +} + +bool address_v6::is_site_local() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_SITELOCAL(&addr_) != 0; +} + +bool address_v6::is_v4_mapped() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_V4MAPPED(&addr_) != 0; +} + +bool address_v6::is_v4_compatible() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_V4COMPAT(&addr_) != 0; +} + +bool address_v6::is_multicast() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_MULTICAST(&addr_) != 0; +} + +bool address_v6::is_multicast_global() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_MC_GLOBAL(&addr_) != 0; +} + +bool address_v6::is_multicast_link_local() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_MC_LINKLOCAL(&addr_) != 0; +} + +bool address_v6::is_multicast_node_local() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_MC_NODELOCAL(&addr_) != 0; +} + +bool address_v6::is_multicast_org_local() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_MC_ORGLOCAL(&addr_) != 0; +} + +bool address_v6::is_multicast_site_local() const +{ + using namespace boost::asio::detail; + return IN6_IS_ADDR_MC_SITELOCAL(&addr_) != 0; +} + +bool operator==(const address_v6& a1, const address_v6& a2) +{ + using namespace std; // For memcmp. + return memcmp(&a1.addr_, &a2.addr_, + sizeof(boost::asio::detail::in6_addr_type)) == 0 + && a1.scope_id_ == a2.scope_id_; +} + +bool operator<(const address_v6& a1, const address_v6& a2) +{ + using namespace std; // For memcmp. + int memcmp_result = memcmp(&a1.addr_, &a2.addr_, + sizeof(boost::asio::detail::in6_addr_type)); + if (memcmp_result < 0) + return true; + if (memcmp_result > 0) + return false; + return a1.scope_id_ < a2.scope_id_; +} + +address_v6 address_v6::loopback() +{ + address_v6 tmp; + boost::asio::detail::in6_addr_type tmp_addr = IN6ADDR_LOOPBACK_INIT; + tmp.addr_ = tmp_addr; + return tmp; +} + +address_v6 address_v6::v4_mapped(const address_v4& addr) +{ + address_v4::bytes_type v4_bytes = addr.to_bytes(); + 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); +} + +address_v6 address_v6::v4_compatible(const address_v4& addr) +{ + address_v4::bytes_type v4_bytes = addr.to_bytes(); + bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; + return address_v6(v6_bytes); +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP diff --git a/include/boost/asio/ip/impl/basic_endpoint.hpp b/include/boost/asio/ip/impl/basic_endpoint.hpp new file mode 100644 index 00000000..474c1933 --- /dev/null +++ b/include/boost/asio/ip/impl/basic_endpoint.hpp @@ -0,0 +1,57 @@ +// +// ip/impl/basic_endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_BASIC_ENDPOINT_HPP +#define BOOST_ASIO_IP_IMPL_BASIC_ENDPOINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_NO_IOSTREAM) + +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, + const basic_endpoint& 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::failbit) + boost::asio::detail::throw_error(ec); + else + os.setstate(std::basic_ostream::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 + +#endif // !defined(BOOST_NO_IOSTREAM) + +#endif // BOOST_ASIO_IP_IMPL_BASIC_ENDPOINT_HPP diff --git a/include/boost/asio/ip/impl/host_name.ipp b/include/boost/asio/ip/impl/host_name.ipp new file mode 100644 index 00000000..a5ba5824 --- /dev/null +++ b/include/boost/asio/ip/impl/host_name.ipp @@ -0,0 +1,56 @@ +// +// ip/impl/host_name.ipp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 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_HOST_NAME_IPP +#define BOOST_ASIO_IP_IMPL_HOST_NAME_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +std::string host_name() +{ + char name[1024]; + boost::system::error_code ec; + if (boost::asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) + { + boost::asio::detail::throw_error(ec); + return std::string(); + } + return std::string(name); +} + +std::string host_name(boost::system::error_code& ec) +{ + char name[1024]; + if (boost::asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) + return std::string(); + return std::string(name); +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_IMPL_HOST_NAME_IPP diff --git a/include/boost/asio/ip/multicast.hpp b/include/boost/asio/ip/multicast.hpp index 3aab7f08..e4d9f88e 100644 --- a/include/boost/asio/ip/multicast.hpp +++ b/include/boost/asio/ip/multicast.hpp @@ -1,6 +1,6 @@ // -// multicast.hpp -// ~~~~~~~~~~~~~ +// ip/multicast.hpp +// ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include +#include + namespace boost { namespace asio { namespace ip { diff --git a/include/boost/asio/ip/resolver_query_base.hpp b/include/boost/asio/ip/resolver_query_base.hpp index 7fe16504..0173e119 100644 --- a/include/boost/asio/ip/resolver_query_base.hpp +++ b/include/boost/asio/ip/resolver_query_base.hpp @@ -1,6 +1,6 @@ // -// resolver_query_base.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// ip/resolver_query_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include -#include - #include +#include + namespace boost { namespace asio { namespace ip { diff --git a/include/boost/asio/ip/resolver_service.hpp b/include/boost/asio/ip/resolver_service.hpp index ba59f6d5..b13e0adb 100644 --- a/include/boost/asio/ip/resolver_service.hpp +++ b/include/boost/asio/ip/resolver_service.hpp @@ -1,6 +1,6 @@ // -// resolver_service.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// ip/resolver_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,14 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include +#include +#include #include #include #include -#include -#include + +#include namespace boost { namespace asio { @@ -73,13 +73,14 @@ public: explicit resolver_service(boost::asio::io_service& io_service) : boost::asio::detail::service_base< resolver_service >(io_service), - service_impl_(boost::asio::use_service(io_service)) + service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { + service_impl_.shutdown_service(); } /// Construct a new resolver implementation. @@ -131,8 +132,8 @@ public: } private: - // The service that provides the platform-specific implementation. - service_impl_type& service_impl_; + // The platform-specific implementation. + service_impl_type service_impl_; }; } // namespace ip diff --git a/include/boost/asio/ip/tcp.hpp b/include/boost/asio/ip/tcp.hpp index 541c95c7..20261488 100644 --- a/include/boost/asio/ip/tcp.hpp +++ b/include/boost/asio/ip/tcp.hpp @@ -1,6 +1,6 @@ // -// tcp.hpp -// ~~~~~~~ +// ip/tcp.hpp +// ~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include #include +#include +#include #include #include #include #include -#include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/ip/udp.hpp b/include/boost/asio/ip/udp.hpp index e592e066..4d78692d 100644 --- a/include/boost/asio/ip/udp.hpp +++ b/include/boost/asio/ip/udp.hpp @@ -1,6 +1,6 @@ // -// udp.hpp -// ~~~~~~~ +// ip/udp.hpp +// ~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,14 +15,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include +#include #include #include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/ip/unicast.hpp b/include/boost/asio/ip/unicast.hpp index c97e6fd1..1f331de6 100644 --- a/include/boost/asio/ip/unicast.hpp +++ b/include/boost/asio/ip/unicast.hpp @@ -1,6 +1,6 @@ // -// unicast.hpp -// ~~~~~~~~~~~ +// ip/unicast.hpp +// ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include +#include + namespace boost { namespace asio { namespace ip { diff --git a/include/boost/asio/ip/v6_only.hpp b/include/boost/asio/ip/v6_only.hpp index 9adcbffc..e9aab314 100644 --- a/include/boost/asio/ip/v6_only.hpp +++ b/include/boost/asio/ip/v6_only.hpp @@ -1,6 +1,6 @@ // -// v6_only.hpp -// ~~~~~~~~~~~ +// ip/v6_only.hpp +// ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,10 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include +#include + namespace boost { namespace asio { namespace ip { diff --git a/include/boost/asio/is_read_buffered.hpp b/include/boost/asio/is_read_buffered.hpp index f0989a2b..e429e6d7 100644 --- a/include/boost/asio/is_read_buffered.hpp +++ b/include/boost/asio/is_read_buffered.hpp @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include - +#include #include #include +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/is_write_buffered.hpp b/include/boost/asio/is_write_buffered.hpp index bcdf77d1..fff68d6a 100644 --- a/include/boost/asio/is_write_buffered.hpp +++ b/include/boost/asio/is_write_buffered.hpp @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include - +#include #include #include +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/local/basic_endpoint.hpp b/include/boost/asio/local/basic_endpoint.hpp index 1e4057ff..2cd93f6c 100644 --- a/include/boost/asio/local/basic_endpoint.hpp +++ b/include/boost/asio/local/basic_endpoint.hpp @@ -1,6 +1,6 @@ // -// basic_endpoint.hpp -// ~~~~~~~~~~~~~~~~~~ +// local/basic_endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Derived from a public domain implementation written by Daniel Casimiro. @@ -16,30 +16,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) -# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -# define BOOST_ASIO_HAS_LOCAL_SOCKETS 1 -# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -#endif // !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) +#include #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ || defined(GENERATING_DOCUMENTATION) +#include + +#if !defined(BOOST_NO_IOSTREAM) +# include +#endif // !defined(BOOST_NO_IOSTREAM) + +#include namespace boost { namespace asio { @@ -75,34 +63,30 @@ public: /// Default constructor. basic_endpoint() { - init("", 0); } /// Construct an endpoint using the specified path name. basic_endpoint(const char* path) + : impl_(path) { - using namespace std; // For strlen. - init(path, strlen(path)); } /// Construct an endpoint using the specified path name. basic_endpoint(const std::string& path) + : impl_(path) { - init(path.data(), path.length()); } /// Copy constructor. basic_endpoint(const basic_endpoint& other) - : data_(other.data_), - path_length_(other.path_length_) + : impl_(other.impl_) { } /// Assign from another endpoint. basic_endpoint& operator=(const basic_endpoint& other) { - data_ = other.data_; - path_length_ = other.path_length_; + impl_ = other.impl_; return *this; } @@ -115,123 +99,96 @@ public: /// Get the underlying endpoint in the native type. data_type* data() { - return &data_.base; + return impl_.data(); } /// Get the underlying endpoint in the native type. const data_type* data() const { - return &data_.base; + return impl_.data(); } /// Get the underlying size of the endpoint in the native type. std::size_t size() const { - return path_length_ - + offsetof(boost::asio::detail::sockaddr_un_type, sun_path); + return impl_.size(); } /// Set the underlying size of the endpoint in the native type. void resize(std::size_t size) { - if (size > sizeof(boost::asio::detail::sockaddr_un_type)) - { - boost::system::system_error e(boost::asio::error::invalid_argument); - boost::throw_exception(e); - } - else if (size == 0) - { - path_length_ = 0; - } - else - { - path_length_ = size - - offsetof(boost::asio::detail::sockaddr_un_type, sun_path); - - // The path returned by the operating system may be NUL-terminated. - if (path_length_ > 0 && data_.local.sun_path[path_length_ - 1] == 0) - --path_length_; - } + impl_.resize(size); } /// Get the capacity of the endpoint in the native type. std::size_t capacity() const { - return sizeof(boost::asio::detail::sockaddr_un_type); + return impl_.capacity(); } /// Get the path associated with the endpoint. std::string path() const { - return std::string(data_.local.sun_path, path_length_); + return impl_.path(); } /// Set the path associated with the endpoint. void path(const char* p) { - using namespace std; // For strlen. - init(p, strlen(p)); + impl_.path(p); } /// Set the path associated with the endpoint. void path(const std::string& p) { - init(p.data(), p.length()); + impl_.path(p); } /// Compare two endpoints for equality. friend bool operator==(const basic_endpoint& e1, const basic_endpoint& e2) { - return e1.path() == e2.path(); + return e1.impl_ == e2.impl_; } /// Compare two endpoints for inequality. friend bool operator!=(const basic_endpoint& e1, const basic_endpoint& e2) { - return e1.path() != e2.path(); + return !(e1.impl_ == e2.impl_); } /// Compare endpoints for ordering. friend bool operator<(const basic_endpoint& e1, const basic_endpoint& e2) { - return e1.path() < e2.path(); + return e1.impl_ < e2.impl_; + } + + /// Compare endpoints for ordering. + friend bool operator>(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return e2.impl_ < e1.impl_; + } + + /// Compare endpoints for ordering. + friend bool operator<=(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return !(e2 < e1); + } + + /// Compare endpoints for ordering. + friend bool operator>=(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return !(e1 < e2); } private: - // The underlying UNIX socket address. - union data_union - { - boost::asio::detail::socket_addr_type base; - boost::asio::detail::sockaddr_un_type local; - } data_; - - // The length of the path associated with the endpoint. - std::size_t path_length_; - - // Initialise with a specified path. - void init(const char* path, std::size_t path_length) - { - if (path_length > sizeof(data_.local.sun_path) - 1) - { - // The buffer is not large enough to store this address. - boost::system::error_code ec(boost::asio::error::name_too_long); - boost::asio::detail::throw_error(ec); - } - - 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, path_length); - path_length_ = path_length; - - // NUL-terminate normal path names. Names that start with a NUL are in the - // UNIX domain protocol's "abstract namespace" and are not NUL-terminated. - if (path_length > 0 && data_.local.sun_path[0] == 0) - data_.local.sun_path[path_length] = 0; - } + // The underlying UNIX domain endpoint. + boost::asio::local::detail::endpoint impl_; }; /// Output an endpoint as a string. @@ -259,9 +216,9 @@ std::basic_ostream& operator<<( } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_LOCAL_BASIC_ENDPOINT_HPP diff --git a/include/boost/asio/local/connect_pair.hpp b/include/boost/asio/local/connect_pair.hpp index 697a0d24..cb08777a 100644 --- a/include/boost/asio/local/connect_pair.hpp +++ b/include/boost/asio/local/connect_pair.hpp @@ -1,6 +1,6 @@ // -// connect_pair.hpp -// ~~~~~~~~~~~~~~~~ +// local/connect_pair.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include +#include #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include +#include +#include + +#include + namespace boost { namespace asio { namespace local { @@ -74,8 +76,9 @@ inline boost::system::error_code connect_pair( if (socket1.assign(protocol, sv[0], ec)) { boost::system::error_code temp_ec; - boost::asio::detail::socket_ops::close(sv[0], temp_ec); - boost::asio::detail::socket_ops::close(sv[1], 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; } @@ -83,7 +86,8 @@ inline boost::system::error_code connect_pair( { boost::system::error_code temp_ec; socket1.close(temp_ec); - boost::asio::detail::socket_ops::close(sv[1], 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; } @@ -94,9 +98,9 @@ inline boost::system::error_code connect_pair( } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_LOCAL_CONNECT_PAIR_HPP diff --git a/include/boost/asio/local/datagram_protocol.hpp b/include/boost/asio/local/datagram_protocol.hpp index 1441ee6a..2d78773e 100644 --- a/include/boost/asio/local/datagram_protocol.hpp +++ b/include/boost/asio/local/datagram_protocol.hpp @@ -1,6 +1,6 @@ // -// datagram_protocol.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// local/datagram_protocol.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include + +#include + namespace boost { namespace asio { namespace local { @@ -72,9 +74,9 @@ public: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP diff --git a/include/boost/asio/local/detail/endpoint.hpp b/include/boost/asio/local/detail/endpoint.hpp new file mode 100644 index 00000000..5fb72979 --- /dev/null +++ b/include/boost/asio/local/detail/endpoint.hpp @@ -0,0 +1,135 @@ +// +// local/detail/endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Derived from a public domain implementation written by Daniel Casimiro. +// +// 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_LOCAL_DETAIL_ENDPOINT_HPP +#define BOOST_ASIO_LOCAL_DETAIL_ENDPOINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace local { +namespace detail { + +// Helper class for implementing a UNIX domain endpoint. +class endpoint +{ +public: + // Default constructor. + BOOST_ASIO_DECL endpoint(); + + // Construct an endpoint using the specified path name. + BOOST_ASIO_DECL endpoint(const char* path); + + // Construct an endpoint using the specified path name. + BOOST_ASIO_DECL endpoint(const std::string& path); + + // Copy constructor. + endpoint(const endpoint& other) + : data_(other.data_), + path_length_(other.path_length_) + { + } + + // Assign from another endpoint. + endpoint& operator=(const endpoint& other) + { + data_ = other.data_; + path_length_ = other.path_length_; + return *this; + } + + // Get the underlying endpoint in the native type. + boost::asio::detail::socket_addr_type* data() + { + return &data_.base; + } + + // Get the underlying endpoint in the native type. + const boost::asio::detail::socket_addr_type* data() const + { + return &data_.base; + } + + // Get the underlying size of the endpoint in the native type. + std::size_t size() const + { + return path_length_ + + offsetof(boost::asio::detail::sockaddr_un_type, sun_path); + } + + // Set the underlying size of the endpoint in the native type. + BOOST_ASIO_DECL void resize(std::size_t size); + + // Get the capacity of the endpoint in the native type. + std::size_t capacity() const + { + return sizeof(boost::asio::detail::sockaddr_un_type); + } + + // Get the path associated with the endpoint. + BOOST_ASIO_DECL std::string path() const; + + // Set the path associated with the endpoint. + BOOST_ASIO_DECL void path(const char* p); + + // Set the path associated with the endpoint. + BOOST_ASIO_DECL void path(const std::string& p); + + // Compare two endpoints for equality. + BOOST_ASIO_DECL friend bool operator==( + const endpoint& e1, const endpoint& e2); + + // Compare endpoints for ordering. + BOOST_ASIO_DECL friend bool operator<( + const endpoint& e1, const endpoint& e2); + +private: + // The underlying UNIX socket address. + union data_union + { + boost::asio::detail::socket_addr_type base; + boost::asio::detail::sockaddr_un_type local; + } data_; + + // The length of the path associated with the endpoint. + std::size_t path_length_; + + // Initialise with a specified path. + BOOST_ASIO_DECL void init(const char* path, std::size_t path_length); +}; + +} // namespace detail +} // namespace local +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +#endif // BOOST_ASIO_LOCAL_DETAIL_ENDPOINT_HPP diff --git a/include/boost/asio/local/detail/impl/endpoint.ipp b/include/boost/asio/local/detail/impl/endpoint.ipp new file mode 100644 index 00000000..ffbc44ed --- /dev/null +++ b/include/boost/asio/local/detail/impl/endpoint.ipp @@ -0,0 +1,130 @@ +// +// local/detail/impl/endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Derived from a public domain implementation written by Daniel Casimiro. +// +// 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_LOCAL_DETAIL_IMPL_ENDPOINT_IPP +#define BOOST_ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace local { +namespace detail { + +endpoint::endpoint() +{ + init("", 0); +} + +endpoint::endpoint(const char* path) +{ + using namespace std; // For strlen. + init(path, strlen(path)); +} + +endpoint::endpoint(const std::string& path) +{ + init(path.data(), path.length()); +} + +void endpoint::resize(std::size_t size) +{ + if (size > sizeof(boost::asio::detail::sockaddr_un_type)) + { + boost::system::error_code ec(boost::asio::error::invalid_argument); + boost::asio::detail::throw_error(ec); + } + else if (size == 0) + { + path_length_ = 0; + } + else + { + path_length_ = size + - offsetof(boost::asio::detail::sockaddr_un_type, sun_path); + + // The path returned by the operating system may be NUL-terminated. + if (path_length_ > 0 && data_.local.sun_path[path_length_ - 1] == 0) + --path_length_; + } +} + +std::string endpoint::path() const +{ + return std::string(data_.local.sun_path, path_length_); +} + +void endpoint::path(const char* p) +{ + using namespace std; // For strlen. + init(p, strlen(p)); +} + +void endpoint::path(const std::string& p) +{ + init(p.data(), p.length()); +} + +bool operator==(const endpoint& e1, const endpoint& e2) +{ + return e1.path() == e2.path(); +} + +bool operator<(const endpoint& e1, const endpoint& e2) +{ + return e1.path() < e2.path(); +} + +void endpoint::init(const char* path, std::size_t path_length) +{ + if (path_length > sizeof(data_.local.sun_path) - 1) + { + // The buffer is not large enough to store this address. + boost::system::error_code ec(boost::asio::error::name_too_long); + boost::asio::detail::throw_error(ec); + } + + 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, path_length); + path_length_ = path_length; + + // NUL-terminate normal path names. Names that start with a NUL are in the + // UNIX domain protocol's "abstract namespace" and are not NUL-terminated. + if (path_length > 0 && data_.local.sun_path[0] == 0) + data_.local.sun_path[path_length] = 0; +} + +} // namespace detail +} // namespace local +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +#endif // BOOST_ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP diff --git a/include/boost/asio/local/stream_protocol.hpp b/include/boost/asio/local/stream_protocol.hpp index f341a8b6..723c348c 100644 --- a/include/boost/asio/local/stream_protocol.hpp +++ b/include/boost/asio/local/stream_protocol.hpp @@ -1,6 +1,6 @@ // -// stream_protocol.hpp -// ~~~~~~~~~~~~~~~~~~~ +// local/stream_protocol.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ + || defined(GENERATING_DOCUMENTATION) #include #include #include -#include #include +#include -#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ - || defined(GENERATING_DOCUMENTATION) +#include namespace boost { namespace asio { @@ -82,9 +84,9 @@ public: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_LOCAL_STREAM_PROTOCOL_HPP diff --git a/include/boost/asio/placeholders.hpp b/include/boost/asio/placeholders.hpp index 55b6fd70..2940edaf 100644 --- a/include/boost/asio/placeholders.hpp +++ b/include/boost/asio/placeholders.hpp @@ -15,12 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/posix/basic_descriptor.hpp b/include/boost/asio/posix/basic_descriptor.hpp index ff9cb870..56ec9d8d 100644 --- a/include/boost/asio/posix/basic_descriptor.hpp +++ b/include/boost/asio/posix/basic_descriptor.hpp @@ -1,6 +1,6 @@ // -// basic_descriptor.hpp -// ~~~~~~~~~~~~~~~~~~~~ +// posix/basic_descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include +#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ + || defined(GENERATING_DOCUMENTATION) #include +#include #include #include -#include + +#include namespace boost { namespace asio { @@ -293,4 +294,7 @@ protected: #include +#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + // || defined(GENERATING_DOCUMENTATION) + #endif // BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_HPP diff --git a/include/boost/asio/posix/basic_stream_descriptor.hpp b/include/boost/asio/posix/basic_stream_descriptor.hpp index d83a7f7a..0f70604b 100644 --- a/include/boost/asio/posix/basic_stream_descriptor.hpp +++ b/include/boost/asio/posix/basic_stream_descriptor.hpp @@ -1,6 +1,6 @@ // -// basic_stream_descriptor.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// posix/basic_stream_descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,21 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include - -#include -#include -#include -#include +#include #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include +#include +#include + +#include + namespace boost { namespace asio { namespace posix { @@ -298,9 +296,9 @@ public: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP diff --git a/include/boost/asio/posix/descriptor_base.hpp b/include/boost/asio/posix/descriptor_base.hpp index ca93f4d4..70bac638 100644 --- a/include/boost/asio/posix/descriptor_base.hpp +++ b/include/boost/asio/posix/descriptor_base.hpp @@ -1,6 +1,6 @@ // -// descriptor_base.hpp -// ~~~~~~~~~~~~~~~~~~~ +// posix/descriptor_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,16 +15,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include -#include +#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ + || defined(GENERATING_DOCUMENTATION) #include #include +#include + namespace boost { namespace asio { namespace posix { @@ -92,4 +92,7 @@ protected: #include +#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + // || defined(GENERATING_DOCUMENTATION) + #endif // BOOST_ASIO_POSIX_DESCRIPTOR_BASE_HPP diff --git a/include/boost/asio/posix/stream_descriptor.hpp b/include/boost/asio/posix/stream_descriptor.hpp index 3b01618d..30b7e372 100644 --- a/include/boost/asio/posix/stream_descriptor.hpp +++ b/include/boost/asio/posix/stream_descriptor.hpp @@ -1,6 +1,6 @@ // -// stream_descriptor.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// posix/stream_descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) +#include + namespace boost { namespace asio { namespace posix { @@ -36,6 +36,4 @@ typedef basic_stream_descriptor<> stream_descriptor; #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_POSIX_STREAM_DESCRIPTOR_HPP diff --git a/include/boost/asio/posix/stream_descriptor_service.hpp b/include/boost/asio/posix/stream_descriptor_service.hpp index 89b9ef4f..c2034da1 100644 --- a/include/boost/asio/posix/stream_descriptor_service.hpp +++ b/include/boost/asio/posix/stream_descriptor_service.hpp @@ -1,6 +1,6 @@ // -// stream_descriptor_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// posix/stream_descriptor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,28 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include - -#include -#include -#include - -#if !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) -# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -# define BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1 -# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -#endif // !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +#include #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include #include +#include + namespace boost { namespace asio { namespace posix { @@ -181,9 +171,9 @@ private: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP diff --git a/include/boost/asio/raw_socket_service.hpp b/include/boost/asio/raw_socket_service.hpp index 23427d7f..0db83b60 100644 --- a/include/boost/asio/raw_socket_service.hpp +++ b/include/boost/asio/raw_socket_service.hpp @@ -15,16 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include #include -#include #if defined(BOOST_ASIO_HAS_IOCP) # include @@ -32,6 +26,8 @@ # include #endif +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/read.hpp b/include/boost/asio/read.hpp index 40ccc008..d2339d59 100644 --- a/include/boost/asio/read.hpp +++ b/include/boost/asio/read.hpp @@ -15,16 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - -#include +#include #include +#include + namespace boost { namespace asio { @@ -538,8 +535,8 @@ void async_read(AsyncReadStream& s, basic_streambuf& b, } // namespace asio } // namespace boost -#include - #include +#include + #endif // BOOST_ASIO_READ_HPP diff --git a/include/boost/asio/read_at.hpp b/include/boost/asio/read_at.hpp index 133f143e..27bad65e 100644 --- a/include/boost/asio/read_at.hpp +++ b/include/boost/asio/read_at.hpp @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include #include -#include - -#include +#include #include +#include + namespace boost { namespace asio { @@ -571,8 +568,8 @@ void async_read_at(AsyncRandomAccessReadDevice& d, } // namespace asio } // namespace boost -#include - #include +#include + #endif // BOOST_ASIO_READ_AT_HPP diff --git a/include/boost/asio/read_until.hpp b/include/boost/asio/read_until.hpp index ec6cb426..aa9d2ba6 100644 --- a/include/boost/asio/read_until.hpp +++ b/include/boost/asio/read_until.hpp @@ -15,27 +15,22 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include +#include #if !defined(BOOST_NO_IOSTREAM) -#include #include -#include #include #include #include #include #include -#include - #include +#include #include +#include + namespace boost { namespace asio { @@ -916,10 +911,10 @@ void async_read_until(AsyncReadStream& s, } // namespace asio } // namespace boost -#include +#include + +#include #endif // !defined(BOOST_NO_IOSTREAM) -#include - #endif // BOOST_ASIO_READ_UNTIL_HPP diff --git a/include/boost/asio/serial_port.hpp b/include/boost/asio/serial_port.hpp index 00546e83..97757394 100644 --- a/include/boost/asio/serial_port.hpp +++ b/include/boost/asio/serial_port.hpp @@ -16,13 +16,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) +#include + namespace boost { namespace asio { @@ -35,6 +35,4 @@ typedef basic_serial_port<> serial_port; #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_SERIAL_PORT_HPP diff --git a/include/boost/asio/serial_port_base.hpp b/include/boost/asio/serial_port_base.hpp index 5f966392..a050df2f 100644 --- a/include/boost/asio/serial_port_base.hpp +++ b/include/boost/asio/serial_port_base.hpp @@ -16,32 +16,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include -#include - -#if !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) -# if defined(BOOST_ASIO_HAS_IOCP) \ - || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -# define BOOST_ASIO_HAS_SERIAL_PORT 1 -# endif // defined(BOOST_ASIO_HAS_IOCP) -#endif // !defined(BOOST_ASIO_DISABLE_STREAM_HANDLE) +#include #if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) -# include # include -# include #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#include #include +#include #if defined(GENERATING_DOCUMENTATION) # define BOOST_ASIO_OPTION_STORAGE implementation_defined @@ -51,6 +37,8 @@ # define BOOST_ASIO_OPTION_STORAGE termios #endif +#include + namespace boost { namespace asio { @@ -68,9 +56,11 @@ public: public: explicit baud_rate(unsigned int rate = 0); unsigned int value() const; - boost::system::error_code store(BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code store( + BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const; - boost::system::error_code load(const BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code load( + const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec); private: unsigned int value_; @@ -84,11 +74,13 @@ public: { public: enum type { none, software, hardware }; - explicit flow_control(type t = none); + BOOST_ASIO_DECL explicit flow_control(type t = none); type value() const; - boost::system::error_code store(BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code store( + BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const; - boost::system::error_code load(const BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code load( + const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec); private: type value_; @@ -102,11 +94,13 @@ public: { public: enum type { none, odd, even }; - explicit parity(type t = none); + BOOST_ASIO_DECL explicit parity(type t = none); type value() const; - boost::system::error_code store(BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code store( + BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const; - boost::system::error_code load(const BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code load( + const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec); private: type value_; @@ -120,11 +114,13 @@ public: { public: enum type { one, onepointfive, two }; - explicit stop_bits(type t = one); + BOOST_ASIO_DECL explicit stop_bits(type t = one); type value() const; - boost::system::error_code store(BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code store( + BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const; - boost::system::error_code load(const BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code load( + const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec); private: type value_; @@ -137,11 +133,13 @@ public: class character_size { public: - explicit character_size(unsigned int t = 8); + BOOST_ASIO_DECL explicit character_size(unsigned int t = 8); unsigned int value() const; - boost::system::error_code store(BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code store( + BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const; - boost::system::error_code load(const BOOST_ASIO_OPTION_STORAGE& storage, + BOOST_ASIO_DECL boost::system::error_code load( + const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec); private: unsigned int value_; @@ -163,13 +161,16 @@ private: } // namespace asio } // namespace boost -#include +#include #undef BOOST_ASIO_OPTION_STORAGE +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_SERIAL_PORT_BASE_HPP diff --git a/include/boost/asio/serial_port_service.hpp b/include/boost/asio/serial_port_service.hpp index f1a23446..b1c83010 100644 --- a/include/boost/asio/serial_port_service.hpp +++ b/include/boost/asio/serial_port_service.hpp @@ -15,24 +15,21 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include +#include #if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include +#include +#include +#include +#include + +#include + namespace boost { namespace asio { @@ -201,9 +198,9 @@ private: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_SERIAL_PORT_SERVICE_HPP diff --git a/include/boost/asio/socket_acceptor_service.hpp b/include/boost/asio/socket_acceptor_service.hpp index 184580fb..3f7436b7 100644 --- a/include/boost/asio/socket_acceptor_service.hpp +++ b/include/boost/asio/socket_acceptor_service.hpp @@ -15,12 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include #include -#include #if defined(BOOST_ASIO_HAS_IOCP) # include @@ -28,6 +26,8 @@ # include #endif +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/socket_base.hpp b/include/boost/asio/socket_base.hpp index 75015bf6..083ffb6e 100644 --- a/include/boost/asio/socket_base.hpp +++ b/include/boost/asio/socket_base.hpp @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include -#include - #include #include #include +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/ssl/basic_context.hpp b/include/boost/asio/ssl/basic_context.hpp index acaa080d..9f9423ef 100644 --- a/include/boost/asio/ssl/basic_context.hpp +++ b/include/boost/asio/ssl/basic_context.hpp @@ -1,6 +1,6 @@ // -// basic_context.hpp -// ~~~~~~~~~~~~~~~~~ +// ssl/basic_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -16,17 +16,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include - +#include #include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/ssl/context.hpp b/include/boost/asio/ssl/context.hpp index e07608bb..2a0c2c41 100644 --- a/include/boost/asio/ssl/context.hpp +++ b/include/boost/asio/ssl/context.hpp @@ -1,6 +1,6 @@ // -// context.hpp -// ~~~~~~~~~~~ +// ssl/context.hpp +// ~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -16,8 +16,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - +#include #include #include @@ -32,6 +31,4 @@ typedef basic_context context; } // namespace asio } // namespace boost -#include - #endif // BOOST_ASIO_SSL_CONTEXT_HPP diff --git a/include/boost/asio/ssl/context_base.hpp b/include/boost/asio/ssl/context_base.hpp index 119d0727..8121500d 100644 --- a/include/boost/asio/ssl/context_base.hpp +++ b/include/boost/asio/ssl/context_base.hpp @@ -1,6 +1,6 @@ // -// context_base.hpp -// ~~~~~~~~~~~~~~~~ +// ssl/context_base.hpp +// ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include +#include #include -#include - #include +#include + namespace boost { namespace asio { namespace ssl { diff --git a/include/boost/asio/ssl/context_service.hpp b/include/boost/asio/ssl/context_service.hpp index 4e33348e..689438d8 100644 --- a/include/boost/asio/ssl/context_service.hpp +++ b/include/boost/asio/ssl/context_service.hpp @@ -1,6 +1,6 @@ // -// context_service.hpp -// ~~~~~~~~~~~~~~~~~~~ +// ssl/context_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -16,19 +16,16 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include -#include - #include #include -#include #include #include +#include + namespace boost { namespace asio { namespace ssl { diff --git a/include/boost/asio/ssl/detail/openssl_context_service.hpp b/include/boost/asio/ssl/detail/openssl_context_service.hpp index 0180c76e..17348349 100644 --- a/include/boost/asio/ssl/detail/openssl_context_service.hpp +++ b/include/boost/asio/ssl/detail/openssl_context_service.hpp @@ -1,6 +1,6 @@ // -// openssl_context_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// ssl/detail/openssl_context_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -16,21 +16,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include -#include - #include #include -#include #include #include #include +#include + namespace boost { namespace asio { namespace ssl { diff --git a/include/boost/asio/ssl/detail/openssl_init.hpp b/include/boost/asio/ssl/detail/openssl_init.hpp index c1043a30..07bd1601 100644 --- a/include/boost/asio/ssl/detail/openssl_init.hpp +++ b/include/boost/asio/ssl/detail/openssl_init.hpp @@ -1,6 +1,6 @@ // -// openssl_init.hpp -// ~~~~~~~~~~~~~~~~ +// ssl/detail/openssl_init.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -16,20 +16,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include -#include #include -#include - #include #include #include +#include + namespace boost { namespace asio { namespace ssl { diff --git a/include/boost/asio/ssl/detail/openssl_operation.hpp b/include/boost/asio/ssl/detail/openssl_operation.hpp index 89b21f63..2eeb023c 100644 --- a/include/boost/asio/ssl/detail/openssl_operation.hpp +++ b/include/boost/asio/ssl/detail/openssl_operation.hpp @@ -1,6 +1,6 @@ // -// openssl_operation.hpp -// ~~~~~~~~~~~~~~~~~~~~~ +// ssl/detail/openssl_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // @@ -15,19 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include -#include - #include -#include -#include #include +#include #include +#include +#include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/ssl/detail/openssl_stream_service.hpp b/include/boost/asio/ssl/detail/openssl_stream_service.hpp index 5d9a99cd..a554921f 100644 --- a/include/boost/asio/ssl/detail/openssl_stream_service.hpp +++ b/include/boost/asio/ssl/detail/openssl_stream_service.hpp @@ -1,6 +1,6 @@ // -// stream_service.hpp -// ~~~~~~~~~~~~~~~~~~ +// ssl/detail/stream_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -16,9 +16,7 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include #include @@ -26,17 +24,17 @@ #include #include #include -#include - +#include #include #include -#include -#include -#include #include #include #include #include +#include +#include + +#include namespace boost { namespace asio { @@ -93,7 +91,7 @@ private: : base_handler(io_service) , handler_(handler) { - set_func(boost::bind( + this->set_func(boost::bind( &io_handler::handler_impl, this, boost::arg<1>(), boost::arg<2>() )); } @@ -117,7 +115,7 @@ private: : base_handler(io_service) , handler_(handler) { - set_func(boost::bind( + this->set_func(boost::bind( &handshake_handler::handler_impl, this, boost::arg<1>(), boost::arg<2>() )); } @@ -142,7 +140,7 @@ private: : base_handler(io_service), handler_(handler) { - set_func(boost::bind( + this->set_func(boost::bind( &shutdown_handler::handler_impl, this, boost::arg<1>(), boost::arg<2>() )); } diff --git a/include/boost/asio/ssl/detail/openssl_types.hpp b/include/boost/asio/ssl/detail/openssl_types.hpp index 2c493c39..712c5539 100644 --- a/include/boost/asio/ssl/detail/openssl_types.hpp +++ b/include/boost/asio/ssl/detail/openssl_types.hpp @@ -1,6 +1,6 @@ // -// openssl_types.hpp -// ~~~~~~~~~~~~~~~~~ +// ssl/detail/openssl_types.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,17 +15,11 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include - -#include +#include #include #include #include #include -#include - -#include +#include #endif // BOOST_ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP diff --git a/include/boost/asio/ssl/stream.hpp b/include/boost/asio/ssl/stream.hpp index 5f70020d..c83d8e2e 100644 --- a/include/boost/asio/ssl/stream.hpp +++ b/include/boost/asio/ssl/stream.hpp @@ -1,6 +1,6 @@ // -// stream.hpp -// ~~~~~~~~~~ +// ssl/stream.hpp +// ~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -16,20 +16,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include #include #include -#include - +#include #include #include #include #include -#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/ssl/stream_base.hpp b/include/boost/asio/ssl/stream_base.hpp index 3238fe4a..2d967d01 100644 --- a/include/boost/asio/ssl/stream_base.hpp +++ b/include/boost/asio/ssl/stream_base.hpp @@ -1,6 +1,6 @@ // -// stream_base.hpp -// ~~~~~~~~~~~~~~~ +// ssl/stream_base.hpp +// ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,11 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include +#include #include -#include -#include namespace boost { namespace asio { diff --git a/include/boost/asio/ssl/stream_service.hpp b/include/boost/asio/ssl/stream_service.hpp index 502f5123..303f8794 100644 --- a/include/boost/asio/ssl/stream_service.hpp +++ b/include/boost/asio/ssl/stream_service.hpp @@ -1,6 +1,6 @@ // -// stream_service.hpp -// ~~~~~~~~~~~~~~~~~~ +// ssl/stream_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) @@ -16,19 +16,15 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include #include -#include - #include -#include #include -#include #include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/strand.hpp b/include/boost/asio/strand.hpp index a64d4867..e0850308 100644 --- a/include/boost/asio/strand.hpp +++ b/include/boost/asio/strand.hpp @@ -15,11 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include #include +#include + +#include namespace boost { namespace asio { diff --git a/include/boost/asio/stream_socket_service.hpp b/include/boost/asio/stream_socket_service.hpp index 15aa6832..101eacbe 100644 --- a/include/boost/asio/stream_socket_service.hpp +++ b/include/boost/asio/stream_socket_service.hpp @@ -15,16 +15,10 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - #include #include -#include #if defined(BOOST_ASIO_HAS_IOCP) # include @@ -32,6 +26,8 @@ # include #endif +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/streambuf.hpp b/include/boost/asio/streambuf.hpp index c112e64d..30196ad7 100644 --- a/include/boost/asio/streambuf.hpp +++ b/include/boost/asio/streambuf.hpp @@ -15,12 +15,12 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if !defined(BOOST_NO_IOSTREAM) +#include + namespace boost { namespace asio { @@ -32,6 +32,4 @@ typedef basic_streambuf<> streambuf; #endif // !defined(BOOST_NO_IOSTREAM) -#include - #endif // BOOST_ASIO_STREAMBUF_HPP diff --git a/include/boost/asio/time_traits.hpp b/include/boost/asio/time_traits.hpp index e0f40ca1..9043d7dc 100644 --- a/include/boost/asio/time_traits.hpp +++ b/include/boost/asio/time_traits.hpp @@ -15,14 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - #include // Must come before posix_time. #include #include #include +#include + namespace boost { namespace asio { diff --git a/include/boost/asio/version.hpp b/include/boost/asio/version.hpp index 481e7bce..0172f738 100644 --- a/include/boost/asio/version.hpp +++ b/include/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 100403 // 1.4.3 +#define BOOST_ASIO_VERSION 100405 // 1.4.5 #endif // BOOST_ASIO_VERSION_HPP diff --git a/include/boost/asio/windows/basic_handle.hpp b/include/boost/asio/windows/basic_handle.hpp index 7bbdb0d3..58bb54dc 100644 --- a/include/boost/asio/windows/basic_handle.hpp +++ b/include/boost/asio/windows/basic_handle.hpp @@ -1,6 +1,6 @@ // -// basic_handle.hpp -// ~~~~~~~~~~~~~~~~ +// windows/basic_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,15 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include -#include -#include -#include +#if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ + || defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) #include -#include #include +#include + +#include namespace boost { namespace asio { @@ -224,4 +226,8 @@ protected: #include +#endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + // || defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) + // || defined(GENERATING_DOCUMENTATION) + #endif // BOOST_ASIO_WINDOWS_BASIC_HANDLE_HPP diff --git a/include/boost/asio/windows/basic_random_access_handle.hpp b/include/boost/asio/windows/basic_random_access_handle.hpp index 06239df6..5c403d02 100644 --- a/include/boost/asio/windows/basic_random_access_handle.hpp +++ b/include/boost/asio/windows/basic_random_access_handle.hpp @@ -1,6 +1,6 @@ // -// basic_random_access_handle.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// windows/basic_random_access_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,21 +15,19 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include - -#include -#include -#include -#include +#include #if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include +#include +#include + +#include + namespace boost { namespace asio { namespace windows { @@ -314,9 +312,9 @@ public: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP diff --git a/include/boost/asio/windows/basic_stream_handle.hpp b/include/boost/asio/windows/basic_stream_handle.hpp index 329cc6fc..340e4024 100644 --- a/include/boost/asio/windows/basic_stream_handle.hpp +++ b/include/boost/asio/windows/basic_stream_handle.hpp @@ -1,6 +1,6 @@ // -// basic_stream_handle.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ +// windows/basic_stream_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,20 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include +#include + +#if defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) -#include #include -#include -#include - #include #include #include #include -#if defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ - || defined(GENERATING_DOCUMENTATION) +#include namespace boost { namespace asio { @@ -296,9 +294,9 @@ public: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP diff --git a/include/boost/asio/windows/overlapped_ptr.hpp b/include/boost/asio/windows/overlapped_ptr.hpp index 58802723..24a199f3 100644 --- a/include/boost/asio/windows/overlapped_ptr.hpp +++ b/include/boost/asio/windows/overlapped_ptr.hpp @@ -1,6 +1,6 @@ // -// overlapped_ptr.hpp -// ~~~~~~~~~~~~~~~~~~ +// windows/overlapped_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,21 +15,17 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include - -#if !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) -# if defined(BOOST_ASIO_HAS_IOCP) -# define BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1 -# endif // defined(BOOST_ASIO_HAS_IOCP) -#endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +#include #if defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include + +#include + namespace boost { namespace asio { namespace windows { @@ -112,9 +108,9 @@ private: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_WINDOWS_OVERLAPPED_PTR_HPP diff --git a/include/boost/asio/windows/random_access_handle.hpp b/include/boost/asio/windows/random_access_handle.hpp index 7707aac1..03d7055b 100644 --- a/include/boost/asio/windows/random_access_handle.hpp +++ b/include/boost/asio/windows/random_access_handle.hpp @@ -1,6 +1,6 @@ // -// random_access_handle.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~ +// windows/random_access_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) +#include + namespace boost { namespace asio { namespace windows { @@ -36,6 +36,4 @@ typedef basic_random_access_handle<> random_access_handle; #endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_HPP diff --git a/include/boost/asio/windows/random_access_handle_service.hpp b/include/boost/asio/windows/random_access_handle_service.hpp index 1dcbee4b..e5a2e11c 100644 --- a/include/boost/asio/windows/random_access_handle_service.hpp +++ b/include/boost/asio/windows/random_access_handle_service.hpp @@ -1,6 +1,6 @@ // -// random_access_handle_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// windows/random_access_handle_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,28 +15,20 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) -# if defined(BOOST_ASIO_HAS_IOCP) -# define BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 -# endif // defined(BOOST_ASIO_HAS_IOCP) -#endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +#include #if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include +#include +#include +#include + +#include + namespace boost { namespace asio { namespace windows { @@ -174,9 +166,9 @@ private: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_SERVICE_HPP diff --git a/include/boost/asio/windows/stream_handle.hpp b/include/boost/asio/windows/stream_handle.hpp index 8e9e4670..ca2a56c5 100644 --- a/include/boost/asio/windows/stream_handle.hpp +++ b/include/boost/asio/windows/stream_handle.hpp @@ -1,6 +1,6 @@ // -// stream_handle.hpp -// ~~~~~~~~~~~~~~~~~~ +// windows/stream_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,13 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #if defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) +#include + namespace boost { namespace asio { namespace windows { @@ -36,6 +36,4 @@ typedef basic_stream_handle<> stream_handle; #endif // defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_WINDOWS_STREAM_HANDLE_HPP diff --git a/include/boost/asio/windows/stream_handle_service.hpp b/include/boost/asio/windows/stream_handle_service.hpp index cc6c6e86..e5346461 100644 --- a/include/boost/asio/windows/stream_handle_service.hpp +++ b/include/boost/asio/windows/stream_handle_service.hpp @@ -1,6 +1,6 @@ // -// stream_handle_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// windows/stream_handle_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // @@ -15,27 +15,18 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#if !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) -# if defined(BOOST_ASIO_HAS_IOCP) -# define BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE 1 -# endif // defined(BOOST_ASIO_HAS_IOCP) -#endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +#include #if defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) +#include +#include +#include +#include + +#include + namespace boost { namespace asio { namespace windows { @@ -172,9 +163,9 @@ private: } // namespace asio } // namespace boost +#include + #endif // defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) -#include - #endif // BOOST_ASIO_WINDOWS_STREAM_HANDLE_SERVICE_HPP diff --git a/include/boost/asio/write.hpp b/include/boost/asio/write.hpp index 2a95735d..0ec08797 100644 --- a/include/boost/asio/write.hpp +++ b/include/boost/asio/write.hpp @@ -15,16 +15,13 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include -#include - -#include +#include #include +#include + namespace boost { namespace asio { @@ -535,8 +532,8 @@ void async_write(AsyncWriteStream& s, basic_streambuf& b, } // namespace asio } // namespace boost -#include - #include +#include + #endif // BOOST_ASIO_WRITE_HPP diff --git a/include/boost/asio/write_at.hpp b/include/boost/asio/write_at.hpp index 74f080a3..a078a703 100644 --- a/include/boost/asio/write_at.hpp +++ b/include/boost/asio/write_at.hpp @@ -15,17 +15,14 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include - -#include +#include #include -#include #include -#include - -#include +#include #include +#include + namespace boost { namespace asio { @@ -558,8 +555,8 @@ void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, } // namespace asio } // namespace boost -#include - #include +#include + #endif // BOOST_ASIO_WRITE_AT_HPP diff --git a/test/Jamfile b/test/Jamfile index 220727e4..c2c38ac1 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -26,6 +26,7 @@ if $(UNIX) template asio_unit_test : @boost/libs/thread/build/boost_thread + @boost/libs/regex/build/boost_regex @boost_system/libs/system/build/boost_system : ../../.. @boost @boost_system BOOST_ALL_NO_LIB=1 diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 8a7f5f9b..6148d2e2 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -39,6 +39,7 @@ project /boost/date_time//boost_date_time /boost/system//boost_system /boost/thread//boost_thread + /boost/regex//boost_regex BOOST_ALL_NO_LIB=1 multi LINUX:_XOPEN_SOURCE=600 diff --git a/test/buffer.cpp b/test/buffer.cpp index a11f15f9..48139932 100644 --- a/test/buffer.cpp +++ b/test/buffer.cpp @@ -16,6 +16,7 @@ // Test that header file is self-contained. #include +#include #include "unit_test.hpp" //------------------------------------------------------------------------------ diff --git a/test/buffered_read_stream.cpp b/test/buffered_read_stream.cpp index 8015a5f4..f3d0a2ef 100644 --- a/test/buffered_read_stream.cpp +++ b/test/buffered_read_stream.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "unit_test.hpp" typedef boost::asio::buffered_read_stream< diff --git a/test/buffered_stream.cpp b/test/buffered_stream.cpp index 0ea15fed..ae6f4529 100644 --- a/test/buffered_stream.cpp +++ b/test/buffered_stream.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "unit_test.hpp" typedef boost::asio::buffered_stream< diff --git a/test/buffered_write_stream.cpp b/test/buffered_write_stream.cpp index f29fff58..b7e444e0 100644 --- a/test/buffered_write_stream.cpp +++ b/test/buffered_write_stream.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "unit_test.hpp" typedef boost::asio::buffered_write_stream< diff --git a/test/buffers_iterator.cpp b/test/buffers_iterator.cpp index 2bcc3b37..226e470e 100644 --- a/test/buffers_iterator.cpp +++ b/test/buffers_iterator.cpp @@ -16,6 +16,7 @@ // Test that header file is self-contained. #include +#include #include #include "unit_test.hpp" @@ -212,18 +213,18 @@ void test() bi11 += 1; bi12 += 1; - static_cast(bi13 - bi1); - static_cast(bi14 - bi2); - static_cast(bi15 - bi3); - static_cast(bi16 - bi4); - static_cast(bi17 - bi5); - static_cast(bi18 - bi6); - static_cast(bi19 - bi7); - static_cast(bi20 - bi8); - static_cast(bi21 - bi9); - static_cast(bi22 - bi10); - static_cast(bi23 - bi11); - static_cast(bi24 - bi12); + (void)static_cast(bi13 - bi1); + (void)static_cast(bi14 - bi2); + (void)static_cast(bi15 - bi3); + (void)static_cast(bi16 - bi4); + (void)static_cast(bi17 - bi5); + (void)static_cast(bi18 - bi6); + (void)static_cast(bi19 - bi7); + (void)static_cast(bi20 - bi8); + (void)static_cast(bi21 - bi9); + (void)static_cast(bi22 - bi10); + (void)static_cast(bi23 - bi11); + (void)static_cast(bi24 - bi12); } catch (std::exception&) { diff --git a/test/ip/multicast.cpp b/test/ip/multicast.cpp index 510bea65..2541cb62 100644 --- a/test/ip/multicast.cpp +++ b/test/ip/multicast.cpp @@ -76,7 +76,7 @@ void test() ip::multicast::hops hops2; sock.get_option(hops2); hops1 = 1; - static_cast(hops1.value()); + (void)static_cast(hops1.value()); // enable_loopback class. @@ -85,9 +85,9 @@ void test() ip::multicast::enable_loopback enable_loopback2; sock.get_option(enable_loopback2); enable_loopback1 = true; - static_cast(enable_loopback1); - static_cast(!enable_loopback1); - static_cast(enable_loopback1.value()); + (void)static_cast(enable_loopback1); + (void)static_cast(!enable_loopback1); + (void)static_cast(enable_loopback1.value()); } catch (std::exception&) { diff --git a/test/ip/tcp.cpp b/test/ip/tcp.cpp index 95f550ef..d3e72f50 100644 --- a/test/ip/tcp.cpp +++ b/test/ip/tcp.cpp @@ -54,9 +54,9 @@ void test() ip::tcp::no_delay no_delay2; sock.get_option(no_delay2); no_delay1 = true; - static_cast(no_delay1); - static_cast(!no_delay1); - static_cast(no_delay1.value()); + (void)static_cast(no_delay1); + (void)static_cast(!no_delay1); + (void)static_cast(no_delay1.value()); } catch (std::exception&) { @@ -551,6 +551,68 @@ void test() //------------------------------------------------------------------------------ +// ip_tcp_resolver_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::tcp::resolver compile and link correctly. Runtime failures are ignored. + +namespace ip_tcp_resolver_compile { + +void resolve_handler(const boost::system::error_code&, + boost::asio::ip::tcp::resolver::iterator) +{ +} + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_service ios; + boost::system::error_code ec; + ip::tcp::resolver::query q(ip::tcp::v4(), "localhost", "0"); + ip::tcp::endpoint e(ip::address_v4::loopback(), 0); + + // basic_resolver constructors. + + ip::tcp::resolver resolver(ios); + + // basic_io_object functions. + + io_service& ios_ref = resolver.io_service(); + (void)ios_ref; + + // basic_resolver functions. + + resolver.cancel(); + + ip::tcp::resolver::iterator iter1 = resolver.resolve(q); + (void)iter1; + + ip::tcp::resolver::iterator iter2 = resolver.resolve(q, ec); + (void)iter2; + + ip::tcp::resolver::iterator iter3 = resolver.resolve(e); + (void)iter3; + + ip::tcp::resolver::iterator iter4 = resolver.resolve(e, ec); + (void)iter4; + + resolver.async_resolve(q, resolve_handler); + + resolver.async_resolve(e, resolve_handler); + } + catch (std::exception&) + { + } +} + +} // namespace ip_tcp_resolver_compile + +//------------------------------------------------------------------------------ + test_suite* init_unit_test_suite(int, char*[]) { test_suite* test = BOOST_TEST_SUITE("ip/tcp"); @@ -559,5 +621,6 @@ test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(&ip_tcp_socket_compile::test)); test->add(BOOST_TEST_CASE(&ip_tcp_socket_runtime::test)); test->add(BOOST_TEST_CASE(&ip_tcp_acceptor_runtime::test)); + test->add(BOOST_TEST_CASE(&ip_tcp_resolver_compile::test)); return test; } diff --git a/test/ip/udp.cpp b/test/ip/udp.cpp index b9b296f7..6cbcc806 100644 --- a/test/ip/udp.cpp +++ b/test/ip/udp.cpp @@ -334,10 +334,73 @@ void test() //------------------------------------------------------------------------------ +// ip_udp_resolver_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::udp::resolver compile and link correctly. Runtime failures are ignored. + +namespace ip_udp_resolver_compile { + +void resolve_handler(const boost::system::error_code&, + boost::asio::ip::udp::resolver::iterator) +{ +} + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_service ios; + boost::system::error_code ec; + ip::udp::resolver::query q(ip::udp::v4(), "localhost", "0"); + ip::udp::endpoint e(ip::address_v4::loopback(), 0); + + // basic_resolver constructors. + + ip::udp::resolver resolver(ios); + + // basic_io_object functions. + + io_service& ios_ref = resolver.io_service(); + (void)ios_ref; + + // basic_resolver functions. + + resolver.cancel(); + + ip::udp::resolver::iterator iter1 = resolver.resolve(q); + (void)iter1; + + ip::udp::resolver::iterator iter2 = resolver.resolve(q, ec); + (void)iter2; + + ip::udp::resolver::iterator iter3 = resolver.resolve(e); + (void)iter3; + + ip::udp::resolver::iterator iter4 = resolver.resolve(e, ec); + (void)iter4; + + resolver.async_resolve(q, resolve_handler); + + resolver.async_resolve(e, resolve_handler); + } + catch (std::exception&) + { + } +} + +} // namespace ip_udp_resolver_compile + +//------------------------------------------------------------------------------ + test_suite* init_unit_test_suite(int, char*[]) { test_suite* test = BOOST_TEST_SUITE("ip/udp"); test->add(BOOST_TEST_CASE(&ip_udp_socket_compile::test)); test->add(BOOST_TEST_CASE(&ip_udp_socket_runtime::test)); + test->add(BOOST_TEST_CASE(&ip_udp_resolver_compile::test)); return test; } diff --git a/test/ip/unicast.cpp b/test/ip/unicast.cpp index 67af4734..06ad0599 100644 --- a/test/ip/unicast.cpp +++ b/test/ip/unicast.cpp @@ -46,7 +46,7 @@ void test() ip::unicast::hops hops2; sock.get_option(hops2); hops1 = 1; - static_cast(hops1.value()); + (void)static_cast(hops1.value()); } catch (std::exception&) { diff --git a/test/ip/v6_only.cpp b/test/ip/v6_only.cpp index 74d9ca9f..8186047a 100644 --- a/test/ip/v6_only.cpp +++ b/test/ip/v6_only.cpp @@ -47,9 +47,9 @@ void test() ip::v6_only v6_only2; sock.get_option(v6_only2); v6_only1 = true; - static_cast(v6_only1); - static_cast(!v6_only1); - static_cast(v6_only1.value()); + (void)static_cast(v6_only1); + (void)static_cast(!v6_only1); + (void)static_cast(v6_only1.value()); } catch (std::exception&) { diff --git a/test/read.cpp b/test/read.cpp index 1e9401d8..7babf655 100644 --- a/test/read.cpp +++ b/test/read.cpp @@ -16,6 +16,7 @@ // Test that header file is self-contained. #include +#include #include #include #include @@ -61,7 +62,7 @@ public: } template - bool check(const Const_Buffers& buffers, size_t length) + bool check_buffers(const Const_Buffers& buffers, size_t length) { if (length != position_) return false; @@ -147,21 +148,21 @@ void test_2_arg_mutable_buffers_1_read() memset(read_buf, 0, sizeof(read_buf)); size_t bytes_transferred = boost::asio::read(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); } void test_2_arg_multi_buffers_read() @@ -177,21 +178,21 @@ void test_2_arg_multi_buffers_read() memset(read_buf, 0, sizeof(read_buf)); size_t bytes_transferred = boost::asio::read(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); } void test_2_arg_streambuf_read() @@ -205,7 +206,7 @@ void test_2_arg_streambuf_read() size_t bytes_transferred = boost::asio::read(s, sb); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -213,7 +214,7 @@ void test_2_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -221,7 +222,7 @@ void test_2_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); } bool old_style_transfer_all(const boost::system::error_code& ec, @@ -249,7 +250,7 @@ void test_3_arg_mutable_buffers_1_read() size_t bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -257,7 +258,7 @@ void test_3_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -265,14 +266,14 @@ void test_3_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -280,7 +281,7 @@ void test_3_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -288,14 +289,14 @@ void test_3_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -303,7 +304,7 @@ void test_3_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -311,14 +312,14 @@ void test_3_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -326,7 +327,7 @@ void test_3_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -334,47 +335,47 @@ void test_3_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); } void test_3_arg_multi_buffers_read() @@ -391,7 +392,7 @@ void test_3_arg_multi_buffers_read() size_t bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -399,7 +400,7 @@ void test_3_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -407,14 +408,14 @@ void test_3_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -422,7 +423,7 @@ void test_3_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -430,14 +431,14 @@ void test_3_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -445,7 +446,7 @@ void test_3_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -453,14 +454,14 @@ void test_3_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -468,7 +469,7 @@ void test_3_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -476,47 +477,47 @@ void test_3_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); } void test_3_arg_streambuf_read() @@ -531,7 +532,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -540,7 +541,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -549,7 +550,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); @@ -557,7 +558,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -566,7 +567,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); BOOST_CHECK(sb.size() == 1); - BOOST_CHECK(s.check(sb.data(), 1)); + BOOST_CHECK(s.check_buffers(sb.data(), 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -575,7 +576,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); @@ -583,7 +584,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -592,7 +593,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -601,7 +602,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); @@ -609,7 +610,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -618,7 +619,7 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); BOOST_CHECK(sb.size() == 42); - BOOST_CHECK(s.check(sb.data(), 42)); + BOOST_CHECK(s.check_buffers(sb.data(), 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -627,14 +628,14 @@ void test_3_arg_streambuf_read() boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); BOOST_CHECK(sb.size() == 50); - BOOST_CHECK(s.check(sb.data(), 50)); + BOOST_CHECK(s.check_buffers(sb.data(), 50)); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); bytes_transferred = boost::asio::read(s, sb, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -642,7 +643,7 @@ void test_3_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -650,14 +651,14 @@ void test_3_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); bytes_transferred = boost::asio::read(s, sb, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -665,7 +666,7 @@ void test_3_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -673,7 +674,7 @@ void test_3_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); } void test_4_arg_mutable_buffers_1_read() @@ -690,7 +691,7 @@ void test_4_arg_mutable_buffers_1_read() size_t bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -700,7 +701,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -710,7 +711,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -719,7 +720,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -729,7 +730,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -739,7 +740,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -748,7 +749,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -758,7 +759,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -768,7 +769,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -777,7 +778,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -787,7 +788,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -797,7 +798,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -805,7 +806,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -815,7 +816,7 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -825,14 +826,14 @@ void test_4_arg_mutable_buffers_1_read() bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -841,7 +842,7 @@ void test_4_arg_mutable_buffers_1_read() error = boost::system::error_code(); bytes_transferred = boost::asio::read(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -850,7 +851,7 @@ void test_4_arg_mutable_buffers_1_read() error = boost::system::error_code(); bytes_transferred = boost::asio::read(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); } @@ -869,7 +870,7 @@ void test_4_arg_multi_buffers_read() size_t bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -879,7 +880,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -889,7 +890,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -898,7 +899,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -908,7 +909,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -918,7 +919,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -927,7 +928,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -937,7 +938,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -947,7 +948,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -956,7 +957,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -966,7 +967,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -976,7 +977,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -984,7 +985,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -994,7 +995,7 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1004,14 +1005,14 @@ void test_4_arg_multi_buffers_read() bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1020,7 +1021,7 @@ void test_4_arg_multi_buffers_read() error = boost::system::error_code(); bytes_transferred = boost::asio::read(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1029,7 +1030,7 @@ void test_4_arg_multi_buffers_read() error = boost::system::error_code(); bytes_transferred = boost::asio::read(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); BOOST_CHECK(!error); } @@ -1046,7 +1047,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1057,7 +1058,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1068,7 +1069,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1078,7 +1079,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1089,7 +1090,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); BOOST_CHECK(sb.size() == 1); - BOOST_CHECK(s.check(sb.data(), 1)); + BOOST_CHECK(s.check_buffers(sb.data(), 1)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1100,7 +1101,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1110,7 +1111,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1121,7 +1122,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1132,7 +1133,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1142,7 +1143,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1153,7 +1154,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); BOOST_CHECK(sb.size() == 42); - BOOST_CHECK(s.check(sb.data(), 42)); + BOOST_CHECK(s.check_buffers(sb.data(), 42)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1164,7 +1165,7 @@ void test_4_arg_streambuf_read() boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); BOOST_CHECK(sb.size() == 50); - BOOST_CHECK(s.check(sb.data(), 50)); + BOOST_CHECK(s.check_buffers(sb.data(), 50)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1173,7 +1174,7 @@ void test_4_arg_streambuf_read() old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1184,7 +1185,7 @@ void test_4_arg_streambuf_read() old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1195,7 +1196,7 @@ void test_4_arg_streambuf_read() old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1203,7 +1204,7 @@ void test_4_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1213,7 +1214,7 @@ void test_4_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -1223,7 +1224,7 @@ void test_4_arg_streambuf_read() bytes_transferred = boost::asio::read(s, sb, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); BOOST_CHECK(!error); } @@ -1254,7 +1255,7 @@ void test_3_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1268,7 +1269,7 @@ void test_3_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1282,7 +1283,7 @@ void test_3_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); } void test_3_arg_multi_buffers_async_read() @@ -1305,7 +1306,7 @@ void test_3_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1319,7 +1320,7 @@ void test_3_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1333,7 +1334,7 @@ void test_3_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); } void test_3_arg_streambuf_async_read() @@ -1354,7 +1355,7 @@ void test_3_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1369,7 +1370,7 @@ void test_3_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1384,7 +1385,7 @@ void test_3_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); } void test_4_arg_mutable_buffers_1_async_read() @@ -1406,7 +1407,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1420,7 +1421,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1434,7 +1435,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1447,7 +1448,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1461,7 +1462,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1475,7 +1476,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1488,7 +1489,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1502,7 +1503,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1516,7 +1517,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1529,7 +1530,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1543,7 +1544,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1557,7 +1558,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1570,7 +1571,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1584,7 +1585,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1598,7 +1599,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1611,7 +1612,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1625,7 +1626,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1639,7 +1640,7 @@ void test_4_arg_mutable_buffers_1_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); } void test_4_arg_multi_buffers_async_read() @@ -1662,7 +1663,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1676,7 +1677,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1690,7 +1691,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1703,7 +1704,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1717,7 +1718,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1731,7 +1732,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1744,7 +1745,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1758,7 +1759,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1772,7 +1773,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1785,7 +1786,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1799,7 +1800,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1813,7 +1814,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1826,7 +1827,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1840,7 +1841,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1854,7 +1855,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1867,7 +1868,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1881,7 +1882,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1895,7 +1896,7 @@ void test_4_arg_multi_buffers_async_read() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(read_data))); } void test_4_arg_streambuf_async_read() @@ -1916,7 +1917,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1931,7 +1932,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1946,7 +1947,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); @@ -1960,7 +1961,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1975,7 +1976,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == 1); - BOOST_CHECK(s.check(sb.data(), 1)); + BOOST_CHECK(s.check_buffers(sb.data(), 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1990,7 +1991,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); @@ -2004,7 +2005,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -2019,7 +2020,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -2034,7 +2035,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == 10); - BOOST_CHECK(s.check(sb.data(), 10)); + BOOST_CHECK(s.check_buffers(sb.data(), 10)); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); @@ -2048,7 +2049,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -2063,7 +2064,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == 42); - BOOST_CHECK(s.check(sb.data(), 42)); + BOOST_CHECK(s.check_buffers(sb.data(), 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -2078,7 +2079,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == 50); - BOOST_CHECK(s.check(sb.data(), 50)); + BOOST_CHECK(s.check_buffers(sb.data(), 50)); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); @@ -2092,7 +2093,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -2107,7 +2108,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -2122,7 +2123,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); sb.consume(sb.size()); @@ -2136,7 +2137,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -2151,7 +2152,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -2166,7 +2167,7 @@ void test_4_arg_streambuf_async_read() ios.run(); BOOST_CHECK(called); BOOST_CHECK(sb.size() == sizeof(read_data)); - BOOST_CHECK(s.check(sb.data(), sizeof(read_data))); + BOOST_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); } test_suite* init_unit_test_suite(int, char*[]) diff --git a/test/read_at.cpp b/test/read_at.cpp index 48a668c5..36fd1c29 100644 --- a/test/read_at.cpp +++ b/test/read_at.cpp @@ -16,11 +16,13 @@ // Test that header file is self-contained. #include +#include #include #include #include #include #include +#include #include "unit_test.hpp" using namespace std; // For memcmp, memcpy and memset. @@ -63,7 +65,7 @@ public: } template - bool check(boost::uint64_t offset, + bool check_buffers(boost::uint64_t offset, const Const_Buffers& buffers, size_t length) { if (offset + length > max_length) @@ -139,7 +141,7 @@ private: static const char read_data[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -void test_3_arg_read_at() +void test_3_arg_mutable_buffers_1_read_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -151,41 +153,144 @@ void test_3_arg_read_at() memset(read_buf, 0, sizeof(read_buf)); size_t bytes_transferred = boost::asio::read_at(s, 0, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_3_arg_multi_buffers_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + char read_buf[sizeof(read_data)]; + boost::array buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + size_t bytes_transferred = boost::asio::read_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_3_arg_streambuf_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + size_t bytes_transferred = boost::asio::read_at(s, 0, sb); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); } bool old_style_transfer_all(const boost::system::error_code& ec, @@ -200,7 +305,7 @@ size_t short_transfer(const boost::system::error_code& ec, return !!ec ? 0 : 3; } -void test_4_arg_read_at() +void test_4_arg_mutable_buffers_1_read_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -213,14 +318,14 @@ void test_4_arg_read_at() size_t bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -228,7 +333,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -236,7 +341,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -244,7 +349,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -252,21 +357,21 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -274,7 +379,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(0, buffers, 1)); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -282,7 +387,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(1234, buffers, 1)); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -290,7 +395,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -298,21 +403,21 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -320,7 +425,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -328,7 +433,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -336,7 +441,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -344,21 +449,21 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -366,7 +471,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(0, buffers, 42)); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -374,7 +479,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(1234, buffers, 42)); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -382,7 +487,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(0, buffers, 50)); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -390,21 +495,21 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(1234, buffers, 50)); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -412,7 +517,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -420,7 +525,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -428,7 +533,7 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -436,50 +541,643 @@ void test_4_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); memset(read_buf, 0, sizeof(read_buf)); bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); } -void test_5_arg_read_at() +void test_4_arg_multi_buffers_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + char read_buf[sizeof(read_data)]; + boost::array buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + size_t bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_4_arg_streambuf_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + size_t bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(sb.size() == 1); + BOOST_CHECK(s.check_buffers(0, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(sb.size() == 1); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(sb.size() == 42); + BOOST_CHECK(s.check_buffers(0, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(sb.size() == 42); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(sb.size() == 50); + BOOST_CHECK(s.check_buffers(0, sb.data(), 50)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(sb.size() == 50); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 50)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); +} + +void test_5_arg_mutable_buffers_1_read_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -493,7 +1191,7 @@ void test_5_arg_read_at() size_t bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -501,7 +1199,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -511,7 +1209,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -521,7 +1219,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -531,7 +1229,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -541,7 +1239,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -550,7 +1248,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -559,7 +1257,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -569,7 +1267,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(0, buffers, 1)); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -579,7 +1277,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(1234, buffers, 1)); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -589,7 +1287,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -599,7 +1297,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -608,7 +1306,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -617,7 +1315,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -627,7 +1325,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -637,7 +1335,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -647,7 +1345,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -657,7 +1355,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -666,7 +1364,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -675,7 +1373,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -685,7 +1383,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(0, buffers, 42)); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -695,7 +1393,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(1234, buffers, 42)); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -705,7 +1403,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(0, buffers, 50)); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -715,7 +1413,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(1234, buffers, 50)); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -723,7 +1421,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -731,7 +1429,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -741,7 +1439,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -751,7 +1449,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -761,7 +1459,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -771,7 +1469,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -779,7 +1477,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -787,7 +1485,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -797,7 +1495,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -807,7 +1505,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -817,7 +1515,7 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); BOOST_CHECK(!error); s.reset(read_data, sizeof(read_data)); @@ -827,7 +1525,746 @@ void test_5_arg_read_at() bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(read_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); +} + +void test_5_arg_multi_buffers_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + char read_buf[sizeof(read_data)]; + boost::array buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_CHECK(!error); +} + +void test_5_arg_streambuf_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(sb.size() == 1); + BOOST_CHECK(s.check_buffers(0, sb.data(), 1)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(sb.size() == 1); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 1)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(sb.size() == 42); + BOOST_CHECK(s.check_buffers(0, sb.data(), 42)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(sb.size() == 42); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 42)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(sb.size() == 50); + BOOST_CHECK(s.check_buffers(0, sb.data(), 50)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(sb.size() == 50); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 50)); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); BOOST_CHECK(!error); } @@ -839,7 +2276,7 @@ void async_read_handler(const boost::system::error_code& e, BOOST_CHECK(bytes_transferred == expected_bytes_transferred); } -void test_4_arg_async_read_at() +void test_4_arg_mutable_buffers_1_async_read_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -858,7 +2295,7 @@ void test_4_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -871,7 +2308,7 @@ void test_4_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -885,7 +2322,7 @@ void test_4_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -899,7 +2336,7 @@ void test_4_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -913,7 +2350,7 @@ void test_4_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -927,10 +2364,197 @@ void test_4_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); } -void test_5_arg_async_read_at() +void test_4_arg_multi_buffers_async_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + char read_buf[sizeof(read_data)]; + boost::array buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_4_arg_streambuf_async_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bool called = false; + boost::asio::async_read_at(s, 0, sb, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); +} + +void test_5_arg_mutable_buffers_1_async_read_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -950,7 +2574,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -964,7 +2588,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -979,7 +2603,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -994,7 +2618,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1009,7 +2633,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1024,7 +2648,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1038,7 +2662,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1052,7 +2676,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1067,7 +2691,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 1)); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1082,7 +2706,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 1)); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1097,7 +2721,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1112,7 +2736,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1126,7 +2750,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1140,7 +2764,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1155,7 +2779,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1170,7 +2794,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1185,7 +2809,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1200,7 +2824,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1214,7 +2838,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1228,7 +2852,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1243,7 +2867,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 42)); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1258,7 +2882,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 42)); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1273,7 +2897,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 50)); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1288,7 +2912,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 50)); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1301,7 +2925,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1314,7 +2938,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1328,7 +2952,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1342,7 +2966,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1356,7 +2980,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1370,7 +2994,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1383,7 +3007,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); memset(read_buf, 0, sizeof(read_buf)); @@ -1396,7 +3020,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1410,7 +3034,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(1); @@ -1424,7 +3048,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1438,7 +3062,7 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); s.reset(read_data, sizeof(read_data)); s.next_read_length(10); @@ -1452,16 +3076,1111 @@ void test_5_arg_async_read_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(read_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_5_arg_multi_buffers_async_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + char read_buf[sizeof(read_data)]; + boost::array buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_5_arg_streambuf_async_read_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bool called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_all(), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 1); + BOOST_CHECK(s.check_buffers(0, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 1); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 10); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 42); + BOOST_CHECK(s.check_buffers(0, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 42); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 50); + BOOST_CHECK(s.check_buffers(0, sb.data(), 50)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == 50); + BOOST_CHECK(s.check_buffers(1234, sb.data(), 50)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, old_style_transfer_all, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, short_transfer, + boost::bind(async_read_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(read_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(sb.size() == sizeof(read_data)); + BOOST_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); } test_suite* init_unit_test_suite(int, char*[]) { - test_suite* test = BOOST_TEST_SUITE("read"); - test->add(BOOST_TEST_CASE(&test_3_arg_read_at)); - test->add(BOOST_TEST_CASE(&test_4_arg_read_at)); - test->add(BOOST_TEST_CASE(&test_5_arg_read_at)); - test->add(BOOST_TEST_CASE(&test_4_arg_async_read_at)); - test->add(BOOST_TEST_CASE(&test_5_arg_async_read_at)); + test_suite* test = BOOST_TEST_SUITE("read_at"); + test->add(BOOST_TEST_CASE(&test_3_arg_mutable_buffers_1_read_at)); + test->add(BOOST_TEST_CASE(&test_3_arg_multi_buffers_read_at)); + test->add(BOOST_TEST_CASE(&test_3_arg_streambuf_read_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_mutable_buffers_1_read_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_multi_buffers_read_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_streambuf_read_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_mutable_buffers_1_read_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_multi_buffers_read_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_streambuf_read_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_mutable_buffers_1_async_read_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_multi_buffers_async_read_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_streambuf_async_read_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_mutable_buffers_1_async_read_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_multi_buffers_async_read_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_streambuf_async_read_at)); return test; } diff --git a/test/serial_port_base.cpp b/test/serial_port_base.cpp index 2dd7f46f..ade5650f 100644 --- a/test/serial_port_base.cpp +++ b/test/serial_port_base.cpp @@ -46,7 +46,7 @@ void test() port.set_option(baud_rate1); serial_port_base::baud_rate baud_rate2; port.get_option(baud_rate2); - static_cast(baud_rate2.value()); + (void)static_cast(baud_rate2.value()); // flow_control class. @@ -55,7 +55,8 @@ void test() port.set_option(flow_control1); serial_port_base::flow_control flow_control2; port.get_option(flow_control2); - static_cast(flow_control2.value()); + (void)static_cast( + flow_control2.value()); // parity class. @@ -63,7 +64,7 @@ void test() port.set_option(parity1); serial_port_base::parity parity2; port.get_option(parity2); - static_cast(parity2.value()); + (void)static_cast(parity2.value()); // stop_bits class. @@ -71,7 +72,7 @@ void test() port.set_option(stop_bits1); serial_port_base::stop_bits stop_bits2; port.get_option(stop_bits2); - static_cast(stop_bits2.value()); + (void)static_cast(stop_bits2.value()); // character_size class. @@ -79,7 +80,7 @@ void test() port.set_option(character_size1); serial_port_base::character_size character_size2; port.get_option(character_size2); - static_cast(character_size2.value()); + (void)static_cast(character_size2.value()); } catch (std::exception&) { diff --git a/test/socket_base.cpp b/test/socket_base.cpp index baaf0e4f..635428d5 100644 --- a/test/socket_base.cpp +++ b/test/socket_base.cpp @@ -60,9 +60,9 @@ void test() socket_base::broadcast broadcast2; sock.get_option(broadcast2); broadcast1 = true; - static_cast(broadcast1); - static_cast(!broadcast1); - static_cast(broadcast1.value()); + (void)static_cast(broadcast1); + (void)static_cast(!broadcast1); + (void)static_cast(broadcast1.value()); // debug class. @@ -71,9 +71,9 @@ void test() socket_base::debug debug2; sock.get_option(debug2); debug1 = true; - static_cast(debug1); - static_cast(!debug1); - static_cast(debug1.value()); + (void)static_cast(debug1); + (void)static_cast(!debug1); + (void)static_cast(debug1.value()); // do_not_route class. @@ -82,9 +82,9 @@ void test() socket_base::do_not_route do_not_route2; sock.get_option(do_not_route2); do_not_route1 = true; - static_cast(do_not_route1); - static_cast(!do_not_route1); - static_cast(do_not_route1.value()); + (void)static_cast(do_not_route1); + (void)static_cast(!do_not_route1); + (void)static_cast(do_not_route1.value()); // keep_alive class. @@ -93,9 +93,9 @@ void test() socket_base::keep_alive keep_alive2; sock.get_option(keep_alive2); keep_alive1 = true; - static_cast(keep_alive1); - static_cast(!keep_alive1); - static_cast(keep_alive1.value()); + (void)static_cast(keep_alive1); + (void)static_cast(!keep_alive1); + (void)static_cast(keep_alive1.value()); // send_buffer_size class. @@ -104,7 +104,7 @@ void test() socket_base::send_buffer_size send_buffer_size2; sock.get_option(send_buffer_size2); send_buffer_size1 = 1; - static_cast(send_buffer_size1.value()); + (void)static_cast(send_buffer_size1.value()); // send_low_watermark class. @@ -113,7 +113,7 @@ void test() socket_base::send_low_watermark send_low_watermark2; sock.get_option(send_low_watermark2); send_low_watermark1 = 1; - static_cast(send_low_watermark1.value()); + (void)static_cast(send_low_watermark1.value()); // receive_buffer_size class. @@ -122,7 +122,7 @@ void test() socket_base::receive_buffer_size receive_buffer_size2; sock.get_option(receive_buffer_size2); receive_buffer_size1 = 1; - static_cast(receive_buffer_size1.value()); + (void)static_cast(receive_buffer_size1.value()); // receive_low_watermark class. @@ -131,7 +131,7 @@ void test() socket_base::receive_low_watermark receive_low_watermark2; sock.get_option(receive_low_watermark2); receive_low_watermark1 = 1; - static_cast(receive_low_watermark1.value()); + (void)static_cast(receive_low_watermark1.value()); // reuse_address class. @@ -140,9 +140,9 @@ void test() socket_base::reuse_address reuse_address2; sock.get_option(reuse_address2); reuse_address1 = true; - static_cast(reuse_address1); - static_cast(!reuse_address1); - static_cast(reuse_address1.value()); + (void)static_cast(reuse_address1); + (void)static_cast(!reuse_address1); + (void)static_cast(reuse_address1.value()); // linger class. @@ -151,9 +151,9 @@ void test() socket_base::linger linger2; sock.get_option(linger2); linger1.enabled(true); - static_cast(linger1.enabled()); + (void)static_cast(linger1.enabled()); linger1.timeout(1); - static_cast(linger1.timeout()); + (void)static_cast(linger1.timeout()); // enable_connection_aborted class. @@ -162,9 +162,9 @@ void test() socket_base::enable_connection_aborted enable_connection_aborted2; sock.get_option(enable_connection_aborted2); enable_connection_aborted1 = true; - static_cast(enable_connection_aborted1); - static_cast(!enable_connection_aborted1); - static_cast(enable_connection_aborted1.value()); + (void)static_cast(enable_connection_aborted1); + (void)static_cast(!enable_connection_aborted1); + (void)static_cast(enable_connection_aborted1.value()); // non_blocking_io class. diff --git a/test/write.cpp b/test/write.cpp index bdffbabc..f4be96e0 100644 --- a/test/write.cpp +++ b/test/write.cpp @@ -62,7 +62,7 @@ public: } template - bool check(const Const_Buffers& buffers, size_t length) + bool check_buffers(const Const_Buffers& buffers, size_t length) { if (length != position_) return false; @@ -148,19 +148,19 @@ void test_2_arg_const_buffers_1_write() s.reset(); size_t bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); } void test_2_arg_mutable_buffers_1_write() @@ -173,19 +173,19 @@ void test_2_arg_mutable_buffers_1_write() s.reset(); size_t bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); } void test_2_arg_multi_buffers_write() @@ -199,19 +199,19 @@ void test_2_arg_multi_buffers_write() s.reset(); size_t bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); } bool old_style_transfer_all(const boost::system::error_code& ec, @@ -237,115 +237,115 @@ void test_3_arg_const_buffers_1_write() size_t bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); } void test_3_arg_mutable_buffers_1_write() @@ -359,115 +359,115 @@ void test_3_arg_mutable_buffers_1_write() size_t bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); } void test_3_arg_multi_buffers_write() @@ -482,115 +482,115 @@ void test_3_arg_multi_buffers_write() size_t bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write(s, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); } void test_4_arg_const_buffers_1_write() @@ -605,7 +605,7 @@ void test_4_arg_const_buffers_1_write() size_t bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -614,7 +614,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -623,7 +623,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -631,7 +631,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -640,7 +640,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); BOOST_CHECK(!error); s.reset(); @@ -649,7 +649,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -657,7 +657,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -666,7 +666,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -675,7 +675,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -683,7 +683,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -692,7 +692,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); BOOST_CHECK(!error); s.reset(); @@ -701,14 +701,14 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -717,7 +717,7 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -726,13 +726,13 @@ void test_4_arg_const_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -740,7 +740,7 @@ void test_4_arg_const_buffers_1_write() error = boost::system::error_code(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -748,7 +748,7 @@ void test_4_arg_const_buffers_1_write() error = boost::system::error_code(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); } @@ -764,7 +764,7 @@ void test_4_arg_mutable_buffers_1_write() size_t bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -773,7 +773,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -782,7 +782,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -790,7 +790,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -799,7 +799,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); BOOST_CHECK(!error); s.reset(); @@ -808,7 +808,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -816,7 +816,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -825,7 +825,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -834,7 +834,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -842,7 +842,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -851,7 +851,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); BOOST_CHECK(!error); s.reset(); @@ -860,14 +860,14 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -876,7 +876,7 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -885,13 +885,13 @@ void test_4_arg_mutable_buffers_1_write() bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -899,7 +899,7 @@ void test_4_arg_mutable_buffers_1_write() error = boost::system::error_code(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); s.reset(); @@ -907,7 +907,7 @@ void test_4_arg_mutable_buffers_1_write() error = boost::system::error_code(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); BOOST_CHECK(!error); } @@ -924,7 +924,7 @@ void test_4_arg_multi_buffers_write() size_t bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -933,7 +933,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -942,7 +942,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -950,7 +950,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -959,7 +959,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); BOOST_CHECK(!error); s.reset(); @@ -968,7 +968,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -976,7 +976,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -985,7 +985,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -994,7 +994,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -1002,7 +1002,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -1011,7 +1011,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); BOOST_CHECK(!error); s.reset(); @@ -1020,14 +1020,14 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -1036,7 +1036,7 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -1045,13 +1045,13 @@ void test_4_arg_multi_buffers_write() bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -1059,7 +1059,7 @@ void test_4_arg_multi_buffers_write() error = boost::system::error_code(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -1067,7 +1067,7 @@ void test_4_arg_multi_buffers_write() error = boost::system::error_code(); bytes_transferred = boost::asio::write(s, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); BOOST_CHECK(!error); } @@ -1096,7 +1096,7 @@ void test_3_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1109,7 +1109,7 @@ void test_3_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1122,7 +1122,7 @@ void test_3_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); } void test_3_arg_mutable_buffers_1_async_write() @@ -1142,7 +1142,7 @@ void test_3_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); @@ -1155,7 +1155,7 @@ void test_3_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(10); @@ -1168,7 +1168,7 @@ void test_3_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); } void test_3_arg_multi_buffers_async_write() @@ -1189,7 +1189,7 @@ void test_3_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1202,7 +1202,7 @@ void test_3_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1215,7 +1215,7 @@ void test_3_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); } void test_4_arg_const_buffers_1_async_write() @@ -1235,7 +1235,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1248,7 +1248,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1261,7 +1261,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); called = false; @@ -1273,7 +1273,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1286,7 +1286,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(); s.next_write_length(10); @@ -1299,7 +1299,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); called = false; @@ -1311,7 +1311,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1324,7 +1324,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); s.next_write_length(10); @@ -1337,7 +1337,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); called = false; @@ -1349,7 +1349,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1362,7 +1362,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(); s.next_write_length(10); @@ -1375,7 +1375,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(); called = false; @@ -1387,7 +1387,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1400,7 +1400,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1413,7 +1413,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); called = false; @@ -1425,7 +1425,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1438,7 +1438,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1451,7 +1451,7 @@ void test_4_arg_const_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); } void test_4_arg_mutable_buffers_1_async_write() @@ -1471,7 +1471,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); @@ -1484,7 +1484,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(10); @@ -1497,7 +1497,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); called = false; @@ -1509,7 +1509,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); @@ -1522,7 +1522,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(); s.next_write_length(10); @@ -1535,7 +1535,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); called = false; @@ -1547,7 +1547,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); @@ -1560,7 +1560,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); s.next_write_length(10); @@ -1573,7 +1573,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); called = false; @@ -1585,7 +1585,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); @@ -1598,7 +1598,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(); s.next_write_length(10); @@ -1611,7 +1611,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(); called = false; @@ -1623,7 +1623,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); @@ -1636,7 +1636,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(10); @@ -1649,7 +1649,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); called = false; @@ -1661,7 +1661,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(1); @@ -1674,7 +1674,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); s.reset(); s.next_write_length(10); @@ -1687,7 +1687,7 @@ void test_4_arg_mutable_buffers_1_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(mutable_write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); } void test_4_arg_multi_buffers_async_write() @@ -1708,7 +1708,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1721,7 +1721,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1734,7 +1734,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); called = false; @@ -1746,7 +1746,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1759,7 +1759,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 1)); + BOOST_CHECK(s.check_buffers(buffers, 1)); s.reset(); s.next_write_length(10); @@ -1772,7 +1772,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); called = false; @@ -1784,7 +1784,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1797,7 +1797,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); s.next_write_length(10); @@ -1810,7 +1810,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 10)); + BOOST_CHECK(s.check_buffers(buffers, 10)); s.reset(); called = false; @@ -1822,7 +1822,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1835,7 +1835,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 42)); + BOOST_CHECK(s.check_buffers(buffers, 42)); s.reset(); s.next_write_length(10); @@ -1848,7 +1848,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, 50)); + BOOST_CHECK(s.check_buffers(buffers, 50)); s.reset(); called = false; @@ -1860,7 +1860,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1873,7 +1873,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1886,7 +1886,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); called = false; @@ -1898,7 +1898,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1911,7 +1911,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1924,7 +1924,7 @@ void test_4_arg_multi_buffers_async_write() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(buffers, sizeof(write_data))); } test_suite* init_unit_test_suite(int, char*[]) diff --git a/test/write_at.cpp b/test/write_at.cpp index c46e86d2..9334c2bf 100644 --- a/test/write_at.cpp +++ b/test/write_at.cpp @@ -16,6 +16,7 @@ // Test that header file is self-contained. #include +#include #include #include #include @@ -56,7 +57,7 @@ public: } template - bool check(boost::uint64_t offset, + bool check_buffers(boost::uint64_t offset, const Const_Buffers& buffers, size_t length) { if (offset + length > max_length) @@ -131,8 +132,10 @@ private: static const char write_data[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +static char mutable_write_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -void test_3_arg_write_at() +void test_3_arg_const_buffers_1_write_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -142,36 +145,121 @@ void test_3_arg_write_at() s.reset(); size_t bytes_transferred = boost::asio::write_at(s, 0, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 0, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 1234, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 0, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 1234, buffers); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); +} + +void test_3_arg_mutable_buffers_1_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::mutable_buffers_1 buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); +} + +void test_3_arg_multi_buffers_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::array buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); } bool old_style_transfer_all(const boost::system::error_code& ec, @@ -186,7 +274,7 @@ size_t short_transfer(const boost::system::error_code& ec, return !!ec ? 0 : 3; } -void test_4_arg_write_at() +void test_4_arg_const_buffers_1_write_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -197,238 +285,723 @@ void test_4_arg_write_at() size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_all()); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(0, buffers, 1)); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(1234, buffers, 1)); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(1)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(10)); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(0, buffers, 42)); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(1234, buffers, 42)); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(0, buffers, 50)); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(42)); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(1234, buffers, 50)); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); s.reset(); bytes_transferred = boost::asio::write_at(s, 0, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 0, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 1234, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 0, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 1234, buffers, old_style_transfer_all); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); } -void test_5_arg_write_at() +void test_4_arg_mutable_buffers_1_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::mutable_buffers_1 buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); +} + +void test_4_arg_multi_buffers_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::array buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); +} + +void test_5_arg_const_buffers_1_write_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -440,14 +1013,14 @@ void test_5_arg_write_at() size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -456,7 +1029,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -465,7 +1038,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -474,7 +1047,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -483,7 +1056,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_all(), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -491,7 +1064,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -499,7 +1072,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -508,7 +1081,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(0, buffers, 1)); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); BOOST_CHECK(!error); s.reset(); @@ -517,7 +1090,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 1); - BOOST_CHECK(s.check(1234, buffers, 1)); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); BOOST_CHECK(!error); s.reset(); @@ -526,7 +1099,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -535,7 +1108,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(1), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -543,7 +1116,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -551,7 +1124,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -560,7 +1133,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -569,7 +1142,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -578,7 +1151,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -587,7 +1160,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(10), error); BOOST_CHECK(bytes_transferred == 10); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); BOOST_CHECK(!error); s.reset(); @@ -595,7 +1168,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -603,7 +1176,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -612,7 +1185,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(0, buffers, 42)); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); BOOST_CHECK(!error); s.reset(); @@ -621,7 +1194,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 42); - BOOST_CHECK(s.check(1234, buffers, 42)); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); BOOST_CHECK(!error); s.reset(); @@ -630,7 +1203,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(0, buffers, 50)); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); BOOST_CHECK(!error); s.reset(); @@ -639,21 +1212,21 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, boost::asio::transfer_at_least(42), error); BOOST_CHECK(bytes_transferred == 50); - BOOST_CHECK(s.check(1234, buffers, 50)); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write_at(s, 0, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -662,7 +1235,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -671,7 +1244,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -680,7 +1253,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -689,21 +1262,21 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, old_style_transfer_all, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -712,7 +1285,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -721,7 +1294,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -730,7 +1303,7 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); BOOST_CHECK(!error); s.reset(); @@ -739,7 +1312,638 @@ void test_5_arg_write_at() bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer, error); BOOST_CHECK(bytes_transferred == sizeof(write_data)); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); +} + +void test_5_arg_mutable_buffers_1_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::mutable_buffers_1 buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_CHECK(!error); +} + +void test_5_arg_multi_buffers_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::array buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 1); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_CHECK(bytes_transferred == 10); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 42); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_CHECK(bytes_transferred == 50); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer, error); + BOOST_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); BOOST_CHECK(!error); } @@ -751,7 +1955,7 @@ void async_write_handler(const boost::system::error_code& e, BOOST_CHECK(bytes_transferred == expected_bytes_transferred); } -void test_4_arg_async_write_at() +void test_4_arg_const_buffers_1_async_write_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -768,7 +1972,7 @@ void test_4_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); called = false; @@ -780,7 +1984,7 @@ void test_4_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -793,7 +1997,7 @@ void test_4_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -806,7 +2010,7 @@ void test_4_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -819,7 +2023,7 @@ void test_4_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -832,7 +2036,7 @@ void test_4_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); called = false; @@ -844,10 +2048,203 @@ void test_4_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); } -void test_5_arg_async_write_at() +void test_4_arg_mutable_buffers_1_async_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::mutable_buffers_1 buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); +} + +void test_4_arg_multi_buffers_async_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::array buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); +} + +void test_5_arg_const_buffers_1_async_write_at() { boost::asio::io_service ios; test_random_access_device s(ios); @@ -865,7 +2262,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); called = false; @@ -878,7 +2275,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -892,7 +2289,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -906,7 +2303,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -920,7 +2317,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -934,7 +2331,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); called = false; @@ -947,7 +2344,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); called = false; @@ -960,7 +2357,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -974,7 +2371,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 1)); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); s.reset(); s.next_write_length(1); @@ -988,7 +2385,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 1)); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); s.reset(); s.next_write_length(10); @@ -1002,7 +2399,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(); s.next_write_length(10); @@ -1016,7 +2413,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(); called = false; @@ -1029,7 +2426,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); called = false; @@ -1042,7 +2439,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1056,7 +2453,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(); s.next_write_length(1); @@ -1070,7 +2467,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(); s.next_write_length(10); @@ -1084,7 +2481,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 10)); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); s.reset(); s.next_write_length(10); @@ -1098,7 +2495,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 10)); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); s.reset(); called = false; @@ -1111,7 +2508,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); called = false; @@ -1124,7 +2521,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1138,7 +2535,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 42)); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); s.reset(); s.next_write_length(1); @@ -1152,7 +2549,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 42)); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); s.reset(); s.next_write_length(10); @@ -1166,7 +2563,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, 50)); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); s.reset(); s.next_write_length(10); @@ -1180,7 +2577,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, 50)); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); s.reset(); called = false; @@ -1192,7 +2589,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); called = false; @@ -1204,7 +2601,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1217,7 +2614,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1230,7 +2627,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1243,7 +2640,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1256,7 +2653,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); called = false; @@ -1268,7 +2665,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); called = false; @@ -1280,7 +2677,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1293,7 +2690,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(1); @@ -1306,7 +2703,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1319,7 +2716,7 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(0, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); s.reset(); s.next_write_length(10); @@ -1332,16 +2729,1003 @@ void test_5_arg_async_write_at() ios.reset(); ios.run(); BOOST_CHECK(called); - BOOST_CHECK(s.check(1234, buffers, sizeof(write_data))); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); +} + +void test_5_arg_mutable_buffers_1_async_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::asio::mutable_buffers_1 buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(mutable_write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); +} + +void test_5_arg_multi_buffers_async_write_at() +{ + boost::asio::io_service ios; + test_random_access_device s(ios); + boost::array buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 1, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 10, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 42, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + 50, &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer, + boost::bind(async_write_handler, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, + sizeof(write_data), &called)); + ios.reset(); + ios.run(); + BOOST_CHECK(called); + BOOST_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); } test_suite* init_unit_test_suite(int, char*[]) { test_suite* test = BOOST_TEST_SUITE("write_at"); - test->add(BOOST_TEST_CASE(&test_3_arg_write_at)); - test->add(BOOST_TEST_CASE(&test_4_arg_write_at)); - test->add(BOOST_TEST_CASE(&test_5_arg_write_at)); - test->add(BOOST_TEST_CASE(&test_4_arg_async_write_at)); - test->add(BOOST_TEST_CASE(&test_5_arg_async_write_at)); + test->add(BOOST_TEST_CASE(&test_3_arg_const_buffers_1_write_at)); + test->add(BOOST_TEST_CASE(&test_3_arg_mutable_buffers_1_write_at)); + test->add(BOOST_TEST_CASE(&test_3_arg_multi_buffers_write_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_const_buffers_1_write_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_mutable_buffers_1_write_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_multi_buffers_write_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_const_buffers_1_write_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_mutable_buffers_1_write_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_multi_buffers_write_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_const_buffers_1_async_write_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_mutable_buffers_1_async_write_at)); + test->add(BOOST_TEST_CASE(&test_4_arg_multi_buffers_async_write_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_const_buffers_1_async_write_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_mutable_buffers_1_async_write_at)); + test->add(BOOST_TEST_CASE(&test_5_arg_multi_buffers_async_write_at)); return test; }