diff options
author | Remko Tronçon <git@el-tramo.be> | 2012-12-23 13:16:26 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2012-12-23 14:43:26 (GMT) |
commit | 491ddd570a752cf9bda85933bed0c6942e39b1f9 (patch) | |
tree | 10c25c1be8cc08d0497df1dccd56a10fbb30beee /3rdParty/Boost/src/boost/asio/basic_socket_streambuf.hpp | |
parent | da7d7a0ca71b80281aa9ff2526290b61ccb0cc60 (diff) | |
download | swift-491ddd570a752cf9bda85933bed0c6942e39b1f9.zip swift-491ddd570a752cf9bda85933bed0c6942e39b1f9.tar.bz2 |
Update Boost to 1.52.0.
Change-Id: I1e56bea2600bf2ed9c5b3aba8c4f9d2a0f350e77
Diffstat (limited to '3rdParty/Boost/src/boost/asio/basic_socket_streambuf.hpp')
-rw-r--r-- | 3rdParty/Boost/src/boost/asio/basic_socket_streambuf.hpp | 386 |
1 files changed, 321 insertions, 65 deletions
diff --git a/3rdParty/Boost/src/boost/asio/basic_socket_streambuf.hpp b/3rdParty/Boost/src/boost/asio/basic_socket_streambuf.hpp index c2a9a99..fb047c6 100644 --- a/3rdParty/Boost/src/boost/asio/basic_socket_streambuf.hpp +++ b/3rdParty/Boost/src/boost/asio/basic_socket_streambuf.hpp @@ -2,7 +2,7 @@ // basic_socket_streambuf.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2012 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) @@ -20,53 +20,64 @@ #if !defined(BOOST_NO_IOSTREAM) #include <streambuf> -#include <boost/array.hpp> -#include <boost/preprocessor/arithmetic/inc.hpp> -#include <boost/preprocessor/repetition/enum_binary_params.hpp> -#include <boost/preprocessor/repetition/enum_params.hpp> -#include <boost/preprocessor/repetition/repeat_from_to.hpp> #include <boost/utility/base_from_member.hpp> #include <boost/asio/basic_socket.hpp> +#include <boost/asio/deadline_timer_service.hpp> +#include <boost/asio/detail/array.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/io_service.hpp> #include <boost/asio/stream_socket_service.hpp> +#include <boost/asio/time_traits.hpp> -#if !defined(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY) -#define BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY 5 -#endif // !defined(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY) +#include <boost/asio/detail/push_options.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include <boost/asio/detail/pop_options.hpp> + +#if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +# include <boost/preprocessor/arithmetic/inc.hpp> +# include <boost/preprocessor/repetition/enum_binary_params.hpp> +# include <boost/preprocessor/repetition/enum_params.hpp> +# include <boost/preprocessor/repetition/repeat_from_to.hpp> + +# if !defined(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY) +# define BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY 5 +# endif // !defined(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY) // A macro that should expand to: // template <typename T1, ..., typename Tn> -// basic_socket_streambuf<Protocol, StreamSocketService>* connect( +// basic_socket_streambuf<Protocol, StreamSocketService, +// Time, TimeTraits, TimerService>* connect( // T1 x1, ..., Tn xn) // { // init_buffers(); -// boost::system::error_code ec; -// this->basic_socket<Protocol, StreamSocketService>::close(ec); +// this->basic_socket<Protocol, StreamSocketService>::close(ec_); // typedef typename Protocol::resolver resolver_type; // typedef typename resolver_type::query resolver_query; // resolver_query query(x1, ..., xn); -// resolve_and_connect(query, ec); -// return !ec ? this : 0; +// resolve_and_connect(query); +// return !ec_ ? this : 0; // } // This macro should only persist within this file. -#define BOOST_ASIO_PRIVATE_CONNECT_DEF( z, n, data ) \ +# define BOOST_ASIO_PRIVATE_CONNECT_DEF( z, n, data ) \ template <BOOST_PP_ENUM_PARAMS(n, typename T)> \ - basic_socket_streambuf<Protocol, StreamSocketService>* connect( \ + basic_socket_streambuf<Protocol, StreamSocketService, \ + Time, TimeTraits, TimerService>* connect( \ BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \ { \ init_buffers(); \ - boost::system::error_code ec; \ - this->basic_socket<Protocol, StreamSocketService>::close(ec); \ + this->basic_socket<Protocol, StreamSocketService>::close(ec_); \ 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; \ + resolve_and_connect(query); \ + return !ec_ ? this : 0; \ } \ /**/ +#endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + #include <boost/asio/detail/push_options.hpp> namespace boost { @@ -74,7 +85,10 @@ namespace asio { /// Iostream streambuf for a socket. template <typename Protocol, - typename StreamSocketService = stream_socket_service<Protocol> > + typename StreamSocketService = stream_socket_service<Protocol>, + typename Time = boost::posix_time::ptime, + typename TimeTraits = boost::asio::time_traits<Time>, + typename TimerService = deadline_timer_service<Time, TimeTraits> > class basic_socket_streambuf : public std::streambuf, private boost::base_from_member<io_service>, @@ -84,11 +98,19 @@ public: /// The endpoint type. typedef typename Protocol::endpoint endpoint_type; + /// The time type. + typedef typename TimeTraits::time_type time_type; + + /// The duration type. + typedef typename TimeTraits::duration_type duration_type; + /// Construct a basic_socket_streambuf without establishing a connection. basic_socket_streambuf() : basic_socket<Protocol, StreamSocketService>( boost::base_from_member<boost::asio::io_service>::member), - unbuffered_(false) + unbuffered_(false), + timer_service_(0), + timer_state_(no_timer) { init_buffers(); } @@ -98,6 +120,8 @@ public: { if (pptr() != pbase()) overflow(traits_type::eof()); + + destroy_timer(); } /// Establish a connection. @@ -107,14 +131,30 @@ public: * @return \c this if a connection was successfully established, a null * pointer otherwise. */ - basic_socket_streambuf<Protocol, StreamSocketService>* connect( + basic_socket_streambuf<Protocol, StreamSocketService, + Time, TimeTraits, TimerService>* connect( const endpoint_type& endpoint) { init_buffers(); - boost::system::error_code ec; - this->basic_socket<Protocol, StreamSocketService>::close(ec); - this->basic_socket<Protocol, StreamSocketService>::connect(endpoint, ec); - return !ec ? this : 0; + + this->basic_socket<Protocol, StreamSocketService>::close(ec_); + + if (timer_state_ == timer_has_expired) + { + ec_ = boost::asio::error::operation_aborted; + return 0; + } + + io_handler handler = { this }; + this->basic_socket<Protocol, StreamSocketService>::async_connect( + endpoint, handler); + + ec_ = boost::asio::error::would_block; + this->get_service().get_io_service().reset(); + do this->get_service().get_io_service().run_one(); + while (ec_ == boost::asio::error::would_block); + + return !ec_ ? this : 0; } #if defined(GENERATING_DOCUMENTATION) @@ -130,6 +170,19 @@ public: template <typename T1, ..., typename TN> basic_socket_streambuf<Protocol, StreamSocketService>* connect( T1 t1, ..., TN tn); +#elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + template <typename... T> + basic_socket_streambuf<Protocol, StreamSocketService, + Time, TimeTraits, TimerService>* connect(T... x) + { + init_buffers(); + this->basic_socket<Protocol, StreamSocketService>::close(ec_); + typedef typename Protocol::resolver resolver_type; + typedef typename resolver_type::query resolver_query; + resolver_query query(x...); + resolve_and_connect(query); + return !ec_ ? this : 0; + } #else BOOST_PP_REPEAT_FROM_TO( 1, BOOST_PP_INC(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY), @@ -141,14 +194,85 @@ public: * @return \c this if a connection was successfully established, a null * pointer otherwise. */ - basic_socket_streambuf<Protocol, StreamSocketService>* close() + basic_socket_streambuf<Protocol, StreamSocketService, + Time, TimeTraits, TimerService>* close() { - boost::system::error_code ec; sync(); - this->basic_socket<Protocol, StreamSocketService>::close(ec); - if (!ec) + this->basic_socket<Protocol, StreamSocketService>::close(ec_); + if (!ec_) init_buffers(); - return !ec ? this : 0; + return !ec_ ? this : 0; + } + + /// Get the last error associated with the stream buffer. + /** + * @return An \c error_code corresponding to the last error from the stream + * buffer. + */ + const boost::system::error_code& puberror() const + { + return error(); + } + + /// Get the stream buffer's expiry time as an absolute time. + /** + * @return An absolute time value representing the stream buffer's expiry + * time. + */ + time_type expires_at() const + { + return timer_service_ + ? timer_service_->expires_at(timer_implementation_) + : time_type(); + } + + /// Set the stream buffer's expiry time as an absolute time. + /** + * This function sets the expiry time associated with the stream. Stream + * operations performed after this time (where the operations cannot be + * completed using the internal buffers) will fail with the error + * boost::asio::error::operation_aborted. + * + * @param expiry_time The expiry time to be used for the stream. + */ + void expires_at(const time_type& expiry_time) + { + construct_timer(); + + boost::system::error_code ec; + timer_service_->expires_at(timer_implementation_, expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_at"); + + start_timer(); + } + + /// Get the stream buffer's expiry time relative to now. + /** + * @return A relative time value representing the stream buffer's expiry time. + */ + duration_type expires_from_now() const + { + return TimeTraits::subtract(expires_at(), TimeTraits::now()); + } + + /// Set the stream buffer's expiry time relative to now. + /** + * This function sets the expiry time associated with the stream. Stream + * operations performed after this time (where the operations cannot be + * completed using the internal buffers) will fail with the error + * boost::asio::error::operation_aborted. + * + * @param expiry_time The expiry time to be used for the timer. + */ + void expires_from_now(const duration_type& expiry_time) + { + construct_timer(); + + boost::system::error_code ec; + timer_service_->expires_from_now(timer_implementation_, expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_from_now"); + + start_timer(); } protected: @@ -156,15 +280,26 @@ protected: { if (gptr() == egptr()) { - boost::system::error_code ec; - std::size_t bytes_transferred = this->service.receive( - this->implementation, + if (timer_state_ == timer_has_expired) + { + ec_ = boost::asio::error::operation_aborted; + return traits_type::eof(); + } + + io_handler handler = { this }; + this->get_service().async_receive(this->get_implementation(), boost::asio::buffer(boost::asio::buffer(get_buffer_) + putback_max), - 0, ec); - if (ec) + 0, handler); + + ec_ = boost::asio::error::would_block; + this->get_service().get_io_service().reset(); + do this->get_service().get_io_service().run_one(); + while (ec_ == boost::asio::error::would_block); + if (ec_) return traits_type::eof(); - setg(get_buffer_.begin(), get_buffer_.begin() + putback_max, - get_buffer_.begin() + putback_max + bytes_transferred); + + setg(&get_buffer_[0], &get_buffer_[0] + putback_max, + &get_buffer_[0] + putback_max + bytes_transferred_); return traits_type::to_int_type(*gptr()); } else @@ -184,13 +319,25 @@ protected: } else { + if (timer_state_ == timer_has_expired) + { + ec_ = boost::asio::error::operation_aborted; + return traits_type::eof(); + } + // Send the single character immediately. - boost::system::error_code ec; char_type ch = traits_type::to_char_type(c); - this->service.send(this->implementation, - boost::asio::buffer(&ch, sizeof(char_type)), 0, ec); - if (ec) + io_handler handler = { this }; + this->get_service().async_send(this->get_implementation(), + boost::asio::buffer(&ch, sizeof(char_type)), 0, handler); + + ec_ = boost::asio::error::would_block; + this->get_service().get_io_service().reset(); + do this->get_service().get_io_service().run_one(); + while (ec_ == boost::asio::error::would_block); + if (ec_) return traits_type::eof(); + return c; } } @@ -201,15 +348,26 @@ protected: boost::asio::buffer(pbase(), pptr() - pbase()); while (boost::asio::buffer_size(buffer) > 0) { - boost::system::error_code ec; - std::size_t bytes_transferred = this->service.send( - this->implementation, boost::asio::buffer(buffer), - 0, ec); - if (ec) + if (timer_state_ == timer_has_expired) + { + ec_ = boost::asio::error::operation_aborted; + return traits_type::eof(); + } + + io_handler handler = { this }; + this->get_service().async_send(this->get_implementation(), + boost::asio::buffer(buffer), 0, handler); + + ec_ = boost::asio::error::would_block; + this->get_service().get_io_service().reset(); + do this->get_service().get_io_service().run_one(); + while (ec_ == boost::asio::error::would_block); + if (ec_) return traits_type::eof(); - buffer = buffer + bytes_transferred; + + buffer = buffer + bytes_transferred_; } - setp(put_buffer_.begin(), put_buffer_.end()); + setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size()); // If the new character is eof then our work here is done. if (traits_type::eq_int_type(c, traits_type::eof())) @@ -239,45 +397,141 @@ protected: return 0; } + /// Get the last error associated with the stream buffer. + /** + * @return An \c error_code corresponding to the last error from the stream + * buffer. + */ + virtual const boost::system::error_code& error() const + { + return ec_; + } + private: void init_buffers() { - setg(get_buffer_.begin(), - get_buffer_.begin() + putback_max, - get_buffer_.begin() + putback_max); + setg(&get_buffer_[0], + &get_buffer_[0] + putback_max, + &get_buffer_[0] + putback_max); if (unbuffered_) setp(0, 0); else - setp(put_buffer_.begin(), put_buffer_.end()); + setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size()); } template <typename ResolverQuery> - void resolve_and_connect(const ResolverQuery& query, - boost::system::error_code& ec) + void resolve_and_connect(const ResolverQuery& query) { typedef typename Protocol::resolver resolver_type; typedef typename resolver_type::iterator iterator_type; resolver_type resolver( boost::base_from_member<boost::asio::io_service>::member); - iterator_type i = resolver.resolve(query, ec); - if (!ec) + iterator_type i = resolver.resolve(query, ec_); + if (!ec_) { iterator_type end; - ec = boost::asio::error::host_not_found; - while (ec && i != end) + ec_ = boost::asio::error::host_not_found; + while (ec_ && i != end) { - this->basic_socket<Protocol, StreamSocketService>::close(); - this->basic_socket<Protocol, StreamSocketService>::connect(*i, ec); + this->basic_socket<Protocol, StreamSocketService>::close(ec_); + + if (timer_state_ == timer_has_expired) + { + ec_ = boost::asio::error::operation_aborted; + return; + } + + io_handler handler = { this }; + this->basic_socket<Protocol, StreamSocketService>::async_connect( + *i, handler); + + ec_ = boost::asio::error::would_block; + this->get_service().get_io_service().reset(); + do this->get_service().get_io_service().run_one(); + while (ec_ == boost::asio::error::would_block); + ++i; } } } + struct io_handler; + friend struct io_handler; + struct io_handler + { + basic_socket_streambuf* this_; + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred = 0) + { + this_->ec_ = ec; + this_->bytes_transferred_ = bytes_transferred; + } + }; + + struct timer_handler; + friend struct timer_handler; + struct timer_handler + { + basic_socket_streambuf* this_; + + void operator()(const boost::system::error_code&) + { + time_type now = TimeTraits::now(); + + time_type expiry_time = this_->timer_service_->expires_at( + this_->timer_implementation_); + + if (TimeTraits::less_than(now, expiry_time)) + { + this_->timer_state_ = timer_is_pending; + this_->timer_service_->async_wait(this_->timer_implementation_, *this); + } + else + { + this_->timer_state_ = timer_has_expired; + boost::system::error_code ec; + this_->basic_socket<Protocol, StreamSocketService>::close(ec); + } + } + }; + + void construct_timer() + { + if (timer_service_ == 0) + { + TimerService& timer_service = use_service<TimerService>( + boost::base_from_member<boost::asio::io_service>::member); + timer_service.construct(timer_implementation_); + timer_service_ = &timer_service; + } + } + + void destroy_timer() + { + if (timer_service_) + timer_service_->destroy(timer_implementation_); + } + + void start_timer() + { + if (timer_state_ != timer_is_pending) + { + timer_handler handler = { this }; + handler(boost::system::error_code()); + } + } + enum { putback_max = 8 }; enum { buffer_size = 512 }; - boost::array<char, buffer_size> get_buffer_; - boost::array<char, buffer_size> put_buffer_; + boost::asio::detail::array<char, buffer_size> get_buffer_; + boost::asio::detail::array<char, buffer_size> put_buffer_; bool unbuffered_; + boost::system::error_code ec_; + std::size_t bytes_transferred_; + TimerService* timer_service_; + typename TimerService::implementation_type timer_implementation_; + enum state { no_timer, timer_is_pending, timer_has_expired } timer_state_; }; } // namespace asio @@ -285,7 +539,9 @@ private: #include <boost/asio/detail/pop_options.hpp> -#undef BOOST_ASIO_PRIVATE_CONNECT_DEF +#if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +# undef BOOST_ASIO_PRIVATE_CONNECT_DEF +#endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #endif // !defined(BOOST_NO_IOSTREAM) |