Update to asio 1.4.1

This commit is contained in:
Andrew Resch 2009-04-19 21:40:09 +00:00
parent 73e58c20c8
commit e08c51e10c
61 changed files with 1141 additions and 554 deletions

View File

@ -142,6 +142,20 @@ public:
return *this; return *this;
} }
/// Get a const reference to the lowest layer.
/**
* This function returns a const reference to the lowest layer in a stack of
* layers. Since a basic_serial_port cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A const reference to the lowest layer in the stack of layers.
* Ownership is not transferred to the caller.
*/
const lowest_layer_type& lowest_layer() const
{
return *this;
}
/// Open the serial port using the specified device name. /// Open the serial port using the specified device name.
/** /**
* This function opens the serial port for the specified device name. * This function opens the serial port for the specified device name.

View File

@ -149,6 +149,20 @@ public:
return *this; return *this;
} }
/// Get a const reference to the lowest layer.
/**
* This function returns a const reference to the lowest layer in a stack of
* layers. Since a basic_socket cannot contain any further layers, it simply
* returns a reference to itself.
*
* @return A const reference to the lowest layer in the stack of layers.
* Ownership is not transferred to the caller.
*/
const lowest_layer_type& lowest_layer() const
{
return *this;
}
/// Open the socket using the specified protocol. /// Open the socket using the specified protocol.
/** /**
* This function opens the socket so that it will use the specified protocol. * This function opens the socket so that it will use the specified protocol.

View File

@ -247,7 +247,8 @@ private:
setp(put_buffer_.begin(), put_buffer_.end()); setp(put_buffer_.begin(), put_buffer_.end());
} }
void resolve_and_connect(const typename Protocol::resolver_query& query, template <typename ResolverQuery>
void resolve_and_connect(const ResolverQuery& query,
asio::error_code& ec) asio::error_code& ec)
{ {
typedef typename Protocol::resolver resolver_type; typedef typename Protocol::resolver resolver_type;

View File

@ -19,6 +19,7 @@
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
#include <algorithm> #include <algorithm>
#include <cstring>
#include <limits> #include <limits>
#include <memory> #include <memory>
#include <stdexcept> #include <stdexcept>
@ -32,6 +33,73 @@
namespace asio { namespace asio {
/// Automatically resizable buffer class based on std::streambuf. /// Automatically resizable buffer class based on std::streambuf.
/**
* The @c basic_streambuf class is derived from @c std::streambuf to associate
* the streambuf's input and output sequences with one or more character
* arrays. These character arrays are internal to the @c basic_streambuf
* object, but direct access to the array elements is provided to permit them
* to be used efficiently with I/O operations. Characters written to the output
* sequence of a @c basic_streambuf object are appended to the input sequence
* of the same object.
*
* The @c basic_streambuf class's public interface is intended to permit the
* following implementation strategies:
*
* @li A single contiguous character array, which is reallocated as necessary
* to accommodate changes in the size of the character sequence. This is the
* implementation approach currently used in Asio.
*
* @li A sequence of one or more character arrays, where each array is of the
* same size. Additional character array objects are appended to the sequence
* to accommodate changes in the size of the character sequence.
*
* @li A sequence of one or more character arrays of varying sizes. Additional
* character array objects are appended to the sequence to accommodate changes
* in the size of the character sequence.
*
* The constructor for basic_streambuf accepts a @c size_t argument specifying
* the maximum of the sum of the sizes of the input sequence and output
* sequence. During the lifetime of the @c basic_streambuf object, the following
* invariant holds:
* @code size() <= max_size()@endcode
* Any member function that would, if successful, cause the invariant to be
* violated shall throw an exception of class @c std::length_error.
*
* The constructor for @c basic_streambuf takes an Allocator argument. A copy
* of this argument is used for any memory allocation performed, by the
* constructor and by all member functions, during the lifetime of each @c
* basic_streambuf object.
*
* @par Examples
* Writing directly from an streambuf to a socket:
* @code
* asio::streambuf b;
* std::ostream os(&b);
* os << "Hello, World!\n";
*
* // try sending some data in input sequence
* size_t n = sock.send(b.data());
*
* b.consume(n); // sent data is removed from input sequence
* @endcode
*
* Reading from a socket directly into a streambuf:
* @code
* asio::streambuf b;
*
* // reserve 512 bytes in output sequence
* asio::streambuf::const_buffers_type bufs = b.prepare(512);
*
* size_t n = sock.receive(bufs);
*
* // received data is "committed" from output sequence to input sequence
* b.commit(n);
*
* std::istream is(&b);
* std::string s;
* is >> s;
* @endcode
*/
template <typename Allocator = std::allocator<char> > template <typename Allocator = std::allocator<char> >
class basic_streambuf class basic_streambuf
: public std::streambuf, : public std::streambuf,
@ -39,17 +107,21 @@ class basic_streambuf
{ {
public: public:
#if defined(GENERATING_DOCUMENTATION) #if defined(GENERATING_DOCUMENTATION)
/// The type used to represent the get area as a list of buffers. /// The type used to represent the input sequence as a list of buffers.
typedef implementation_defined const_buffers_type; typedef implementation_defined const_buffers_type;
/// The type used to represent the put area as a list of buffers. /// The type used to represent the output sequence as a list of buffers.
typedef implementation_defined mutable_buffers_type; typedef implementation_defined mutable_buffers_type;
#else #else
typedef asio::const_buffers_1 const_buffers_type; typedef asio::const_buffers_1 const_buffers_type;
typedef asio::mutable_buffers_1 mutable_buffers_type; typedef asio::mutable_buffers_1 mutable_buffers_type;
#endif #endif
/// Construct a buffer with a specified maximum size. /// Construct a basic_streambuf object.
/**
* Constructs a streambuf with the specified maximum size. The initial size
* of the streambuf's input sequence is 0.
*/
explicit basic_streambuf( explicit basic_streambuf(
std::size_t max_size = (std::numeric_limits<std::size_t>::max)(), std::size_t max_size = (std::numeric_limits<std::size_t>::max)(),
const Allocator& allocator = Allocator()) const Allocator& allocator = Allocator())
@ -62,42 +134,100 @@ public:
setp(&buffer_[0], &buffer_[0] + pend); setp(&buffer_[0], &buffer_[0] + pend);
} }
/// Return the size of the get area in characters. /// Get the size of the input sequence.
/**
* @returns The size of the input sequence. The value is equal to that
* calculated for @c s in the following code:
* @code
* size_t s = 0;
* const_buffers_type bufs = data();
* const_buffers_type::const_iterator i = bufs.begin();
* while (i != bufs.end())
* {
* const_buffer buf(*i++);
* s += buffer_size(buf);
* }
* @endcode
*/
std::size_t size() const std::size_t size() const
{ {
return pptr() - gptr(); return pptr() - gptr();
} }
/// Return the maximum size of the buffer. /// Get the maximum size of the basic_streambuf.
/**
* @returns The allowed maximum of the sum of the sizes of the input sequence
* and output sequence.
*/
std::size_t max_size() const std::size_t max_size() const
{ {
return max_size_; return max_size_;
} }
/// Get a list of buffers that represents the get area. /// Get a list of buffers that represents the input sequence.
/**
* @returns An object of type @c const_buffers_type that satisfies
* ConstBufferSequence requirements, representing all character arrays in the
* input sequence.
*
* @note The returned object is invalidated by any @c basic_streambuf member
* function that modifies the input sequence or output sequence.
*/
const_buffers_type data() const const_buffers_type data() const
{ {
return asio::buffer(asio::const_buffer(gptr(), return asio::buffer(asio::const_buffer(gptr(),
(pptr() - gptr()) * sizeof(char_type))); (pptr() - gptr()) * sizeof(char_type)));
} }
/// Get a list of buffers that represents the put area, with the given size. /// Get a list of buffers that represents the output sequence, with the given
mutable_buffers_type prepare(std::size_t size) /// size.
/**
* Ensures that the output sequence can accommodate @c n characters,
* reallocating character array objects as necessary.
*
* @returns An object of type @c mutable_buffers_type that satisfies
* MutableBufferSequence requirements, representing character array objects
* at the start of the output sequence such that the sum of the buffer sizes
* is @c n.
*
* @throws std::length_error If <tt>size() + n > max_size()</tt>.
*
* @note The returned object is invalidated by any @c basic_streambuf member
* function that modifies the input sequence or output sequence.
*/
mutable_buffers_type prepare(std::size_t n)
{ {
reserve(size); reserve(n);
return asio::buffer(asio::mutable_buffer( return asio::buffer(asio::mutable_buffer(
pptr(), size * sizeof(char_type))); pptr(), n * sizeof(char_type)));
} }
/// Move the start of the put area by the specified number of characters. /// Move characters from the output sequence to the input sequence.
/**
* Appends @c n characters from the start of the output sequence to the input
* sequence. The beginning of the output sequence is advanced by @c n
* characters.
*
* Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and
* no intervening operations that modify the input or output sequence.
*
* @throws std::length_error If @c n is greater than the size of the output
* sequence.
*/
void commit(std::size_t n) void commit(std::size_t n)
{ {
if (pptr() + n > epptr()) if (pptr() + n > epptr())
n = epptr() - pptr(); n = epptr() - pptr();
pbump(static_cast<int>(n)); pbump(static_cast<int>(n));
setg(eback(), gptr(), pptr());
} }
/// Move the start of the get area by the specified number of characters. /// Remove characters from the input sequence.
/**
* Removes @c n characters from the beginning of the input sequence.
*
* @throws std::length_error If <tt>n > size()</tt>.
*/
void consume(std::size_t n) void consume(std::size_t n)
{ {
if (gptr() + n > pptr()) if (gptr() + n > pptr())
@ -108,6 +238,10 @@ public:
protected: protected:
enum { buffer_delta = 128 }; enum { buffer_delta = 128 };
/// Override std::streambuf behaviour.
/**
* Behaves according to the specification of @c std::streambuf::underflow().
*/
int_type underflow() int_type underflow()
{ {
if (gptr() < pptr()) if (gptr() < pptr())
@ -121,6 +255,13 @@ protected:
} }
} }
/// Override std::streambuf behaviour.
/**
* Behaves according to the specification of @c std::streambuf::overflow(),
* with the specialisation that @c std::length_error is thrown if appending
* the character to the input sequence would require the condition
* <tt>size() > max_size()</tt> to be true.
*/
int_type overflow(int_type c) int_type overflow(int_type c)
{ {
if (!traits_type::eq_int_type(c, traits_type::eof())) if (!traits_type::eq_int_type(c, traits_type::eof()))
@ -150,7 +291,6 @@ protected:
{ {
// Get current stream positions as offsets. // Get current stream positions as offsets.
std::size_t gnext = gptr() - &buffer_[0]; std::size_t gnext = gptr() - &buffer_[0];
std::size_t gend = egptr() - &buffer_[0];
std::size_t pnext = pptr() - &buffer_[0]; std::size_t pnext = pptr() - &buffer_[0];
std::size_t pend = epptr() - &buffer_[0]; std::size_t pend = epptr() - &buffer_[0];
@ -163,9 +303,8 @@ protected:
// Shift existing contents of get area to start of buffer. // Shift existing contents of get area to start of buffer.
if (gnext > 0) if (gnext > 0)
{ {
std::rotate(&buffer_[0], &buffer_[0] + gnext, &buffer_[0] + pend);
gend -= gnext;
pnext -= gnext; pnext -= gnext;
std::memmove(&buffer_[0], &buffer_[0] + gnext, pnext);
} }
// Ensure buffer is large enough to hold at least the specified size. // Ensure buffer is large enough to hold at least the specified size.
@ -173,7 +312,8 @@ protected:
{ {
if (n <= max_size_ && pnext <= max_size_ - n) if (n <= max_size_ && pnext <= max_size_ - n)
{ {
buffer_.resize((std::max<std::size_t>)(pnext + n, 1)); pend = pnext + n;
buffer_.resize((std::max<std::size_t>)(pend, 1));
} }
else else
{ {
@ -182,8 +322,8 @@ protected:
} }
// Update stream positions. // Update stream positions.
setg(&buffer_[0], &buffer_[0], &buffer_[0] + gend); setg(&buffer_[0], &buffer_[0], &buffer_[0] + pnext);
setp(&buffer_[0] + pnext, &buffer_[0] + pnext + n); setp(&buffer_[0] + pnext, &buffer_[0] + pend);
} }
private: private:

View File

@ -93,6 +93,12 @@ public:
return next_layer_.lowest_layer(); return next_layer_.lowest_layer();
} }
/// Get a const reference to the lowest layer.
const lowest_layer_type& lowest_layer() const
{
return next_layer_.lowest_layer();
}
/// (Deprecated: use get_io_service().) Get the io_service associated with /// (Deprecated: use get_io_service().) Get the io_service associated with
/// the object. /// the object.
asio::io_service& io_service() asio::io_service& io_service()

View File

@ -83,6 +83,12 @@ public:
return stream_impl_.lowest_layer(); return stream_impl_.lowest_layer();
} }
/// Get a const reference to the lowest layer.
const lowest_layer_type& lowest_layer() const
{
return stream_impl_.lowest_layer();
}
/// (Deprecated: use get_io_service().) Get the io_service associated with /// (Deprecated: use get_io_service().) Get the io_service associated with
/// the object. /// the object.
asio::io_service& io_service() asio::io_service& io_service()

View File

@ -94,6 +94,12 @@ public:
return next_layer_.lowest_layer(); return next_layer_.lowest_layer();
} }
/// Get a const reference to the lowest layer.
const lowest_layer_type& lowest_layer() const
{
return next_layer_.lowest_layer();
}
/// (Deprecated: use get_io_service().) Get the io_service associated with /// (Deprecated: use get_io_service().) Get the io_service associated with
/// the object. /// the object.
asio::io_service& io_service() asio::io_service& io_service()

View File

@ -21,6 +21,7 @@
#include <cstddef> #include <cstddef>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/iterator/iterator_facade.hpp> #include <boost/iterator/iterator_facade.hpp>
#include <boost/type_traits/is_convertible.hpp> #include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/add_const.hpp> #include <boost/type_traits/add_const.hpp>
@ -100,6 +101,9 @@ public:
/// Construct an iterator representing the beginning of the buffers' data. /// Construct an iterator representing the beginning of the buffers' data.
static buffers_iterator begin(const BufferSequence& buffers) static buffers_iterator begin(const BufferSequence& buffers)
#if BOOST_WORKAROUND(__GNUC__, == 4) && BOOST_WORKAROUND(__GNUC_MINOR__, == 3)
__attribute__ ((noinline))
#endif
{ {
buffers_iterator new_iter; buffers_iterator new_iter;
new_iter.begin_ = buffers.begin(); new_iter.begin_ = buffers.begin();
@ -117,6 +121,9 @@ public:
/// Construct an iterator representing the end of the buffers' data. /// Construct an iterator representing the end of the buffers' data.
static buffers_iterator end(const BufferSequence& buffers) static buffers_iterator end(const BufferSequence& buffers)
#if BOOST_WORKAROUND(__GNUC__, == 4) && BOOST_WORKAROUND(__GNUC_MINOR__, == 3)
__attribute__ ((noinline))
#endif
{ {
buffers_iterator new_iter; buffers_iterator new_iter;
new_iter.begin_ = buffers.begin(); new_iter.begin_ = buffers.begin();

View File

@ -26,22 +26,40 @@ namespace asio {
namespace detail { namespace detail {
// The default maximum number of bytes to transfer in a single operation.
enum { default_max_transfer_size = 65536 };
// Adapt result of old-style completion conditions (which had a bool result
// where true indicated that the operation was complete).
inline std::size_t adapt_completion_condition_result(bool result)
{
return result ? 0 : default_max_transfer_size;
}
// Adapt result of current completion conditions (which have a size_t result
// where 0 means the operation is complete, and otherwise the result is the
// maximum number of bytes to transfer on the next underlying operation).
inline std::size_t adapt_completion_condition_result(std::size_t result)
{
return result;
}
class transfer_all_t class transfer_all_t
{ {
public: public:
typedef bool result_type; typedef std::size_t result_type;
template <typename Error> template <typename Error>
bool operator()(const Error& err, std::size_t) std::size_t operator()(const Error& err, std::size_t)
{ {
return !!err; return !!err ? 0 : default_max_transfer_size;
} }
}; };
class transfer_at_least_t class transfer_at_least_t
{ {
public: public:
typedef bool result_type; typedef std::size_t result_type;
explicit transfer_at_least_t(std::size_t minimum) explicit transfer_at_least_t(std::size_t minimum)
: minimum_(minimum) : minimum_(minimum)
@ -49,9 +67,10 @@ public:
} }
template <typename Error> template <typename Error>
bool operator()(const Error& err, std::size_t bytes_transferred) std::size_t operator()(const Error& err, std::size_t bytes_transferred)
{ {
return !!err || bytes_transferred >= minimum_; return (!!err || bytes_transferred >= minimum_)
? 0 : default_max_transfer_size;
} }
private: private:

View File

@ -20,11 +20,13 @@
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
#include <algorithm> #include <algorithm>
#include <cstddef> #include <cstddef>
#include <limits>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/iterator/iterator_facade.hpp> #include <boost/iterator/iterator_facade.hpp>
#include "asio/detail/pop_options.hpp" #include "asio/detail/pop_options.hpp"
#include "asio/buffer.hpp" #include "asio/buffer.hpp"
#include "asio/completion_condition.hpp"
namespace asio { namespace asio {
namespace detail { namespace detail {
@ -46,33 +48,33 @@ public:
// Construct with a buffer for the first entry and an iterator // Construct with a buffer for the first entry and an iterator
// range for the remaining entries. // range for the remaining entries.
consuming_buffers_iterator(bool at_end, const Buffer& first, consuming_buffers_iterator(bool at_end, const Buffer& first,
Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder) Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder,
: at_end_(at_end), std::size_t max_size)
: at_end_(max_size > 0 ? at_end : true),
first_(buffer(first, max_size)), first_(buffer(first, max_size)),
begin_remainder_(begin_remainder), begin_remainder_(begin_remainder),
end_remainder_(end_remainder), end_remainder_(end_remainder),
offset_(0) offset_(0),
max_size_(max_size)
{ {
} }
private: private:
friend class boost::iterator_core_access; friend class boost::iterator_core_access;
enum { max_size = 65536 };
void increment() void increment()
{ {
if (!at_end_) if (!at_end_)
{ {
if (begin_remainder_ == end_remainder_ if (begin_remainder_ == end_remainder_
|| offset_ + buffer_size(first_) >= max_size) || offset_ + buffer_size(first_) >= max_size_)
{ {
at_end_ = true; at_end_ = true;
} }
else else
{ {
offset_ += buffer_size(first_); offset_ += buffer_size(first_);
first_ = buffer(*begin_remainder_++, max_size - offset_); first_ = buffer(*begin_remainder_++, max_size_ - offset_);
} }
} }
} }
@ -99,6 +101,7 @@ private:
Buffer_Iterator begin_remainder_; Buffer_Iterator begin_remainder_;
Buffer_Iterator end_remainder_; Buffer_Iterator end_remainder_;
std::size_t offset_; std::size_t offset_;
std::size_t max_size_;
}; };
// A proxy for a sub-range in a list of buffers. // A proxy for a sub-range in a list of buffers.
@ -118,7 +121,8 @@ public:
: buffers_(buffers), : buffers_(buffers),
at_end_(buffers_.begin() == buffers_.end()), at_end_(buffers_.begin() == buffers_.end()),
first_(*buffers_.begin()), first_(*buffers_.begin()),
begin_remainder_(buffers_.begin()) begin_remainder_(buffers_.begin()),
max_size_((std::numeric_limits<std::size_t>::max)())
{ {
if (!at_end_) if (!at_end_)
++begin_remainder_; ++begin_remainder_;
@ -129,7 +133,8 @@ public:
: buffers_(other.buffers_), : buffers_(other.buffers_),
at_end_(other.at_end_), at_end_(other.at_end_),
first_(other.first_), first_(other.first_),
begin_remainder_(buffers_.begin()) begin_remainder_(buffers_.begin()),
max_size_(other.max_size_)
{ {
typename Buffers::const_iterator first = other.buffers_.begin(); typename Buffers::const_iterator first = other.buffers_.begin();
typename Buffers::const_iterator second = other.begin_remainder_; typename Buffers::const_iterator second = other.begin_remainder_;
@ -146,13 +151,15 @@ public:
typename Buffers::const_iterator first = other.buffers_.begin(); typename Buffers::const_iterator first = other.buffers_.begin();
typename Buffers::const_iterator second = other.begin_remainder_; typename Buffers::const_iterator second = other.begin_remainder_;
std::advance(begin_remainder_, std::distance(first, second)); std::advance(begin_remainder_, std::distance(first, second));
max_size_ = other.max_size_;
return *this; return *this;
} }
// Get a forward-only iterator to the first element. // Get a forward-only iterator to the first element.
const_iterator begin() const const_iterator begin() const
{ {
return const_iterator(at_end_, first_, begin_remainder_, buffers_.end()); return const_iterator(at_end_, first_,
begin_remainder_, buffers_.end(), max_size_);
} }
// Get a forward-only iterator for one past the last element. // Get a forward-only iterator for one past the last element.
@ -161,6 +168,12 @@ public:
return const_iterator(); return const_iterator();
} }
// Set the maximum size for a single transfer.
void set_max_size(std::size_t max_size)
{
max_size_ = max_size;
}
// Consume the specified number of bytes from the buffers. // Consume the specified number of bytes from the buffers.
void consume(std::size_t size) void consume(std::size_t size)
{ {
@ -197,6 +210,7 @@ private:
bool at_end_; bool at_end_;
Buffer first_; Buffer first_;
typename Buffers::const_iterator begin_remainder_; typename Buffers::const_iterator begin_remainder_;
std::size_t max_size_;
}; };
// Specialisation for null_buffers to ensure that the null_buffers type is // Specialisation for null_buffers to ensure that the null_buffers type is
@ -211,6 +225,11 @@ public:
// No-op. // No-op.
} }
void set_max_size(std::size_t)
{
// No-op.
}
void consume(std::size_t) void consume(std::size_t)
{ {
// No-op. // No-op.

View File

@ -63,6 +63,7 @@ public:
deadline_timer_service<Time_Traits, Timer_Scheduler> >(io_service), deadline_timer_service<Time_Traits, Timer_Scheduler> >(io_service),
scheduler_(asio::use_service<Timer_Scheduler>(io_service)) scheduler_(asio::use_service<Timer_Scheduler>(io_service))
{ {
scheduler_.init_task();
scheduler_.add_timer_queue(timer_queue_); scheduler_.add_timer_queue(timer_queue_);
} }

View File

@ -58,17 +58,28 @@ inline int close(int d, asio::error_code& ec)
return error_wrapper(::close(d), ec); return error_wrapper(::close(d), ec);
} }
inline void init_buf_iov_base(void*& base, void* addr)
{
base = addr;
}
template <typename T>
inline void init_buf_iov_base(T& base, void* addr)
{
base = static_cast<T>(addr);
}
typedef iovec buf; typedef iovec buf;
inline void init_buf(buf& b, void* data, size_t size) inline void init_buf(buf& b, void* data, size_t size)
{ {
b.iov_base = data; init_buf_iov_base(b.iov_base, data);
b.iov_len = size; b.iov_len = size;
} }
inline void init_buf(buf& b, const void* data, size_t size) inline void init_buf(buf& b, const void* data, size_t size)
{ {
b.iov_base = const_cast<void*>(data); init_buf_iov_base(b.iov_base, const_cast<void*>(data));
b.iov_len = size; b.iov_len = size;
} }

View File

@ -122,6 +122,17 @@ public:
timer_queues_.clear(); timer_queues_.clear();
} }
// Initialise the task, but only if the reactor is not in its own thread.
void init_task()
{
if (!Own_Thread)
{
typedef task_io_service<dev_poll_reactor<Own_Thread> >
task_io_service_type;
use_service<task_io_service_type>(this->get_io_service()).init_task();
}
}
// Register a socket with the reactor. Returns 0 on success, system error // Register a socket with the reactor. Returns 0 on success, system error
// code on failure. // code on failure.
int register_descriptor(socket_type, per_descriptor_data&) int register_descriptor(socket_type, per_descriptor_data&)
@ -421,6 +432,7 @@ private:
more_writes = write_op_queue_.perform_operation(descriptor, ec); more_writes = write_op_queue_.perform_operation(descriptor, ec);
else else
more_writes = write_op_queue_.has_operation(descriptor); more_writes = write_op_queue_.has_operation(descriptor);
if ((events[i].events & (POLLERR | POLLHUP)) != 0 if ((events[i].events & (POLLERR | POLLHUP)) != 0
&& (events[i].events & ~(POLLERR | POLLHUP)) == 0 && (events[i].events & ~(POLLERR | POLLHUP)) == 0
&& !more_except && !more_reads && !more_writes) && !more_except && !more_reads && !more_writes)

View File

@ -123,6 +123,16 @@ public:
timer_queues_.clear(); timer_queues_.clear();
} }
// Initialise the task, but only if the reactor is not in its own thread.
void init_task()
{
if (!Own_Thread)
{
typedef task_io_service<epoll_reactor<Own_Thread> > task_io_service_type;
use_service<task_io_service_type>(this->get_io_service()).init_task();
}
}
// Register a socket with the reactor. Returns 0 on success, system error // Register a socket with the reactor. Returns 0 on success, system error
// code on failure. // code on failure.
int register_descriptor(socket_type descriptor, int register_descriptor(socket_type descriptor,
@ -495,6 +505,7 @@ private:
more_writes = write_op_queue_.perform_operation(descriptor, ec); more_writes = write_op_queue_.perform_operation(descriptor, ec);
else else
more_writes = write_op_queue_.has_operation(descriptor); more_writes = write_op_queue_.has_operation(descriptor);
if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0 if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0
&& (events[i].events & ~(EPOLLERR | EPOLLHUP)) == 0 && (events[i].events & ~(EPOLLERR | EPOLLHUP)) == 0
&& !more_except && !more_reads && !more_writes) && !more_except && !more_reads && !more_writes)

View File

@ -131,6 +131,16 @@ public:
timer_queues_.clear(); timer_queues_.clear();
} }
// Initialise the task, but only if the reactor is not in its own thread.
void init_task()
{
if (!Own_Thread)
{
typedef task_io_service<kqueue_reactor<Own_Thread> > task_io_service_type;
use_service<task_io_service_type>(this->get_io_service()).init_task();
}
}
// Register a socket with the reactor. Returns 0 on success, system error // Register a socket with the reactor. Returns 0 on success, system error
// code on failure. // code on failure.
int register_descriptor(socket_type, per_descriptor_data& descriptor_data) int register_descriptor(socket_type, per_descriptor_data& descriptor_data)

View File

@ -38,12 +38,9 @@ class null_thread
: private noncopyable : private noncopyable
{ {
public: public:
// The purpose of the thread.
enum purpose { internal, external };
// Constructor. // Constructor.
template <typename Function> template <typename Function>
null_thread(Function f, purpose = internal) null_thread(Function f)
{ {
asio::system_error e( asio::system_error e(
asio::error::operation_not_supported, "thread"); asio::error::operation_not_supported, "thread");

View File

@ -71,7 +71,8 @@ public:
void interrupt() void interrupt()
{ {
char byte = 0; char byte = 0;
::write(write_descriptor_, &byte, 1); int result = ::write(write_descriptor_, &byte, 1);
(void)result;
} }
// Reset the select interrupt. Returns true if the call was interrupted. // Reset the select interrupt. Returns true if the call was interrupted.

View File

@ -17,6 +17,10 @@
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
#include <cstring>
#include "asio/detail/pop_options.hpp"
#include "asio/detail/socket_types.hpp" #include "asio/detail/socket_types.hpp"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)

View File

@ -42,12 +42,9 @@ class posix_thread
: private noncopyable : private noncopyable
{ {
public: public:
// The purpose of the thread.
enum purpose { internal, external };
// Constructor. // Constructor.
template <typename Function> template <typename Function>
posix_thread(Function f, purpose = internal) posix_thread(Function f)
: joined_(false) : joined_(false)
{ {
std::auto_ptr<func_base> arg(new func<Function>(f)); std::auto_ptr<func_base> arg(new func<Function>(f));

View File

@ -81,6 +81,7 @@ public:
reactive_descriptor_service<Reactor> >(io_service), reactive_descriptor_service<Reactor> >(io_service),
reactor_(asio::use_service<Reactor>(io_service)) reactor_(asio::use_service<Reactor>(io_service))
{ {
reactor_.init_task();
} }
// Destroy all user-defined handler objects owned by the service. // Destroy all user-defined handler objects owned by the service.

View File

@ -119,6 +119,7 @@ public:
ios.c_cflag |= CS8; ios.c_cflag |= CS8;
#endif #endif
ios.c_iflag |= IGNPAR; ios.c_iflag |= IGNPAR;
ios.c_cflag |= CREAD | CLOCAL;
descriptor_ops::clear_error(ec); descriptor_ops::clear_error(ec);
s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec); s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec);
} }

View File

@ -73,10 +73,21 @@ public:
enum enum
{ {
user_set_non_blocking = 1, // The user wants a non-blocking socket. // The user wants a non-blocking socket.
internal_non_blocking = 2, // The socket has been set non-blocking. user_set_non_blocking = 1,
enable_connection_aborted = 4, // User wants connection_aborted errors.
user_set_linger = 8 // The user set the linger option. // 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. // Flags indicating the current state of the socket.
@ -98,6 +109,7 @@ public:
reactive_socket_service<Protocol, Reactor> >(io_service), reactive_socket_service<Protocol, Reactor> >(io_service),
reactor_(asio::use_service<Reactor>(io_service)) reactor_(asio::use_service<Reactor>(io_service))
{ {
reactor_.init_task();
} }
// Destroy all user-defined handler objects owned by the service. // Destroy all user-defined handler objects owned by the service.
@ -119,12 +131,12 @@ public:
{ {
reactor_.close_descriptor(impl.socket_, impl.reactor_data_); reactor_.close_descriptor(impl.socket_, impl.reactor_data_);
if (impl.flags_ & implementation_type::internal_non_blocking) if (impl.flags_ & implementation_type::non_blocking)
{ {
ioctl_arg_type non_blocking = 0; ioctl_arg_type non_blocking = 0;
asio::error_code ignored_ec; asio::error_code ignored_ec;
socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec);
impl.flags_ &= ~implementation_type::internal_non_blocking; impl.flags_ &= ~implementation_type::non_blocking;
} }
if (impl.flags_ & implementation_type::user_set_linger) if (impl.flags_ & implementation_type::user_set_linger)
@ -213,12 +225,12 @@ public:
{ {
reactor_.close_descriptor(impl.socket_, impl.reactor_data_); reactor_.close_descriptor(impl.socket_, impl.reactor_data_);
if (impl.flags_ & implementation_type::internal_non_blocking) if (impl.flags_ & implementation_type::non_blocking)
{ {
ioctl_arg_type non_blocking = 0; ioctl_arg_type non_blocking = 0;
asio::error_code ignored_ec; asio::error_code ignored_ec;
socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec);
impl.flags_ &= ~implementation_type::internal_non_blocking; impl.flags_ &= ~implementation_type::non_blocking;
} }
if (socket_ops::close(impl.socket_, ec) == socket_error_retval) if (socket_ops::close(impl.socket_, ec) == socket_error_retval)
@ -432,11 +444,35 @@ public:
if (command.name() == static_cast<int>(FIONBIO)) if (command.name() == static_cast<int>(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 (command.get()) if (command.get())
impl.flags_ |= implementation_type::user_set_non_blocking; new_flags |= implementation_type::user_set_non_blocking;
else else
impl.flags_ &= ~implementation_type::user_set_non_blocking; new_flags &= ~implementation_type::user_set_non_blocking;
ec = asio::error_code();
// 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);
}
else
{
ec = asio::error_code();
}
// Update socket implementation's flags only if successful.
if (!ec)
impl.flags_ = new_flags;
} }
else else
{ {
@ -529,18 +565,6 @@ public:
return 0; return 0;
} }
// Make socket 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 (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
return 0;
impl.flags_ |= implementation_type::internal_non_blocking;
}
}
// Send the data. // Send the data.
for (;;) for (;;)
{ {
@ -683,12 +707,15 @@ public:
// Make socket non-blocking. // Make socket non-blocking.
if (!(impl.flags_ & implementation_type::internal_non_blocking)) if (!(impl.flags_ & implementation_type::internal_non_blocking))
{ {
ioctl_arg_type non_blocking = 1; if (!(impl.flags_ & implementation_type::non_blocking))
asio::error_code ec;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
{ {
this->get_io_service().post(bind_handler(handler, ec, 0)); ioctl_arg_type non_blocking = 1;
return; asio::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; impl.flags_ |= implementation_type::internal_non_blocking;
} }
@ -772,18 +799,6 @@ public:
asio::buffer_size(buffer)); asio::buffer_size(buffer));
} }
// Make socket 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 (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
return 0;
impl.flags_ |= implementation_type::internal_non_blocking;
}
}
// Send the data. // Send the data.
for (;;) for (;;)
{ {
@ -911,12 +926,15 @@ public:
// Make socket non-blocking. // Make socket non-blocking.
if (!(impl.flags_ & implementation_type::internal_non_blocking)) if (!(impl.flags_ & implementation_type::internal_non_blocking))
{ {
ioctl_arg_type non_blocking = 1; if (!(impl.flags_ & implementation_type::non_blocking))
asio::error_code ec;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
{ {
this->get_io_service().post(bind_handler(handler, ec, 0)); ioctl_arg_type non_blocking = 1;
return; asio::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; impl.flags_ |= implementation_type::internal_non_blocking;
} }
@ -980,18 +998,6 @@ public:
return 0; return 0;
} }
// Make socket 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 (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
return 0;
impl.flags_ |= implementation_type::internal_non_blocking;
}
}
// Receive some data. // Receive some data.
for (;;) for (;;)
{ {
@ -1147,12 +1153,15 @@ public:
// Make socket non-blocking. // Make socket non-blocking.
if (!(impl.flags_ & implementation_type::internal_non_blocking)) if (!(impl.flags_ & implementation_type::internal_non_blocking))
{ {
ioctl_arg_type non_blocking = 1; if (!(impl.flags_ & implementation_type::non_blocking))
asio::error_code ec;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
{ {
this->get_io_service().post(bind_handler(handler, ec, 0)); ioctl_arg_type non_blocking = 1;
return; asio::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; impl.flags_ |= implementation_type::internal_non_blocking;
} }
@ -1224,18 +1233,6 @@ public:
asio::buffer_size(buffer)); asio::buffer_size(buffer));
} }
// Make socket 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 (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
return 0;
impl.flags_ |= implementation_type::internal_non_blocking;
}
}
// Receive some data. // Receive some data.
for (;;) for (;;)
{ {
@ -1384,12 +1381,15 @@ public:
// Make socket non-blocking. // Make socket non-blocking.
if (!(impl.flags_ & implementation_type::internal_non_blocking)) if (!(impl.flags_ & implementation_type::internal_non_blocking))
{ {
ioctl_arg_type non_blocking = 1; if (!(impl.flags_ & implementation_type::non_blocking))
asio::error_code ec;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
{ {
this->get_io_service().post(bind_handler(handler, ec, 0)); ioctl_arg_type non_blocking = 1;
return; asio::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; impl.flags_ |= implementation_type::internal_non_blocking;
} }
@ -1449,18 +1449,6 @@ public:
return ec; return ec;
} }
// Make socket 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 (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
return ec;
impl.flags_ |= implementation_type::internal_non_blocking;
}
}
// Accept a socket. // Accept a socket.
for (;;) for (;;)
{ {
@ -1622,12 +1610,15 @@ public:
// Make socket non-blocking. // Make socket non-blocking.
if (!(impl.flags_ & implementation_type::internal_non_blocking)) if (!(impl.flags_ & implementation_type::internal_non_blocking))
{ {
ioctl_arg_type non_blocking = 1; if (!(impl.flags_ & implementation_type::non_blocking))
asio::error_code ec;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
{ {
this->get_io_service().post(bind_handler(handler, ec)); ioctl_arg_type non_blocking = 1;
return; asio::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; impl.flags_ |= implementation_type::internal_non_blocking;
} }
@ -1651,18 +1642,30 @@ public:
return ec; return ec;
} }
if (impl.flags_ & implementation_type::internal_non_blocking)
{
// Mark the socket as blocking while we perform the connect.
ioctl_arg_type non_blocking = 0;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
return ec;
impl.flags_ &= ~implementation_type::internal_non_blocking;
}
// Perform the connect operation. // Perform the connect operation.
socket_ops::connect(impl.socket_, socket_ops::connect(impl.socket_,
peer_endpoint.data(), peer_endpoint.size(), ec); peer_endpoint.data(), peer_endpoint.size(), ec);
if (ec != asio::error::in_progress
&& ec != 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 = asio::error_code(connect_error,
asio::error::get_system_category());
return ec; return ec;
} }
@ -1730,12 +1733,15 @@ public:
// Make socket non-blocking. // Make socket non-blocking.
if (!(impl.flags_ & implementation_type::internal_non_blocking)) if (!(impl.flags_ & implementation_type::internal_non_blocking))
{ {
ioctl_arg_type non_blocking = 1; if (!(impl.flags_ & implementation_type::non_blocking))
asio::error_code ec;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
{ {
this->get_io_service().post(bind_handler(handler, ec)); ioctl_arg_type non_blocking = 1;
return; asio::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; impl.flags_ |= implementation_type::internal_non_blocking;
} }

View File

@ -329,7 +329,7 @@ private:
void start_work_thread() void start_work_thread()
{ {
asio::detail::mutex::scoped_lock lock(mutex_); asio::detail::mutex::scoped_lock lock(mutex_);
if (work_thread_ == 0) if (!work_thread_)
{ {
work_thread_.reset(new asio::detail::thread( work_thread_.reset(new asio::detail::thread(
work_io_service_runner(*work_io_service_))); work_io_service_runner(*work_io_service_)));

View File

@ -21,6 +21,7 @@
#include <boost/config.hpp> #include <boost/config.hpp>
#include "asio/detail/pop_options.hpp" #include "asio/detail/pop_options.hpp"
#include "asio/detail/eventfd_select_interrupter.hpp"
#include "asio/detail/pipe_select_interrupter.hpp" #include "asio/detail/pipe_select_interrupter.hpp"
#include "asio/detail/socket_select_interrupter.hpp" #include "asio/detail/socket_select_interrupter.hpp"
@ -29,6 +30,8 @@ namespace detail {
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
typedef socket_select_interrupter select_interrupter; typedef socket_select_interrupter select_interrupter;
#elif defined(ASIO_HAS_EVENTFD)
typedef eventfd_select_interrupter select_interrupter;
#else #else
typedef pipe_select_interrupter select_interrupter; typedef pipe_select_interrupter select_interrupter;
#endif #endif

View File

@ -110,6 +110,16 @@ public:
timer_queues_.clear(); timer_queues_.clear();
} }
// Initialise the task, but only if the reactor is not in its own thread.
void init_task()
{
if (!Own_Thread)
{
typedef task_io_service<select_reactor<Own_Thread> > task_io_service_type;
use_service<task_io_service_type>(this->get_io_service()).init_task();
}
}
// Register a socket with the reactor. Returns 0 on success, system error // Register a socket with the reactor. Returns 0 on success, system error
// code on failure. // code on failure.
int register_descriptor(socket_type, per_descriptor_data&) int register_descriptor(socket_type, per_descriptor_data&)

View File

@ -36,6 +36,21 @@
namespace asio { namespace asio {
namespace detail { namespace detail {
#if defined(__GNUC__)
# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
# pragma GCC visibility push (default)
# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
#endif // defined(__GNUC__)
template <typename T>
class typeid_wrapper {};
#if defined(__GNUC__)
# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
# pragma GCC visibility pop
# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
#endif // defined(__GNUC__)
class service_registry class service_registry
: private noncopyable : private noncopyable
{ {
@ -168,7 +183,7 @@ private:
void init_service_id(asio::io_service::service& service, void init_service_id(asio::io_service::service& service,
const asio::detail::service_id<Service>& /*id*/) const asio::detail::service_id<Service>& /*id*/)
{ {
service.type_info_ = &typeid(Service); service.type_info_ = &typeid(typeid_wrapper<Service>);
service.id_ = 0; service.id_ = 0;
} }
#endif // !defined(ASIO_NO_TYPEID) #endif // !defined(ASIO_NO_TYPEID)
@ -188,7 +203,8 @@ private:
const asio::io_service::service& service, const asio::io_service::service& service,
const asio::detail::service_id<Service>& /*id*/) const asio::detail::service_id<Service>& /*id*/)
{ {
return service.type_info_ != 0 && *service.type_info_ == typeid(Service); return service.type_info_ != 0
&& *service.type_info_ == typeid(typeid_wrapper<Service>);
} }
#endif // !defined(ASIO_NO_TYPEID) #endif // !defined(ASIO_NO_TYPEID)

View File

@ -102,7 +102,7 @@ inline socket_type accept(socket_type s, socket_addr_type* addr,
} }
#endif #endif
#if defined(BOOST_WINDOWS) && defined(UNDER_CE) #if defined(BOOST_WINDOWS)
clear_error(ec); clear_error(ec);
#endif #endif
@ -122,7 +122,7 @@ inline int bind(socket_type s, const socket_addr_type* addr,
clear_error(ec); clear_error(ec);
int result = error_wrapper(call_bind( int result = error_wrapper(call_bind(
&msghdr::msg_namelen, s, addr, addrlen), ec); &msghdr::msg_namelen, s, addr, addrlen), ec);
#if defined(BOOST_WINDOWS) && defined(UNDER_CE) #if defined(BOOST_WINDOWS)
if (result == 0) if (result == 0)
clear_error(ec); clear_error(ec);
#endif #endif
@ -134,10 +134,8 @@ inline int close(socket_type s, asio::error_code& ec)
clear_error(ec); clear_error(ec);
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
int result = error_wrapper(::closesocket(s), ec); int result = error_wrapper(::closesocket(s), ec);
# if defined(UNDER_CE)
if (result == 0) if (result == 0)
clear_error(ec); clear_error(ec);
# endif
return result; return result;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
return error_wrapper(::close(s), ec); return error_wrapper(::close(s), ec);
@ -148,7 +146,7 @@ inline int shutdown(socket_type s, int what, asio::error_code& ec)
{ {
clear_error(ec); clear_error(ec);
int result = error_wrapper(::shutdown(s, what), ec); int result = error_wrapper(::shutdown(s, what), ec);
#if defined(BOOST_WINDOWS) && defined(UNDER_CE) #if defined(BOOST_WINDOWS)
if (result == 0) if (result == 0)
clear_error(ec); clear_error(ec);
#endif #endif
@ -168,7 +166,7 @@ inline int connect(socket_type s, const socket_addr_type* addr,
clear_error(ec); clear_error(ec);
int result = error_wrapper(call_connect( int result = error_wrapper(call_connect(
&msghdr::msg_namelen, s, addr, addrlen), ec); &msghdr::msg_namelen, s, addr, addrlen), ec);
#if defined(BOOST_WINDOWS) && defined(UNDER_CE) #if defined(BOOST_WINDOWS)
if (result == 0) if (result == 0)
clear_error(ec); clear_error(ec);
#endif #endif
@ -195,13 +193,24 @@ inline int listen(socket_type s, int backlog, asio::error_code& ec)
{ {
clear_error(ec); clear_error(ec);
int result = error_wrapper(::listen(s, backlog), ec); int result = error_wrapper(::listen(s, backlog), ec);
#if defined(BOOST_WINDOWS) && defined(UNDER_CE) #if defined(BOOST_WINDOWS)
if (result == 0) if (result == 0)
clear_error(ec); clear_error(ec);
#endif #endif
return result; return result;
} }
inline void init_buf_iov_base(void*& base, void* addr)
{
base = addr;
}
template <typename T>
inline void init_buf_iov_base(T& base, void* addr)
{
base = static_cast<T>(addr);
}
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
typedef WSABUF buf; typedef WSABUF buf;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@ -214,7 +223,7 @@ inline void init_buf(buf& b, void* data, size_t size)
b.buf = static_cast<char*>(data); b.buf = static_cast<char*>(data);
b.len = static_cast<u_long>(size); b.len = static_cast<u_long>(size);
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
b.iov_base = data; init_buf_iov_base(b.iov_base, data);
b.iov_len = size; b.iov_len = size;
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
} }
@ -225,7 +234,7 @@ inline void init_buf(buf& b, const void* data, size_t size)
b.buf = static_cast<char*>(const_cast<void*>(data)); b.buf = static_cast<char*>(const_cast<void*>(data));
b.len = static_cast<u_long>(size); b.len = static_cast<u_long>(size);
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
b.iov_base = const_cast<void*>(data); init_buf_iov_base(b.iov_base, const_cast<void*>(data));
b.iov_len = size; b.iov_len = size;
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
} }
@ -265,9 +274,7 @@ inline int recv(socket_type s, buf* bufs, size_t count, int flags,
recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec);
if (result != 0) if (result != 0)
return -1; return -1;
# if defined(UNDER_CE)
clear_error(ec); clear_error(ec);
# endif
return bytes_transferred; return bytes_transferred;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
msghdr msg = msghdr(); msghdr msg = msghdr();
@ -293,9 +300,7 @@ inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags,
*addrlen = (std::size_t)tmp_addrlen; *addrlen = (std::size_t)tmp_addrlen;
if (result != 0) if (result != 0)
return -1; return -1;
# if defined(UNDER_CE)
clear_error(ec); clear_error(ec);
# endif
return bytes_transferred; return bytes_transferred;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
msghdr msg = msghdr(); msghdr msg = msghdr();
@ -322,9 +327,7 @@ inline int send(socket_type s, const buf* bufs, size_t count, int flags,
send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); send_buf_count, &bytes_transferred, send_flags, 0, 0), ec);
if (result != 0) if (result != 0)
return -1; return -1;
# if defined(UNDER_CE)
clear_error(ec); clear_error(ec);
# endif
return bytes_transferred; return bytes_transferred;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
msghdr msg = msghdr(); msghdr msg = msghdr();
@ -351,9 +354,7 @@ inline int sendto(socket_type s, const buf* bufs, size_t count, int flags,
static_cast<int>(addrlen), 0, 0), ec); static_cast<int>(addrlen), 0, 0), ec);
if (result != 0) if (result != 0)
return -1; return -1;
# if defined(UNDER_CE)
clear_error(ec); clear_error(ec);
# endif
return bytes_transferred; return bytes_transferred;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
msghdr msg = msghdr(); msghdr msg = msghdr();
@ -388,9 +389,7 @@ inline socket_type socket(int af, int type, int protocol,
reinterpret_cast<const char*>(&optval), sizeof(optval)); reinterpret_cast<const char*>(&optval), sizeof(optval));
} }
# if defined(UNDER_CE)
clear_error(ec); clear_error(ec);
# endif
return s; return s;
#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) #elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
@ -452,7 +451,7 @@ inline int setsockopt(socket_type s, int level, int optname,
clear_error(ec); clear_error(ec);
int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen,
s, level, optname, optval, optlen), ec); s, level, optname, optval, optlen), ec);
# if defined(BOOST_WINDOWS) && defined(UNDER_CE) # if defined(BOOST_WINDOWS)
if (result == 0) if (result == 0)
clear_error(ec); clear_error(ec);
# endif # endif
@ -525,10 +524,8 @@ inline int getsockopt(socket_type s, int level, int optname, void* optval,
*static_cast<DWORD*>(optval) = 1; *static_cast<DWORD*>(optval) = 1;
clear_error(ec); clear_error(ec);
} }
# if defined(UNDER_CE)
if (result == 0) if (result == 0)
clear_error(ec); clear_error(ec);
# endif
return result; return result;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
clear_error(ec); clear_error(ec);
@ -566,7 +563,7 @@ inline int getpeername(socket_type s, socket_addr_type* addr,
clear_error(ec); clear_error(ec);
int result = error_wrapper(call_getpeername( int result = error_wrapper(call_getpeername(
&msghdr::msg_namelen, s, addr, addrlen), ec); &msghdr::msg_namelen, s, addr, addrlen), ec);
#if defined(BOOST_WINDOWS) && defined(UNDER_CE) #if defined(BOOST_WINDOWS)
if (result == 0) if (result == 0)
clear_error(ec); clear_error(ec);
#endif #endif
@ -589,7 +586,7 @@ inline int getsockname(socket_type s, socket_addr_type* addr,
clear_error(ec); clear_error(ec);
int result = error_wrapper(call_getsockname( int result = error_wrapper(call_getsockname(
&msghdr::msg_namelen, s, addr, addrlen), ec); &msghdr::msg_namelen, s, addr, addrlen), ec);
#if defined(BOOST_WINDOWS) && defined(UNDER_CE) #if defined(BOOST_WINDOWS)
if (result == 0) if (result == 0)
clear_error(ec); clear_error(ec);
#endif #endif
@ -602,10 +599,8 @@ inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg,
clear_error(ec); clear_error(ec);
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec);
# if defined(UNDER_CE)
if (result == 0) if (result == 0)
clear_error(ec); clear_error(ec);
# endif
return result; return result;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
return error_wrapper(::ioctl(s, cmd, arg), ec); return error_wrapper(::ioctl(s, cmd, arg), ec);
@ -647,7 +642,7 @@ inline int select(int nfds, fd_set* readfds, fd_set* writefds,
#else #else
int result = error_wrapper(::select(nfds, readfds, int result = error_wrapper(::select(nfds, readfds,
writefds, exceptfds, timeout), ec); writefds, exceptfds, timeout), ec);
# if defined(BOOST_WINDOWS) && defined(UNDER_CE) # if defined(BOOST_WINDOWS)
if (result >= 0) if (result >= 0)
clear_error(ec); clear_error(ec);
# endif # endif
@ -663,10 +658,8 @@ inline int poll_read(socket_type s, asio::error_code& ec)
FD_SET(s, &fds); FD_SET(s, &fds);
clear_error(ec); clear_error(ec);
int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec); int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec);
# if defined(UNDER_CE)
if (result >= 0) if (result >= 0)
clear_error(ec); clear_error(ec);
# endif
return result; return result;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
pollfd fds; pollfd fds;
@ -686,10 +679,32 @@ inline int poll_write(socket_type s, asio::error_code& ec)
FD_SET(s, &fds); FD_SET(s, &fds);
clear_error(ec); clear_error(ec);
int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec); int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec);
# if defined(UNDER_CE)
if (result >= 0) if (result >= 0)
clear_error(ec); clear_error(ec);
# endif return result;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
pollfd fds;
fds.fd = s;
fds.events = POLLOUT;
fds.revents = 0;
clear_error(ec);
return error_wrapper(::poll(&fds, 1, -1), ec);
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
}
inline int poll_connect(socket_type s, asio::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; return result;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
pollfd fds; pollfd fds;
@ -837,10 +852,8 @@ inline int inet_pton(int af, const char* src, void* dest,
if (result == socket_error_retval && !ec) if (result == socket_error_retval && !ec)
ec = asio::error::invalid_argument; ec = asio::error::invalid_argument;
#if defined(UNDER_CE)
if (result != socket_error_retval) if (result != socket_error_retval)
clear_error(ec); clear_error(ec);
#endif
return result == socket_error_retval ? -1 : 1; return result == socket_error_retval ? -1 : 1;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@ -869,7 +882,7 @@ inline int gethostname(char* name, int namelen, asio::error_code& ec)
{ {
clear_error(ec); clear_error(ec);
int result = error_wrapper(::gethostname(name, namelen), ec); int result = error_wrapper(::gethostname(name, namelen), ec);
#if defined(BOOST_WINDOWS) && defined(UNDER_CE) #if defined(BOOST_WINDOWS)
if (result == 0) if (result == 0)
clear_error(ec); clear_error(ec);
#endif #endif
@ -912,9 +925,7 @@ inline hostent* gethostbyaddr(const char* addr, int length, int af,
hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec);
if (!retval) if (!retval)
return 0; return 0;
# if defined(UNDER_CE)
clear_error(ec); clear_error(ec);
# endif
*result = *retval; *result = *retval;
return retval; return retval;
#elif defined(__sun) || defined(__QNX__) #elif defined(__sun) || defined(__QNX__)
@ -963,9 +974,7 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result,
hostent* retval = error_wrapper(::gethostbyname(name), ec); hostent* retval = error_wrapper(::gethostbyname(name), ec);
if (!retval) if (!retval)
return 0; return 0;
# if defined(UNDER_CE)
clear_error(ec); clear_error(ec);
# endif
*result = *retval; *result = *retval;
return result; return result;
#elif defined(__sun) || defined(__QNX__) #elif defined(__sun) || defined(__QNX__)

View File

@ -28,11 +28,15 @@
# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) # endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) # if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
# if defined(_MSC_VER) || defined(__BORLANDC__) # if defined(_MSC_VER) || defined(__BORLANDC__)
# pragma message("Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately") # pragma message( \
# pragma message("Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target)") "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__) # else // defined(_MSC_VER) || defined(__BORLANDC__)
# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately # warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately.
# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target) # 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__) # endif // defined(_MSC_VER) || defined(__BORLANDC__)
# define _WIN32_WINNT 0x0501 # define _WIN32_WINNT 0x0501
# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) # endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
@ -187,7 +191,12 @@ const int shutdown_both = SHUT_RDWR;
const int message_peek = MSG_PEEK; const int message_peek = MSG_PEEK;
const int message_out_of_band = MSG_OOB; const int message_out_of_band = MSG_OOB;
const int message_do_not_route = MSG_DONTROUTE; const int message_do_not_route = MSG_DONTROUTE;
# if defined(IOV_MAX)
const int max_iov_len = IOV_MAX; const int max_iov_len = IOV_MAX;
# else
// POSIX platforms are not required to define IOV_MAX.
const int max_iov_len = 16;
# endif
#endif #endif
const int custom_socket_option_level = 0xA5100000; const int custom_socket_option_level = 0xA5100000;
const int enable_connection_aborted_option = 1; const int enable_connection_aborted_option = 1;

View File

@ -44,14 +44,13 @@ public:
task_io_service(asio::io_service& io_service) task_io_service(asio::io_service& io_service)
: asio::detail::service_base<task_io_service<Task> >(io_service), : asio::detail::service_base<task_io_service<Task> >(io_service),
mutex_(), mutex_(),
task_(use_service<Task>(io_service)), task_(0),
task_interrupted_(true), task_interrupted_(true),
outstanding_work_(0), outstanding_work_(0),
stopped_(false), stopped_(false),
shutdown_(false), shutdown_(false),
first_idle_thread_(0) first_idle_thread_(0)
{ {
handler_queue_.push(&task_handler_);
} }
void init(size_t /*concurrency_hint*/) void init(size_t /*concurrency_hint*/)
@ -74,8 +73,20 @@ public:
h->destroy(); h->destroy();
} }
// Reset handler queue to initial state. // Reset to initial state.
handler_queue_.push(&task_handler_); task_ = 0;
}
// Initialise the task, if required.
void init_task()
{
asio::detail::mutex::scoped_lock lock(mutex_);
if (!shutdown_ && !task_)
{
task_ = &use_service<Task>(this->get_io_service());
handler_queue_.push(&task_handler_);
interrupt_one_idle_thread(lock);
}
} }
// Run the event loop until interrupted or no more work. // Run the event loop until interrupted or no more work.
@ -194,10 +205,10 @@ public:
// Wake up a thread to execute the handler. // Wake up a thread to execute the handler.
if (!interrupt_one_idle_thread(lock)) if (!interrupt_one_idle_thread(lock))
{ {
if (!task_interrupted_) if (!task_interrupted_ && task_)
{ {
task_interrupted_ = true; task_interrupted_ = true;
task_.interrupt(); task_->interrupt();
} }
} }
} }
@ -246,7 +257,7 @@ private:
// Run the task. May throw an exception. Only block if the handler // Run the task. May throw an exception. Only block if the handler
// queue is empty and we have an idle_thread_info object, otherwise // queue is empty and we have an idle_thread_info object, otherwise
// we want to return as soon as possible. // we want to return as soon as possible.
task_.run(!more_handlers && !polling); task_->run(!more_handlers && !polling);
} }
else else
{ {
@ -285,10 +296,10 @@ private:
{ {
stopped_ = true; stopped_ = true;
interrupt_all_idle_threads(lock); interrupt_all_idle_threads(lock);
if (!task_interrupted_) if (!task_interrupted_ && task_)
{ {
task_interrupted_ = true; task_interrupted_ = true;
task_.interrupt(); task_->interrupt();
} }
} }
@ -376,7 +387,7 @@ private:
asio::detail::mutex mutex_; asio::detail::mutex mutex_;
// The task to be run by this service. // The task to be run by this service.
Task& task_; Task* task_;
// Handler object to represent the position of the task in the queue. // Handler object to represent the position of the task in the queue.
class task_handler class task_handler

View File

@ -49,7 +49,7 @@ public:
: asio::detail::service_base<task_io_service<Task> >(io_service), : asio::detail::service_base<task_io_service<Task> >(io_service),
front_mutex_(), front_mutex_(),
back_mutex_(), back_mutex_(),
task_(use_service<Task>(io_service)), task_(&use_service<Task>(io_service)),
outstanding_work_(0), outstanding_work_(0),
front_stopped_(false), front_stopped_(false),
back_stopped_(false), back_stopped_(false),
@ -57,7 +57,6 @@ public:
back_first_idle_thread_(0), back_first_idle_thread_(0),
back_task_thread_(0) back_task_thread_(0)
{ {
handler_queue_.push(&task_handler_);
} }
void init(size_t /*concurrency_hint*/) void init(size_t /*concurrency_hint*/)
@ -76,8 +75,20 @@ public:
if (h != &task_handler_) if (h != &task_handler_)
h->destroy(); h->destroy();
// Reset handler queue to initial state. // Reset to initial state.
handler_queue_.push(&task_handler_); task_ = 0;
}
// Initialise the task, if required.
void init_task()
{
asio::detail::mutex::scoped_lock back_lock(back_mutex_);
if (!back_shutdown_ && !task_)
{
task_ = &use_service<Task>(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. // Run the event loop until interrupted or no more work.
@ -286,7 +297,7 @@ private:
// queue is empty and we're not polling, otherwise we want to return // queue is empty and we're not polling, otherwise we want to return
// as soon as possible. // as soon as possible.
task_has_run = true; task_has_run = true;
task_.run(!more_handlers && !polling); task_->run(!more_handlers && !polling);
} }
else else
{ {
@ -341,10 +352,10 @@ private:
idle_thread->next = 0; idle_thread->next = 0;
idle_thread->wakeup_event.signal(back_lock); idle_thread->wakeup_event.signal(back_lock);
} }
else if (back_task_thread_) else if (back_task_thread_ && task_)
{ {
back_task_thread_ = 0; back_task_thread_ = 0;
task_.interrupt(); task_->interrupt();
} }
} }
@ -360,10 +371,10 @@ private:
idle_thread->wakeup_event.signal(back_lock); idle_thread->wakeup_event.signal(back_lock);
} }
if (back_task_thread_) if (back_task_thread_ && task_)
{ {
back_task_thread_ = 0; back_task_thread_ = 0;
task_.interrupt(); task_->interrupt();
} }
} }
@ -414,7 +425,7 @@ private:
asio::detail::mutex back_mutex_; asio::detail::mutex back_mutex_;
// The task to be run by this service. // The task to be run by this service.
Task& task_; Task* task_;
// Handler object to represent the position of the task in the queue. // Handler object to represent the position of the task in the queue.
class task_handler class task_handler

View File

@ -148,6 +148,11 @@ public:
timer_queues_.clear(); timer_queues_.clear();
} }
// Initialise the task. Nothing to do here.
void init_task()
{
}
// Register a handle with the IO completion port. // Register a handle with the IO completion port.
asio::error_code register_handle( asio::error_code register_handle(
HANDLE handle, asio::error_code& ec) HANDLE handle, asio::error_code& ec)
@ -530,7 +535,7 @@ private:
// Wake up next thread that is blocked on GetQueuedCompletionStatus. // Wake up next thread that is blocked on GetQueuedCompletionStatus.
if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
{ {
DWORD last_error = ::GetLastError(); last_error = ::GetLastError();
ec = asio::error_code(last_error, ec = asio::error_code(last_error,
asio::error::get_system_category()); asio::error::get_system_category());
return 0; return 0;

View File

@ -36,6 +36,7 @@ namespace asio {
namespace detail { namespace detail {
class win_iocp_io_service; class win_iocp_io_service;
class win_iocp_overlapped_ptr;
} // namespace detail } // namespace detail
} // namespace asio } // namespace asio

View File

@ -39,45 +39,67 @@ namespace detail {
unsigned int __stdcall win_thread_function(void* arg); unsigned int __stdcall win_thread_function(void* arg);
class win_thread #if (WINVER < 0x0500)
: private noncopyable void __stdcall apc_function(ULONG data);
#else
void __stdcall apc_function(ULONG_PTR data);
#endif
template <typename T>
class win_thread_base
{ {
public: public:
// The purpose of the thread. static bool terminate_threads()
enum purpose { internal, external }; {
return ::InterlockedExchangeAdd(&terminate_threads_, 0) != 0;
}
static void set_terminate_threads(bool b)
{
::InterlockedExchange(&terminate_threads_, b ? 1 : 0);
}
private:
static long terminate_threads_;
};
template <typename T>
long win_thread_base<T>::terminate_threads_ = 0;
class win_thread
: private noncopyable,
public win_thread_base<win_thread>
{
public:
// Constructor. // Constructor.
template <typename Function> template <typename Function>
win_thread(Function f, purpose p = internal) win_thread(Function f)
: exit_event_(0) : exit_event_(0)
{ {
std::auto_ptr<func_base> arg(new func<Function>(f)); std::auto_ptr<func_base> arg(new func<Function>(f));
::HANDLE entry_event = 0; ::HANDLE entry_event = 0;
if (p == internal) arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0);
if (!entry_event)
{ {
arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0); DWORD last_error = ::GetLastError();
if (!entry_event) asio::system_error e(
{ asio::error_code(last_error,
DWORD last_error = ::GetLastError(); asio::error::get_system_category()),
asio::system_error e( "thread.entry_event");
asio::error_code(last_error, boost::throw_exception(e);
asio::error::get_system_category()), }
"thread.entry_event");
boost::throw_exception(e);
}
arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0); arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0);
if (!exit_event_) if (!exit_event_)
{ {
DWORD last_error = ::GetLastError(); DWORD last_error = ::GetLastError();
::CloseHandle(entry_event); ::CloseHandle(entry_event);
asio::system_error e( asio::system_error e(
asio::error_code(last_error, asio::error_code(last_error,
asio::error::get_system_category()), asio::error::get_system_category()),
"thread.exit_event"); "thread.exit_event");
boost::throw_exception(e); boost::throw_exception(e);
}
} }
unsigned int thread_id = 0; unsigned int thread_id = 0;
@ -117,14 +139,15 @@ public:
// Wait for the thread to exit. // Wait for the thread to exit.
void join() void join()
{ {
if (exit_event_) ::WaitForSingleObject(exit_event_, INFINITE);
::CloseHandle(exit_event_);
if (terminate_threads())
{ {
::WaitForSingleObject(exit_event_, INFINITE);
::CloseHandle(exit_event_);
::TerminateThread(thread_, 0); ::TerminateThread(thread_, 0);
} }
else else
{ {
::QueueUserAPC(apc_function, thread_, 0);
::WaitForSingleObject(thread_, INFINITE); ::WaitForSingleObject(thread_, INFINITE);
} }
} }
@ -132,6 +155,12 @@ public:
private: private:
friend unsigned int __stdcall win_thread_function(void* arg); friend unsigned int __stdcall win_thread_function(void* arg);
#if (WINVER < 0x0500)
friend void __stdcall apc_function(ULONG);
#else
friend void __stdcall apc_function(ULONG_PTR);
#endif
class func_base class func_base
{ {
public: public:
@ -169,21 +198,30 @@ inline unsigned int __stdcall win_thread_function(void* arg)
std::auto_ptr<win_thread::func_base> func( std::auto_ptr<win_thread::func_base> func(
static_cast<win_thread::func_base*>(arg)); static_cast<win_thread::func_base*>(arg));
if (func->entry_event_) ::SetEvent(func->entry_event_);
::SetEvent(func->entry_event_);
func->run(); func->run();
if (HANDLE exit_event = func->exit_event_) // 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
func.reset(); // joined during global object destruction then it may be killed using
::SetEvent(exit_event); // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx
::Sleep(INFINITE); // 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; return 0;
} }
#if (WINVER < 0x0500)
inline void __stdcall apc_function(ULONG) {}
#else
inline void __stdcall apc_function(ULONG_PTR) {}
#endif
} // namespace detail } // namespace detail
} // namespace asio } // namespace asio

View File

@ -42,12 +42,9 @@ class wince_thread
: private noncopyable : private noncopyable
{ {
public: public:
// The purpose of the thread.
enum purpose { internal, external };
// Constructor. // Constructor.
template <typename Function> template <typename Function>
wince_thread(Function f, purpose = internal) wince_thread(Function f)
{ {
std::auto_ptr<func_base> arg(new func<Function>(f)); std::auto_ptr<func_base> arg(new func<Function>(f));
DWORD thread_id = 0; DWORD thread_id = 0;

View File

@ -83,6 +83,7 @@ inline std::string error_code::message() const
if (category() != error::get_system_category()) if (category() != error::get_system_category())
return "asio error"; return "asio error";
#if defined(__sun) || defined(__QNX__) #if defined(__sun) || defined(__QNX__)
using namespace std;
return strerror(value_); return strerror(value_);
#elif defined(__MACH__) && defined(__APPLE__) \ #elif defined(__MACH__) && defined(__APPLE__) \
|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) \ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) \

View File

@ -37,18 +37,20 @@ template <typename SyncReadStream, typename MutableBufferSequence,
std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec) CompletionCondition completion_condition, asio::error_code& ec)
{ {
ec = asio::error_code();
asio::detail::consuming_buffers< asio::detail::consuming_buffers<
mutable_buffer, MutableBufferSequence> tmp(buffers); mutable_buffer, MutableBufferSequence> tmp(buffers);
std::size_t total_transferred = 0; std::size_t total_transferred = 0;
tmp.set_max_size(detail::adapt_completion_condition_result(
completion_condition(ec, total_transferred)));
while (tmp.begin() != tmp.end()) while (tmp.begin() != tmp.end())
{ {
std::size_t bytes_transferred = s.read_some(tmp, ec); std::size_t bytes_transferred = s.read_some(tmp, ec);
tmp.consume(bytes_transferred); tmp.consume(bytes_transferred);
total_transferred += bytes_transferred; total_transferred += bytes_transferred;
if (completion_condition(ec, total_transferred)) tmp.set_max_size(detail::adapt_completion_condition_result(
return total_transferred; completion_condition(ec, total_transferred)));
} }
ec = asio::error_code();
return total_transferred; return total_transferred;
} }
@ -78,18 +80,23 @@ std::size_t read(SyncReadStream& s,
asio::basic_streambuf<Allocator>& b, asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition, asio::error_code& ec) CompletionCondition completion_condition, asio::error_code& ec)
{ {
ec = asio::error_code();
std::size_t total_transferred = 0; 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 = std::min<std::size_t>(512,
std::min<std::size_t>(max_size, b.max_size() - b.size()));
while (bytes_available > 0)
{ {
std::size_t bytes_available =
std::min<std::size_t>(512, b.max_size() - b.size());
std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec); std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec);
b.commit(bytes_transferred); b.commit(bytes_transferred);
total_transferred += bytes_transferred; total_transferred += bytes_transferred;
if (b.size() == b.max_size() max_size = detail::adapt_completion_condition_result(
|| completion_condition(ec, total_transferred)) completion_condition(ec, total_transferred));
return total_transferred; bytes_available = std::min<std::size_t>(512,
std::min<std::size_t>(max_size, b.max_size() - b.size()));
} }
return total_transferred;
} }
template <typename SyncReadStream, typename Allocator> template <typename SyncReadStream, typename Allocator>
@ -139,8 +146,9 @@ namespace detail
{ {
total_transferred_ += bytes_transferred; total_transferred_ += bytes_transferred;
buffers_.consume(bytes_transferred); buffers_.consume(bytes_transferred);
if (completion_condition_(ec, total_transferred_) buffers_.set_max_size(detail::adapt_completion_condition_result(
|| buffers_.begin() == buffers_.end()) completion_condition_(ec, total_transferred_)));
if (buffers_.begin() == buffers_.end())
{ {
handler_(ec, total_transferred_); handler_(ec, total_transferred_);
} }
@ -197,6 +205,18 @@ inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
{ {
asio::detail::consuming_buffers< asio::detail::consuming_buffers<
mutable_buffer, MutableBufferSequence> tmp(buffers); mutable_buffer, MutableBufferSequence> tmp(buffers);
asio::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, s.async_read_some(tmp,
detail::read_handler<AsyncReadStream, MutableBufferSequence, detail::read_handler<AsyncReadStream, MutableBufferSequence,
CompletionCondition, ReadHandler>( CompletionCondition, ReadHandler>(
@ -234,15 +254,17 @@ namespace detail
{ {
total_transferred_ += bytes_transferred; total_transferred_ += bytes_transferred;
streambuf_.commit(bytes_transferred); streambuf_.commit(bytes_transferred);
if (streambuf_.size() == streambuf_.max_size() std::size_t max_size = detail::adapt_completion_condition_result(
|| completion_condition_(ec, total_transferred_)) completion_condition_(ec, total_transferred_));
std::size_t bytes_available = std::min<std::size_t>(512,
std::min<std::size_t>(max_size,
streambuf_.max_size() - streambuf_.size()));
if (bytes_available == 0)
{ {
handler_(ec, total_transferred_); handler_(ec, total_transferred_);
} }
else else
{ {
std::size_t bytes_available =
std::min<std::size_t>(512, streambuf_.max_size() - streambuf_.size());
stream_.async_read_some(streambuf_.prepare(bytes_available), *this); stream_.async_read_some(streambuf_.prepare(bytes_available), *this);
} }
} }
@ -292,8 +314,19 @@ inline void async_read(AsyncReadStream& s,
asio::basic_streambuf<Allocator>& b, asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition, ReadHandler handler) CompletionCondition completion_condition, ReadHandler handler)
{ {
std::size_t bytes_available = asio::error_code ec;
std::min<std::size_t>(512, b.max_size() - b.size()); 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<std::size_t>(512,
std::min<std::size_t>(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), s.async_read_some(b.prepare(bytes_available),
detail::read_streambuf_handler<AsyncReadStream, Allocator, detail::read_streambuf_handler<AsyncReadStream, Allocator,
CompletionCondition, ReadHandler>( CompletionCondition, ReadHandler>(

View File

@ -38,19 +38,21 @@ std::size_t read_at(SyncRandomAccessReadDevice& d,
boost::uint64_t offset, const MutableBufferSequence& buffers, boost::uint64_t offset, const MutableBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec) CompletionCondition completion_condition, asio::error_code& ec)
{ {
ec = asio::error_code();
asio::detail::consuming_buffers< asio::detail::consuming_buffers<
mutable_buffer, MutableBufferSequence> tmp(buffers); mutable_buffer, MutableBufferSequence> tmp(buffers);
std::size_t total_transferred = 0; std::size_t total_transferred = 0;
tmp.set_max_size(detail::adapt_completion_condition_result(
completion_condition(ec, total_transferred)));
while (tmp.begin() != tmp.end()) while (tmp.begin() != tmp.end())
{ {
std::size_t bytes_transferred = d.read_some_at( std::size_t bytes_transferred = d.read_some_at(
offset + total_transferred, tmp, ec); offset + total_transferred, tmp, ec);
tmp.consume(bytes_transferred); tmp.consume(bytes_transferred);
total_transferred += bytes_transferred; total_transferred += bytes_transferred;
if (completion_condition(ec, total_transferred)) tmp.set_max_size(detail::adapt_completion_condition_result(
return total_transferred; completion_condition(ec, total_transferred)));
} }
ec = asio::error_code();
return total_transferred; return total_transferred;
} }
@ -151,8 +153,9 @@ namespace detail
{ {
total_transferred_ += bytes_transferred; total_transferred_ += bytes_transferred;
buffers_.consume(bytes_transferred); buffers_.consume(bytes_transferred);
if (completion_condition_(ec, total_transferred_) buffers_.set_max_size(detail::adapt_completion_condition_result(
|| buffers_.begin() == buffers_.end()) completion_condition_(ec, total_transferred_)));
if (buffers_.begin() == buffers_.end())
{ {
handler_(ec, total_transferred_); handler_(ec, total_transferred_);
} }
@ -214,6 +217,18 @@ inline void async_read_at(AsyncRandomAccessReadDevice& d,
{ {
asio::detail::consuming_buffers< asio::detail::consuming_buffers<
mutable_buffer, MutableBufferSequence> tmp(buffers); mutable_buffer, MutableBufferSequence> tmp(buffers);
asio::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())
{
d.get_io_service().post(detail::bind_handler(
handler, ec, total_transferred));
return;
}
d.async_read_some_at(offset, tmp, d.async_read_some_at(offset, tmp,
detail::read_at_handler<AsyncRandomAccessReadDevice, detail::read_at_handler<AsyncRandomAccessReadDevice,
MutableBufferSequence, CompletionCondition, ReadHandler>( MutableBufferSequence, CompletionCondition, ReadHandler>(
@ -253,15 +268,17 @@ namespace detail
{ {
total_transferred_ += bytes_transferred; total_transferred_ += bytes_transferred;
streambuf_.commit(bytes_transferred); streambuf_.commit(bytes_transferred);
if (streambuf_.size() == streambuf_.max_size() std::size_t max_size = detail::adapt_completion_condition_result(
|| completion_condition_(ec, total_transferred_)) completion_condition_(ec, total_transferred_));
std::size_t bytes_available = std::min<std::size_t>(512,
std::min<std::size_t>(max_size,
streambuf_.max_size() - streambuf_.size()));
if (bytes_available == 0)
{ {
handler_(ec, total_transferred_); handler_(ec, total_transferred_);
} }
else else
{ {
std::size_t bytes_available =
std::min<std::size_t>(512, streambuf_.max_size() - streambuf_.size());
stream_.async_read_some_at(offset_ + total_transferred_, stream_.async_read_some_at(offset_ + total_transferred_,
streambuf_.prepare(bytes_available), *this); streambuf_.prepare(bytes_available), *this);
} }
@ -313,8 +330,19 @@ inline void async_read_at(AsyncRandomAccessReadDevice& d,
boost::uint64_t offset, asio::basic_streambuf<Allocator>& b, boost::uint64_t offset, asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition, ReadHandler handler) CompletionCondition completion_condition, ReadHandler handler)
{ {
std::size_t bytes_available = asio::error_code ec;
std::min<std::size_t>(512, b.max_size() - b.size()); 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<std::size_t>(512,
std::min<std::size_t>(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), d.async_read_some_at(offset, b.prepare(bytes_available),
detail::read_at_streambuf_handler<AsyncRandomAccessReadDevice, Allocator, detail::read_at_streambuf_handler<AsyncRandomAccessReadDevice, Allocator,
CompletionCondition, ReadHandler>( CompletionCondition, ReadHandler>(

View File

@ -277,19 +277,16 @@ std::size_t read_until(SyncReadStream& s,
// Look for a match. // Look for a match.
std::pair<iterator, bool> result = match_condition(start, end); std::pair<iterator, bool> result = match_condition(start, end);
if (result.first != end) if (result.second)
{ {
if (result.second) // Full match. We're done.
{ ec = asio::error_code();
// Full match. We're done. return result.first - begin;
ec = asio::error_code(); }
return result.first - begin; else if (result.first != end)
} {
else // Partial match. Next search needs to start from beginning of match.
{ next_search_start = result.first - begin;
// Partial match. Next search needs to start from beginning of match.
next_search_start = result.first - begin;
}
} }
else else
{ {
@ -448,7 +445,7 @@ void async_read_until(AsyncReadStream& s,
// Found a match. We're done. // Found a match. We're done.
asio::error_code ec; asio::error_code ec;
std::size_t bytes = iter - begin + 1; std::size_t bytes = iter - begin + 1;
s.io_service().post(detail::bind_handler(handler, ec, bytes)); s.get_io_service().post(detail::bind_handler(handler, ec, bytes));
return; return;
} }
@ -456,7 +453,7 @@ void async_read_until(AsyncReadStream& s,
if (b.size() == b.max_size()) if (b.size() == b.max_size())
{ {
asio::error_code ec(error::not_found); asio::error_code ec(error::not_found);
s.io_service().post(detail::bind_handler(handler, ec, 0)); s.get_io_service().post(detail::bind_handler(handler, ec, 0));
return; return;
} }
@ -537,8 +534,8 @@ namespace detail
if (streambuf_.size() == streambuf_.max_size()) if (streambuf_.size() == streambuf_.max_size())
{ {
std::size_t bytes = 0; std::size_t bytes = 0;
asio::error_code ec(error::not_found); asio::error_code ec2(error::not_found);
handler_(ec, bytes); handler_(ec2, bytes);
return; return;
} }
@ -609,7 +606,7 @@ void async_read_until(AsyncReadStream& s,
// Full match. We're done. // Full match. We're done.
asio::error_code ec; asio::error_code ec;
std::size_t bytes = result.first - begin + delim.length(); std::size_t bytes = result.first - begin + delim.length();
s.io_service().post(detail::bind_handler(handler, ec, bytes)); s.get_io_service().post(detail::bind_handler(handler, ec, bytes));
return; return;
} }
else else
@ -628,7 +625,7 @@ void async_read_until(AsyncReadStream& s,
if (b.size() == b.max_size()) if (b.size() == b.max_size())
{ {
asio::error_code ec(error::not_found); asio::error_code ec(error::not_found);
s.io_service().post(detail::bind_handler(handler, ec, 0)); s.get_io_service().post(detail::bind_handler(handler, ec, 0));
return; return;
} }
@ -782,7 +779,7 @@ void async_read_until(AsyncReadStream& s,
// Full match. We're done. // Full match. We're done.
asio::error_code ec; asio::error_code ec;
std::size_t bytes = match_results[0].second - begin; std::size_t bytes = match_results[0].second - begin;
s.io_service().post(detail::bind_handler(handler, ec, bytes)); s.get_io_service().post(detail::bind_handler(handler, ec, bytes));
return; return;
} }
else else
@ -801,7 +798,7 @@ void async_read_until(AsyncReadStream& s,
if (b.size() == b.max_size()) if (b.size() == b.max_size())
{ {
asio::error_code ec(error::not_found); asio::error_code ec(error::not_found);
s.io_service().post(detail::bind_handler(handler, ec, 0)); s.get_io_service().post(detail::bind_handler(handler, ec, 0));
return; return;
} }
@ -857,20 +854,17 @@ namespace detail
// Look for a match. // Look for a match.
std::pair<iterator, bool> result = match_condition_(start, end); std::pair<iterator, bool> result = match_condition_(start, end);
if (result.first != end) if (result.second)
{ {
if (result.second) // Full match. We're done.
{ std::size_t bytes = result.first - begin;
// Full match. We're done. handler_(ec, bytes);
std::size_t bytes = result.first - begin; return;
handler_(ec, bytes); }
return; else if (result.first != end)
} {
else // Partial match. Next search needs to start from beginning of match.
{ next_search_start_ = result.first - begin;
// Partial match. Next search needs to start from beginning of match.
next_search_start_ = result.first - begin;
}
} }
else else
{ {
@ -950,21 +944,18 @@ void async_read_until(AsyncReadStream& s,
// Look for a match. // Look for a match.
std::size_t next_search_start; std::size_t next_search_start;
std::pair<iterator, bool> result = match_condition(begin, end); std::pair<iterator, bool> result = match_condition(begin, end);
if (result.first != end) if (result.second)
{ {
if (result.second) // Full match. We're done.
{ asio::error_code ec;
// Full match. We're done. std::size_t bytes = result.first - begin;
asio::error_code ec; s.get_io_service().post(detail::bind_handler(handler, ec, bytes));
std::size_t bytes = result.first - begin; return;
s.io_service().post(detail::bind_handler(handler, ec, bytes)); }
return; else if (result.first != end)
} {
else // Partial match. Next search needs to start from beginning of match.
{ next_search_start = result.first - begin;
// Partial match. Next search needs to start from beginning of match.
next_search_start = result.first - begin;
}
} }
else else
{ {
@ -976,7 +967,7 @@ void async_read_until(AsyncReadStream& s,
if (b.size() == b.max_size()) if (b.size() == b.max_size())
{ {
asio::error_code ec(error::not_found); asio::error_code ec(error::not_found);
s.io_service().post(detail::bind_handler(handler, ec, 0)); s.get_io_service().post(detail::bind_handler(handler, ec, 0));
return; return;
} }

View File

@ -32,18 +32,20 @@ template <typename SyncWriteStream, typename ConstBufferSequence,
std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec) CompletionCondition completion_condition, asio::error_code& ec)
{ {
ec = asio::error_code();
asio::detail::consuming_buffers< asio::detail::consuming_buffers<
const_buffer, ConstBufferSequence> tmp(buffers); const_buffer, ConstBufferSequence> tmp(buffers);
std::size_t total_transferred = 0; std::size_t total_transferred = 0;
tmp.set_max_size(detail::adapt_completion_condition_result(
completion_condition(ec, total_transferred)));
while (tmp.begin() != tmp.end()) while (tmp.begin() != tmp.end())
{ {
std::size_t bytes_transferred = s.write_some(tmp, ec); std::size_t bytes_transferred = s.write_some(tmp, ec);
tmp.consume(bytes_transferred); tmp.consume(bytes_transferred);
total_transferred += bytes_transferred; total_transferred += bytes_transferred;
if (completion_condition(ec, total_transferred)) tmp.set_max_size(detail::adapt_completion_condition_result(
return total_transferred; completion_condition(ec, total_transferred)));
} }
ec = asio::error_code();
return total_transferred; return total_transferred;
} }
@ -125,8 +127,9 @@ namespace detail
{ {
total_transferred_ += bytes_transferred; total_transferred_ += bytes_transferred;
buffers_.consume(bytes_transferred); buffers_.consume(bytes_transferred);
if (completion_condition_(ec, total_transferred_) buffers_.set_max_size(detail::adapt_completion_condition_result(
|| buffers_.begin() == buffers_.end()) completion_condition_(ec, total_transferred_)));
if (buffers_.begin() == buffers_.end())
{ {
handler_(ec, total_transferred_); handler_(ec, total_transferred_);
} }
@ -183,6 +186,18 @@ inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
{ {
asio::detail::consuming_buffers< asio::detail::consuming_buffers<
const_buffer, ConstBufferSequence> tmp(buffers); const_buffer, ConstBufferSequence> tmp(buffers);
asio::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, s.async_write_some(tmp,
detail::write_handler<AsyncWriteStream, ConstBufferSequence, detail::write_handler<AsyncWriteStream, ConstBufferSequence,
CompletionCondition, WriteHandler>( CompletionCondition, WriteHandler>(

View File

@ -33,19 +33,21 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d,
boost::uint64_t offset, const ConstBufferSequence& buffers, boost::uint64_t offset, const ConstBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec) CompletionCondition completion_condition, asio::error_code& ec)
{ {
ec = asio::error_code();
asio::detail::consuming_buffers< asio::detail::consuming_buffers<
const_buffer, ConstBufferSequence> tmp(buffers); const_buffer, ConstBufferSequence> tmp(buffers);
std::size_t total_transferred = 0; std::size_t total_transferred = 0;
tmp.set_max_size(detail::adapt_completion_condition_result(
completion_condition(ec, total_transferred)));
while (tmp.begin() != tmp.end()) while (tmp.begin() != tmp.end())
{ {
std::size_t bytes_transferred = d.write_some_at( std::size_t bytes_transferred = d.write_some_at(
offset + total_transferred, tmp, ec); offset + total_transferred, tmp, ec);
tmp.consume(bytes_transferred); tmp.consume(bytes_transferred);
total_transferred += bytes_transferred; total_transferred += bytes_transferred;
if (completion_condition(ec, total_transferred)) tmp.set_max_size(detail::adapt_completion_condition_result(
return total_transferred; completion_condition(ec, total_transferred)));
} }
ec = asio::error_code();
return total_transferred; return total_transferred;
} }
@ -135,8 +137,9 @@ namespace detail
{ {
total_transferred_ += bytes_transferred; total_transferred_ += bytes_transferred;
buffers_.consume(bytes_transferred); buffers_.consume(bytes_transferred);
if (completion_condition_(ec, total_transferred_) buffers_.set_max_size(detail::adapt_completion_condition_result(
|| buffers_.begin() == buffers_.end()) completion_condition_(ec, total_transferred_)));
if (buffers_.begin() == buffers_.end())
{ {
handler_(ec, total_transferred_); handler_(ec, total_transferred_);
} }
@ -196,6 +199,18 @@ inline void async_write_at(AsyncRandomAccessWriteDevice& d,
{ {
asio::detail::consuming_buffers< asio::detail::consuming_buffers<
const_buffer, ConstBufferSequence> tmp(buffers); const_buffer, ConstBufferSequence> tmp(buffers);
asio::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())
{
d.get_io_service().post(detail::bind_handler(
handler, ec, total_transferred));
return;
}
d.async_write_some_at(offset, tmp, d.async_write_some_at(offset, tmp,
detail::write_at_handler<AsyncRandomAccessWriteDevice, detail::write_at_handler<AsyncRandomAccessWriteDevice,
ConstBufferSequence, CompletionCondition, WriteHandler>( ConstBufferSequence, CompletionCondition, WriteHandler>(

View File

@ -134,6 +134,7 @@ private:
// The type of the platform-specific implementation. // The type of the platform-specific implementation.
#if defined(ASIO_HAS_IOCP) #if defined(ASIO_HAS_IOCP)
typedef detail::win_iocp_io_service impl_type; typedef detail::win_iocp_io_service impl_type;
friend class detail::win_iocp_overlapped_ptr;
#elif defined(ASIO_HAS_EPOLL) #elif defined(ASIO_HAS_EPOLL)
typedef detail::task_io_service<detail::epoll_reactor<false> > impl_type; typedef detail::task_io_service<detail::epoll_reactor<false> > impl_type;
#elif defined(ASIO_HAS_KQUEUE) #elif defined(ASIO_HAS_KQUEUE)

View File

@ -18,7 +18,9 @@
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
#include <climits>
#include <string> #include <string>
#include <stdexcept>
#include <boost/array.hpp> #include <boost/array.hpp>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp" #include "asio/detail/pop_options.hpp"
@ -55,6 +57,15 @@ public:
/// Construct an address from raw bytes. /// Construct an address from raw bytes.
explicit address_v4(const bytes_type& 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. using namespace std; // For memcpy.
memcpy(&addr_.s_addr, bytes.elems, 4); memcpy(&addr_.s_addr, bytes.elems, 4);
} }
@ -62,6 +73,14 @@ public:
/// Construct an address from a unsigned long in host byte order. /// Construct an address from a unsigned long in host byte order.
explicit address_v4(unsigned long addr) 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 = asio::detail::socket_ops::host_to_network_long(addr); addr_.s_addr = asio::detail::socket_ops::host_to_network_long(addr);
} }

View File

@ -62,6 +62,17 @@ public:
explicit address_v6(const bytes_type& bytes, unsigned long scope_id = 0) explicit address_v6(const bytes_type& bytes, unsigned long scope_id = 0)
: scope_id_(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. using namespace std; // For memcpy.
memcpy(addr_.s6_addr, bytes.elems, 16); memcpy(addr_.s6_addr, bytes.elems, 16);
} }
@ -165,7 +176,11 @@ public:
address_v4 to_v4() const address_v4 to_v4() const
{ {
if (!is_v4_mapped() && !is_v4_compatible()) if (!is_v4_mapped() && !is_v4_compatible())
throw std::bad_cast(); {
std::bad_cast ex;
boost::throw_exception(ex);
}
address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12], address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12],
addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } }; addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } };
return address_v4(v4_bytes); return address_v4(v4_bytes);

View File

@ -75,7 +75,7 @@ public:
return this->service.cancel(this->implementation); return this->service.cancel(this->implementation);
} }
/// Resolve a query to a list of entries. /// Perform forward resolution of a query to a list of entries.
/** /**
* This function is used to resolve a query into a list of endpoint entries. * This function is used to resolve a query into a list of endpoint entries.
* *
@ -99,7 +99,7 @@ public:
return i; return i;
} }
/// Resolve a query to a list of entries. /// Perform forward resolution of a query to a list of entries.
/** /**
* This function is used to resolve a query into a list of endpoint entries. * This function is used to resolve a query into a list of endpoint entries.
* *
@ -121,7 +121,7 @@ public:
return this->service.resolve(this->implementation, q, ec); return this->service.resolve(this->implementation, q, ec);
} }
/// Asynchronously resolve a query to a list of entries. /// Asynchronously perform forward resolution of a query to a list of entries.
/** /**
* This function is used to asynchronously resolve a query into a list of * This function is used to asynchronously resolve a query into a list of
* endpoint entries. * endpoint entries.
@ -153,7 +153,7 @@ public:
return this->service.async_resolve(this->implementation, q, handler); return this->service.async_resolve(this->implementation, q, handler);
} }
/// Resolve an endpoint to a list of entries. /// Perform reverse resolution of an endpoint to a list of entries.
/** /**
* This function is used to resolve an endpoint into a list of endpoint * This function is used to resolve an endpoint into a list of endpoint
* entries. * entries.
@ -179,7 +179,7 @@ public:
return i; return i;
} }
/// Resolve an endpoint to a list of entries. /// Perform reverse resolution of an endpoint to a list of entries.
/** /**
* This function is used to resolve an endpoint into a list of endpoint * This function is used to resolve an endpoint into a list of endpoint
* entries. * entries.
@ -203,7 +203,8 @@ public:
return this->service.resolve(this->implementation, e, ec); return this->service.resolve(this->implementation, e, ec);
} }
/// Asynchronously resolve an endpoint to a list of entries. /// Asynchronously perform reverse resolution of an endpoint to a list of
/// entries.
/** /**
* This function is used to asynchronously resolve an endpoint into a list of * This function is used to asynchronously resolve an endpoint into a list of
* endpoint entries. * endpoint entries.

View File

@ -40,7 +40,7 @@ public:
#if defined(__sun) || defined(__osf__) #if defined(__sun) || defined(__osf__)
typedef unsigned char ipv4_value_type; typedef unsigned char ipv4_value_type;
typedef unsigned char ipv6_value_type; typedef unsigned char ipv6_value_type;
#elif defined(_AIX) || defined(__hpux) #elif defined(_AIX) || defined(__hpux) || defined(__QNXNTO__)
typedef unsigned char ipv4_value_type; typedef unsigned char ipv4_value_type;
typedef unsigned int ipv6_value_type; typedef unsigned int ipv6_value_type;
#else #else

View File

@ -69,17 +69,19 @@ public:
# else # else
BOOST_STATIC_CONSTANT(int, numeric_service = 0); BOOST_STATIC_CONSTANT(int, numeric_service = 0);
# endif # endif
# if defined(AI_V4MAPPED) // 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); BOOST_STATIC_CONSTANT(int, v4_mapped = AI_V4MAPPED);
# else # else
BOOST_STATIC_CONSTANT(int, v4_mapped = 0); BOOST_STATIC_CONSTANT(int, v4_mapped = 0);
# endif # endif
# if defined(AI_ALL) # if defined(AI_ALL) && !defined(__QNXNTO__)
BOOST_STATIC_CONSTANT(int, all_matching = AI_ALL); BOOST_STATIC_CONSTANT(int, all_matching = AI_ALL);
# else # else
BOOST_STATIC_CONSTANT(int, all_matching = 0); BOOST_STATIC_CONSTANT(int, all_matching = 0);
# endif # endif
# if defined(AI_ADDRCONFIG) # if defined(AI_ADDRCONFIG) && !defined(__QNXNTO__)
BOOST_STATIC_CONSTANT(int, address_configured = AI_ADDRCONFIG); BOOST_STATIC_CONSTANT(int, address_configured = AI_ADDRCONFIG);
# else # else
BOOST_STATIC_CONSTANT(int, address_configured = 0); BOOST_STATIC_CONSTANT(int, address_configured = 0);

View File

@ -148,7 +148,7 @@ public:
- offsetof(asio::detail::sockaddr_un_type, sun_path); - offsetof(asio::detail::sockaddr_un_type, sun_path);
// The path returned by the operating system may be NUL-terminated. // The path returned by the operating system may be NUL-terminated.
if (path_length_ > 0 && data_.local.sun_path[path_length_] == 0) if (path_length_ > 0 && data_.local.sun_path[path_length_ - 1] == 0)
--path_length_; --path_length_;
} }
} }

View File

@ -99,6 +99,20 @@ public:
return *this; return *this;
} }
/// Get a const reference to the lowest layer.
/**
* This function returns a const reference to the lowest layer in a stack of
* layers. Since a basic_descriptor cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A const reference to the lowest layer in the stack of layers.
* Ownership is not transferred to the caller.
*/
const lowest_layer_type& lowest_layer() const
{
return *this;
}
/// Assign an existing native descriptor to the descriptor. /// Assign an existing native descriptor to the descriptor.
/* /*
* This function opens the descriptor to hold an existing native descriptor. * This function opens the descriptor to hold an existing native descriptor.

View File

@ -45,7 +45,7 @@ namespace asio {
* *
* @li An error occurred. * @li An error occurred.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* read_some function. * read_some function.
* *
* @param s The stream from which the data is to be read. The type must support * @param s The stream from which the data is to be read. The type must support
@ -84,7 +84,7 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers);
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* read_some function. * read_some function.
* *
* @param s The stream from which the data is to be read. The type must support * @param s The stream from which the data is to be read. The type must support
@ -97,15 +97,16 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers);
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object * whether the read operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* const asio::error_code& error, // Result of latest read_some * // Result of latest read_some operation.
* // operation. * const asio::error_code& error,
* *
* std::size_t bytes_transferred // Number of bytes transferred * // Number of bytes transferred so far.
* // so far. * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the read operation is complete. False * A return value of 0 indicates that the read operation is complete. A non-zero
* indicates that further calls to the stream's read_some function are required. * return value indicates the maximum number of bytes to be read on the next
* call to the stream's read_some function.
* *
* @returns The number of bytes transferred. * @returns The number of bytes transferred.
* *
@ -134,7 +135,7 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* read_some function. * read_some function.
* *
* @param s The stream from which the data is to be read. The type must support * @param s The stream from which the data is to be read. The type must support
@ -147,15 +148,16 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object * whether the read operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* const asio::error_code& error, // Result of latest read_some * // Result of latest read_some operation.
* // operation. * const asio::error_code& error,
* *
* std::size_t bytes_transferred // Number of bytes transferred * // Number of bytes transferred so far.
* // so far. * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the read operation is complete. False * A return value of 0 indicates that the read operation is complete. A non-zero
* indicates that further calls to the stream's read_some function are required. * return value indicates the maximum number of bytes to be read on the next
* call to the stream's read_some function.
* *
* @param ec Set to indicate what error occurred, if any. * @param ec Set to indicate what error occurred, if any.
* *
@ -174,7 +176,7 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
* *
* @li An error occurred. * @li An error occurred.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* read_some function. * read_some function.
* *
* @param s The stream from which the data is to be read. The type must support * @param s The stream from which the data is to be read. The type must support
@ -201,7 +203,7 @@ std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b);
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* read_some function. * read_some function.
* *
* @param s The stream from which the data is to be read. The type must support * @param s The stream from which the data is to be read. The type must support
@ -212,15 +214,16 @@ std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b);
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object * whether the read operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* const asio::error_code& error, // Result of latest read_some * // Result of latest read_some operation.
* // operation. * const asio::error_code& error,
* *
* std::size_t bytes_transferred // Number of bytes transferred * // Number of bytes transferred so far.
* // so far. * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the read operation is complete. False * A return value of 0 indicates that the read operation is complete. A non-zero
* indicates that further calls to the stream's read_some function are required. * return value indicates the maximum number of bytes to be read on the next
* call to the stream's read_some function.
* *
* @returns The number of bytes transferred. * @returns The number of bytes transferred.
* *
@ -238,7 +241,7 @@ std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* read_some function. * read_some function.
* *
* @param s The stream from which the data is to be read. The type must support * @param s The stream from which the data is to be read. The type must support
@ -249,15 +252,16 @@ std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object * whether the read operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* const asio::error_code& error, // Result of latest read_some * // Result of latest read_some operation.
* // operation. * const asio::error_code& error,
* *
* std::size_t bytes_transferred // Number of bytes transferred * // Number of bytes transferred so far.
* // so far. * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the read operation is complete. False * A return value of 0 indicates that the read operation is complete. A non-zero
* indicates that further calls to the stream's read_some function are required. * return value indicates the maximum number of bytes to be read on the next
* call to the stream's read_some function.
* *
* @param ec Set to indicate what error occurred, if any. * @param ec Set to indicate what error occurred, if any.
* *
@ -291,7 +295,7 @@ std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b,
* *
* @li An error occurred. * @li An error occurred.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* async_read_some function. * async_read_some function.
* *
* @param s The stream from which the data is to be read. The type must support * @param s The stream from which the data is to be read. The type must support
@ -365,16 +369,16 @@ void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object * whether the read operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* const asio::error_code& error, // Result of latest read_some * // Result of latest async_read_some operation.
* // operation. * const asio::error_code& error,
* *
* std::size_t bytes_transferred // Number of bytes transferred * // Number of bytes transferred so far.
* // so far. * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the read operation is complete. False * A return value of 0 indicates that the read operation is complete. A non-zero
* indicates that further calls to the stream's async_read_some function are * return value indicates the maximum number of bytes to be read on the next
* required. * call to the stream's async_read_some function.
* *
* @param handler The handler to be called when the read operation completes. * @param handler The handler to be called when the read operation completes.
* Copies will be made of the handler as required. The function signature of the * Copies will be made of the handler as required. The function signature of the
@ -418,7 +422,7 @@ void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
* *
* @li An error occurred. * @li An error occurred.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* async_read_some function. * async_read_some function.
* *
* @param s The stream from which the data is to be read. The type must support * @param s The stream from which the data is to be read. The type must support
@ -465,7 +469,7 @@ void async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* async_read_some function. * async_read_some function.
* *
* @param s The stream from which the data is to be read. The type must support * @param s The stream from which the data is to be read. The type must support
@ -478,16 +482,16 @@ void async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object * whether the read operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* const asio::error_code& error, // Result of latest read_some * // Result of latest async_read_some operation.
* // operation. * const asio::error_code& error,
* *
* std::size_t bytes_transferred // Number of bytes transferred * // Number of bytes transferred so far.
* // so far. * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the read operation is complete. False * A return value of 0 indicates that the read operation is complete. A non-zero
* indicates that further calls to the stream's async_read_some function are * return value indicates the maximum number of bytes to be read on the next
* required. * call to the stream's async_read_some function.
* *
* @param handler The handler to be called when the read operation completes. * @param handler The handler to be called when the read operation completes.
* Copies will be made of the handler as required. The function signature of the * Copies will be made of the handler as required. The function signature of the

View File

@ -48,7 +48,7 @@ namespace asio {
* *
* @li An error occurred. * @li An error occurred.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* read_some_at function. * read_some_at function.
* *
* @param d The device from which the data is to be read. The type must support * @param d The device from which the data is to be read. The type must support
@ -92,7 +92,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* read_some_at function. * read_some_at function.
* *
* @param d The device from which the data is to be read. The type must support * @param d The device from which the data is to be read. The type must support
@ -107,16 +107,16 @@ std::size_t read_at(SyncRandomAccessReadDevice& d,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object * whether the read operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* // Result of latest read_some_at operation. * // Result of latest read_some_at operation.
* const asio::error_code& error, * const asio::error_code& error,
* *
* // Number of bytes transferred so far. * // Number of bytes transferred so far.
* std::size_t bytes_transferred * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the read operation is complete. False * A return value of 0 indicates that the read operation is complete. A non-zero
* indicates that further calls to the device's read_some_at function are * return value indicates the maximum number of bytes to be read on the next
* required. * call to the device's read_some_at function.
* *
* @returns The number of bytes transferred. * @returns The number of bytes transferred.
* *
@ -148,7 +148,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* read_some_at function. * read_some_at function.
* *
* @param d The device from which the data is to be read. The type must support * @param d The device from which the data is to be read. The type must support
@ -163,16 +163,16 @@ std::size_t read_at(SyncRandomAccessReadDevice& d,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object * whether the read operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* const asio::error_code& error, // Result of latest read_some_at * // Result of latest read_some_at operation.
* // operation. * const asio::error_code& error,
* *
* std::size_t bytes_transferred // Number of bytes transferred * // Number of bytes transferred so far.
* // so far. * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the read operation is complete. False * A return value of 0 indicates that the read operation is complete. A non-zero
* indicates that further calls to the device's read_some_at function are * return value indicates the maximum number of bytes to be read on the next
* required. * call to the device's read_some_at function.
* *
* @param ec Set to indicate what error occurred, if any. * @param ec Set to indicate what error occurred, if any.
* *
@ -194,7 +194,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d,
* *
* @li An error occurred. * @li An error occurred.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* read_some_at function. * read_some_at function.
* *
* @param d The device from which the data is to be read. The type must support * @param d The device from which the data is to be read. The type must support
@ -226,7 +226,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* read_some_at function. * read_some_at function.
* *
* @param d The device from which the data is to be read. The type must support * @param d The device from which the data is to be read. The type must support
@ -239,16 +239,16 @@ std::size_t read_at(SyncRandomAccessReadDevice& d,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object * whether the read operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* // Result of latest read_some_at operation. * // Result of latest read_some_at operation.
* const asio::error_code& error, * const asio::error_code& error,
* *
* // Number of bytes transferred so far. * // Number of bytes transferred so far.
* std::size_t bytes_transferred * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the read operation is complete. False * A return value of 0 indicates that the read operation is complete. A non-zero
* indicates that further calls to the device's read_some_at function are * return value indicates the maximum number of bytes to be read on the next
* required. * call to the device's read_some_at function.
* *
* @returns The number of bytes transferred. * @returns The number of bytes transferred.
* *
@ -269,7 +269,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* read_some_at function. * read_some_at function.
* *
* @param d The device from which the data is to be read. The type must support * @param d The device from which the data is to be read. The type must support
@ -282,16 +282,16 @@ std::size_t read_at(SyncRandomAccessReadDevice& d,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object * whether the read operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* // Result of latest read_some_at operation. * // Result of latest read_some_at operation.
* const asio::error_code& error, * const asio::error_code& error,
* *
* // Number of bytes transferred so far. * // Number of bytes transferred so far.
* std::size_t bytes_transferred * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the read operation is complete. False * A return value of 0 indicates that the read operation is complete. A non-zero
* indicates that further calls to the device's read_some_at function are * return value indicates the maximum number of bytes to be read on the next
* required. * call to the device's read_some_at function.
* *
* @param ec Set to indicate what error occurred, if any. * @param ec Set to indicate what error occurred, if any.
* *
@ -326,7 +326,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d,
* *
* @li An error occurred. * @li An error occurred.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* async_read_some_at function. * async_read_some_at function.
* *
* @param d The device from which the data is to be read. The type must support * @param d The device from which the data is to be read. The type must support
@ -404,16 +404,16 @@ void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object * whether the read operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* // Result of latest read_some_at operation. * // Result of latest async_read_some_at operation.
* const asio::error_code& error, * const asio::error_code& error,
* *
* // Number of bytes transferred so far. * // Number of bytes transferred so far.
* std::size_t bytes_transferred * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the read operation is complete. False * A return value of 0 indicates that the read operation is complete. A non-zero
* indicates that further calls to the device's async_read_some_at function are * return value indicates the maximum number of bytes to be read on the next
* required. * call to the device's async_read_some_at function.
* *
* @param handler The handler to be called when the read operation completes. * @param handler The handler to be called when the read operation completes.
* Copies will be made of the handler as required. The function signature of the * Copies will be made of the handler as required. The function signature of the
@ -458,7 +458,7 @@ void async_read_at(AsyncRandomAccessReadDevice& d,
* *
* @li An error occurred. * @li An error occurred.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* async_read_some_at function. * async_read_some_at function.
* *
* @param d The device from which the data is to be read. The type must support * @param d The device from which the data is to be read. The type must support
@ -508,7 +508,7 @@ void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* async_read_some_at function. * async_read_some_at function.
* *
* @param d The device from which the data is to be read. The type must support * @param d The device from which the data is to be read. The type must support
@ -523,16 +523,16 @@ void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the read operation is complete. The signature of the function object * whether the read operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* // Result of latest read_some_at operation. * // Result of latest async_read_some_at operation.
* const asio::error_code& error, * const asio::error_code& error,
* *
* // Number of bytes transferred so far. * // Number of bytes transferred so far.
* std::size_t bytes_transferred * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the read operation is complete. False * A return value of 0 indicates that the read operation is complete. A non-zero
* indicates that further calls to the device's async_read_some_at function are * return value indicates the maximum number of bytes to be read on the next
* required. * call to the device's async_read_some_at function.
* *
* @param handler The handler to be called when the read operation completes. * @param handler The handler to be called when the read operation completes.
* Copies will be made of the handler as required. The function signature of the * Copies will be made of the handler as required. The function signature of the

View File

@ -24,6 +24,7 @@
#include <boost/type_traits/is_function.hpp> #include <boost/type_traits/is_function.hpp>
#include <boost/type_traits/remove_pointer.hpp> #include <boost/type_traits/remove_pointer.hpp>
#include <boost/utility/enable_if.hpp> #include <boost/utility/enable_if.hpp>
#include <boost/detail/workaround.hpp>
#include <string> #include <string>
#include "asio/detail/pop_options.hpp" #include "asio/detail/pop_options.hpp"
@ -34,6 +35,20 @@ namespace asio {
namespace detail namespace detail
{ {
#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610))
template <typename T>
struct has_result_type
{
template <typename U> struct inner
{
struct big { char a[100]; };
static big helper(U, ...);
static char helper(U, typename U::result_type* = 0);
};
static const T& ref();
enum { value = (sizeof((inner<const T&>::helper)((ref)())) == 1) };
};
#else // BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610))
template <typename T> template <typename T>
struct has_result_type struct has_result_type
{ {
@ -43,6 +58,7 @@ namespace detail
static const T& ref(); static const T& ref();
enum { value = (sizeof((helper)((ref)())) == 1) }; enum { value = (sizeof((helper)((ref)())) == 1) };
}; };
#endif // BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610))
} // namespace detail } // namespace detail
/// Type trait used to determine whether a type can be used as a match condition /// Type trait used to determine whether a type can be used as a match condition

View File

@ -308,9 +308,9 @@ public:
::BIO_free(bio); ::BIO_free(bio);
int result = ::SSL_CTX_set_tmp_dh(impl, dh); int result = ::SSL_CTX_set_tmp_dh(impl, dh);
::DH_free(dh);
if (result != 1) if (result != 1)
{ {
::DH_free(dh);
ec = asio::error::invalid_argument; ec = asio::error::invalid_argument;
return ec; return ec;
} }

View File

@ -21,6 +21,7 @@
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
#include <vector> #include <vector>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include "asio/detail/pop_options.hpp" #include "asio/detail/pop_options.hpp"
@ -86,11 +87,15 @@ private:
private: private:
static unsigned long openssl_id_func() static unsigned long openssl_id_func()
{ {
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
return ::GetCurrentThreadId();
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
void* id = instance()->thread_id_; void* id = instance()->thread_id_;
if (id == 0) if (id == 0)
instance()->thread_id_ = id = &id; // Ugh. instance()->thread_id_ = id = &id; // Ugh.
BOOST_ASSERT(sizeof(unsigned long) >= sizeof(void*)); BOOST_ASSERT(sizeof(unsigned long) >= sizeof(void*));
return reinterpret_cast<unsigned long>(id); return reinterpret_cast<unsigned long>(id);
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
} }
static void openssl_locking_func(int mode, int n, static void openssl_locking_func(int mode, int n,
@ -105,8 +110,10 @@ private:
// Mutexes to be used in locking callbacks. // Mutexes to be used in locking callbacks.
std::vector<boost::shared_ptr<asio::detail::mutex> > mutexes_; std::vector<boost::shared_ptr<asio::detail::mutex> > mutexes_;
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
// The thread identifiers to be used by openssl. // The thread identifiers to be used by openssl.
asio::detail::tss_ptr<void> thread_id_; asio::detail::tss_ptr<void> thread_id_;
#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
}; };
public: public:

View File

@ -158,6 +158,10 @@ public:
0; 0;
int sys_error_code = ERR_get_error(); int sys_error_code = ERR_get_error();
if (error_code == SSL_ERROR_SSL)
return handler_(asio::error_code(
error_code, asio::error::get_ssl_category()), rc);
bool is_read_needed = (error_code == SSL_ERROR_WANT_READ); bool is_read_needed = (error_code == SSL_ERROR_WANT_READ);
bool is_write_needed = (error_code == SSL_ERROR_WANT_WRITE || bool is_write_needed = (error_code == SSL_ERROR_WANT_WRITE ||
::BIO_ctrl_pending( ssl_bio_ )); ::BIO_ctrl_pending( ssl_bio_ ));

View File

@ -336,7 +336,7 @@ public:
buffer_size = max_buffer_size; buffer_size = max_buffer_size;
boost::function<int (SSL*)> send_func = boost::function<int (SSL*)> send_func =
boost::bind(&::SSL_write, boost::arg<1>(), boost::bind(boost::type<int>(), &::SSL_write, boost::arg<1>(),
asio::buffer_cast<const void*>(*buffers.begin()), asio::buffer_cast<const void*>(*buffers.begin()),
static_cast<int>(buffer_size)); static_cast<int>(buffer_size));
openssl_operation<Stream> op( openssl_operation<Stream> op(
@ -372,7 +372,7 @@ public:
buffer_size = max_buffer_size; buffer_size = max_buffer_size;
boost::function<int (SSL*)> send_func = boost::function<int (SSL*)> send_func =
boost::bind(&::SSL_write, boost::arg<1>(), boost::bind(boost::type<int>(), &::SSL_write, boost::arg<1>(),
asio::buffer_cast<const void*>(*buffers.begin()), asio::buffer_cast<const void*>(*buffers.begin()),
static_cast<int>(buffer_size)); static_cast<int>(buffer_size));
@ -410,7 +410,7 @@ public:
buffer_size = max_buffer_size; buffer_size = max_buffer_size;
boost::function<int (SSL*)> recv_func = boost::function<int (SSL*)> recv_func =
boost::bind(&::SSL_read, boost::arg<1>(), boost::bind(boost::type<int>(), &::SSL_read, boost::arg<1>(),
asio::buffer_cast<void*>(*buffers.begin()), asio::buffer_cast<void*>(*buffers.begin()),
static_cast<int>(buffer_size)); static_cast<int>(buffer_size));
openssl_operation<Stream> op(recv_func, openssl_operation<Stream> op(recv_func,
@ -446,7 +446,7 @@ public:
buffer_size = max_buffer_size; buffer_size = max_buffer_size;
boost::function<int (SSL*)> recv_func = boost::function<int (SSL*)> recv_func =
boost::bind(&::SSL_read, boost::arg<1>(), boost::bind(boost::type<int>(), &::SSL_read, boost::arg<1>(),
asio::buffer_cast<void*>(*buffers.begin()), asio::buffer_cast<void*>(*buffers.begin()),
static_cast<int>(buffer_size)); static_cast<int>(buffer_size));

View File

@ -149,6 +149,19 @@ public:
return next_layer_.lowest_layer(); return next_layer_.lowest_layer();
} }
/// Get a const reference to the lowest layer.
/**
* This function returns a const reference to the lowest layer in a stack of
* stream layers.
*
* @return A const reference to the lowest layer in the stack of stream
* layers. Ownership is not transferred to the caller.
*/
const lowest_layer_type& lowest_layer() const
{
return next_layer_.lowest_layer();
}
/// Get the underlying implementation in the native type. /// Get the underlying implementation in the native type.
/** /**
* This function may be used to obtain the underlying implementation of the * This function may be used to obtain the underlying implementation of the

View File

@ -58,7 +58,7 @@ public:
*/ */
template <typename Function> template <typename Function>
explicit thread(Function f) explicit thread(Function f)
: impl_(f, asio::detail::thread::external) : impl_(f)
{ {
} }

View File

@ -18,6 +18,6 @@
// ASIO_VERSION % 100 is the sub-minor version // ASIO_VERSION % 100 is the sub-minor version
// ASIO_VERSION / 100 % 1000 is the minor version // ASIO_VERSION / 100 % 1000 is the minor version
// ASIO_VERSION / 100000 is the major version // ASIO_VERSION / 100000 is the major version
#define ASIO_VERSION 100100 // 1.1.0 #define ASIO_VERSION 100401 // 1.4.1
#endif // ASIO_VERSION_HPP #endif // ASIO_VERSION_HPP

View File

@ -94,6 +94,20 @@ public:
return *this; return *this;
} }
/// Get a const reference to the lowest layer.
/**
* This function returns a const reference to the lowest layer in a stack of
* layers. Since a basic_handle cannot contain any further layers, it simply
* returns a reference to itself.
*
* @return A const reference to the lowest layer in the stack of layers.
* Ownership is not transferred to the caller.
*/
const lowest_layer_type& lowest_layer() const
{
return *this;
}
/// Assign an existing native handle to the handle. /// Assign an existing native handle to the handle.
/* /*
* This function opens the handle to hold an existing native handle. * This function opens the handle to hold an existing native handle.

View File

@ -44,7 +44,7 @@ namespace asio {
* *
* @li An error occurred. * @li An error occurred.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* write_some function. * write_some function.
* *
* @param s The stream to which the data is to be written. The type must support * @param s The stream to which the data is to be written. The type must support
@ -83,7 +83,7 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers);
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* write_some function. * write_some function.
* *
* @param s The stream to which the data is to be written. The type must support * @param s The stream to which the data is to be written. The type must support
@ -96,16 +96,16 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers);
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object * whether the write operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* const asio::error_code& error, // Result of latest write_some * // Result of latest write_some operation.
* // operation. * const asio::error_code& error,
* *
* std::size_t bytes_transferred // Number of bytes transferred * // Number of bytes transferred so far.
* // so far. * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the write operation is complete. False * A return value of 0 indicates that the write operation is complete. A
* indicates that further calls to the stream's write_some function are * non-zero return value indicates the maximum number of bytes to be written on
* required. * the next call to the stream's write_some function.
* *
* @returns The number of bytes transferred. * @returns The number of bytes transferred.
* *
@ -134,7 +134,7 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* write_some function. * write_some function.
* *
* @param s The stream to which the data is to be written. The type must support * @param s The stream to which the data is to be written. The type must support
@ -147,16 +147,16 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object * whether the write operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* const asio::error_code& error, // Result of latest write_some * // Result of latest write_some operation.
* // operation. * const asio::error_code& error,
* *
* std::size_t bytes_transferred // Number of bytes transferred * // Number of bytes transferred so far.
* // so far. * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the write operation is complete. False * A return value of 0 indicates that the write operation is complete. A
* indicates that further calls to the stream's write_some function are * non-zero return value indicates the maximum number of bytes to be written on
* required. * the next call to the stream's write_some function.
* *
* @param ec Set to indicate what error occurred, if any. * @param ec Set to indicate what error occurred, if any.
* *
@ -177,7 +177,7 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
* *
* @li An error occurred. * @li An error occurred.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* write_some function. * write_some function.
* *
* @param s The stream to which the data is to be written. The type must support * @param s The stream to which the data is to be written. The type must support
@ -206,7 +206,7 @@ std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b);
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* write_some function. * write_some function.
* *
* @param s The stream to which the data is to be written. The type must support * @param s The stream to which the data is to be written. The type must support
@ -217,16 +217,16 @@ std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b);
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object * whether the write operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* const asio::error_code& error, // Result of latest write_some * // Result of latest write_some operation.
* // operation. * const asio::error_code& error,
* *
* std::size_t bytes_transferred // Number of bytes transferred * // Number of bytes transferred so far.
* // so far. * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the write operation is complete. False * A return value of 0 indicates that the write operation is complete. A
* indicates that further calls to the stream's write_some function are * non-zero return value indicates the maximum number of bytes to be written on
* required. * the next call to the stream's write_some function.
* *
* @returns The number of bytes transferred. * @returns The number of bytes transferred.
* *
@ -246,7 +246,7 @@ std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* write_some function. * write_some function.
* *
* @param s The stream to which the data is to be written. The type must support * @param s The stream to which the data is to be written. The type must support
@ -257,16 +257,16 @@ std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object * whether the write operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* const asio::error_code& error, // Result of latest write_some * // Result of latest write_some operation.
* // operation. * const asio::error_code& error,
* *
* std::size_t bytes_transferred // Number of bytes transferred * // Number of bytes transferred so far.
* // so far. * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the write operation is complete. False * A return value of 0 indicates that the write operation is complete. A
* indicates that further calls to the stream's write_some function are * non-zero return value indicates the maximum number of bytes to be written on
* required. * the next call to the stream's write_some function.
* *
* @param ec Set to indicate what error occurred, if any. * @param ec Set to indicate what error occurred, if any.
* *
@ -300,7 +300,7 @@ std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b,
* *
* @li An error occurred. * @li An error occurred.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* async_write_some function. * async_write_some function.
* *
* @param s The stream to which the data is to be written. The type must support * @param s The stream to which the data is to be written. The type must support
@ -354,7 +354,7 @@ void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* async_write_some function. * async_write_some function.
* *
* @param s The stream to which the data is to be written. The type must support * @param s The stream to which the data is to be written. The type must support
@ -368,16 +368,16 @@ void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object * whether the write operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* const asio::error_code& error, // Result of latest write_some * // Result of latest async_write_some operation.
* // operation. * const asio::error_code& error,
* *
* std::size_t bytes_transferred // Number of bytes transferred * // Number of bytes transferred so far.
* // so far. * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the write operation is complete. False * A return value of 0 indicates that the write operation is complete. A
* indicates that further calls to the stream's async_write_some function are * non-zero return value indicates the maximum number of bytes to be written on
* required. * the next call to the stream's async_write_some function.
* *
* @param handler The handler to be called when the write operation completes. * @param handler The handler to be called when the write operation completes.
* Copies will be made of the handler as required. The function signature of the * Copies will be made of the handler as required. The function signature of the
@ -422,7 +422,7 @@ void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
* *
* @li An error occurred. * @li An error occurred.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* async_write_some function. * async_write_some function.
* *
* @param s The stream to which the data is to be written. The type must support * @param s The stream to which the data is to be written. The type must support
@ -464,7 +464,7 @@ void async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the stream's * This operation is implemented in terms of zero or more calls to the stream's
* async_write_some function. * async_write_some function.
* *
* @param s The stream to which the data is to be written. The type must support * @param s The stream to which the data is to be written. The type must support
@ -477,16 +477,16 @@ void async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object * whether the write operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* const asio::error_code& error, // Result of latest write_some * // Result of latest async_write_some operation.
* // operation. * const asio::error_code& error,
* *
* std::size_t bytes_transferred // Number of bytes transferred * // Number of bytes transferred so far.
* // so far. * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the write operation is complete. False * A return value of 0 indicates that the write operation is complete. A
* indicates that further calls to the stream's async_write_some function are * non-zero return value indicates the maximum number of bytes to be written on
* required. * the next call to the stream's async_write_some function.
* *
* @param handler The handler to be called when the write operation completes. * @param handler The handler to be called when the write operation completes.
* Copies will be made of the handler as required. The function signature of the * Copies will be made of the handler as required. The function signature of the

View File

@ -46,7 +46,7 @@ namespace asio {
* *
* @li An error occurred. * @li An error occurred.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* write_some_at function. * write_some_at function.
* *
* @param d The device to which the data is to be written. The type must support * @param d The device to which the data is to be written. The type must support
@ -89,7 +89,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* write_some_at function. * write_some_at function.
* *
* @param d The device to which the data is to be written. The type must support * @param d The device to which the data is to be written. The type must support
@ -104,16 +104,16 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object * whether the write operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* // Result of latest write_some_at operation. * // Result of latest write_some_at operation.
* const asio::error_code& error, * const asio::error_code& error,
* *
* // Number of bytes transferred so far. * // Number of bytes transferred so far.
* std::size_t bytes_transferred * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the write operation is complete. False * A return value of 0 indicates that the write operation is complete. A
* indicates that further calls to the device's write_some_at function are * non-zero return value indicates the maximum number of bytes to be written on
* required. * the next call to the device's write_some_at function.
* *
* @returns The number of bytes transferred. * @returns The number of bytes transferred.
* *
@ -144,7 +144,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* write_some_at function. * write_some_at function.
* *
* @param d The device to which the data is to be written. The type must support * @param d The device to which the data is to be written. The type must support
@ -159,16 +159,16 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object * whether the write operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* // Result of latest write_some_at operation. * // Result of latest write_some_at operation.
* const asio::error_code& error, * const asio::error_code& error,
* *
* // Number of bytes transferred so far. * // Number of bytes transferred so far.
* std::size_t bytes_transferred * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the write operation is complete. False * A return value of 0 indicates that the write operation is complete. A
* indicates that further calls to the device's write_some_at function are * non-zero return value indicates the maximum number of bytes to be written on
* required. * the next call to the device's write_some_at function.
* *
* @param ec Set to indicate what error occurred, if any. * @param ec Set to indicate what error occurred, if any.
* *
@ -191,7 +191,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d,
* *
* @li An error occurred. * @li An error occurred.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* write_some_at function. * write_some_at function.
* *
* @param d The device to which the data is to be written. The type must support * @param d The device to which the data is to be written. The type must support
@ -224,7 +224,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* write_some_at function. * write_some_at function.
* *
* @param d The device to which the data is to be written. The type must support * @param d The device to which the data is to be written. The type must support
@ -237,16 +237,16 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object * whether the write operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* // Result of latest write_some_at operation. * // Result of latest write_some_at operation.
* const asio::error_code& error, * const asio::error_code& error,
* *
* // Number of bytes transferred so far. * // Number of bytes transferred so far.
* std::size_t bytes_transferred * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the write operation is complete. False * A return value of 0 indicates that the write operation is complete. A
* indicates that further calls to the device's write_some_at function are * non-zero return value indicates the maximum number of bytes to be written on
* required. * the next call to the device's write_some_at function.
* *
* @returns The number of bytes transferred. * @returns The number of bytes transferred.
* *
@ -267,7 +267,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* write_some_at function. * write_some_at function.
* *
* @param d The device to which the data is to be written. The type must support * @param d The device to which the data is to be written. The type must support
@ -280,16 +280,16 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object * whether the write operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* // Result of latest write_some_at operation. * // Result of latest write_some_at operation.
* const asio::error_code& error, * const asio::error_code& error,
* *
* // Number of bytes transferred so far. * // Number of bytes transferred so far.
* std::size_t bytes_transferred * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the write operation is complete. False * A return value of 0 indicates that the write operation is complete. A
* indicates that further calls to the device's write_some_at function are * non-zero return value indicates the maximum number of bytes to be written on
* required. * the next call to the device's write_some_at function.
* *
* @param ec Set to indicate what error occurred, if any. * @param ec Set to indicate what error occurred, if any.
* *
@ -324,7 +324,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset,
* *
* @li An error occurred. * @li An error occurred.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* async_write_some_at function. * async_write_some_at function.
* *
* @param d The device to which the data is to be written. The type must support * @param d The device to which the data is to be written. The type must support
@ -380,7 +380,7 @@ void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* async_write_some_at function. * async_write_some_at function.
* *
* @param d The device to which the data is to be written. The type must support * @param d The device to which the data is to be written. The type must support
@ -396,16 +396,16 @@ void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object * whether the write operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* // Result of latest write_some_at operation. * // Result of latest async_write_some_at operation.
* const asio::error_code& error, * const asio::error_code& error,
* *
* // Number of bytes transferred so far. * // Number of bytes transferred so far.
* std::size_t bytes_transferred * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the write operation is complete. False * A return value of 0 indicates that the write operation is complete. A
* indicates that further calls to the device's async_write_some_at function are * non-zero return value indicates the maximum number of bytes to be written on
* required. * the next call to the device's async_write_some_at function.
* *
* @param handler The handler to be called when the write operation completes. * @param handler The handler to be called when the write operation completes.
* Copies will be made of the handler as required. The function signature of the * Copies will be made of the handler as required. The function signature of the
@ -451,7 +451,7 @@ void async_write_at(AsyncRandomAccessWriteDevice& d,
* *
* @li An error occurred. * @li An error occurred.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* async_write_some_at function. * async_write_some_at function.
* *
* @param d The device to which the data is to be written. The type must support * @param d The device to which the data is to be written. The type must support
@ -496,7 +496,7 @@ void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset,
* *
* @li The completion_condition function object returns true. * @li The completion_condition function object returns true.
* *
* This operation is implemented in terms of one or more calls to the device's * This operation is implemented in terms of zero or more calls to the device's
* async_write_some_at function. * async_write_some_at function.
* *
* @param d The device to which the data is to be written. The type must support * @param d The device to which the data is to be written. The type must support
@ -511,16 +511,16 @@ void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset,
* @param completion_condition The function object to be called to determine * @param completion_condition The function object to be called to determine
* whether the write operation is complete. The signature of the function object * whether the write operation is complete. The signature of the function object
* must be: * must be:
* @code bool completion_condition( * @code std::size_t completion_condition(
* // Result of latest async_write_some_at operation. * // Result of latest async_write_some_at operation.
* const asio::error_code& error, * const asio::error_code& error,
* *
* // Number of bytes transferred so far. * // Number of bytes transferred so far.
* std::size_t bytes_transferred * std::size_t bytes_transferred
* ); @endcode * ); @endcode
* A return value of true indicates that the write operation is complete. False * A return value of 0 indicates that the write operation is complete. A
* indicates that further calls to the device's async_write_some_at function are * non-zero return value indicates the maximum number of bytes to be written on
* required. * the next call to the device's async_write_some_at function.
* *
* @param handler The handler to be called when the write operation completes. * @param handler The handler to be called when the write operation completes.
* Copies will be made of the handler as required. The function signature of the * Copies will be made of the handler as required. The function signature of the