summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Resch <andrewresch@gmail.com>2009-04-19 21:40:09 +0000
committerAndrew Resch <andrewresch@gmail.com>2009-04-19 21:40:09 +0000
commitf77d678788e30db4ea83e4271e0a63af7feb1cf6 (patch)
tree14d2484b48549de4bfa1e27ec918f5505fdce71e
parent4280a3220e38f95b4dd559a6de22713de0579a50 (diff)
downloaddeluge-f77d678788e30db4ea83e4271e0a63af7feb1cf6.tar.gz
deluge-f77d678788e30db4ea83e4271e0a63af7feb1cf6.tar.bz2
deluge-f77d678788e30db4ea83e4271e0a63af7feb1cf6.zip
Update to asio 1.4.1
-rw-r--r--libtorrent/include/asio/basic_serial_port.hpp14
-rw-r--r--libtorrent/include/asio/basic_socket.hpp14
-rw-r--r--libtorrent/include/asio/basic_socket_streambuf.hpp3
-rw-r--r--libtorrent/include/asio/basic_streambuf.hpp176
-rw-r--r--libtorrent/include/asio/buffered_read_stream.hpp6
-rw-r--r--libtorrent/include/asio/buffered_stream.hpp6
-rw-r--r--libtorrent/include/asio/buffered_write_stream.hpp6
-rw-r--r--libtorrent/include/asio/buffers_iterator.hpp7
-rw-r--r--libtorrent/include/asio/completion_condition.hpp31
-rw-r--r--libtorrent/include/asio/detail/consuming_buffers.hpp39
-rw-r--r--libtorrent/include/asio/detail/deadline_timer_service.hpp1
-rw-r--r--libtorrent/include/asio/detail/descriptor_ops.hpp15
-rw-r--r--libtorrent/include/asio/detail/dev_poll_reactor.hpp12
-rw-r--r--libtorrent/include/asio/detail/epoll_reactor.hpp11
-rw-r--r--libtorrent/include/asio/detail/kqueue_reactor.hpp10
-rw-r--r--libtorrent/include/asio/detail/null_thread.hpp5
-rw-r--r--libtorrent/include/asio/detail/pipe_select_interrupter.hpp3
-rw-r--r--libtorrent/include/asio/detail/posix_fd_set_adapter.hpp4
-rw-r--r--libtorrent/include/asio/detail/posix_thread.hpp5
-rw-r--r--libtorrent/include/asio/detail/reactive_descriptor_service.hpp1
-rw-r--r--libtorrent/include/asio/detail/reactive_serial_port_service.hpp1
-rw-r--r--libtorrent/include/asio/detail/reactive_socket_service.hpp226
-rw-r--r--libtorrent/include/asio/detail/resolver_service.hpp2
-rw-r--r--libtorrent/include/asio/detail/select_interrupter.hpp3
-rw-r--r--libtorrent/include/asio/detail/select_reactor.hpp10
-rw-r--r--libtorrent/include/asio/detail/service_registry.hpp20
-rw-r--r--libtorrent/include/asio/detail/socket_ops.hpp85
-rw-r--r--libtorrent/include/asio/detail/socket_types.hpp17
-rw-r--r--libtorrent/include/asio/detail/task_io_service.hpp31
-rw-r--r--libtorrent/include/asio/detail/task_io_service_2lock.hpp31
-rw-r--r--libtorrent/include/asio/detail/win_iocp_io_service.hpp7
-rw-r--r--libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp1
-rw-r--r--libtorrent/include/asio/detail/win_thread.hpp116
-rw-r--r--libtorrent/include/asio/detail/wince_thread.hpp5
-rw-r--r--libtorrent/include/asio/impl/error_code.ipp1
-rw-r--r--libtorrent/include/asio/impl/read.ipp67
-rw-r--r--libtorrent/include/asio/impl/read_at.ipp50
-rw-r--r--libtorrent/include/asio/impl/read_until.ipp87
-rw-r--r--libtorrent/include/asio/impl/write.ipp25
-rw-r--r--libtorrent/include/asio/impl/write_at.ipp25
-rw-r--r--libtorrent/include/asio/io_service.hpp1
-rw-r--r--libtorrent/include/asio/ip/address_v4.hpp19
-rw-r--r--libtorrent/include/asio/ip/address_v6.hpp17
-rw-r--r--libtorrent/include/asio/ip/basic_resolver.hpp13
-rw-r--r--libtorrent/include/asio/ip/detail/socket_option.hpp2
-rw-r--r--libtorrent/include/asio/ip/resolver_query_base.hpp8
-rw-r--r--libtorrent/include/asio/local/basic_endpoint.hpp2
-rw-r--r--libtorrent/include/asio/posix/basic_descriptor.hpp14
-rw-r--r--libtorrent/include/asio/read.hpp110
-rw-r--r--libtorrent/include/asio/read_at.hpp78
-rw-r--r--libtorrent/include/asio/read_until.hpp16
-rw-r--r--libtorrent/include/asio/ssl/detail/openssl_context_service.hpp2
-rw-r--r--libtorrent/include/asio/ssl/detail/openssl_init.hpp7
-rw-r--r--libtorrent/include/asio/ssl/detail/openssl_operation.hpp4
-rw-r--r--libtorrent/include/asio/ssl/detail/openssl_stream_service.hpp8
-rw-r--r--libtorrent/include/asio/ssl/stream.hpp13
-rw-r--r--libtorrent/include/asio/thread.hpp2
-rw-r--r--libtorrent/include/asio/version.hpp2
-rw-r--r--libtorrent/include/asio/windows/basic_handle.hpp14
-rw-r--r--libtorrent/include/asio/write.hpp116
-rw-r--r--libtorrent/include/asio/write_at.hpp70
61 files changed, 1142 insertions, 555 deletions
diff --git a/libtorrent/include/asio/basic_serial_port.hpp b/libtorrent/include/asio/basic_serial_port.hpp
index ffe2b0213..681205963 100644
--- a/libtorrent/include/asio/basic_serial_port.hpp
+++ b/libtorrent/include/asio/basic_serial_port.hpp
@@ -142,6 +142,20 @@ public:
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.
/**
* This function opens the serial port for the specified device name.
diff --git a/libtorrent/include/asio/basic_socket.hpp b/libtorrent/include/asio/basic_socket.hpp
index f494c1725..eb9e34d15 100644
--- a/libtorrent/include/asio/basic_socket.hpp
+++ b/libtorrent/include/asio/basic_socket.hpp
@@ -149,6 +149,20 @@ public:
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.
/**
* This function opens the socket so that it will use the specified protocol.
diff --git a/libtorrent/include/asio/basic_socket_streambuf.hpp b/libtorrent/include/asio/basic_socket_streambuf.hpp
index 0bcd3b7a9..5f301ee34 100644
--- a/libtorrent/include/asio/basic_socket_streambuf.hpp
+++ b/libtorrent/include/asio/basic_socket_streambuf.hpp
@@ -247,7 +247,8 @@ private:
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)
{
typedef typename Protocol::resolver resolver_type;
diff --git a/libtorrent/include/asio/basic_streambuf.hpp b/libtorrent/include/asio/basic_streambuf.hpp
index 41649cc43..599cb702c 100644
--- a/libtorrent/include/asio/basic_streambuf.hpp
+++ b/libtorrent/include/asio/basic_streambuf.hpp
@@ -19,6 +19,7 @@
#include "asio/detail/push_options.hpp"
#include <algorithm>
+#include <cstring>
#include <limits>
#include <memory>
#include <stdexcept>
@@ -32,6 +33,73 @@
namespace asio {
/// 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> >
class basic_streambuf
: public std::streambuf,
@@ -39,17 +107,21 @@ class basic_streambuf
{
public:
#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;
- /// 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;
#else
typedef asio::const_buffers_1 const_buffers_type;
typedef asio::mutable_buffers_1 mutable_buffers_type;
#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(
std::size_t max_size = (std::numeric_limits<std::size_t>::max)(),
const Allocator& allocator = Allocator())
@@ -62,42 +134,100 @@ public:
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
{
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
{
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
{
return asio::buffer(asio::const_buffer(gptr(),
(pptr() - gptr()) * sizeof(char_type)));
}
- /// Get a list of buffers that represents the put area, with the given size.
- mutable_buffers_type prepare(std::size_t size)
+ /// Get a list of buffers that represents the output sequence, with the given
+ /// 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(
- 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)
{
if (pptr() + n > epptr())
n = epptr() - pptr();
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)
{
if (gptr() + n > pptr())
@@ -108,6 +238,10 @@ public:
protected:
enum { buffer_delta = 128 };
+ /// Override std::streambuf behaviour.
+ /**
+ * Behaves according to the specification of @c std::streambuf::underflow().
+ */
int_type underflow()
{
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)
{
if (!traits_type::eq_int_type(c, traits_type::eof()))
@@ -150,7 +291,6 @@ protected:
{
// Get current stream positions as offsets.
std::size_t gnext = gptr() - &buffer_[0];
- std::size_t gend = egptr() - &buffer_[0];
std::size_t pnext = pptr() - &buffer_[0];
std::size_t pend = epptr() - &buffer_[0];
@@ -163,9 +303,8 @@ protected:
// Shift existing contents of get area to start of buffer.
if (gnext > 0)
{
- std::rotate(&buffer_[0], &buffer_[0] + gnext, &buffer_[0] + pend);
- gend -= gnext;
pnext -= gnext;
+ std::memmove(&buffer_[0], &buffer_[0] + gnext, pnext);
}
// 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)
{
- buffer_.resize((std::max<std::size_t>)(pnext + n, 1));
+ pend = pnext + n;
+ buffer_.resize((std::max<std::size_t>)(pend, 1));
}
else
{
@@ -182,8 +322,8 @@ protected:
}
// Update stream positions.
- setg(&buffer_[0], &buffer_[0], &buffer_[0] + gend);
- setp(&buffer_[0] + pnext, &buffer_[0] + pnext + n);
+ setg(&buffer_[0], &buffer_[0], &buffer_[0] + pnext);
+ setp(&buffer_[0] + pnext, &buffer_[0] + pend);
}
private:
diff --git a/libtorrent/include/asio/buffered_read_stream.hpp b/libtorrent/include/asio/buffered_read_stream.hpp
index 673cce38d..f88d53cef 100644
--- a/libtorrent/include/asio/buffered_read_stream.hpp
+++ b/libtorrent/include/asio/buffered_read_stream.hpp
@@ -93,6 +93,12 @@ public:
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
/// the object.
asio::io_service& io_service()
diff --git a/libtorrent/include/asio/buffered_stream.hpp b/libtorrent/include/asio/buffered_stream.hpp
index a02dc88c1..1d7ea9df0 100644
--- a/libtorrent/include/asio/buffered_stream.hpp
+++ b/libtorrent/include/asio/buffered_stream.hpp
@@ -83,6 +83,12 @@ public:
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
/// the object.
asio::io_service& io_service()
diff --git a/libtorrent/include/asio/buffered_write_stream.hpp b/libtorrent/include/asio/buffered_write_stream.hpp
index 0ebd3454e..90c36081f 100644
--- a/libtorrent/include/asio/buffered_write_stream.hpp
+++ b/libtorrent/include/asio/buffered_write_stream.hpp
@@ -94,6 +94,12 @@ public:
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
/// the object.
asio::io_service& io_service()
diff --git a/libtorrent/include/asio/buffers_iterator.hpp b/libtorrent/include/asio/buffers_iterator.hpp
index cc13bb5e2..48a7d5a98 100644
--- a/libtorrent/include/asio/buffers_iterator.hpp
+++ b/libtorrent/include/asio/buffers_iterator.hpp
@@ -21,6 +21,7 @@
#include <cstddef>
#include <boost/assert.hpp>
#include <boost/config.hpp>
+#include <boost/detail/workaround.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/add_const.hpp>
@@ -100,6 +101,9 @@ public:
/// Construct an iterator representing the beginning of the buffers' data.
static buffers_iterator begin(const BufferSequence& buffers)
+#if BOOST_WORKAROUND(__GNUC__, == 4) && BOOST_WORKAROUND(__GNUC_MINOR__, == 3)
+ __attribute__ ((noinline))
+#endif
{
buffers_iterator new_iter;
new_iter.begin_ = buffers.begin();
@@ -117,6 +121,9 @@ public:
/// Construct an iterator representing the end of the buffers' data.
static buffers_iterator end(const BufferSequence& buffers)
+#if BOOST_WORKAROUND(__GNUC__, == 4) && BOOST_WORKAROUND(__GNUC_MINOR__, == 3)
+ __attribute__ ((noinline))
+#endif
{
buffers_iterator new_iter;
new_iter.begin_ = buffers.begin();
diff --git a/libtorrent/include/asio/completion_condition.hpp b/libtorrent/include/asio/completion_condition.hpp
index b4d59089a..3f712e356 100644
--- a/libtorrent/include/asio/completion_condition.hpp
+++ b/libtorrent/include/asio/completion_condition.hpp
@@ -26,22 +26,40 @@ namespace asio {
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
{
public:
- typedef bool result_type;
+ typedef std::size_t result_type;
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
{
public:
- typedef bool result_type;
+ typedef std::size_t result_type;
explicit transfer_at_least_t(std::size_t minimum)
: minimum_(minimum)
@@ -49,9 +67,10 @@ public:
}
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:
diff --git a/libtorrent/include/asio/detail/consuming_buffers.hpp b/libtorrent/include/asio/detail/consuming_buffers.hpp
index 8e88e361d..bdc8fc927 100644
--- a/libtorrent/include/asio/detail/consuming_buffers.hpp
+++ b/libtorrent/include/asio/detail/consuming_buffers.hpp
@@ -20,11 +20,13 @@
#include "asio/detail/push_options.hpp"
#include <algorithm>
#include <cstddef>
+#include <limits>
#include <boost/config.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include "asio/detail/pop_options.hpp"
#include "asio/buffer.hpp"
+#include "asio/completion_condition.hpp"
namespace asio {
namespace detail {
@@ -46,33 +48,33 @@ public:
// Construct with a buffer for the first entry and an iterator
// range for the remaining entries.
consuming_buffers_iterator(bool at_end, const Buffer& first,
- Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder)
- : at_end_(at_end),
+ Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder,
+ std::size_t max_size)
+ : at_end_(max_size > 0 ? at_end : true),
first_(buffer(first, max_size)),
begin_remainder_(begin_remainder),
end_remainder_(end_remainder),
- offset_(0)
+ offset_(0),
+ max_size_(max_size)
{
}
private:
friend class boost::iterator_core_access;
- enum { max_size = 65536 };
-
void increment()
{
if (!at_end_)
{
if (begin_remainder_ == end_remainder_
- || offset_ + buffer_size(first_) >= max_size)
+ || offset_ + buffer_size(first_) >= max_size_)
{
at_end_ = true;
}
else
{
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 end_remainder_;
std::size_t offset_;
+ std::size_t max_size_;
};
// A proxy for a sub-range in a list of buffers.
@@ -118,7 +121,8 @@ public:
: buffers_(buffers),
at_end_(buffers_.begin() == buffers_.end()),
first_(*buffers_.begin()),
- begin_remainder_(buffers_.begin())
+ begin_remainder_(buffers_.begin()),
+ max_size_((std::numeric_limits<std::size_t>::max)())
{
if (!at_end_)
++begin_remainder_;
@@ -129,7 +133,8 @@ public:
: buffers_(other.buffers_),
at_end_(other.at_end_),
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 second = other.begin_remainder_;
@@ -146,13 +151,15 @@ public:
typename Buffers::const_iterator first = other.buffers_.begin();
typename Buffers::const_iterator second = other.begin_remainder_;
std::advance(begin_remainder_, std::distance(first, second));
+ max_size_ = other.max_size_;
return *this;
}
// Get a forward-only iterator to the first element.
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.
@@ -161,6 +168,12 @@ public:
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.
void consume(std::size_t size)
{
@@ -197,6 +210,7 @@ private:
bool at_end_;
Buffer first_;
typename Buffers::const_iterator begin_remainder_;
+ std::size_t max_size_;
};
// Specialisation for null_buffers to ensure that the null_buffers type is
@@ -211,6 +225,11 @@ public:
// No-op.
}
+ void set_max_size(std::size_t)
+ {
+ // No-op.
+ }
+
void consume(std::size_t)
{
// No-op.
diff --git a/libtorrent/include/asio/detail/deadline_timer_service.hpp b/libtorrent/include/asio/detail/deadline_timer_service.hpp
index 6f30d7546..b4a660fe0 100644
--- a/libtorrent/include/asio/detail/deadline_timer_service.hpp
+++ b/libtorrent/include/asio/detail/deadline_timer_service.hpp
@@ -63,6 +63,7 @@ public:
deadline_timer_service<Time_Traits, Timer_Scheduler> >(io_service),
scheduler_(asio::use_service<Timer_Scheduler>(io_service))
{
+ scheduler_.init_task();
scheduler_.add_timer_queue(timer_queue_);
}
diff --git a/libtorrent/include/asio/detail/descriptor_ops.hpp b/libtorrent/include/asio/detail/descriptor_ops.hpp
index 6de34f621..e886b27f4 100644
--- a/libtorrent/include/asio/detail/descriptor_ops.hpp
+++ b/libtorrent/include/asio/detail/descriptor_ops.hpp
@@ -58,17 +58,28 @@ inline int close(int d, asio::error_code& 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;
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;
}
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;
}
diff --git a/libtorrent/include/asio/detail/dev_poll_reactor.hpp b/libtorrent/include/asio/detail/dev_poll_reactor.hpp
index 4eb387eb1..3edc3699c 100644
--- a/libtorrent/include/asio/detail/dev_poll_reactor.hpp
+++ b/libtorrent/include/asio/detail/dev_poll_reactor.hpp
@@ -122,6 +122,17 @@ public:
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
// code on failure.
int register_descriptor(socket_type, per_descriptor_data&)
@@ -421,6 +432,7 @@ private:
more_writes = write_op_queue_.perform_operation(descriptor, ec);
else
more_writes = write_op_queue_.has_operation(descriptor);
+
if ((events[i].events & (POLLERR | POLLHUP)) != 0
&& (events[i].events & ~(POLLERR | POLLHUP)) == 0
&& !more_except && !more_reads && !more_writes)
diff --git a/libtorrent/include/asio/detail/epoll_reactor.hpp b/libtorrent/include/asio/detail/epoll_reactor.hpp
index 07bd7e1b6..a5d173483 100644
--- a/libtorrent/include/asio/detail/epoll_reactor.hpp
+++ b/libtorrent/include/asio/detail/epoll_reactor.hpp
@@ -123,6 +123,16 @@ public:
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
// code on failure.
int register_descriptor(socket_type descriptor,
@@ -495,6 +505,7 @@ private:
more_writes = write_op_queue_.perform_operation(descriptor, ec);
else
more_writes = write_op_queue_.has_operation(descriptor);
+
if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0
&& (events[i].events & ~(EPOLLERR | EPOLLHUP)) == 0
&& !more_except && !more_reads && !more_writes)
diff --git a/libtorrent/include/asio/detail/kqueue_reactor.hpp b/libtorrent/include/asio/detail/kqueue_reactor.hpp
index 1d0d21aba..5996b6ce7 100644
--- a/libtorrent/include/asio/detail/kqueue_reactor.hpp
+++ b/libtorrent/include/asio/detail/kqueue_reactor.hpp
@@ -131,6 +131,16 @@ public:
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
// code on failure.
int register_descriptor(socket_type, per_descriptor_data& descriptor_data)
diff --git a/libtorrent/include/asio/detail/null_thread.hpp b/libtorrent/include/asio/detail/null_thread.hpp
index f08b7b378..f91ca53e0 100644
--- a/libtorrent/include/asio/detail/null_thread.hpp
+++ b/libtorrent/include/asio/detail/null_thread.hpp
@@ -38,12 +38,9 @@ class null_thread
: private noncopyable
{
public:
- // The purpose of the thread.
- enum purpose { internal, external };
-
// Constructor.
template <typename Function>
- null_thread(Function f, purpose = internal)
+ null_thread(Function f)
{
asio::system_error e(
asio::error::operation_not_supported, "thread");
diff --git a/libtorrent/include/asio/detail/pipe_select_interrupter.hpp b/libtorrent/include/asio/detail/pipe_select_interrupter.hpp
index e0a224e33..e62d0c7b7 100644
--- a/libtorrent/include/asio/detail/pipe_select_interrupter.hpp
+++ b/libtorrent/include/asio/detail/pipe_select_interrupter.hpp
@@ -71,7 +71,8 @@ public:
void interrupt()
{
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.
diff --git a/libtorrent/include/asio/detail/posix_fd_set_adapter.hpp b/libtorrent/include/asio/detail/posix_fd_set_adapter.hpp
index 5519b9abc..443774347 100644
--- a/libtorrent/include/asio/detail/posix_fd_set_adapter.hpp
+++ b/libtorrent/include/asio/detail/posix_fd_set_adapter.hpp
@@ -17,6 +17,10 @@
#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"
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
diff --git a/libtorrent/include/asio/detail/posix_thread.hpp b/libtorrent/include/asio/detail/posix_thread.hpp
index fe5f82905..892ffe076 100644
--- a/libtorrent/include/asio/detail/posix_thread.hpp
+++ b/libtorrent/include/asio/detail/posix_thread.hpp
@@ -42,12 +42,9 @@ class posix_thread
: private noncopyable
{
public:
- // The purpose of the thread.
- enum purpose { internal, external };
-
// Constructor.
template <typename Function>
- posix_thread(Function f, purpose = internal)
+ posix_thread(Function f)
: joined_(false)
{
std::auto_ptr<func_base> arg(new func<Function>(f));
diff --git a/libtorrent/include/asio/detail/reactive_descriptor_service.hpp b/libtorrent/include/asio/detail/reactive_descriptor_service.hpp
index 12a0c36b4..10263ea08 100644
--- a/libtorrent/include/asio/detail/reactive_descriptor_service.hpp
+++ b/libtorrent/include/asio/detail/reactive_descriptor_service.hpp
@@ -81,6 +81,7 @@ public:
reactive_descriptor_service<Reactor> >(io_service),
reactor_(asio::use_service<Reactor>(io_service))
{
+ reactor_.init_task();
}
// Destroy all user-defined handler objects owned by the service.
diff --git a/libtorrent/include/asio/detail/reactive_serial_port_service.hpp b/libtorrent/include/asio/detail/reactive_serial_port_service.hpp
index 5db94a2dd..2fcf8c755 100644
--- a/libtorrent/include/asio/detail/reactive_serial_port_service.hpp
+++ b/libtorrent/include/asio/detail/reactive_serial_port_service.hpp
@@ -119,6 +119,7 @@ public:
ios.c_cflag |= CS8;
#endif
ios.c_iflag |= IGNPAR;
+ ios.c_cflag |= CREAD | CLOCAL;
descriptor_ops::clear_error(ec);
s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec);
}
diff --git a/libtorrent/include/asio/detail/reactive_socket_service.hpp b/libtorrent/include/asio/detail/reactive_socket_service.hpp
index c7aedf88e..7c4c7efff 100644
--- a/libtorrent/include/asio/detail/reactive_socket_service.hpp
+++ b/libtorrent/include/asio/detail/reactive_socket_service.hpp
@@ -73,10 +73,21 @@ public:
enum
{
- user_set_non_blocking = 1, // The user wants a non-blocking socket.
- internal_non_blocking = 2, // The socket has been set non-blocking.
- enable_connection_aborted = 4, // User wants connection_aborted errors.
- user_set_linger = 8 // The user set the linger option.
+ // The user wants a non-blocking socket.
+ user_set_non_blocking = 1,
+
+ // The implementation wants a non-blocking socket (in order to be able to
+ // perform asynchronous read and write operations).
+ internal_non_blocking = 2,
+
+ // Helper "flag" used to determine whether the socket is non-blocking.
+ non_blocking = user_set_non_blocking | internal_non_blocking,
+
+ // User wants connection_aborted errors, which are disabled by default.
+ enable_connection_aborted = 4,
+
+ // The user set the linger option. Needs to be checked when closing.
+ user_set_linger = 8
};
// Flags indicating the current state of the socket.
@@ -98,6 +109,7 @@ public:
reactive_socket_service<Protocol, Reactor> >(io_service),
reactor_(asio::use_service<Reactor>(io_service))
{
+ reactor_.init_task();
}
// Destroy all user-defined handler objects owned by the service.
@@ -119,12 +131,12 @@ public:
{
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;
asio::error_code 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)
@@ -213,12 +225,12 @@ public:
{
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;
asio::error_code 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)
@@ -432,11 +444,35 @@ public:
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())
- impl.flags_ |= implementation_type::user_set_non_blocking;
+ new_flags |= implementation_type::user_set_non_blocking;
else
- impl.flags_ &= ~implementation_type::user_set_non_blocking;
- ec = asio::error_code();
+ new_flags &= ~implementation_type::user_set_non_blocking;
+
+ // Perform ioctl on socket if the non-blocking state has changed.
+ if (!(impl.flags_ & implementation_type::non_blocking)
+ && (new_flags & implementation_type::non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec);
+ }
+ else if ((impl.flags_ & implementation_type::non_blocking)
+ && !(new_flags & implementation_type::non_blocking))
+ {
+ ioctl_arg_type non_blocking = 0;
+ socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec);
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+
+ // Update socket implementation's flags only if successful.
+ if (!ec)
+ impl.flags_ = new_flags;
}
else
{
@@ -529,18 +565,6 @@ public:
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.
for (;;)
{
@@ -683,12 +707,15 @@ public:
// Make socket non-blocking.
if (!(impl.flags_ & implementation_type::internal_non_blocking))
{
- ioctl_arg_type non_blocking = 1;
- asio::error_code ec;
- if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ if (!(impl.flags_ & implementation_type::non_blocking))
{
- this->get_io_service().post(bind_handler(handler, ec, 0));
- return;
+ ioctl_arg_type non_blocking = 1;
+ 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;
}
@@ -772,18 +799,6 @@ public:
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.
for (;;)
{
@@ -911,12 +926,15 @@ public:
// Make socket non-blocking.
if (!(impl.flags_ & implementation_type::internal_non_blocking))
{
- ioctl_arg_type non_blocking = 1;
- asio::error_code ec;
- if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ if (!(impl.flags_ & implementation_type::non_blocking))
{
- this->get_io_service().post(bind_handler(handler, ec, 0));
- return;
+ ioctl_arg_type non_blocking = 1;
+ 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;
}
@@ -980,18 +998,6 @@ public:
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.
for (;;)
{
@@ -1147,12 +1153,15 @@ public:
// Make socket non-blocking.
if (!(impl.flags_ & implementation_type::internal_non_blocking))
{
- ioctl_arg_type non_blocking = 1;
- asio::error_code ec;
- if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ if (!(impl.flags_ & implementation_type::non_blocking))
{
- this->get_io_service().post(bind_handler(handler, ec, 0));
- return;
+ ioctl_arg_type non_blocking = 1;
+ 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;
}
@@ -1224,18 +1233,6 @@ public:
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.
for (;;)
{
@@ -1384,12 +1381,15 @@ public:
// Make socket non-blocking.
if (!(impl.flags_ & implementation_type::internal_non_blocking))
{
- ioctl_arg_type non_blocking = 1;
- asio::error_code ec;
- if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ if (!(impl.flags_ & implementation_type::non_blocking))
{
- this->get_io_service().post(bind_handler(handler, ec, 0));
- return;
+ ioctl_arg_type non_blocking = 1;
+ 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;
}
@@ -1449,18 +1449,6 @@ public:
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.
for (;;)
{
@@ -1622,12 +1610,15 @@ public:
// Make socket non-blocking.
if (!(impl.flags_ & implementation_type::internal_non_blocking))
{
- ioctl_arg_type non_blocking = 1;
- asio::error_code ec;
- if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ if (!(impl.flags_ & implementation_type::non_blocking))
{
- this->get_io_service().post(bind_handler(handler, ec));
- return;
+ ioctl_arg_type non_blocking = 1;
+ 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;
}
@@ -1651,18 +1642,30 @@ public:
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.
socket_ops::connect(impl.socket_,
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;
}
@@ -1730,12 +1733,15 @@ public:
// Make socket non-blocking.
if (!(impl.flags_ & implementation_type::internal_non_blocking))
{
- ioctl_arg_type non_blocking = 1;
- asio::error_code ec;
- if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ if (!(impl.flags_ & implementation_type::non_blocking))
{
- this->get_io_service().post(bind_handler(handler, ec));
- return;
+ ioctl_arg_type non_blocking = 1;
+ 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;
}
diff --git a/libtorrent/include/asio/detail/resolver_service.hpp b/libtorrent/include/asio/detail/resolver_service.hpp
index 172a8fc6d..e9a4a5eff 100644
--- a/libtorrent/include/asio/detail/resolver_service.hpp
+++ b/libtorrent/include/asio/detail/resolver_service.hpp
@@ -329,7 +329,7 @@ private:
void start_work_thread()
{
asio::detail::mutex::scoped_lock lock(mutex_);
- if (work_thread_ == 0)
+ if (!work_thread_)
{
work_thread_.reset(new asio::detail::thread(
work_io_service_runner(*work_io_service_)));
diff --git a/libtorrent/include/asio/detail/select_interrupter.hpp b/libtorrent/include/asio/detail/select_interrupter.hpp
index 4277e4758..db5e6c760 100644
--- a/libtorrent/include/asio/detail/select_interrupter.hpp
+++ b/libtorrent/include/asio/detail/select_interrupter.hpp
@@ -21,6 +21,7 @@
#include <boost/config.hpp>
#include "asio/detail/pop_options.hpp"
+#include "asio/detail/eventfd_select_interrupter.hpp"
#include "asio/detail/pipe_select_interrupter.hpp"
#include "asio/detail/socket_select_interrupter.hpp"
@@ -29,6 +30,8 @@ namespace detail {
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
typedef socket_select_interrupter select_interrupter;
+#elif defined(ASIO_HAS_EVENTFD)
+typedef eventfd_select_interrupter select_interrupter;
#else
typedef pipe_select_interrupter select_interrupter;
#endif
diff --git a/libtorrent/include/asio/detail/select_reactor.hpp b/libtorrent/include/asio/detail/select_reactor.hpp
index 78a364ee0..9c86c253a 100644
--- a/libtorrent/include/asio/detail/select_reactor.hpp
+++ b/libtorrent/include/asio/detail/select_reactor.hpp
@@ -110,6 +110,16 @@ public:
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
// code on failure.
int register_descriptor(socket_type, per_descriptor_data&)
diff --git a/libtorrent/include/asio/detail/service_registry.hpp b/libtorrent/include/asio/detail/service_registry.hpp
index f517cbbf1..a4c2ecbe1 100644
--- a/libtorrent/include/asio/detail/service_registry.hpp
+++ b/libtorrent/include/asio/detail/service_registry.hpp
@@ -36,6 +36,21 @@
namespace asio {
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
: private noncopyable
{
@@ -168,7 +183,7 @@ private:
void init_service_id(asio::io_service::service& service,
const asio::detail::service_id<Service>& /*id*/)
{
- service.type_info_ = &typeid(Service);
+ service.type_info_ = &typeid(typeid_wrapper<Service>);
service.id_ = 0;
}
#endif // !defined(ASIO_NO_TYPEID)
@@ -188,7 +203,8 @@ private:
const asio::io_service::service& service,
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)
diff --git a/libtorrent/include/asio/detail/socket_ops.hpp b/libtorrent/include/asio/detail/socket_ops.hpp
index 231bc61c5..1f00b4ce4 100644
--- a/libtorrent/include/asio/detail/socket_ops.hpp
+++ b/libtorrent/include/asio/detail/socket_ops.hpp
@@ -102,7 +102,7 @@ inline socket_type accept(socket_type s, socket_addr_type* addr,
}
#endif
-#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+#if defined(BOOST_WINDOWS)
clear_error(ec);
#endif
@@ -122,7 +122,7 @@ inline int bind(socket_type s, const socket_addr_type* addr,
clear_error(ec);
int result = error_wrapper(call_bind(
&msghdr::msg_namelen, s, addr, addrlen), ec);
-#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+#if defined(BOOST_WINDOWS)
if (result == 0)
clear_error(ec);
#endif
@@ -134,10 +134,8 @@ inline int close(socket_type s, asio::error_code& ec)
clear_error(ec);
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
int result = error_wrapper(::closesocket(s), ec);
-# if defined(UNDER_CE)
if (result == 0)
clear_error(ec);
-# endif
return result;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
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);
int result = error_wrapper(::shutdown(s, what), ec);
-#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+#if defined(BOOST_WINDOWS)
if (result == 0)
clear_error(ec);
#endif
@@ -168,7 +166,7 @@ inline int connect(socket_type s, const socket_addr_type* addr,
clear_error(ec);
int result = error_wrapper(call_connect(
&msghdr::msg_namelen, s, addr, addrlen), ec);
-#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+#if defined(BOOST_WINDOWS)
if (result == 0)
clear_error(ec);
#endif
@@ -195,13 +193,24 @@ inline int listen(socket_type s, int backlog, asio::error_code& ec)
{
clear_error(ec);
int result = error_wrapper(::listen(s, backlog), ec);
-#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+#if defined(BOOST_WINDOWS)
if (result == 0)
clear_error(ec);
#endif
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__)
typedef WSABUF buf;
#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.len = static_cast<u_long>(size);
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
- b.iov_base = data;
+ init_buf_iov_base(b.iov_base, data);
b.iov_len = size;
#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.len = static_cast<u_long>(size);
#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;
#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);
if (result != 0)
return -1;
-# if defined(UNDER_CE)
clear_error(ec);
-# endif
return bytes_transferred;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
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;
if (result != 0)
return -1;
-# if defined(UNDER_CE)
clear_error(ec);
-# endif
return bytes_transferred;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
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);
if (result != 0)
return -1;
-# if defined(UNDER_CE)
clear_error(ec);
-# endif
return bytes_transferred;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
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);
if (result != 0)
return -1;
-# if defined(UNDER_CE)
clear_error(ec);
-# endif
return bytes_transferred;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
msghdr msg = msghdr();
@@ -388,9 +389,7 @@ inline socket_type socket(int af, int type, int protocol,
reinterpret_cast<const char*>(&optval), sizeof(optval));
}
-# if defined(UNDER_CE)
clear_error(ec);
-# endif
return s;
#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
@@ -452,7 +451,7 @@ inline int setsockopt(socket_type s, int level, int optname,
clear_error(ec);
int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen,
s, level, optname, optval, optlen), ec);
-# if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+# if defined(BOOST_WINDOWS)
if (result == 0)
clear_error(ec);
# endif
@@ -525,10 +524,8 @@ inline int getsockopt(socket_type s, int level, int optname, void* optval,
*static_cast<DWORD*>(optval) = 1;
clear_error(ec);
}
-# if defined(UNDER_CE)
if (result == 0)
clear_error(ec);
-# endif
return result;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
clear_error(ec);
@@ -566,7 +563,7 @@ inline int getpeername(socket_type s, socket_addr_type* addr,
clear_error(ec);
int result = error_wrapper(call_getpeername(
&msghdr::msg_namelen, s, addr, addrlen), ec);
-#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+#if defined(BOOST_WINDOWS)
if (result == 0)
clear_error(ec);
#endif
@@ -589,7 +586,7 @@ inline int getsockname(socket_type s, socket_addr_type* addr,
clear_error(ec);
int result = error_wrapper(call_getsockname(
&msghdr::msg_namelen, s, addr, addrlen), ec);
-#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+#if defined(BOOST_WINDOWS)
if (result == 0)
clear_error(ec);
#endif
@@ -602,10 +599,8 @@ inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg,
clear_error(ec);
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec);
-# if defined(UNDER_CE)
if (result == 0)
clear_error(ec);
-# endif
return result;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
return error_wrapper(::ioctl(s, cmd, arg), ec);
@@ -647,7 +642,7 @@ inline int select(int nfds, fd_set* readfds, fd_set* writefds,
#else
int result = error_wrapper(::select(nfds, readfds,
writefds, exceptfds, timeout), ec);
-# if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+# if defined(BOOST_WINDOWS)
if (result >= 0)
clear_error(ec);
# endif
@@ -663,10 +658,8 @@ inline int poll_read(socket_type s, asio::error_code& ec)
FD_SET(s, &fds);
clear_error(ec);
int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec);
-# if defined(UNDER_CE)
if (result >= 0)
clear_error(ec);
-# endif
return result;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
pollfd fds;
@@ -686,10 +679,32 @@ inline int poll_write(socket_type s, asio::error_code& ec)
FD_SET(s, &fds);
clear_error(ec);
int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec);
-# if defined(UNDER_CE)
if (result >= 0)
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;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
pollfd fds;
@@ -837,10 +852,8 @@ inline int inet_pton(int af, const char* src, void* dest,
if (result == socket_error_retval && !ec)
ec = asio::error::invalid_argument;
-#if defined(UNDER_CE)
if (result != socket_error_retval)
clear_error(ec);
-#endif
return result == socket_error_retval ? -1 : 1;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -869,7 +882,7 @@ inline int gethostname(char* name, int namelen, asio::error_code& ec)
{
clear_error(ec);
int result = error_wrapper(::gethostname(name, namelen), ec);
-#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+#if defined(BOOST_WINDOWS)
if (result == 0)
clear_error(ec);
#endif
@@ -912,9 +925,7 @@ inline hostent* gethostbyaddr(const char* addr, int length, int af,
hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec);
if (!retval)
return 0;
-# if defined(UNDER_CE)
clear_error(ec);
-# endif
*result = *retval;
return retval;
#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);
if (!retval)
return 0;
-# if defined(UNDER_CE)
clear_error(ec);
-# endif
*result = *retval;
return result;
#elif defined(__sun) || defined(__QNX__)
diff --git a/libtorrent/include/asio/detail/socket_types.hpp b/libtorrent/include/asio/detail/socket_types.hpp
index b2acb6931..f58374322 100644
--- a/libtorrent/include/asio/detail/socket_types.hpp
+++ b/libtorrent/include/asio/detail/socket_types.hpp
@@ -28,11 +28,15 @@
# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
# if defined(_MSC_VER) || defined(__BORLANDC__)
-# pragma message("Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately")
-# pragma message("Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target)")
+# pragma message( \
+ "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\
+ "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\
+ "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\
+ "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).")
# else // defined(_MSC_VER) || defined(__BORLANDC__)
-# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately
-# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target)
+# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately.
+# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line.
+# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).
# endif // defined(_MSC_VER) || defined(__BORLANDC__)
# define _WIN32_WINNT 0x0501
# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
@@ -187,7 +191,12 @@ const int shutdown_both = SHUT_RDWR;
const int message_peek = MSG_PEEK;
const int message_out_of_band = MSG_OOB;
const int message_do_not_route = MSG_DONTROUTE;
+# if defined(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
const int custom_socket_option_level = 0xA5100000;
const int enable_connection_aborted_option = 1;
diff --git a/libtorrent/include/asio/detail/task_io_service.hpp b/libtorrent/include/asio/detail/task_io_service.hpp
index beba1f251..2b89c55b5 100644
--- a/libtorrent/include/asio/detail/task_io_service.hpp
+++ b/libtorrent/include/asio/detail/task_io_service.hpp
@@ -44,14 +44,13 @@ public:
task_io_service(asio::io_service& io_service)
: asio::detail::service_base<task_io_service<Task> >(io_service),
mutex_(),
- task_(use_service<Task>(io_service)),
+ task_(0),
task_interrupted_(true),
outstanding_work_(0),
stopped_(false),
shutdown_(false),
first_idle_thread_(0)
{
- handler_queue_.push(&task_handler_);
}
void init(size_t /*concurrency_hint*/)
@@ -74,8 +73,20 @@ public:
h->destroy();
}
- // Reset handler queue to initial state.
- handler_queue_.push(&task_handler_);
+ // Reset to initial state.
+ 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.
@@ -194,10 +205,10 @@ public:
// Wake up a thread to execute the handler.
if (!interrupt_one_idle_thread(lock))
{
- if (!task_interrupted_)
+ if (!task_interrupted_ && task_)
{
task_interrupted_ = true;
- task_.interrupt();
+ task_->interrupt();
}
}
}
@@ -246,7 +257,7 @@ private:
// Run the task. May throw an exception. Only block if the handler
// queue is empty and we have an idle_thread_info object, otherwise
// we want to return as soon as possible.
- task_.run(!more_handlers && !polling);
+ task_->run(!more_handlers && !polling);
}
else
{
@@ -285,10 +296,10 @@ private:
{
stopped_ = true;
interrupt_all_idle_threads(lock);
- if (!task_interrupted_)
+ if (!task_interrupted_ && task_)
{
task_interrupted_ = true;
- task_.interrupt();
+ task_->interrupt();
}
}
@@ -376,7 +387,7 @@ private:
asio::detail::mutex mutex_;
// The task to be run by this service.
- Task& task_;
+ Task* task_;
// Handler object to represent the position of the task in the queue.
class task_handler
diff --git a/libtorrent/include/asio/detail/task_io_service_2lock.hpp b/libtorrent/include/asio/detail/task_io_service_2lock.hpp
index 9b0221bbb..f040e6599 100644
--- a/libtorrent/include/asio/detail/task_io_service_2lock.hpp
+++ b/libtorrent/include/asio/detail/task_io_service_2lock.hpp
@@ -49,7 +49,7 @@ public:
: asio::detail::service_base<task_io_service<Task> >(io_service),
front_mutex_(),
back_mutex_(),
- task_(use_service<Task>(io_service)),
+ task_(&use_service<Task>(io_service)),
outstanding_work_(0),
front_stopped_(false),
back_stopped_(false),
@@ -57,7 +57,6 @@ public:
back_first_idle_thread_(0),
back_task_thread_(0)
{
- handler_queue_.push(&task_handler_);
}
void init(size_t /*concurrency_hint*/)
@@ -76,8 +75,20 @@ public:
if (h != &task_handler_)
h->destroy();
- // Reset handler queue to initial state.
- handler_queue_.push(&task_handler_);
+ // Reset to initial state.
+ 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.
@@ -286,7 +297,7 @@ private:
// queue is empty and we're not polling, otherwise we want to return
// as soon as possible.
task_has_run = true;
- task_.run(!more_handlers && !polling);
+ task_->run(!more_handlers && !polling);
}
else
{
@@ -341,10 +352,10 @@ private:
idle_thread->next = 0;
idle_thread->wakeup_event.signal(back_lock);
}
- else if (back_task_thread_)
+ else if (back_task_thread_ && task_)
{
back_task_thread_ = 0;
- task_.interrupt();
+ task_->interrupt();
}
}
@@ -360,10 +371,10 @@ private:
idle_thread->wakeup_event.signal(back_lock);
}
- if (back_task_thread_)
+ if (back_task_thread_ && task_)
{
back_task_thread_ = 0;
- task_.interrupt();
+ task_->interrupt();
}
}
@@ -414,7 +425,7 @@ private:
asio::detail::mutex back_mutex_;
// The task to be run by this service.
- Task& task_;
+ Task* task_;
// Handler object to represent the position of the task in the queue.
class task_handler
diff --git a/libtorrent/include/asio/detail/win_iocp_io_service.hpp b/libtorrent/include/asio/detail/win_iocp_io_service.hpp
index 7f6d631c0..f649a30c6 100644
--- a/libtorrent/include/asio/detail/win_iocp_io_service.hpp
+++ b/libtorrent/include/asio/detail/win_iocp_io_service.hpp
@@ -148,6 +148,11 @@ public:
timer_queues_.clear();
}
+ // Initialise the task. Nothing to do here.
+ void init_task()
+ {
+ }
+
// Register a handle with the IO completion port.
asio::error_code register_handle(
HANDLE handle, asio::error_code& ec)
@@ -530,7 +535,7 @@ private:
// Wake up next thread that is blocked on GetQueuedCompletionStatus.
if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
{
- DWORD last_error = ::GetLastError();
+ last_error = ::GetLastError();
ec = asio::error_code(last_error,
asio::error::get_system_category());
return 0;
diff --git a/libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp b/libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp
index a40c6a871..85aba21a7 100644
--- a/libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp
+++ b/libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp
@@ -36,6 +36,7 @@ namespace asio {
namespace detail {
class win_iocp_io_service;
+class win_iocp_overlapped_ptr;
} // namespace detail
} // namespace asio
diff --git a/libtorrent/include/asio/detail/win_thread.hpp b/libtorrent/include/asio/detail/win_thread.hpp
index 17d912565..d26826843 100644
--- a/libtorrent/include/asio/detail/win_thread.hpp
+++ b/libtorrent/include/asio/detail/win_thread.hpp
@@ -39,45 +39,67 @@ namespace detail {
unsigned int __stdcall win_thread_function(void* arg);
-class win_thread
- : private noncopyable
+#if (WINVER < 0x0500)
+void __stdcall apc_function(ULONG data);
+#else
+void __stdcall apc_function(ULONG_PTR data);
+#endif
+
+template <typename T>
+class win_thread_base
{
public:
- // The purpose of the thread.
- enum purpose { internal, external };
+ static bool terminate_threads()
+ {
+ 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.
template <typename Function>
- win_thread(Function f, purpose p = internal)
+ win_thread(Function f)
: exit_event_(0)
{
std::auto_ptr<func_base> arg(new func<Function>(f));
::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);
- if (!entry_event)
- {
- DWORD last_error = ::GetLastError();
- asio::system_error e(
- asio::error_code(last_error,
- asio::error::get_system_category()),
- "thread.entry_event");
- boost::throw_exception(e);
- }
-
- arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0);
- if (!exit_event_)
- {
- DWORD last_error = ::GetLastError();
- ::CloseHandle(entry_event);
- asio::system_error e(
- asio::error_code(last_error,
- asio::error::get_system_category()),
- "thread.exit_event");
- boost::throw_exception(e);
- }
+ DWORD last_error = ::GetLastError();
+ asio::system_error e(
+ asio::error_code(last_error,
+ asio::error::get_system_category()),
+ "thread.entry_event");
+ boost::throw_exception(e);
+ }
+
+ arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0);
+ if (!exit_event_)
+ {
+ DWORD last_error = ::GetLastError();
+ ::CloseHandle(entry_event);
+ asio::system_error e(
+ asio::error_code(last_error,
+ asio::error::get_system_category()),
+ "thread.exit_event");
+ boost::throw_exception(e);
}
unsigned int thread_id = 0;
@@ -117,14 +139,15 @@ public:
// Wait for the thread to exit.
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);
}
else
{
+ ::QueueUserAPC(apc_function, thread_, 0);
::WaitForSingleObject(thread_, INFINITE);
}
}
@@ -132,6 +155,12 @@ public:
private:
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
{
public:
@@ -169,21 +198,30 @@ inline unsigned int __stdcall win_thread_function(void* arg)
std::auto_ptr<win_thread::func_base> func(
static_cast<win_thread::func_base*>(arg));
- if (func->entry_event_)
- ::SetEvent(func->entry_event_);
+ ::SetEvent(func->entry_event_);
func->run();
- if (HANDLE exit_event = func->exit_event_)
- {
- func.reset();
- ::SetEvent(exit_event);
- ::Sleep(INFINITE);
- }
+ // Signal that the thread has finished its work, but rather than returning go
+ // to sleep to put the thread into a well known state. If the thread is being
+ // joined during global object destruction then it may be killed using
+ // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx
+ // call will be interrupted using QueueUserAPC and the thread will shut down
+ // cleanly.
+ HANDLE exit_event = func->exit_event_;
+ func.reset();
+ ::SetEvent(exit_event);
+ ::SleepEx(INFINITE, TRUE);
return 0;
}
+#if (WINVER < 0x0500)
+inline void __stdcall apc_function(ULONG) {}
+#else
+inline void __stdcall apc_function(ULONG_PTR) {}
+#endif
+
} // namespace detail
} // namespace asio
diff --git a/libtorrent/include/asio/detail/wince_thread.hpp b/libtorrent/include/asio/detail/wince_thread.hpp
index 5a558b9ef..d0b4a9f51 100644
--- a/libtorrent/include/asio/detail/wince_thread.hpp
+++ b/libtorrent/include/asio/detail/wince_thread.hpp
@@ -42,12 +42,9 @@ class wince_thread
: private noncopyable
{
public:
- // The purpose of the thread.
- enum purpose { internal, external };
-
// Constructor.
template <typename Function>
- wince_thread(Function f, purpose = internal)
+ wince_thread(Function f)
{
std::auto_ptr<func_base> arg(new func<Function>(f));
DWORD thread_id = 0;
diff --git a/libtorrent/include/asio/impl/error_code.ipp b/libtorrent/include/asio/impl/error_code.ipp
index fa0520a9f..865600d7b 100644
--- a/libtorrent/include/asio/impl/error_code.ipp
+++ b/libtorrent/include/asio/impl/error_code.ipp
@@ -83,6 +83,7 @@ inline std::string error_code::message() const
if (category() != error::get_system_category())
return "asio error";
#if defined(__sun) || defined(__QNX__)
+ using namespace std;
return strerror(value_);
#elif defined(__MACH__) && defined(__APPLE__) \
|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
diff --git a/libtorrent/include/asio/impl/read.ipp b/libtorrent/include/asio/impl/read.ipp
index b3d573905..1f1fa6fc6 100644
--- a/libtorrent/include/asio/impl/read.ipp
+++ b/libtorrent/include/asio/impl/read.ipp
@@ -37,18 +37,20 @@ template <typename SyncReadStream, typename MutableBufferSequence,
std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec)
{
+ ec = asio::error_code();
asio::detail::consuming_buffers<
mutable_buffer, MutableBufferSequence> tmp(buffers);
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())
{
std::size_t bytes_transferred = s.read_some(tmp, ec);
tmp.consume(bytes_transferred);
total_transferred += bytes_transferred;
- if (completion_condition(ec, total_transferred))
- return total_transferred;
+ tmp.set_max_size(detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred)));
}
- ec = asio::error_code();
return total_transferred;
}
@@ -78,18 +80,23 @@ std::size_t read(SyncReadStream& s,
asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition, asio::error_code& ec)
{
+ ec = asio::error_code();
std::size_t total_transferred = 0;
- for (;;)
+ std::size_t max_size = detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred));
+ std::size_t bytes_available = 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);
b.commit(bytes_transferred);
total_transferred += bytes_transferred;
- if (b.size() == b.max_size()
- || completion_condition(ec, total_transferred))
- return total_transferred;
+ max_size = detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred));
+ bytes_available = 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>
@@ -139,8 +146,9 @@ namespace detail
{
total_transferred_ += bytes_transferred;
buffers_.consume(bytes_transferred);
- if (completion_condition_(ec, total_transferred_)
- || buffers_.begin() == buffers_.end())
+ buffers_.set_max_size(detail::adapt_completion_condition_result(
+ completion_condition_(ec, total_transferred_)));
+ if (buffers_.begin() == buffers_.end())
{
handler_(ec, total_transferred_);
}
@@ -197,6 +205,18 @@ inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
{
asio::detail::consuming_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,
detail::read_handler<AsyncReadStream, MutableBufferSequence,
CompletionCondition, ReadHandler>(
@@ -234,15 +254,17 @@ namespace detail
{
total_transferred_ += bytes_transferred;
streambuf_.commit(bytes_transferred);
- if (streambuf_.size() == streambuf_.max_size()
- || completion_condition_(ec, total_transferred_))
+ 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,
+ streambuf_.max_size() - streambuf_.size()));
+ if (bytes_available == 0)
{
handler_(ec, total_transferred_);
}
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);
}
}
@@ -292,8 +314,19 @@ inline void async_read(AsyncReadStream& s,
asio::basic_streambuf<Allocator>& b,
CompletionCondition completion_condition, ReadHandler handler)
{
- std::size_t bytes_available =
- std::min<std::size_t>(512, b.max_size() - b.size());
+ asio::error_code ec;
+ std::size_t total_transferred = 0;
+ std::size_t max_size = detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred));
+ std::size_t bytes_available = std::min<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),
detail::read_streambuf_handler<AsyncReadStream, Allocator,
CompletionCondition, ReadHandler>(
diff --git a/libtorrent/include/asio/impl/read_at.ipp b/libtorrent/include/asio/impl/read_at.ipp
index 2412487b5..403ff31ac 100644
--- a/libtorrent/include/asio/impl/read_at.ipp
+++ b/libtorrent/include/asio/impl/read_at.ipp
@@ -38,19 +38,21 @@ std::size_t read_at(SyncRandomAccessReadDevice& d,
boost::uint64_t offset, const MutableBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec)
{
+ ec = asio::error_code();
asio::detail::consuming_buffers<
mutable_buffer, MutableBufferSequence> tmp(buffers);
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())
{
std::size_t bytes_transferred = d.read_some_at(
offset + total_transferred, tmp, ec);
tmp.consume(bytes_transferred);
total_transferred += bytes_transferred;
- if (completion_condition(ec, total_transferred))
- return total_transferred;
+ tmp.set_max_size(detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred)));
}
- ec = asio::error_code();
return total_transferred;
}
@@ -151,8 +153,9 @@ namespace detail
{
total_transferred_ += bytes_transferred;
buffers_.consume(bytes_transferred);
- if (completion_condition_(ec, total_transferred_)
- || buffers_.begin() == buffers_.end())
+ buffers_.set_max_size(detail::adapt_completion_condition_result(
+ completion_condition_(ec, total_transferred_)));
+ if (buffers_.begin() == buffers_.end())
{
handler_(ec, total_transferred_);
}
@@ -214,6 +217,18 @@ inline void async_read_at(AsyncRandomAccessReadDevice& d,
{
asio::detail::consuming_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,
detail::read_at_handler<AsyncRandomAccessReadDevice,
MutableBufferSequence, CompletionCondition, ReadHandler>(
@@ -253,15 +268,17 @@ namespace detail
{
total_transferred_ += bytes_transferred;
streambuf_.commit(bytes_transferred);
- if (streambuf_.size() == streambuf_.max_size()
- || completion_condition_(ec, total_transferred_))
+ 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,
+ streambuf_.max_size() - streambuf_.size()));
+ if (bytes_available == 0)
{
handler_(ec, total_transferred_);
}
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_,
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,
CompletionCondition completion_condition, ReadHandler handler)
{
- std::size_t bytes_available =
- std::min<std::size_t>(512, b.max_size() - b.size());
+ asio::error_code ec;
+ std::size_t total_transferred = 0;
+ std::size_t max_size = detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred));
+ std::size_t bytes_available = std::min<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),
detail::read_at_streambuf_handler<AsyncRandomAccessReadDevice, Allocator,
CompletionCondition, ReadHandler>(
diff --git a/libtorrent/include/asio/impl/read_until.ipp b/libtorrent/include/asio/impl/read_until.ipp
index b88b14194..3ed7dbe7c 100644
--- a/libtorrent/include/asio/impl/read_until.ipp
+++ b/libtorrent/include/asio/impl/read_until.ipp
@@ -277,19 +277,16 @@ std::size_t read_until(SyncReadStream& s,
// Look for a match.
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();
- return result.first - begin;
- }
- else
- {
- // Partial match. Next search needs to start from beginning of match.
- next_search_start = result.first - begin;
- }
+ // Full match. We're done.
+ ec = asio::error_code();
+ return result.first - begin;
+ }
+ else if (result.first != end)
+ {
+ // Partial match. Next search needs to start from beginning of match.
+ next_search_start = result.first - begin;
}
else
{
@@ -448,7 +445,7 @@ void async_read_until(AsyncReadStream& s,
// Found a match. We're done.
asio::error_code ec;
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;
}
@@ -456,7 +453,7 @@ void async_read_until(AsyncReadStream& s,
if (b.size() == b.max_size())
{
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;
}
@@ -537,8 +534,8 @@ namespace detail
if (streambuf_.size() == streambuf_.max_size())
{
std::size_t bytes = 0;
- asio::error_code ec(error::not_found);
- handler_(ec, bytes);
+ asio::error_code ec2(error::not_found);
+ handler_(ec2, bytes);
return;
}
@@ -609,7 +606,7 @@ void async_read_until(AsyncReadStream& s,
// Full match. We're done.
asio::error_code ec;
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;
}
else
@@ -628,7 +625,7 @@ void async_read_until(AsyncReadStream& s,
if (b.size() == b.max_size())
{
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;
}
@@ -782,7 +779,7 @@ void async_read_until(AsyncReadStream& s,
// Full match. We're done.
asio::error_code ec;
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;
}
else
@@ -801,7 +798,7 @@ void async_read_until(AsyncReadStream& s,
if (b.size() == b.max_size())
{
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;
}
@@ -857,20 +854,17 @@ namespace detail
// Look for a match.
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;
- handler_(ec, bytes);
- return;
- }
- else
- {
- // Partial match. Next search needs to start from beginning of match.
- next_search_start_ = result.first - begin;
- }
+ // Full match. We're done.
+ std::size_t bytes = result.first - begin;
+ handler_(ec, bytes);
+ return;
+ }
+ else if (result.first != end)
+ {
+ // Partial match. Next search needs to start from beginning of match.
+ next_search_start_ = result.first - begin;
}
else
{
@@ -950,21 +944,18 @@ void async_read_until(AsyncReadStream& s,
// Look for a match.
std::size_t next_search_start;
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;
- std::size_t bytes = result.first - begin;
- s.io_service().post(detail::bind_handler(handler, ec, bytes));
- return;
- }
- else
- {
- // Partial match. Next search needs to start from beginning of match.
- next_search_start = result.first - begin;
- }
+ // Full match. We're done.
+ asio::error_code ec;
+ std::size_t bytes = result.first - begin;
+ s.get_io_service().post(detail::bind_handler(handler, ec, bytes));
+ return;
+ }
+ else if (result.first != end)
+ {
+ // Partial match. Next search needs to start from beginning of match.
+ next_search_start = result.first - begin;
}
else
{
@@ -976,7 +967,7 @@ void async_read_until(AsyncReadStream& s,
if (b.size() == b.max_size())
{
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;
}
diff --git a/libtorrent/include/asio/impl/write.ipp b/libtorrent/include/asio/impl/write.ipp
index 43bc2972a..b9305a08a 100644
--- a/libtorrent/include/asio/impl/write.ipp
+++ b/libtorrent/include/asio/impl/write.ipp
@@ -32,18 +32,20 @@ template <typename SyncWriteStream, typename ConstBufferSequence,
std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec)
{
+ ec = asio::error_code();
asio::detail::consuming_buffers<
const_buffer, ConstBufferSequence> tmp(buffers);
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())
{
std::size_t bytes_transferred = s.write_some(tmp, ec);
tmp.consume(bytes_transferred);
total_transferred += bytes_transferred;
- if (completion_condition(ec, total_transferred))
- return total_transferred;
+ tmp.set_max_size(detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred)));
}
- ec = asio::error_code();
return total_transferred;
}
@@ -125,8 +127,9 @@ namespace detail
{
total_transferred_ += bytes_transferred;
buffers_.consume(bytes_transferred);
- if (completion_condition_(ec, total_transferred_)
- || buffers_.begin() == buffers_.end())
+ buffers_.set_max_size(detail::adapt_completion_condition_result(
+ completion_condition_(ec, total_transferred_)));
+ if (buffers_.begin() == buffers_.end())
{
handler_(ec, total_transferred_);
}
@@ -183,6 +186,18 @@ inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
{
asio::detail::consuming_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,
detail::write_handler<AsyncWriteStream, ConstBufferSequence,
CompletionCondition, WriteHandler>(
diff --git a/libtorrent/include/asio/impl/write_at.ipp b/libtorrent/include/asio/impl/write_at.ipp
index c6fa3078c..4c8c70d59 100644
--- a/libtorrent/include/asio/impl/write_at.ipp
+++ b/libtorrent/include/asio/impl/write_at.ipp
@@ -33,19 +33,21 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d,
boost::uint64_t offset, const ConstBufferSequence& buffers,
CompletionCondition completion_condition, asio::error_code& ec)
{
+ ec = asio::error_code();
asio::detail::consuming_buffers<
const_buffer, ConstBufferSequence> tmp(buffers);
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())
{
std::size_t bytes_transferred = d.write_some_at(
offset + total_transferred, tmp, ec);
tmp.consume(bytes_transferred);
total_transferred += bytes_transferred;
- if (completion_condition(ec, total_transferred))
- return total_transferred;
+ tmp.set_max_size(detail::adapt_completion_condition_result(
+ completion_condition(ec, total_transferred)));
}
- ec = asio::error_code();
return total_transferred;
}
@@ -135,8 +137,9 @@ namespace detail
{
total_transferred_ += bytes_transferred;
buffers_.consume(bytes_transferred);
- if (completion_condition_(ec, total_transferred_)
- || buffers_.begin() == buffers_.end())
+ buffers_.set_max_size(detail::adapt_completion_condition_result(
+ completion_condition_(ec, total_transferred_)));
+ if (buffers_.begin() == buffers_.end())
{
handler_(ec, total_transferred_);
}
@@ -196,6 +199,18 @@ inline void async_write_at(AsyncRandomAccessWriteDevice& d,
{
asio::detail::consuming_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,
detail::write_at_handler<AsyncRandomAccessWriteDevice,
ConstBufferSequence, CompletionCondition, WriteHandler>(
diff --git a/libtorrent/include/asio/io_service.hpp b/libtorrent/include/asio/io_service.hpp
index b6a34fdc4..ad37aee14 100644
--- a/libtorrent/include/asio/io_service.hpp
+++ b/libtorrent/include/asio/io_service.hpp
@@ -134,6 +134,7 @@ private:
// The type of the platform-specific implementation.
#if defined(ASIO_HAS_IOCP)
typedef detail::win_iocp_io_service impl_type;
+ friend class detail::win_iocp_overlapped_ptr;
#elif defined(ASIO_HAS_EPOLL)
typedef detail::task_io_service<detail::epoll_reactor<false> > impl_type;
#elif defined(ASIO_HAS_KQUEUE)
diff --git a/libtorrent/include/asio/ip/address_v4.hpp b/libtorrent/include/asio/ip/address_v4.hpp
index cda2a11c0..05f38596f 100644
--- a/libtorrent/include/asio/ip/address_v4.hpp
+++ b/libtorrent/include/asio/ip/address_v4.hpp
@@ -18,7 +18,9 @@
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
+#include <climits>
#include <string>
+#include <stdexcept>
#include <boost/array.hpp>
#include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp"
@@ -55,6 +57,15 @@ public:
/// Construct an address from raw bytes.
explicit address_v4(const bytes_type& bytes)
{
+#if UCHAR_MAX > 0xFF
+ if (bytes[0] > 0xFF || bytes[1] > 0xFF
+ || bytes[2] > 0xFF || bytes[3] > 0xFF)
+ {
+ std::out_of_range ex("address_v4 from bytes_type");
+ boost::throw_exception(ex);
+ }
+#endif // UCHAR_MAX > 0xFF
+
using namespace std; // For memcpy.
memcpy(&addr_.s_addr, bytes.elems, 4);
}
@@ -62,6 +73,14 @@ public:
/// Construct an address from a unsigned long in host byte order.
explicit address_v4(unsigned long addr)
{
+#if ULONG_MAX > 0xFFFFFFFF
+ if (addr > 0xFFFFFFFF)
+ {
+ std::out_of_range ex("address_v4 from unsigned long");
+ boost::throw_exception(ex);
+ }
+#endif // ULONG_MAX > 0xFFFFFFFF
+
addr_.s_addr = asio::detail::socket_ops::host_to_network_long(addr);
}
diff --git a/libtorrent/include/asio/ip/address_v6.hpp b/libtorrent/include/asio/ip/address_v6.hpp
index c317fe487..789ec09a9 100644
--- a/libtorrent/include/asio/ip/address_v6.hpp
+++ b/libtorrent/include/asio/ip/address_v6.hpp
@@ -62,6 +62,17 @@ public:
explicit address_v6(const bytes_type& bytes, unsigned long scope_id = 0)
: scope_id_(scope_id)
{
+#if UCHAR_MAX > 0xFF
+ for (std::size_t i = 0; i < bytes.size(); ++i)
+ {
+ if (bytes[i] > 0xFF)
+ {
+ std::out_of_range ex("address_v6 from bytes_type");
+ boost::throw_exception(ex);
+ }
+ }
+#endif // UCHAR_MAX > 0xFF
+
using namespace std; // For memcpy.
memcpy(addr_.s6_addr, bytes.elems, 16);
}
@@ -165,7 +176,11 @@ public:
address_v4 to_v4() const
{
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],
addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } };
return address_v4(v4_bytes);
diff --git a/libtorrent/include/asio/ip/basic_resolver.hpp b/libtorrent/include/asio/ip/basic_resolver.hpp
index d5593778d..154c2ad0a 100644
--- a/libtorrent/include/asio/ip/basic_resolver.hpp
+++ b/libtorrent/include/asio/ip/basic_resolver.hpp
@@ -75,7 +75,7 @@ public:
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.
*
@@ -99,7 +99,7 @@ public:
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.
*
@@ -121,7 +121,7 @@ public:
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
* endpoint entries.
@@ -153,7 +153,7 @@ public:
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
* entries.
@@ -179,7 +179,7 @@ public:
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
* entries.
@@ -203,7 +203,8 @@ public:
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
* endpoint entries.
diff --git a/libtorrent/include/asio/ip/detail/socket_option.hpp b/libtorrent/include/asio/ip/detail/socket_option.hpp
index a3496fd56..912a1dc57 100644
--- a/libtorrent/include/asio/ip/detail/socket_option.hpp
+++ b/libtorrent/include/asio/ip/detail/socket_option.hpp
@@ -40,7 +40,7 @@ public:
#if defined(__sun) || defined(__osf__)
typedef unsigned char ipv4_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 int ipv6_value_type;
#else
diff --git a/libtorrent/include/asio/ip/resolver_query_base.hpp b/libtorrent/include/asio/ip/resolver_query_base.hpp
index 16f846642..c6addb10c 100644
--- a/libtorrent/include/asio/ip/resolver_query_base.hpp
+++ b/libtorrent/include/asio/ip/resolver_query_base.hpp
@@ -69,17 +69,19 @@ public:
# else
BOOST_STATIC_CONSTANT(int, numeric_service = 0);
# 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);
# else
BOOST_STATIC_CONSTANT(int, v4_mapped = 0);
# endif
-# if defined(AI_ALL)
+# if defined(AI_ALL) && !defined(__QNXNTO__)
BOOST_STATIC_CONSTANT(int, all_matching = AI_ALL);
# else
BOOST_STATIC_CONSTANT(int, all_matching = 0);
# endif
-# if defined(AI_ADDRCONFIG)
+# if defined(AI_ADDRCONFIG) && !defined(__QNXNTO__)
BOOST_STATIC_CONSTANT(int, address_configured = AI_ADDRCONFIG);
# else
BOOST_STATIC_CONSTANT(int, address_configured = 0);
diff --git a/libtorrent/include/asio/local/basic_endpoint.hpp b/libtorrent/include/asio/local/basic_endpoint.hpp
index 75dd092e3..4ab652b44 100644
--- a/libtorrent/include/asio/local/basic_endpoint.hpp
+++ b/libtorrent/include/asio/local/basic_endpoint.hpp
@@ -148,7 +148,7 @@ public:
- offsetof(asio::detail::sockaddr_un_type, sun_path);
// The path returned by the operating system may be NUL-terminated.
- if (path_length_ > 0 && data_.local.sun_path[path_length_] == 0)
+ if (path_length_ > 0 && data_.local.sun_path[path_length_ - 1] == 0)
--path_length_;
}
}
diff --git a/libtorrent/include/asio/posix/basic_descriptor.hpp b/libtorrent/include/asio/posix/basic_descriptor.hpp
index 241a3e315..c440c04ff 100644
--- a/libtorrent/include/asio/posix/basic_descriptor.hpp
+++ b/libtorrent/include/asio/posix/basic_descriptor.hpp
@@ -99,6 +99,20 @@ public:
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.
/*
* This function opens the descriptor to hold an existing native descriptor.
diff --git a/libtorrent/include/asio/read.hpp b/libtorrent/include/asio/read.hpp
index 7c0b82247..ddbe5d4c9 100644
--- a/libtorrent/include/asio/read.hpp
+++ b/libtorrent/include/asio/read.hpp
@@ -45,7 +45,7 @@ namespace asio {
*
* @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.
*
* @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.
*
- * 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.
*
* @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
* whether the read operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
- * const asio::error_code& error, // Result of latest read_some
- * // operation.
+ * @code std::size_t completion_condition(
+ * // Result of latest read_some operation.
+ * const asio::error_code& error,
*
- * std::size_t bytes_transferred // Number of bytes transferred
- * // so far.
+ * // Number of bytes transferred so far.
+ * std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the read operation is complete. False
- * indicates that further calls to the stream's read_some function are required.
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's read_some function.
*
* @returns The number of bytes transferred.
*
@@ -134,7 +135,7 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
*
* @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.
*
* @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
* whether the read operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
- * const asio::error_code& error, // Result of latest read_some
- * // operation.
+ * @code std::size_t completion_condition(
+ * // Result of latest read_some operation.
+ * const asio::error_code& error,
*
- * std::size_t bytes_transferred // Number of bytes transferred
- * // so far.
+ * // Number of bytes transferred so far.
+ * std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the read operation is complete. False
- * indicates that further calls to the stream's read_some function are required.
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's read_some function.
*
* @param ec Set to indicate what error occurred, if any.
*
@@ -174,7 +176,7 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers,
*
* @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.
*
* @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.
*
- * 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.
*
* @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
* whether the read operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
- * const asio::error_code& error, // Result of latest read_some
- * // operation.
+ * @code std::size_t completion_condition(
+ * // Result of latest read_some operation.
+ * const asio::error_code& error,
*
- * std::size_t bytes_transferred // Number of bytes transferred
- * // so far.
+ * // Number of bytes transferred so far.
+ * std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the read operation is complete. False
- * indicates that further calls to the stream's read_some function are required.
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's read_some function.
*
* @returns The number of bytes transferred.
*
@@ -238,7 +241,7 @@ std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b,
*
* @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.
*
* @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
* whether the read operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
- * const asio::error_code& error, // Result of latest read_some
- * // operation.
+ * @code std::size_t completion_condition(
+ * // Result of latest read_some operation.
+ * const asio::error_code& error,
*
- * std::size_t bytes_transferred // Number of bytes transferred
- * // so far.
+ * // Number of bytes transferred so far.
+ * std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the read operation is complete. False
- * indicates that further calls to the stream's read_some function are required.
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's read_some function.
*
* @param ec Set to indicate what error occurred, if any.
*
@@ -291,7 +295,7 @@ std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& b,
*
* @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.
*
* @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
* whether the read operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
- * const asio::error_code& error, // Result of latest read_some
- * // operation.
+ * @code std::size_t completion_condition(
+ * // Result of latest async_read_some operation.
+ * const asio::error_code& error,
*
- * std::size_t bytes_transferred // Number of bytes transferred
- * // so far.
+ * // Number of bytes transferred so far.
+ * std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the read operation is complete. False
- * indicates that further calls to the stream's async_read_some function are
- * required.
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's async_read_some function.
*
* @param handler The handler to be called when the read operation completes.
* Copies will be made of the handler as required. The function signature of the
@@ -418,7 +422,7 @@ void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers,
*
* @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.
*
* @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.
*
- * 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.
*
* @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
* whether the read operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
- * const asio::error_code& error, // Result of latest read_some
- * // operation.
+ * @code std::size_t completion_condition(
+ * // Result of latest async_read_some operation.
+ * const asio::error_code& error,
*
- * std::size_t bytes_transferred // Number of bytes transferred
- * // so far.
+ * // Number of bytes transferred so far.
+ * std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the read operation is complete. False
- * indicates that further calls to the stream's async_read_some function are
- * required.
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the stream's async_read_some function.
*
* @param handler The handler to be called when the read operation completes.
* Copies will be made of the handler as required. The function signature of the
diff --git a/libtorrent/include/asio/read_at.hpp b/libtorrent/include/asio/read_at.hpp
index bcc247a0f..5c4339c48 100644
--- a/libtorrent/include/asio/read_at.hpp
+++ b/libtorrent/include/asio/read_at.hpp
@@ -48,7 +48,7 @@ namespace asio {
*
* @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.
*
* @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.
*
- * 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.
*
* @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
* whether the read operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
+ * @code std::size_t completion_condition(
* // Result of latest read_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the read operation is complete. False
- * indicates that further calls to the device's read_some_at function are
- * required.
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the device's read_some_at function.
*
* @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.
*
- * 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.
*
* @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
* whether the read operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
- * const asio::error_code& error, // Result of latest read_some_at
- * // operation.
+ * @code std::size_t completion_condition(
+ * // Result of latest read_some_at operation.
+ * const asio::error_code& error,
*
- * std::size_t bytes_transferred // Number of bytes transferred
- * // so far.
+ * // Number of bytes transferred so far.
+ * std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the read operation is complete. False
- * indicates that further calls to the device's read_some_at function are
- * required.
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the device's read_some_at function.
*
* @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.
*
- * 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.
*
* @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.
*
- * 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.
*
* @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
* whether the read operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
+ * @code std::size_t completion_condition(
* // Result of latest read_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the read operation is complete. False
- * indicates that further calls to the device's read_some_at function are
- * required.
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the device's read_some_at function.
*
* @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.
*
- * 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.
*
* @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
* whether the read operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
+ * @code std::size_t completion_condition(
* // Result of latest read_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the read operation is complete. False
- * indicates that further calls to the device's read_some_at function are
- * required.
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the device's read_some_at function.
*
* @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.
*
- * 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.
*
* @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
* whether the read operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
- * // Result of latest read_some_at operation.
+ * @code std::size_t completion_condition(
+ * // Result of latest async_read_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the read operation is complete. False
- * indicates that further calls to the device's async_read_some_at function are
- * required.
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the device's async_read_some_at function.
*
* @param handler The handler to be called when the read operation completes.
* Copies will be made of the handler as required. The function signature of the
@@ -458,7 +458,7 @@ void async_read_at(AsyncRandomAccessReadDevice& d,
*
* @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.
*
* @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.
*
- * 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.
*
* @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
* whether the read operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
- * // Result of latest read_some_at operation.
+ * @code std::size_t completion_condition(
+ * // Result of latest async_read_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the read operation is complete. False
- * indicates that further calls to the device's async_read_some_at function are
- * required.
+ * A return value of 0 indicates that the read operation is complete. A non-zero
+ * return value indicates the maximum number of bytes to be read on the next
+ * call to the device's async_read_some_at function.
*
* @param handler The handler to be called when the read operation completes.
* Copies will be made of the handler as required. The function signature of the
diff --git a/libtorrent/include/asio/read_until.hpp b/libtorrent/include/asio/read_until.hpp
index 69922e266..33a6a0cc9 100644
--- a/libtorrent/include/asio/read_until.hpp
+++ b/libtorrent/include/asio/read_until.hpp
@@ -24,6 +24,7 @@
#include <boost/type_traits/is_function.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/utility/enable_if.hpp>
+#include <boost/detail/workaround.hpp>
#include <string>
#include "asio/detail/pop_options.hpp"
@@ -34,6 +35,20 @@ namespace asio {
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>
struct has_result_type
{
@@ -43,6 +58,7 @@ namespace detail
static const T& ref();
enum { value = (sizeof((helper)((ref)())) == 1) };
};
+#endif // BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610))
} // namespace detail
/// Type trait used to determine whether a type can be used as a match condition
diff --git a/libtorrent/include/asio/ssl/detail/openssl_context_service.hpp b/libtorrent/include/asio/ssl/detail/openssl_context_service.hpp
index 5a90d5a2f..3e4e05a93 100644
--- a/libtorrent/include/asio/ssl/detail/openssl_context_service.hpp
+++ b/libtorrent/include/asio/ssl/detail/openssl_context_service.hpp
@@ -308,9 +308,9 @@ public:
::BIO_free(bio);
int result = ::SSL_CTX_set_tmp_dh(impl, dh);
+ ::DH_free(dh);
if (result != 1)
{
- ::DH_free(dh);
ec = asio::error::invalid_argument;
return ec;
}
diff --git a/libtorrent/include/asio/ssl/detail/openssl_init.hpp b/libtorrent/include/asio/ssl/detail/openssl_init.hpp
index 07d7e6674..0b2cf7939 100644
--- a/libtorrent/include/asio/ssl/detail/openssl_init.hpp
+++ b/libtorrent/include/asio/ssl/detail/openssl_init.hpp
@@ -21,6 +21,7 @@
#include "asio/detail/push_options.hpp"
#include <vector>
#include <boost/assert.hpp>
+#include <boost/config.hpp>
#include <boost/shared_ptr.hpp>
#include "asio/detail/pop_options.hpp"
@@ -86,11 +87,15 @@ private:
private:
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_;
if (id == 0)
instance()->thread_id_ = id = &id; // Ugh.
BOOST_ASSERT(sizeof(unsigned long) >= sizeof(void*));
return reinterpret_cast<unsigned long>(id);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
}
static void openssl_locking_func(int mode, int n,
@@ -105,8 +110,10 @@ private:
// Mutexes to be used in locking callbacks.
std::vector<boost::shared_ptr<asio::detail::mutex> > mutexes_;
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
// The thread identifiers to be used by openssl.
asio::detail::tss_ptr<void> thread_id_;
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
};
public:
diff --git a/libtorrent/include/asio/ssl/detail/openssl_operation.hpp b/libtorrent/include/asio/ssl/detail/openssl_operation.hpp
index c8603ac1e..c8db9514e 100644
--- a/libtorrent/include/asio/ssl/detail/openssl_operation.hpp
+++ b/libtorrent/include/asio/ssl/detail/openssl_operation.hpp
@@ -158,6 +158,10 @@ public:
0;
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_write_needed = (error_code == SSL_ERROR_WANT_WRITE ||
::BIO_ctrl_pending( ssl_bio_ ));
diff --git a/libtorrent/include/asio/ssl/detail/openssl_stream_service.hpp b/libtorrent/include/asio/ssl/detail/openssl_stream_service.hpp
index 710c935cf..3bf939f0a 100644
--- a/libtorrent/include/asio/ssl/detail/openssl_stream_service.hpp
+++ b/libtorrent/include/asio/ssl/detail/openssl_stream_service.hpp
@@ -336,7 +336,7 @@ public:
buffer_size = max_buffer_size;
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()),
static_cast<int>(buffer_size));
openssl_operation<Stream> op(
@@ -372,7 +372,7 @@ public:
buffer_size = max_buffer_size;
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()),
static_cast<int>(buffer_size));
@@ -410,7 +410,7 @@ public:
buffer_size = max_buffer_size;
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()),
static_cast<int>(buffer_size));
openssl_operation<Stream> op(recv_func,
@@ -446,7 +446,7 @@ public:
buffer_size = max_buffer_size;
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()),
static_cast<int>(buffer_size));
diff --git a/libtorrent/include/asio/ssl/stream.hpp b/libtorrent/include/asio/ssl/stream.hpp
index 77ced5bfe..c3a069f27 100644
--- a/libtorrent/include/asio/ssl/stream.hpp
+++ b/libtorrent/include/asio/ssl/stream.hpp
@@ -149,6 +149,19 @@ public:
return next_layer_.lowest_layer();
}
+ /// Get a const reference to the lowest layer.
+ /**
+ * This function returns a const reference to the lowest layer in a stack of
+ * stream layers.
+ *
+ * @return A const reference to the lowest layer in the stack of stream
+ * layers. Ownership is not transferred to the caller.
+ */
+ const lowest_layer_type& lowest_layer() const
+ {
+ return next_layer_.lowest_layer();
+ }
+
/// Get the underlying implementation in the native type.
/**
* This function may be used to obtain the underlying implementation of the
diff --git a/libtorrent/include/asio/thread.hpp b/libtorrent/include/asio/thread.hpp
index b0f786c6b..7cc8cdf0b 100644
--- a/libtorrent/include/asio/thread.hpp
+++ b/libtorrent/include/asio/thread.hpp
@@ -58,7 +58,7 @@ public:
*/
template <typename Function>
explicit thread(Function f)
- : impl_(f, asio::detail::thread::external)
+ : impl_(f)
{
}
diff --git a/libtorrent/include/asio/version.hpp b/libtorrent/include/asio/version.hpp
index df2fa9f84..6a107ba5b 100644
--- a/libtorrent/include/asio/version.hpp
+++ b/libtorrent/include/asio/version.hpp
@@ -18,6 +18,6 @@
// ASIO_VERSION % 100 is the sub-minor version
// ASIO_VERSION / 100 % 1000 is the minor 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
diff --git a/libtorrent/include/asio/windows/basic_handle.hpp b/libtorrent/include/asio/windows/basic_handle.hpp
index f436436b7..3762f1d45 100644
--- a/libtorrent/include/asio/windows/basic_handle.hpp
+++ b/libtorrent/include/asio/windows/basic_handle.hpp
@@ -94,6 +94,20 @@ public:
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.
/*
* This function opens the handle to hold an existing native handle.
diff --git a/libtorrent/include/asio/write.hpp b/libtorrent/include/asio/write.hpp
index b1965880b..2c8e75b51 100644
--- a/libtorrent/include/asio/write.hpp
+++ b/libtorrent/include/asio/write.hpp
@@ -44,7 +44,7 @@ namespace asio {
*
* @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.
*
* @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.
*
- * 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.
*
* @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
* whether the write operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
- * const asio::error_code& error, // Result of latest write_some
- * // operation.
+ * @code std::size_t completion_condition(
+ * // Result of latest write_some operation.
+ * const asio::error_code& error,
*
- * std::size_t bytes_transferred // Number of bytes transferred
- * // so far.
+ * // Number of bytes transferred so far.
+ * std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the write operation is complete. False
- * indicates that further calls to the stream's write_some function are
- * required.
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's write_some function.
*
* @returns The number of bytes transferred.
*
@@ -134,7 +134,7 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
*
* @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.
*
* @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
* whether the write operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
- * const asio::error_code& error, // Result of latest write_some
- * // operation.
+ * @code std::size_t completion_condition(
+ * // Result of latest write_some operation.
+ * const asio::error_code& error,
*
- * std::size_t bytes_transferred // Number of bytes transferred
- * // so far.
+ * // Number of bytes transferred so far.
+ * std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the write operation is complete. False
- * indicates that further calls to the stream's write_some function are
- * required.
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's write_some function.
*
* @param ec Set to indicate what error occurred, if any.
*
@@ -177,7 +177,7 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers,
*
* @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.
*
* @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.
*
- * 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.
*
* @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
* whether the write operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
- * const asio::error_code& error, // Result of latest write_some
- * // operation.
+ * @code std::size_t completion_condition(
+ * // Result of latest write_some operation.
+ * const asio::error_code& error,
*
- * std::size_t bytes_transferred // Number of bytes transferred
- * // so far.
+ * // Number of bytes transferred so far.
+ * std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the write operation is complete. False
- * indicates that further calls to the stream's write_some function are
- * required.
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's write_some function.
*
* @returns The number of bytes transferred.
*
@@ -246,7 +246,7 @@ std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b,
*
* @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.
*
* @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
* whether the write operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
- * const asio::error_code& error, // Result of latest write_some
- * // operation.
+ * @code std::size_t completion_condition(
+ * // Result of latest write_some operation.
+ * const asio::error_code& error,
*
- * std::size_t bytes_transferred // Number of bytes transferred
- * // so far.
+ * // Number of bytes transferred so far.
+ * std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the write operation is complete. False
- * indicates that further calls to the stream's write_some function are
- * required.
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's write_some function.
*
* @param ec Set to indicate what error occurred, if any.
*
@@ -300,7 +300,7 @@ std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& b,
*
* @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.
*
* @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.
*
- * 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.
*
* @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
* whether the write operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
- * const asio::error_code& error, // Result of latest write_some
- * // operation.
+ * @code std::size_t completion_condition(
+ * // Result of latest async_write_some operation.
+ * const asio::error_code& error,
*
- * std::size_t bytes_transferred // Number of bytes transferred
- * // so far.
+ * // Number of bytes transferred so far.
+ * std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the write operation is complete. False
- * indicates that further calls to the stream's async_write_some function are
- * required.
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's async_write_some function.
*
* @param handler The handler to be called when the write operation completes.
* Copies will be made of the handler as required. The function signature of the
@@ -422,7 +422,7 @@ void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers,
*
* @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.
*
* @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.
*
- * 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.
*
* @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
* whether the write operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
- * const asio::error_code& error, // Result of latest write_some
- * // operation.
+ * @code std::size_t completion_condition(
+ * // Result of latest async_write_some operation.
+ * const asio::error_code& error,
*
- * std::size_t bytes_transferred // Number of bytes transferred
- * // so far.
+ * // Number of bytes transferred so far.
+ * std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the write operation is complete. False
- * indicates that further calls to the stream's async_write_some function are
- * required.
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the stream's async_write_some function.
*
* @param handler The handler to be called when the write operation completes.
* Copies will be made of the handler as required. The function signature of the
diff --git a/libtorrent/include/asio/write_at.hpp b/libtorrent/include/asio/write_at.hpp
index a17733fff..a72061371 100644
--- a/libtorrent/include/asio/write_at.hpp
+++ b/libtorrent/include/asio/write_at.hpp
@@ -46,7 +46,7 @@ namespace asio {
*
* @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.
*
* @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.
*
- * 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.
*
* @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
* whether the write operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
+ * @code std::size_t completion_condition(
* // Result of latest write_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the write operation is complete. False
- * indicates that further calls to the device's write_some_at function are
- * required.
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the device's write_some_at function.
*
* @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.
*
- * 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.
*
* @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
* whether the write operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
+ * @code std::size_t completion_condition(
* // Result of latest write_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the write operation is complete. False
- * indicates that further calls to the device's write_some_at function are
- * required.
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the device's write_some_at function.
*
* @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.
*
- * 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.
*
* @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.
*
- * 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.
*
* @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
* whether the write operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
+ * @code std::size_t completion_condition(
* // Result of latest write_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the write operation is complete. False
- * indicates that further calls to the device's write_some_at function are
- * required.
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the device's write_some_at function.
*
* @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.
*
- * 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.
*
* @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
* whether the write operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
+ * @code std::size_t completion_condition(
* // Result of latest write_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the write operation is complete. False
- * indicates that further calls to the device's write_some_at function are
- * required.
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the device's write_some_at function.
*
* @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.
*
- * 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.
*
* @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.
*
- * 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.
*
* @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
* whether the write operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
- * // Result of latest write_some_at operation.
+ * @code std::size_t completion_condition(
+ * // Result of latest async_write_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the write operation is complete. False
- * indicates that further calls to the device's async_write_some_at function are
- * required.
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the device's async_write_some_at function.
*
* @param handler The handler to be called when the write operation completes.
* Copies will be made of the handler as required. The function signature of the
@@ -451,7 +451,7 @@ void async_write_at(AsyncRandomAccessWriteDevice& d,
*
* @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.
*
* @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.
*
- * 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.
*
* @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
* whether the write operation is complete. The signature of the function object
* must be:
- * @code bool completion_condition(
+ * @code std::size_t completion_condition(
* // Result of latest async_write_some_at operation.
* const asio::error_code& error,
*
* // Number of bytes transferred so far.
* std::size_t bytes_transferred
* ); @endcode
- * A return value of true indicates that the write operation is complete. False
- * indicates that further calls to the device's async_write_some_at function are
- * required.
+ * A return value of 0 indicates that the write operation is complete. A
+ * non-zero return value indicates the maximum number of bytes to be written on
+ * the next call to the device's async_write_some_at function.
*
* @param handler The handler to be called when the write operation completes.
* Copies will be made of the handler as required. The function signature of the