Update socket iostreams to adhere to the TS.
diff --git a/asio/include/asio/basic_socket_iostream.hpp b/asio/include/asio/basic_socket_iostream.hpp
index 1ada7ce..ad4759b 100644
--- a/asio/include/asio/basic_socket_iostream.hpp
+++ b/asio/include/asio/basic_socket_iostream.hpp
@@ -36,8 +36,8 @@
// explicit basic_socket_iostream(T1 x1, ..., Tn xn)
// : std::basic_iostream<char>(
// &this->detail::socket_iostream_base<
-// Protocol ASIO_SVC_TARG, Time,
-// TimeTraits ASIO_SVC_TARG1>::streambuf_)
+// Protocol ASIO_SVC_TARG, Clock,
+// WaitTraits ASIO_SVC_TARG1>::streambuf_)
// {
// if (rdbuf()->connect(x1, ..., xn) == 0)
// this->setstate(std::ios_base::failbit);
@@ -49,8 +49,8 @@
explicit basic_socket_iostream(ASIO_VARIADIC_BYVAL_PARAMS(n)) \
: std::basic_iostream<char>( \
&this->detail::socket_iostream_base< \
- Protocol ASIO_SVC_TARG, Time, \
- TimeTraits ASIO_SVC_TARG1>::streambuf_) \
+ Protocol ASIO_SVC_TARG, Clock, \
+ WaitTraits ASIO_SVC_TARG1>::streambuf_) \
{ \
this->setf(std::ios_base::unitbuf); \
if (rdbuf()->connect(ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \
@@ -86,12 +86,34 @@
// A separate base class is used to ensure that the streambuf is initialised
// prior to the basic_socket_iostream's basic_iostream base class.
template <typename Protocol ASIO_SVC_TPARAM,
- typename Time, typename TimeTraits ASIO_SVC_TPARAM1>
+ typename Clock, typename WaitTraits ASIO_SVC_TPARAM1>
class socket_iostream_base
{
protected:
+ socket_iostream_base()
+ {
+ }
+
+#if defined(ASIO_HAS_MOVE)
+ socket_iostream_base(socket_iostream_base&& other)
+ : streambuf_(std::move(other.streambuf_))
+ {
+ }
+
+ socket_iostream_base(basic_stream_socket<Protocol> s)
+ : streambuf_(std::move(s))
+ {
+ }
+
+ socket_iostream_base& operator=(socket_iostream_base&& other)
+ {
+ streambuf_ = std::move(other.streambuf_);
+ return *this;
+ }
+#endif // defined(ASIO_HAS_MOVE)
+
basic_socket_streambuf<Protocol ASIO_SVC_TARG,
- Time, TimeTraits ASIO_SVC_TARG1> streambuf_;
+ Clock, WaitTraits ASIO_SVC_TARG1> streambuf_;
};
} // namespace detail
@@ -103,12 +125,12 @@
template <typename Protocol
ASIO_SVC_TPARAM_DEF1(= stream_socket_service<Protocol>),
#if defined(ASIO_HAS_BOOST_DATE_TIME)
- typename Time = boost::posix_time::ptime,
- typename TimeTraits = time_traits<Time>
- ASIO_SVC_TPARAM1_DEF2(= deadline_timer_service<Time, TimeTraits>)>
+ typename Clock = boost::posix_time::ptime,
+ typename WaitTraits = time_traits<Clock>
+ ASIO_SVC_TPARAM1_DEF2(= deadline_timer_service<Clock, WaitTraits>)>
#else
- typename Time = chrono::steady_clock,
- typename TimeTraits = wait_traits<Time>
+ typename Clock = chrono::steady_clock,
+ typename WaitTraits = wait_traits<Clock>
ASIO_SVC_TPARAM1_DEF1(= steady_timer::service_type)>
#endif
class basic_socket_iostream;
@@ -118,42 +140,48 @@
/// Iostream interface for a socket.
#if defined(GENERATING_DOCUMENTATION)
template <typename Protocol,
- typename Time = chrono::steady_clock,
- typename TimeTraits = wait_traits<Time> >
+ typename Clock = chrono::steady_clock,
+ typename WaitTraits = wait_traits<Clock> >
#else // defined(GENERATING_DOCUMENTATION)
template <typename Protocol ASIO_SVC_TPARAM,
- typename Time, typename TimeTraits ASIO_SVC_TPARAM1>
+ typename Clock, typename WaitTraits ASIO_SVC_TPARAM1>
#endif // defined(GENERATING_DOCUMENTATION)
class basic_socket_iostream
: private detail::socket_iostream_base<Protocol
- ASIO_SVC_TARG, Time, TimeTraits ASIO_SVC_TARG1>,
+ ASIO_SVC_TARG, Clock, WaitTraits ASIO_SVC_TARG1>,
public std::basic_iostream<char>
{
private:
// These typedefs are intended keep this class's implementation independent
- // of whether it's using Boost.DateTime, Boost.Chrono or std::chrono.
+ // of whether it's using Boost.DateClock, Boost.Chrono or std::chrono.
#if defined(ASIO_HAS_BOOST_DATE_TIME)
- typedef TimeTraits traits_helper;
+ typedef WaitTraits traits_helper;
#else
- typedef detail::chrono_time_traits<Time, TimeTraits> traits_helper;
+ typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper;
#endif
public:
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
+ /// The clock type.
+ typedef Clock clock_type;
+
#if defined(GENERATING_DOCUMENTATION)
/// (Deprecated: Use time_point.) The time type.
- typedef typename TimeTraits::time_type time_type;
+ typedef typename WaitTraits::time_type time_type;
/// The time type.
- typedef typename TimeTraits::time_point time_point;
+ typedef typename WaitTraits::time_point time_point;
/// (Deprecated: Use duration.) The duration type.
- typedef typename TimeTraits::duration_type duration_type;
+ typedef typename WaitTraits::duration_type duration_type;
/// The duration type.
- typedef typename TimeTraits::duration duration;
+ typedef typename WaitTraits::duration duration;
#else
# if !defined(ASIO_NO_DEPRECATED)
typedef typename traits_helper::time_type time_type;
@@ -167,12 +195,49 @@
basic_socket_iostream()
: std::basic_iostream<char>(
&this->detail::socket_iostream_base<
- Protocol ASIO_SVC_TARG, Time,
- TimeTraits ASIO_SVC_TARG1>::streambuf_)
+ Protocol ASIO_SVC_TARG, Clock,
+ WaitTraits ASIO_SVC_TARG1>::streambuf_)
{
this->setf(std::ios_base::unitbuf);
}
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+ /// Construct a basic_socket_iostream from the supplied socket.
+ explicit basic_socket_iostream(basic_stream_socket<protocol_type> s)
+ : detail::socket_iostream_base<
+ Protocol ASIO_SVC_TARG, Clock,
+ WaitTraits ASIO_SVC_TARG1>(std::move(s)),
+ std::basic_iostream<char>(
+ &this->detail::socket_iostream_base<
+ Protocol ASIO_SVC_TARG, Clock,
+ WaitTraits ASIO_SVC_TARG1>::streambuf_)
+ {
+ this->setf(std::ios_base::unitbuf);
+ }
+
+ /// Move-construct a basic_socket_iostream from another.
+ basic_socket_iostream(basic_socket_iostream&& other)
+ : detail::socket_iostream_base<
+ Protocol ASIO_SVC_TARG, Clock,
+ WaitTraits ASIO_SVC_TARG1>(std::move(other)),
+ std::basic_iostream<char>(std::move(other))
+ {
+ this->set_rdbuf(&this->detail::socket_iostream_base<
+ Protocol ASIO_SVC_TARG, Clock,
+ WaitTraits ASIO_SVC_TARG1>::streambuf_);
+ }
+
+ /// Move-assign a basic_socket_iostream from another.
+ basic_socket_iostream& operator=(basic_socket_iostream&& other)
+ {
+ std::basic_iostream<char>::operator=(std::move(other));
+ detail::socket_iostream_base<
+ Protocol ASIO_SVC_TARG, Clock,
+ WaitTraits ASIO_SVC_TARG1>::operator=(std::move(other));
+ return *this;
+ }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
#if defined(GENERATING_DOCUMENTATION)
/// Establish a connection to an endpoint corresponding to a resolver query.
/**
@@ -187,8 +252,8 @@
explicit basic_socket_iostream(T... x)
: std::basic_iostream<char>(
&this->detail::socket_iostream_base<
- Protocol ASIO_SVC_TARG, Time,
- TimeTraits ASIO_SVC_TARG1>::streambuf_)
+ Protocol ASIO_SVC_TARG, Clock,
+ WaitTraits ASIO_SVC_TARG1>::streambuf_)
{
this->setf(std::ios_base::unitbuf);
if (rdbuf()->connect(x...) == 0)
@@ -227,13 +292,13 @@
/// Return a pointer to the underlying streambuf.
basic_socket_streambuf<Protocol ASIO_SVC_TARG,
- Time, TimeTraits ASIO_SVC_TARG1>* rdbuf() const
+ Clock, WaitTraits ASIO_SVC_TARG1>* rdbuf() const
{
return const_cast<basic_socket_streambuf<Protocol ASIO_SVC_TARG,
- Time, TimeTraits ASIO_SVC_TARG1>*>(
+ Clock, WaitTraits ASIO_SVC_TARG1>*>(
&this->detail::socket_iostream_base<
- Protocol ASIO_SVC_TARG, Time,
- TimeTraits ASIO_SVC_TARG1>::streambuf_);
+ Protocol ASIO_SVC_TARG, Clock,
+ WaitTraits ASIO_SVC_TARG1>::streambuf_);
}
/// Get a reference to the underlying socket.
@@ -333,6 +398,12 @@
rdbuf()->expires_from_now(expiry_time);
}
#endif // !defined(ASIO_NO_DEPRECATED)
+
+private:
+ // Disallow copying and assignment.
+ basic_socket_iostream(const basic_socket_iostream&) ASIO_DELETED;
+ basic_socket_iostream& operator=(
+ const basic_socket_iostream&) ASIO_DELETED;
};
} // namespace asio
diff --git a/asio/include/asio/basic_socket_streambuf.hpp b/asio/include/asio/basic_socket_streambuf.hpp
index 01821ec..42fb3ca 100644
--- a/asio/include/asio/basic_socket_streambuf.hpp
+++ b/asio/include/asio/basic_socket_streambuf.hpp
@@ -20,8 +20,11 @@
#if !defined(ASIO_NO_IOSTREAM)
#include <streambuf>
+#include <vector>
#include "asio/basic_socket.hpp"
-#include "asio/detail/array.hpp"
+#include "asio/basic_stream_socket.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/memory.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/io_context.hpp"
@@ -48,9 +51,8 @@
// basic_socket_streambuf* connect(T1 x1, ..., Tn xn)
// {
// init_buffers();
-// this->basic_socket<Protocol ASIO_SVC_TARG>::close(ec_);
// typedef typename Protocol::resolver resolver_type;
-// resolver_type resolver(detail::socket_streambuf_base::io_context_);
+// resolver_type resolver(socket().get_executor().context());
// connect_to_endpoints(
// resolver.resolve(x1, ..., xn, ec_));
// return !ec_ ? this : 0;
@@ -62,9 +64,8 @@
basic_socket_streambuf* connect(ASIO_VARIADIC_BYVAL_PARAMS(n)) \
{ \
init_buffers(); \
- this->basic_socket<Protocol ASIO_SVC_TARG>::close(ec_); \
typedef typename Protocol::resolver resolver_type; \
- resolver_type resolver(detail::socket_streambuf_base::io_context_); \
+ resolver_type resolver(socket().get_executor().context()); \
connect_to_endpoints( \
resolver.resolve(ASIO_VARIADIC_BYVAL_ARGS(n), ec_)); \
return !ec_ ? this : 0; \
@@ -82,12 +83,36 @@
namespace asio {
namespace detail {
-// A separate base class is used to ensure that the io_context is initialised
-// prior to the basic_socket_streambuf's basic_socket base class.
-class socket_streambuf_base
+// A separate base class is used to ensure that the io_context member is
+// initialised prior to the basic_socket_streambuf's basic_socket base class.
+class socket_streambuf_io_context
{
protected:
- io_context io_context_;
+ socket_streambuf_io_context(io_context* ctx)
+ : default_io_context_(ctx)
+ {
+ }
+
+ shared_ptr<io_context> default_io_context_;
+};
+
+// A separate base class is used to ensure that the dynamically allocated
+// buffers are constructed prior to the basic_socket_streambuf's basic_socket
+// base class. This makes moving the socket is the last potentially throwing
+// step in the streambuf's move constructor, giving the constructor a strong
+// exception safety guarantee.
+class socket_streambuf_buffers
+{
+protected:
+ socket_streambuf_buffers()
+ : get_buffer_(buffer_size),
+ put_buffer_(buffer_size)
+ {
+ }
+
+ enum { buffer_size = 512 };
+ std::vector<char> get_buffer_;
+ std::vector<char> put_buffer_;
};
} // namespace detail
@@ -99,12 +124,12 @@
template <typename Protocol
ASIO_SVC_TPARAM_DEF1(= stream_socket_service<Protocol>),
#if defined(ASIO_HAS_BOOST_DATE_TIME)
- typename Time = boost::posix_time::ptime,
- typename TimeTraits = time_traits<Time>
- ASIO_SVC_TPARAM1_DEF2(= deadline_timer_service<Time, TimeTraits>)>
+ typename Clock = boost::posix_time::ptime,
+ typename WaitTraits = time_traits<Clock>
+ ASIO_SVC_TPARAM1_DEF2(= deadline_timer_service<Clock, WaitTraits>)>
#else
- typename Time = chrono::steady_clock,
- typename TimeTraits = wait_traits<Time>
+ typename Clock = chrono::steady_clock,
+ typename WaitTraits = wait_traits<Clock>
ASIO_SVC_TPARAM1_DEF1(= steady_timer::service_type)>
#endif
class basic_socket_streambuf;
@@ -114,15 +139,16 @@
/// Iostream streambuf for a socket.
#if defined(GENERATING_DOCUMENTATION)
template <typename Protocol,
- typename Time = chrono::steady_clock,
- typename TimeTraits = wait_traits<Time> >
+ typename Clock = chrono::steady_clock,
+ typename WaitTraits = wait_traits<Clock> >
#else // defined(GENERATING_DOCUMENTATION)
template <typename Protocol ASIO_SVC_TPARAM,
- typename Time, typename TimeTraits ASIO_SVC_TPARAM1>
+ typename Clock, typename WaitTraits ASIO_SVC_TPARAM1>
#endif // defined(GENERATING_DOCUMENTATION)
class basic_socket_streambuf
: public std::streambuf,
- private detail::socket_streambuf_base,
+ private detail::socket_streambuf_io_context,
+ private detail::socket_streambuf_buffers,
#if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
private basic_socket<Protocol ASIO_SVC_TARG>
#else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
@@ -131,29 +157,35 @@
{
private:
// These typedefs are intended keep this class's implementation independent
- // of whether it's using Boost.DateTime, Boost.Chrono or std::chrono.
+ // of whether it's using Boost.DateClock, Boost.Chrono or std::chrono.
#if defined(ASIO_HAS_BOOST_DATE_TIME)
- typedef TimeTraits traits_helper;
+ typedef WaitTraits traits_helper;
#else
- typedef detail::chrono_time_traits<Time, TimeTraits> traits_helper;
+ typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper;
#endif
public:
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
+ /// The clock type.
+ typedef Clock clock_type;
+
#if defined(GENERATING_DOCUMENTATION)
/// (Deprecated: Use time_point.) The time type.
- typedef typename TimeTraits::time_type time_type;
+ typedef typename WaitTraits::time_type time_type;
/// The time type.
- typedef typename TimeTraits::time_point time_point;
+ typedef typename WaitTraits::time_point time_point;
/// (Deprecated: Use duration.) The duration type.
- typedef typename TimeTraits::duration_type duration_type;
+ typedef typename WaitTraits::duration_type duration_type;
/// The duration type.
- typedef typename TimeTraits::duration duration;
+ typedef typename WaitTraits::duration duration;
#else
# if !defined(ASIO_NO_DEPRECATED)
typedef typename traits_helper::time_type time_type;
@@ -165,22 +197,64 @@
/// Construct a basic_socket_streambuf without establishing a connection.
basic_socket_streambuf()
- : basic_socket<Protocol ASIO_SVC_TARG>(
- this->detail::socket_streambuf_base::io_context_),
- unbuffered_(false),
- timer_service_(0),
- timer_state_(no_timer)
+ : detail::socket_streambuf_io_context(new io_context),
+ basic_socket<Protocol ASIO_SVC_TARG>(*default_io_context_),
+ expiry_time_(max_expiry_time())
{
init_buffers();
}
+#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+ /// Construct a basic_socket_streambuf from the supplied socket.
+ explicit basic_socket_streambuf(basic_stream_socket<protocol_type> s)
+ : detail::socket_streambuf_io_context(0),
+ basic_socket<Protocol ASIO_SVC_TARG>(std::move(s)),
+ expiry_time_(max_expiry_time())
+ {
+ init_buffers();
+ }
+
+ /// Move-construct a basic_socket_streambuf from another.
+ basic_socket_streambuf(basic_socket_streambuf&& other)
+ : detail::socket_streambuf_io_context(other),
+ basic_socket<Protocol ASIO_SVC_TARG>(std::move(other.socket())),
+ ec_(other.ec_),
+ expiry_time_(other.expiry_time_)
+ {
+ get_buffer_.swap(other.get_buffer_);
+ put_buffer_.swap(other.put_buffer_);
+ setg(other.eback(), other.gptr(), other.egptr());
+ setp(other.pptr(), other.epptr());
+ other.ec_ = asio::error_code();
+ other.expiry_time_ = max_expiry_time();
+ other.init_buffers();
+ }
+
+ /// Move-assign a basic_socket_streambuf from another.
+ basic_socket_streambuf& operator=(basic_socket_streambuf&& other)
+ {
+ this->close();
+ socket() = std::move(other.socket());
+ detail::socket_streambuf_io_context::operator=(other);
+ ec_ = other.ec_;
+ expiry_time_ = other.expiry_time_;
+ get_buffer_.swap(other.get_buffer_);
+ put_buffer_.swap(other.put_buffer_);
+ setg(other.eback(), other.gptr(), other.egptr());
+ setp(other.pptr(), other.epptr());
+ other.ec_ = asio::error_code();
+ other.expiry_time_ = max_expiry_time();
+ other.put_buffer_.resize(buffer_size);
+ other.init_buffers();
+ return *this;
+ }
+#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
/// Destructor flushes buffered data.
virtual ~basic_socket_streambuf()
{
if (pptr() != pbase())
overflow(traits_type::eof());
-
- destroy_timer();
}
/// Establish a connection.
@@ -193,24 +267,8 @@
basic_socket_streambuf* connect(const endpoint_type& endpoint)
{
init_buffers();
-
- this->basic_socket<Protocol ASIO_SVC_TARG>::close(ec_);
-
- if (timer_state_ == timer_has_expired)
- {
- ec_ = asio::error::operation_aborted;
- return 0;
- }
-
- io_handler handler = { this };
- this->basic_socket<Protocol ASIO_SVC_TARG>::async_connect(
- endpoint, handler);
-
- ec_ = asio::error::would_block;
- this->get_service().get_io_context().restart();
- do this->get_service().get_io_context().run_one();
- while (ec_ == asio::error::would_block);
-
+ ec_ = asio::error_code();
+ this->connect_to_endpoints(&endpoint, &endpoint + 1);
return !ec_ ? this : 0;
}
@@ -231,9 +289,8 @@
basic_socket_streambuf* connect(T... x)
{
init_buffers();
- this->basic_socket<Protocol ASIO_SVC_TARG>::close(ec_);
typedef typename Protocol::resolver resolver_type;
- resolver_type resolver(detail::socket_streambuf_base::io_context_);
+ resolver_type resolver(socket().get_executor().context());
connect_to_endpoints(resolver.resolve(x..., ec_));
return !ec_ ? this : 0;
}
@@ -249,7 +306,7 @@
basic_socket_streambuf* close()
{
sync();
- this->basic_socket<Protocol ASIO_SVC_TARG>::close(ec_);
+ socket().close(ec_);
if (!ec_)
init_buffers();
return !ec_ ? this : 0;
@@ -291,9 +348,7 @@
*/
time_point expires_at() const
{
- return timer_service_
- ? timer_service_->expires_at(timer_implementation_)
- : time_point();
+ return expiry_time_;
}
#endif // !defined(ASIO_NO_DEPRECATED)
@@ -304,13 +359,7 @@
*/
time_point expiry() const
{
- return timer_service_
-#if defined(ASIO_HAS_BOOST_DATE_TIME)
- ? timer_service_->expires_at(timer_implementation_)
-#else // defined(ASIO_HAS_BOOST_DATE_TIME)
- ? timer_service_->expiry(timer_implementation_)
-#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
- : time_point();
+ return expiry_time_;
}
/// Set the stream buffer's expiry time as an absolute time.
@@ -324,13 +373,7 @@
*/
void expires_at(const time_point& expiry_time)
{
- construct_timer();
-
- asio::error_code ec;
- timer_service_->expires_at(timer_implementation_, expiry_time, ec);
- asio::detail::throw_error(ec, "expires_at");
-
- start_timer();
+ expiry_time_ = expiry_time;
}
/// Set the stream buffer's expiry time relative to now.
@@ -344,17 +387,7 @@
*/
void expires_after(const duration& expiry_time)
{
- construct_timer();
-
- asio::error_code ec;
-#if defined(ASIO_HAS_BOOST_DATE_TIME)
- timer_service_->expires_from_now(timer_implementation_, expiry_time, ec);
-#else // defined(ASIO_HAS_BOOST_DATE_TIME)
- timer_service_->expires_after(timer_implementation_, expiry_time, ec);
-#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
- asio::detail::throw_error(ec, "expires_after");
-
- start_timer();
+ expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time);
}
#if !defined(ASIO_NO_DEPRECATED)
@@ -380,108 +413,124 @@
*/
void expires_from_now(const duration& expiry_time)
{
- construct_timer();
-
- asio::error_code ec;
- timer_service_->expires_from_now(timer_implementation_, expiry_time, ec);
- asio::detail::throw_error(ec, "expires_from_now");
-
- start_timer();
+ expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time);
}
#endif // !defined(ASIO_NO_DEPRECATED)
protected:
int_type underflow()
{
- if (gptr() == egptr())
+#if defined(ASIO_WINDOWS_RUNTIME)
+ ec_ = asio::error::operation_not_supported;
+ return traits_type::eof();
+#else // defined(ASIO_WINDOWS_RUNTIME)
+ if (gptr() != egptr())
+ return traits_type::eof();
+
+ for (;;)
{
- if (timer_state_ == timer_has_expired)
+ // Check if we are past the expiry time.
+ if (traits_helper::less_than(expiry_time_, traits_helper::now()))
{
- ec_ = asio::error::operation_aborted;
+ ec_ = asio::error::timed_out;
return traits_type::eof();
}
- io_handler handler = { this };
- this->get_service().async_receive(this->get_implementation(),
- asio::buffer(asio::buffer(get_buffer_) + putback_max),
- 0, handler);
+ // Try to complete the operation without blocking.
+ if (!socket().native_non_blocking())
+ socket().native_non_blocking(true, ec_);
+ detail::buffer_sequence_adapter<mutable_buffer, mutable_buffer>
+ bufs(asio::buffer(get_buffer_) + putback_max);
+ detail::signed_size_type bytes = detail::socket_ops::recv(
+ socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_);
- ec_ = asio::error::would_block;
- this->get_service().get_io_context().restart();
- do this->get_service().get_io_context().run_one();
- while (ec_ == asio::error::would_block);
- if (ec_)
+ // Check if operation succeeded.
+ if (bytes > 0)
+ {
+ setg(&get_buffer_[0], &get_buffer_[0] + putback_max,
+ &get_buffer_[0] + putback_max + bytes);
+ return traits_type::to_int_type(*gptr());
+ }
+
+ // Check for EOF.
+ if (bytes == 0)
+ {
+ ec_ = asio::error::eof;
+ return traits_type::eof();
+ }
+
+ // Operation failed.
+ if (ec_ != asio::error::would_block
+ && ec_ != asio::error::try_again)
return traits_type::eof();
- setg(&get_buffer_[0], &get_buffer_[0] + putback_max,
- &get_buffer_[0] + putback_max + bytes_transferred_);
- return traits_type::to_int_type(*gptr());
+ // Wait for socket to become ready.
+ if (detail::socket_ops::poll_read(
+ socket().native_handle(), 0, timeout(), ec_) < 0)
+ return traits_type::eof();
}
- else
- {
- return traits_type::eof();
- }
+#endif // defined(ASIO_WINDOWS_RUNTIME)
}
int_type overflow(int_type c)
{
- if (unbuffered_)
+#if defined(ASIO_WINDOWS_RUNTIME)
+ ec_ = asio::error::operation_not_supported;
+ return traits_type::eof();
+#else // defined(ASIO_WINDOWS_RUNTIME)
+ char_type ch = traits_type::to_char_type(c);
+
+ // Determine what needs to be sent.
+ const_buffer output_buffer;
+ if (put_buffer_.empty())
{
if (traits_type::eq_int_type(c, traits_type::eof()))
- {
- // Nothing to do.
- return traits_type::not_eof(c);
- }
- else
- {
- if (timer_state_ == timer_has_expired)
- {
- ec_ = asio::error::operation_aborted;
- return traits_type::eof();
- }
-
- // Send the single character immediately.
- char_type ch = traits_type::to_char_type(c);
- io_handler handler = { this };
- this->get_service().async_send(this->get_implementation(),
- asio::buffer(&ch, sizeof(char_type)), 0, handler);
-
- ec_ = asio::error::would_block;
- this->get_service().get_io_context().restart();
- do this->get_service().get_io_context().run_one();
- while (ec_ == asio::error::would_block);
- if (ec_)
- return traits_type::eof();
-
- return c;
- }
+ return traits_type::not_eof(c); // Nothing to do.
+ output_buffer = asio::buffer(&ch, sizeof(char_type));
}
else
{
- // Send all data in the output buffer.
- asio::const_buffer buffer =
- asio::buffer(pbase(), pptr() - pbase());
- while (buffer.size() > 0)
+ output_buffer = asio::buffer(pbase(),
+ (pptr() - pbase()) * sizeof(char_type));
+ }
+
+ while (output_buffer.size() > 0)
+ {
+ // Check if we are past the expiry time.
+ if (traits_helper::less_than(expiry_time_, traits_helper::now()))
{
- if (timer_state_ == timer_has_expired)
- {
- ec_ = asio::error::operation_aborted;
- return traits_type::eof();
- }
-
- io_handler handler = { this };
- this->get_service().async_send(this->get_implementation(),
- asio::buffer(buffer), 0, handler);
-
- ec_ = asio::error::would_block;
- this->get_service().get_io_context().restart();
- do this->get_service().get_io_context().run_one();
- while (ec_ == asio::error::would_block);
- if (ec_)
- return traits_type::eof();
-
- buffer = buffer + bytes_transferred_;
+ ec_ = asio::error::timed_out;
+ return traits_type::eof();
}
+
+ // Try to complete the operation without blocking.
+ if (!socket().native_non_blocking())
+ socket().native_non_blocking(true, ec_);
+ detail::buffer_sequence_adapter<
+ const_buffer, const_buffer> bufs(output_buffer);
+ detail::signed_size_type bytes = detail::socket_ops::send(
+ socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_);
+
+ // Check if operation succeeded.
+ if (bytes > 0)
+ {
+ output_buffer += static_cast<std::size_t>(bytes);
+ continue;
+ }
+
+ // Operation failed.
+ if (ec_ != asio::error::would_block
+ && ec_ != asio::error::try_again)
+ return traits_type::eof();
+
+ // Wait for socket to become ready.
+ if (detail::socket_ops::poll_write(
+ socket().native_handle(), 0, timeout(), ec_) < 0)
+ return traits_type::eof();
+ }
+
+ if (!put_buffer_.empty())
+ {
setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
// If the new character is eof then our work here is done.
@@ -489,10 +538,12 @@
return traits_type::not_eof(c);
// Add the new character to the output buffer.
- *pptr() = traits_type::to_char_type(c);
+ *pptr() = ch;
pbump(1);
- return c;
}
+
+ return c;
+#endif // defined(ASIO_WINDOWS_RUNTIME)
}
int sync()
@@ -504,8 +555,9 @@
{
if (pptr() == pbase() && s == 0 && n == 0)
{
- unbuffered_ = true;
+ put_buffer_.clear();
setp(0, 0);
+ sync();
return this;
}
@@ -513,131 +565,117 @@
}
private:
+ // Disallow copying and assignment.
+ basic_socket_streambuf(const basic_socket_streambuf&) ASIO_DELETED;
+ basic_socket_streambuf& operator=(
+ const basic_socket_streambuf&) ASIO_DELETED;
+
void init_buffers()
{
setg(&get_buffer_[0],
&get_buffer_[0] + putback_max,
&get_buffer_[0] + putback_max);
- if (unbuffered_)
+
+ if (put_buffer_.empty())
setp(0, 0);
else
setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
}
+ int timeout() const
+ {
+ int64_t msec = traits_helper::to_posix_duration(
+ traits_helper::subtract(expiry_time_,
+ traits_helper::now())).total_milliseconds();
+ if (msec > (std::numeric_limits<int>::max)())
+ msec = (std::numeric_limits<int>::max)();
+ else if (msec < 0)
+ msec = 0;
+ return static_cast<int>(msec);
+ }
+
template <typename EndpointSequence>
void connect_to_endpoints(const EndpointSequence& endpoints)
{
- if (!ec_)
- {
- typename EndpointSequence::iterator i = endpoints.begin();
- typename EndpointSequence::iterator end = endpoints.end();
- ec_ = asio::error::host_not_found;
- while (ec_ && i != end)
- {
- this->basic_socket<Protocol ASIO_SVC_TARG>::close(ec_);
-
- if (timer_state_ == timer_has_expired)
- {
- ec_ = asio::error::operation_aborted;
- return;
- }
-
- io_handler handler = { this };
- this->basic_socket<Protocol ASIO_SVC_TARG>::async_connect(
- *i, handler);
-
- ec_ = asio::error::would_block;
- this->get_service().get_io_context().restart();
- do this->get_service().get_io_context().run_one();
- while (ec_ == asio::error::would_block);
-
- ++i;
- }
- }
+ this->connect_to_endpoints(endpoints.begin(), endpoints.end());
}
- struct io_handler;
- friend struct io_handler;
- struct io_handler
+ template <typename EndpointIterator>
+ void connect_to_endpoints(EndpointIterator begin, EndpointIterator end)
{
- basic_socket_streambuf* this_;
+#if defined(ASIO_WINDOWS_RUNTIME)
+ ec_ = asio::error::operation_not_supported;
+#else // defined(ASIO_WINDOWS_RUNTIME)
+ if (ec_)
+ return;
- void operator()(const asio::error_code& ec,
- std::size_t bytes_transferred = 0)
+ ec_ = asio::error::not_found;
+ for (EndpointIterator i = begin; i != end; ++i)
{
- this_->ec_ = ec;
- this_->bytes_transferred_ = bytes_transferred;
+ // Check if we are past the expiry time.
+ if (traits_helper::less_than(expiry_time_, traits_helper::now()))
+ {
+ ec_ = asio::error::timed_out;
+ return;
+ }
+
+ // Close and reopen the socket.
+ typename Protocol::endpoint ep(*i);
+ socket().close(ec_);
+ socket().open(ep.protocol(), ec_);
+ if (ec_)
+ continue;
+
+ // Try to complete the operation without blocking.
+ if (!socket().native_non_blocking())
+ socket().native_non_blocking(true, ec_);
+ detail::socket_ops::connect(socket().native_handle(),
+ ep.data(), ep.size(), ec_);
+
+ // Check if operation succeeded.
+ if (!ec_)
+ return;
+
+ // Operation failed.
+ if (ec_ != asio::error::in_progress
+ && ec_ != asio::error::would_block)
+ continue;
+
+ // Wait for socket to become ready.
+ if (detail::socket_ops::poll_connect(
+ socket().native_handle(), timeout(), ec_) < 0)
+ continue;
+
+ // Get the error code from the connect operation.
+ int connect_error = 0;
+ size_t connect_error_len = sizeof(connect_error);
+ if (detail::socket_ops::getsockopt(socket().native_handle(), 0,
+ SOL_SOCKET, SO_ERROR, &connect_error, &connect_error_len, ec_)
+ == detail::socket_error_retval)
+ return;
+
+ // Check the result of the connect operation.
+ ec_ = asio::error_code(connect_error,
+ asio::error::get_system_category());
+ if (!ec_)
+ return;
}
- };
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+ }
- struct timer_handler;
- friend struct timer_handler;
- struct timer_handler
+ // Helper function to get the maximum expiry time.
+ static time_point max_expiry_time()
{
- basic_socket_streambuf* this_;
-
- void operator()(const asio::error_code&)
- {
- time_point now = traits_helper::now();
-
#if defined(ASIO_HAS_BOOST_DATE_TIME)
- time_point expiry_time = this_->timer_service_->expires_at(
- this_->timer_implementation_);
+ return boost::posix_time::pos_infin;
#else // defined(ASIO_HAS_BOOST_DATE_TIME)
- time_point expiry_time = this_->timer_service_->expiry(
- this_->timer_implementation_);
+ return (time_point::max)();
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
-
- if (traits_helper::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;
- asio::error_code ec;
- this_->basic_socket<Protocol ASIO_SVC_TARG>::close(ec);
- }
- }
- };
-
- void construct_timer()
- {
- if (timer_service_ == 0)
- {
- ASIO_SVC_T1& timer_service = use_service<ASIO_SVC_T1>(
- detail::socket_streambuf_base::io_context_);
- 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(asio::error_code());
- }
}
enum { putback_max = 8 };
- enum { buffer_size = 512 };
- asio::detail::array<char, buffer_size> get_buffer_;
- asio::detail::array<char, buffer_size> put_buffer_;
- bool unbuffered_;
asio::error_code ec_;
- std::size_t bytes_transferred_;
- ASIO_SVC_T1* timer_service_;
- typename ASIO_SVC_T1::implementation_type timer_implementation_;
- enum state { no_timer, timer_is_pending, timer_has_expired } timer_state_;
+ time_point expiry_time_;
};
} // namespace asio
diff --git a/asio/include/asio/detail/impl/socket_ops.ipp b/asio/include/asio/detail/impl/socket_ops.ipp
index b643c8b..d9cc1c9 100644
--- a/asio/include/asio/detail/impl/socket_ops.ipp
+++ b/asio/include/asio/detail/impl/socket_ops.ipp
@@ -168,7 +168,7 @@
return invalid_socket;
// Wait for socket to become ready.
- if (socket_ops::poll_read(s, 0, ec) < 0)
+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)
return invalid_socket;
}
}
@@ -505,7 +505,7 @@
}
// Wait for socket to become ready.
- if (socket_ops::poll_connect(s, ec) < 0)
+ if (socket_ops::poll_connect(s, -1, ec) < 0)
return;
// Get the error code from the connect operation.
@@ -827,7 +827,7 @@
return 0;
// Wait for socket to become ready.
- if (socket_ops::poll_read(s, 0, ec) < 0)
+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)
return 0;
}
}
@@ -966,7 +966,7 @@
return 0;
// Wait for socket to become ready.
- if (socket_ops::poll_read(s, 0, ec) < 0)
+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)
return 0;
}
}
@@ -1079,7 +1079,7 @@
return 0;
// Wait for socket to become ready.
- if (socket_ops::poll_read(s, 0, ec) < 0)
+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)
return 0;
}
}
@@ -1206,7 +1206,7 @@
return 0;
// Wait for socket to become ready.
- if (socket_ops::poll_write(s, 0, ec) < 0)
+ if (socket_ops::poll_write(s, 0, -1, ec) < 0)
return 0;
}
}
@@ -1330,7 +1330,7 @@
return 0;
// Wait for socket to become ready.
- if (socket_ops::poll_write(s, 0, ec) < 0)
+ if (socket_ops::poll_write(s, 0, -1, ec) < 0)
return 0;
}
}
@@ -1784,7 +1784,8 @@
#endif
}
-int poll_read(socket_type s, state_type state, asio::error_code& ec)
+int poll_read(socket_type s, state_type state,
+ int msec, asio::error_code& ec)
{
if (s == invalid_socket)
{
@@ -1798,10 +1799,22 @@
fd_set fds;
FD_ZERO(&fds);
FD_SET(s, &fds);
- timeval zero_timeout;
- zero_timeout.tv_sec = 0;
- zero_timeout.tv_usec = 0;
- timeval* timeout = (state & user_set_non_blocking) ? &zero_timeout : 0;
+ timeval timeout_obj;
+ timeval* timeout;
+ if (state & user_set_non_blocking)
+ {
+ timeout_obj.tv_sec = 0;
+ timeout_obj.tv_usec = 0;
+ timeout = &timeout_obj;
+ }
+ else if (msec >= 0)
+ {
+ timeout_obj.tv_sec = msec / 1000;
+ timeout_obj.tv_usec = (msec % 1000) * 1000;
+ timeout = &timeout_obj;
+ }
+ else
+ timeout = 0;
clear_last_error();
int result = error_wrapper(::select(s + 1, &fds, 0, 0, timeout), ec);
#else // defined(ASIO_WINDOWS)
@@ -1811,7 +1824,7 @@
fds.fd = s;
fds.events = POLLIN;
fds.revents = 0;
- int timeout = (state & user_set_non_blocking) ? 0 : -1;
+ int timeout = (state & user_set_non_blocking) ? 0 : msec;
clear_last_error();
int result = error_wrapper(::poll(&fds, 1, timeout), ec);
#endif // defined(ASIO_WINDOWS)
@@ -1825,7 +1838,8 @@
return result;
}
-int poll_write(socket_type s, state_type state, asio::error_code& ec)
+int poll_write(socket_type s, state_type state,
+ int msec, asio::error_code& ec)
{
if (s == invalid_socket)
{
@@ -1839,10 +1853,22 @@
fd_set fds;
FD_ZERO(&fds);
FD_SET(s, &fds);
- timeval zero_timeout;
- zero_timeout.tv_sec = 0;
- zero_timeout.tv_usec = 0;
- timeval* timeout = (state & user_set_non_blocking) ? &zero_timeout : 0;
+ timeval timeout_obj;
+ timeval* timeout;
+ if (state & user_set_non_blocking)
+ {
+ timeout_obj.tv_sec = 0;
+ timeout_obj.tv_usec = 0;
+ timeout = &timeout_obj;
+ }
+ else if (msec >= 0)
+ {
+ timeout_obj.tv_sec = msec / 1000;
+ timeout_obj.tv_usec = (msec % 1000) * 1000;
+ timeout = &timeout_obj;
+ }
+ else
+ timeout = 0;
clear_last_error();
int result = error_wrapper(::select(s + 1, 0, &fds, 0, timeout), ec);
#else // defined(ASIO_WINDOWS)
@@ -1852,7 +1878,7 @@
fds.fd = s;
fds.events = POLLOUT;
fds.revents = 0;
- int timeout = (state & user_set_non_blocking) ? 0 : -1;
+ int timeout = (state & user_set_non_blocking) ? 0 : msec;
clear_last_error();
int result = error_wrapper(::poll(&fds, 1, timeout), ec);
#endif // defined(ASIO_WINDOWS)
@@ -1866,7 +1892,8 @@
return result;
}
-int poll_error(socket_type s, state_type state, asio::error_code& ec)
+int poll_error(socket_type s, state_type state,
+ int msec, asio::error_code& ec)
{
if (s == invalid_socket)
{
@@ -1880,10 +1907,22 @@
fd_set fds;
FD_ZERO(&fds);
FD_SET(s, &fds);
- timeval zero_timeout;
- zero_timeout.tv_sec = 0;
- zero_timeout.tv_usec = 0;
- timeval* timeout = (state & user_set_non_blocking) ? &zero_timeout : 0;
+ timeval timeout_obj;
+ timeval* timeout;
+ if (state & user_set_non_blocking)
+ {
+ timeout_obj.tv_sec = 0;
+ timeout_obj.tv_usec = 0;
+ timeout = &timeout_obj;
+ }
+ else if (msec >= 0)
+ {
+ timeout_obj.tv_sec = msec / 1000;
+ timeout_obj.tv_usec = (msec % 1000) * 1000;
+ timeout = &timeout_obj;
+ }
+ else
+ timeout = 0;
clear_last_error();
int result = error_wrapper(::select(s + 1, 0, 0, &fds, timeout), ec);
#else // defined(ASIO_WINDOWS)
@@ -1893,7 +1932,7 @@
fds.fd = s;
fds.events = POLLPRI | POLLERR | POLLHUP;
fds.revents = 0;
- int timeout = (state & user_set_non_blocking) ? 0 : -1;
+ int timeout = (state & user_set_non_blocking) ? 0 : msec;
clear_last_error();
int result = error_wrapper(::poll(&fds, 1, timeout), ec);
#endif // defined(ASIO_WINDOWS)
@@ -1907,7 +1946,7 @@
return result;
}
-int poll_connect(socket_type s, asio::error_code& ec)
+int poll_connect(socket_type s, int msec, asio::error_code& ec)
{
if (s == invalid_socket)
{
@@ -1924,9 +1963,19 @@
fd_set except_fds;
FD_ZERO(&except_fds);
FD_SET(s, &except_fds);
+ timeval timeout_obj;
+ timeval* timeout;
+ if (msec >= 0)
+ {
+ timeout_obj.tv_sec = msec / 1000;
+ timeout_obj.tv_usec = (msec % 1000) * 1000;
+ timeout = &timeout_obj;
+ }
+ else
+ timeout = 0;
clear_last_error();
int result = error_wrapper(::select(
- s + 1, 0, &write_fds, &except_fds, 0), ec);
+ s + 1, 0, &write_fds, &except_fds, timeout), ec);
if (result >= 0)
ec = asio::error_code();
return result;
@@ -1938,7 +1987,7 @@
fds.events = POLLOUT;
fds.revents = 0;
clear_last_error();
- int result = error_wrapper(::poll(&fds, 1, -1), ec);
+ int result = error_wrapper(::poll(&fds, 1, msec), ec);
if (result >= 0)
ec = asio::error_code();
return result;
diff --git a/asio/include/asio/detail/reactive_socket_service.hpp b/asio/include/asio/detail/reactive_socket_service.hpp
index e12e835..4ba2556 100644
--- a/asio/include/asio/detail/reactive_socket_service.hpp
+++ b/asio/include/asio/detail/reactive_socket_service.hpp
@@ -231,7 +231,7 @@
asio::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_write(impl.socket_, impl.state_, ec);
+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
return 0;
}
@@ -310,7 +310,7 @@
asio::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_read(impl.socket_, impl.state_, ec);
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
// Reset endpoint since it can be given no sensible value at this time.
sender_endpoint = endpoint_type();
diff --git a/asio/include/asio/detail/reactive_socket_service_base.hpp b/asio/include/asio/detail/reactive_socket_service_base.hpp
index 0d9a767..3b5b014 100644
--- a/asio/include/asio/detail/reactive_socket_service_base.hpp
+++ b/asio/include/asio/detail/reactive_socket_service_base.hpp
@@ -171,13 +171,13 @@
switch (w)
{
case socket_base::wait_read:
- socket_ops::poll_read(impl.socket_, impl.state_, ec);
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
break;
case socket_base::wait_write:
- socket_ops::poll_write(impl.socket_, impl.state_, ec);
+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
break;
case socket_base::wait_error:
- socket_ops::poll_error(impl.socket_, impl.state_, ec);
+ socket_ops::poll_error(impl.socket_, impl.state_, -1, ec);
break;
default:
ec = asio::error::invalid_argument;
@@ -246,7 +246,7 @@
socket_base::message_flags, asio::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_write(impl.socket_, impl.state_, ec);
+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
return 0;
}
@@ -316,7 +316,7 @@
socket_base::message_flags, asio::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_read(impl.socket_, impl.state_, ec);
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
return 0;
}
@@ -396,7 +396,7 @@
socket_base::message_flags& out_flags, asio::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_read(impl.socket_, impl.state_, ec);
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
// Clear out_flags, since we cannot give it any other sensible value when
// performing a null_buffers operation.
diff --git a/asio/include/asio/detail/socket_ops.hpp b/asio/include/asio/detail/socket_ops.hpp
index 880c8e6..5529a27 100644
--- a/asio/include/asio/detail/socket_ops.hpp
+++ b/asio/include/asio/detail/socket_ops.hpp
@@ -263,15 +263,16 @@
fd_set* exceptfds, timeval* timeout, asio::error_code& ec);
ASIO_DECL int poll_read(socket_type s,
- state_type state, asio::error_code& ec);
+ state_type state, int msec, asio::error_code& ec);
ASIO_DECL int poll_write(socket_type s,
- state_type state, asio::error_code& ec);
+ state_type state, int msec, asio::error_code& ec);
ASIO_DECL int poll_error(socket_type s,
- state_type state, asio::error_code& ec);
+ state_type state, int msec, asio::error_code& ec);
-ASIO_DECL int poll_connect(socket_type s, asio::error_code& ec);
+ASIO_DECL int poll_connect(socket_type s,
+ int msec, asio::error_code& ec);
#endif // !defined(ASIO_WINDOWS_RUNTIME)
diff --git a/asio/include/asio/detail/win_iocp_socket_service.hpp b/asio/include/asio/detail/win_iocp_socket_service.hpp
index 787267d..9040f7c 100644
--- a/asio/include/asio/detail/win_iocp_socket_service.hpp
+++ b/asio/include/asio/detail/win_iocp_socket_service.hpp
@@ -315,7 +315,7 @@
asio::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_write(impl.socket_, impl.state_, ec);
+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
return 0;
}
@@ -391,7 +391,7 @@
socket_base::message_flags, asio::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_read(impl.socket_, impl.state_, ec);
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
// Reset endpoint since it can be given no sensible value at this time.
sender_endpoint = endpoint_type();
diff --git a/asio/include/asio/detail/win_iocp_socket_service_base.hpp b/asio/include/asio/detail/win_iocp_socket_service_base.hpp
index c671835..9f22adc 100644
--- a/asio/include/asio/detail/win_iocp_socket_service_base.hpp
+++ b/asio/include/asio/detail/win_iocp_socket_service_base.hpp
@@ -188,13 +188,13 @@
switch (w)
{
case socket_base::wait_read:
- socket_ops::poll_read(impl.socket_, impl.state_, ec);
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
break;
case socket_base::wait_write:
- socket_ops::poll_write(impl.socket_, impl.state_, ec);
+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
break;
case socket_base::wait_error:
- socket_ops::poll_error(impl.socket_, impl.state_, ec);
+ socket_ops::poll_error(impl.socket_, impl.state_, -1, ec);
break;
default:
ec = asio::error::invalid_argument;
@@ -260,7 +260,7 @@
socket_base::message_flags, asio::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_write(impl.socket_, impl.state_, ec);
+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
return 0;
}
@@ -326,7 +326,7 @@
socket_base::message_flags, asio::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_read(impl.socket_, impl.state_, ec);
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
return 0;
}
@@ -395,7 +395,7 @@
socket_base::message_flags& out_flags, asio::error_code& ec)
{
// Wait for socket to become ready.
- socket_ops::poll_read(impl.socket_, impl.state_, ec);
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
// Clear out_flags, since we cannot give it any other sensible value when
// performing a null_buffers operation.
diff --git a/asio/src/tests/unit/ip/tcp.cpp b/asio/src/tests/unit/ip/tcp.cpp
index 28e9a1f..8217d05 100644
--- a/asio/src/tests/unit/ip/tcp.cpp
+++ b/asio/src/tests/unit/ip/tcp.cpp
@@ -1269,7 +1269,90 @@
}
}
-} // namespace ip_tcp_resolver_compile
+} // namespace ip_tcp_resolver_entry_compile
+
+//------------------------------------------------------------------------------
+
+// ip_tcp_iostream_compile test
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The following test checks that all public types and member functions on the
+// class ip::tcp::iostream compile and link correctly. Runtime failures are
+// ignored.
+
+namespace ip_tcp_iostream_compile {
+
+void test()
+{
+#if !defined(ASIO_NO_IOSTREAM)
+ using namespace asio;
+ namespace ip = asio::ip;
+
+ asio::io_context ioc;
+ asio::ip::tcp::socket sock(ioc);
+
+ // basic_socket_iostream typedefs.
+
+ (void)static_cast<ip::tcp::iostream::protocol_type*>(0);
+ (void)static_cast<ip::tcp::iostream::endpoint_type*>(0);
+ (void)static_cast<ip::tcp::iostream::clock_type*>(0);
+ (void)static_cast<ip::tcp::iostream::time_point*>(0);
+ (void)static_cast<ip::tcp::iostream::duration*>(0);
+ (void)static_cast<ip::tcp::iostream::traits_type*>(0);
+
+ // basic_socket_iostream constructors.
+
+ ip::tcp::iostream ios1;
+
+#if defined(ASIO_HAS_MOVE)
+ ip::tcp::iostream ios2(std::move(sock));
+#endif // defined(ASIO_HAS_MOVE)
+
+ ip::tcp::iostream ios3("hostname", "service");
+
+ // basic_socket_iostream operators.
+
+#if defined(ASIO_HAS_MOVE)
+ ios1 = ip::tcp::iostream();
+
+ ios2 = std::move(ios1);
+#endif // defined(ASIO_HAS_MOVE)
+
+ // basic_socket_iostream members.
+
+ ios1.connect("hostname", "service");
+
+ ios1.close();
+
+ (void)static_cast<std::streambuf*>(ios1.rdbuf());
+
+#if defined(ASIO_ENABLE_OLD_SERVICES)
+ basic_socket<ip::tcp, stream_socket_service<ip::tcp> >& sref = ios1.socket();
+#else // defined(ASIO_ENABLE_OLD_SERVICES)
+ basic_socket<ip::tcp>& sref = ios1.socket();
+#endif // defined(ASIO_ENABLE_OLD_SERVICES)
+ (void)sref;
+
+ error_code ec = ios1.error();
+ (void)ec;
+
+ ip::tcp::iostream::time_point tp = ios1.expiry();
+ (void)tp;
+
+ ios1.expires_at(tp);
+
+ ip::tcp::iostream::duration d;
+ ios1.expires_after(d);
+
+ // iostream operators.
+
+ int i = 0;
+ ios1 >> i;
+ ios1 << i;
+#endif // !defined(ASIO_NO_IOSTREAM)
+}
+
+} // namespace ip_tcp_iostream_compile
+
//------------------------------------------------------------------------------
ASIO_TEST_SUITE
@@ -1283,4 +1366,6 @@
ASIO_TEST_CASE(ip_tcp_acceptor_runtime::test)
ASIO_TEST_CASE(ip_tcp_resolver_compile::test)
ASIO_TEST_CASE(ip_tcp_resolver_entry_compile::test)
+ ASIO_TEST_CASE(ip_tcp_resolver_entry_compile::test)
+ ASIO_COMPILE_TEST_CASE(ip_tcp_iostream_compile::test)
)