co_spawn
to correctly
propagate exceptions resulting from cancellation to the completion handler.
std::launder
to fix undefined behaviour in
awaitable<>
internal storage.
file_base::append
flag in the Windows implementation of file support.
fcntl
if a call to ioctl
fails.
experimental::coro
were both used in the same translation unit.
async_result
primary template's concept checking to correctly handle lvalue-qualified
completion signatures.
bind_allocator
, bind_executor
,
bind_immediate_executor
and bind_cancellation_slot
completion token adapters to adapt each other.
experimental::ranged_parallel_group
operation so that it moves the completion_order
vector when invoking the completion handler.
asio/experimental/parallel_group.hpp
header
so that it is self-contained.
ip::basic_resolver_query
, io_context::strand
,
and coroutine
.
any_completion_handler
and compilation using ASIO_USE_TS_EXECUTOR_AS_DEFAULT
.
any_completion_handler
object's associators.
ssl::stream<>
class's async_handshake
operation so that it works with a defaulted completion token.
asio::execution
namespace.
std::bind
.
try_send_via_dispatch
and try_send_n_via_dispatch
functions to channels.
any_completion_handler
.
spawn
-based
stackful coroutines would terminate the program when used with asynchronous
operations that have a completion signature starting with std::exception_ptr
.
bind_allocator
,
bind_cancellation_slot
and bind_immediate_executor
to not require a return_type
type alias in the adapted async_result
specialisation.
co_spawn
operation's cancellation support.
thread_local
keyword if
available.
experimental::co_composed
to correctly state that terminal
cancellation is enabled by default.
async_compose
.
bind_immediate_executor
to the Completion Token
Adapters
overview.
experimental
channel
for mutual exclusion
between cooperating asynchronous actors.
associated_immediate_executor
to any_completion_handler
.
query
,
require
or prefer
with an empty any_executor
.
experimental::coro
for a spurious syntax error when compiling with MSVC.
io_uring
support is enabled.
experimental::basic_channel
and experimental::basic_concurrent_channel
.
signal_set
error handling code paths.
bad_address_cast
to not use a deprecated implicit copy constructor.
dev_poll_reactor
backend.
io_uring
backend to ensure the internal timeout
operations, used to implement io_context::run_for
and io_context::run_until
, are cleaned up correctly.
co_spawn
implementation's entry point, reducing memory consumption.
awaitable<>
-based
coroutine's ability to co_await
asynchronous operations packaged as function objects.
co_composed
.
const_buffers_1
and mutable_buffers_1
types
to asio::buffer()
would result in the contiguous iterator overloads being incorrectly chosen.
ssl::stream<>
.
ip::address_v4::to_ulong
as deprecated in the documentation.
basic_socket_acceptor::async_accept
concept requirement checking to be compatible with lambdas that have a
deduced return type.
use_future
's
compatibility traits.
as_tuple
compatibility
with legacy completion tokens.
redirect_error
compatibility
with new completion tokens.
this_coro
to prevent
inadvertent co_await
of
boolean expressions.
experimental::use_coro
implementation.
is_async_operation
and completion_signature_of
.
experimental::promise
.
experimental::coro
use with custom allocators.
io_uring
.
any_completion_handler<>
, co_composed
,
and immediate completion support to the documentation overview.
Added the ability to customise the execution of a completion handler when
an operation completes immediately. This change adds the associated_immediate_executor
associator
trait, bind_immediate_executor
function, and immediate_executor_binder
adapter. When a supported operation completes immediately (that is, within
the initiating function) the associated immmediate executor is obtained,
and the completion handler is delivered through that executor as if by
using asio::dispatch
on that executor. By default,
the immediate executor delivers the completion handler as if using asio::post
via the operation's I/O executor.
For example, to allow a recursive call to the completion handler of an
async_read_some
operation,
we may specify that immediate completion is delivered via a system_executor
:
my_socket.async_read_some(my_buffer, bind_immediate_executor( system_executor(), [](error_code e, size_t n) { // ... } ) );
Immediate execution is currently supported for asynchronous operations
on reactor-based sockets and descriptors, and for asynchronous operations
on channels.
Added user-defined literals for buffer types. The _buf
literal suffix, defined in namespace asio::buffer_literals
,
may be used to create const_buffer objects from string, binary integer,
and hexadecimal integer literals. These buffer literals may be arbitrarily
long. For example:
using namespace asio::buffer_literals; asio::const_buffer b1 = "hello"_buf; asio::const_buffer b2 = 0xdeadbeef_buf; asio::const_buffer b3 = 0x01234567'89abcdef'01234567'89abcdef_buf; asio::const_buffer b4 = 0b1010101011001100_buf;
The memory associated with a buffer literal is valid for the lifetime
of the program. This means that the buffer can be safely used with asynchronous
operations:
async_write(my_socket, "hello"_buf, my_handler);
local::seq_packet_protocol
to represent AF_UNIX
with
SOCK_SEQPACKET
.
Exposed sigaction()
flags via optional argument to signal_set::add
.
When registering a signal, it is now possible to pass flags that specify
the behaviour associated with the signal. These flags are specified as
an enum type in a new class, signal_set_base, and are passed to the underlying
sigaction()
call. For example:
asio::signal_set sigs(my_io_context); sigs.add(SIGINT, asio::signal_set::flags::restart);
Specifying flags other than flags::dont_care
will fail unless sigaction()
is supported by the target operating
system. Since signal registration is global, conflicting flags (multiple
registrations that pass differing flags other than flags::dont_care
)
will also result in an error.
allocator_binder
,
executor_binder
, and cancellation_slot_binder
to support detection
of unspecialised associators.
associated_cancellation_slot<reference_wrapper>::get()
.
awaitable
handling
for completion signatures containing std::exception_ptr
.
experimental::channel
try_send
failure after a cancel
.
thread_pool::join()
deadlock when the pool has no internal threads.
release()
when using io_uring
.
io_uring
backend.
get_associated_executor
.
experimental::channel
is closed.
any_completion_handler
assignment operator to work correctly.
any_completion_handler
to prevent accidental
copying
uint64_t
for OpenSSL options, to match OpenSSL 3.
deferred
interoperability
with multiple completion signatures.
any_completion_handler
to the documentation.
spawn
and co_spawn
implementations to dispatch
cancellation handlers on the correct executor. When a completion handler
uses a specified (i.e. non-default) associated executor, cancellation handlers
are dispatched to the executor that was passed to spawn()
or co_spawn()
.
spawn
to ensure the
completion handler is dispatched through the correct executor.
snprintf
rather than sprintf
on
latest Xcode, to address deprecation warnings.
co_spawn
and any_completion_handler
.
select_reactor::run
when it is run on an internal thread.
(BOOST_)ASIO_DISABLE_SMALL_BLOCK_RECYCLING
is
defined.
std::invoke_result
when targeting C++17 or
later.
experimental::coro
implementation.
io_uring
to the implementation notes.
Added the consign
completion
token adapter, which can be used to attach additional values to a completion
handler. This is typically used to keep at least one copy of an object,
such as a smart pointer, alive until the completion handler is called.
For example:
auto timer1 = std::make_shared<asio::steady_timer>(my_io_context); timer1->expires_after(std::chrono::seconds(1)); timer1->async_wait( asio::consign( [](asio::error_code ec) { // ... }, timer1 ) );
Added any_completion_handler<>
, which can be used to type-erase
completion handlers. A typical use case is to enable separate compilation
of asynchronous operation implementations. For example:
// Header file: void async_sleep_impl( asio::any_completion_handler<void(asio::error_code)> handler, asio::any_io_executor ex, std::chrono::nanoseconds duration); template <typename CompletionToken> inline auto async_sleep(asio::any_io_executor ex, std::chrono::nanoseconds duration, CompletionToken&& token) { return asio::async_initiate< CompletionToken, void(asio::error_code)>( async_sleep_impl, token, std::move(ex), duration); } // Separately compiled source file: void async_sleep_impl( asio::any_completion_handler<void(asio::error_code)> handler, asio::any_io_executor ex, std::chrono::nanoseconds duration) { auto timer = std::make_shared<asio::steady_timer>(ex, duration); timer->async_wait(asio::consign(std::move(handler), timer)); }
Added experimental::co_composed
which facilitates a lightweight
implementation of user-defined asynchronous operations using C++20 coroutines.
The following example illustrates a simple asynchronous operation that
implements an echo protocol in terms of a coroutine:
template <typename CompletionToken> auto async_echo(tcp::socket& socket, CompletionToken&& token) { return asio::async_initiate< CompletionToken, void(asio::error_code)>( asio::experimental::co_composed< void(asio::error_code)>( [](auto state, tcp::socket& socket) -> void { try { state.throw_if_cancelled(true); state.reset_cancellation_state( asio::enable_terminal_cancellation()); for (;;) { char data[1024]; std::size_t n = co_await socket.async_read_some( asio::buffer(data), asio::deferred); co_await asio::async_write(socket, asio::buffer(data, n), asio::deferred); } } catch (const asio::system_error& e) { co_return {e.code()}; } }, socket), token, std::ref(socket)); }
Add range-based experimental::make_parallel_group() overloads that may
be used to launch a dynamically-sized set of asynchronous operations, where
all operations are the same type. For example:
using op_type = decltype( socket1.async_read_some( asio::buffer(data1), asio::deferred ) ); std::vector<op_type> ops; ops.push_back( socket1.async_read_some( asio::buffer(data1), asio::deferred ) ); ops.push_back( socket2.async_read_some( asio::buffer(data2), asio::deferred ) ); asio::experimental::make_parallel_group(ops).async_wait( asio::experimental::wait_for_all(), []( std::vector<std::size_t> completion_order, std::vector<asio::error_code> e, std::vector<std::size_t> n ) { for (std::size_t i = 0; i < completion_order.size(); ++i) { std::size_t idx = completion_order[i]; std::cout << "socket " << idx << " finished: "; std::cout << e[idx] << ", " << n[idx] << "\n"; } } );
Thanks go to Klemens Morgenstern for supplying part of this implementation.
any_completion_executor
,
a type-erased wrappers for executors that are associated with completion
handlers.
context
query
to use_future's executor.
execution::any_executor<>
and any_io_executor
.
execution::any_executor
objects to improve the performance of copy and move operations.
associated_cancellation_slot
specialisation for std::reference_wrapper
.
get
functions.
spawn
implementation
to catch unhandled exceptions and rethrow them outside of the spawned "thread".
spawn
"thread" objects.
dispatch
to mean the executor is used as-is. An execution context's default executor
is imbued with the possibly-blocking property.
execution::execute
customisation point. Use execute
as a member function.
parallel_group
example.
experimental::channel_traits
specialisations.
R(error_code)
signature.
cancelled()
public on the async_compose
'self' object.
async_compose
'self' object.
release()
for Windows overlapped handles.
experimental::coro
,
regularised experimental::use_coro
,
and fixed allocator handling. This means that use_coro
does not return a coro object, just like use_awaitable does, i.e. it's
an overhead that buys us type erasure. Allocators can now be set for coro
by including allocator_arg
in the coro signature.
experimental::promise
and made it an asynchronous operation object.
post
/defer
overloads on ability to require
blocking.never
.
fcntl
if ioctl
fails with ENOTTY
when setting non-blocking mode.
awaitable<>
-based coroutines when they directly
co_await
an asynchronous
operation, by eliminating the copy of the operation object in await_transform
.
spawn()
-based stackful coroutines by storing
a reference to the yield context in the completion handler, rather than
storing a copy of the executor.
index_sequence
emulation when variadic templates are unavailable.
std::aligned_alloc
for older Apple platforms.
experimental::coro
implementation.
spawn()
-based
stackful coroutine is cleaned up immediately after it completes.
select_reactor
,
on Windows, to ensure that any exception resulting from failure to recreate
its interrupter's sockets will be allowed to propagate out through io_context::run()
.
system_error
workaround, as more recent runtime redistributables appear to have fixed
the issue.
async_compose
example to use a return type compatible with the new async_result
form.
decltype
,
to all asynchronous operations' initiating functions when using C++11.
This change enables the new form of async_result
,
where the return type can vary per operation, for C++11.
append
, prepend
, as_tuple
,
and deferred
to the asio
namespace, and made them compatible
with C++11. These are no longer experimental facilities, although the names
have temporarily been retained under the asio::experimental
namespace for backwards compatibility.
buffer()
overloads for contiguous containers, such as std::span
.
Added the ability for awaitable<>
-based coroutines to directly co_await
operations that are packaged
as function objects. For example, using deferred
:
asio::awaitable<void> my_coro() { asio::steady_timer timer(co_await asio::this_coro::executor); timer.expires_after(std::chrono::seconds(5)); co_await timer.async_wait(asio::deferred); }
or with a handcrafted function object:
asio::awaitable<void> my_coro() { asio::steady_timer timer(co_await asio::this_coro::executor); timer.expires_after(std::chrono::seconds(5)); co_await [&](auto&& token) { return timer.async_wait(std::forward<decltype(token)>(token)); }; }
Changed spawn()
to be a completion token-based asynchronous operation. This introduces
new spawn()
overloads that conform to the requirements for asynchronous operations.
For example:
std::string do_read(asio::yield_context yield) { char data[1024]; size_t n = my_socket.async_read_some(asio::buffer(data), yield); return std::string(data, n); } asio::spawn(my_executor, do_read, [](std::exception_ptr ex, std::string result) { // ... });
These new spawn()
overloads support cancellation, and the basic_yield_context
completion token has also been enhanced to support move-only and variadic
result types. When targeting C++11 and later, these functions are implemented
in terms of Boost.Context directly. The existing overloads have been retained
but are deprecated.
Added the is_async_operation
trait and async_operation
concept. The is_async_operation
trait may be used to determine if a function object, and optional arguments,
may be called to initiate an asynchronous operation. For example, when
using deferred
:
auto d = my_timer.async_wait(asio::deferred); static_assert(asio::is_async_operation<decltype(d)>::value);
or with a handcrafted asynchronous operation:
struct my_async_op { asio::ip::tcp::socket& socket_ = ...; template <typename Token> auto operator()(asio::const_buffer data, Token&& token) { return asio::async_write(socket_, data, std::forward<Token>(token)); } }; static_assert( asio::is_async_operation< my_async_op, asio::const_buffer>::value);
Added the completion_signature_of
trait. The completion_signature_of
trait (and corresponding type alias completion_signature_of_t
)
may be used to determine the completion signature of an asynchronous operation.
For example:
auto d = my_timer.async_wait(asio::deferred); using sig = asio::completion_signature_of<decltype(d)>::type; // sig is void(error_code)
or with a handcrafted asynchronous operation:
struct my_async_op { asio::ip::tcp::socket& socket_ = ...; template <typename Token> auto operator()(asio::const_buffer data, Token&& token) { return asio::async_write(socket_, data, std::forward<Token>(token)); } }; using sig = asio::completion_signature_of< my_async_op, asio::const_buffer>::type; // sig is void(error_code, size_t)
object_handle
,
Windows stream handles, and Windows random-access handles.
release()
member functions to pipes, Windows stream handles, and Windows random-access
handles.
Endpoint
implementations that return void
pointers from their data()
member functions, as per the documented
Endpoint
type requirements.
all()
and race()
from experimental::promise
, as experimental::parallel_group
covers this functionality.
-masm=intel
.
shutdown()
calls are thread-safe with respect to
certain other synchronous operations on the same socket.
std::invoke_result
for clang/libc++.
experimental::parallel_group
initiation incorrectly moved arguments instead of forwarding them.
post()
, dispatch()
, and defer()
, where the the associated allocator may
be obtained from an already moved-from completion handler.
awaitable<>
implementation to propagate exceptions from awaited initiation functions
through the current completion handler.
std::aligned_alloc
with gcc
.
std::aligned_storage
on newer compilers.
async_result
form.
fopen()
.
EAGAIN
as an indication
of an in-progress connect operation.
experimental::basic_channel::reset()
and experimental::basic_concurrent_channel::reset()
so that they work correctly for an unclosed channel.
experimental::promise
operations race()
and all()
.
co_spawn
implementation
to explicitly dispatch cancellation signals through the specified executor,
if the the completion handler has an associated executor of its own.
make_strand()
, make_work_guard()
, ip::address_v4
,
ip::address_v6
, experimental::basic_channel
,
and experimental::basic_concurrent_channel
.
async_compose
, experimental::deferred
, experimental::parallel_group
,
experimental::promise
, channels, and completion token
adapters.
io_context
reference documentation to use executor_work_guard
when preventing the io_context
from running out of work.
deadline_timer
from the Overview documentation.
bind_allocator
, to
simplify associating a custom allocator with a completion token or handler.
file_base::sync_all_on_write
flag, which maps to
O_SYNC
on POSIX and FILE_FLAG_WRITE_THROUGH
on Windows.
basic_file::release()
.
recycling_allocator
as part of the public interface.
nodiscard
attribute
to the following functions:
bind_allocator()
bind_cancellation_slot()
bind_executor()
buffer()
dynamic_buffer()
experimental::append()
experimental::as_single()
experimental::as_tuple()
experimental::make_parallel_group()
experimental::prepend()
get_associated_allocator()
get_associated_cancellation_slot()
get_associated_executor()
make_work_guard()
SSL*
into an ssl::stream<>
.
executor_work_guard<>
even when ASIO_NO_TS_EXECUTORS
is defined.
bind_cancellation_slot
compatibility with legacy completion tokens.
bind_executor
compatibility
with legacy completion tokens.
associator
specialisations
for experimental::append
and experimental::prepend
,
to correctly propagate the associated allocator, executor, and cancellation
slot.
awaitable
.
asio/io_context.hpp
is included.
associated_allocator
template was not correctly detecting the nested T::allocator_type
.
io_uring
implementation of async_receive_from
operation for sockets.
io_uring
implementation of write_some_at
operation for files.
io_uring
implementation to correctly check that
it is not the default before registering with reactor.
io_uring
in some build configurations.
experimental::coro
's per-operation cancellation to
clear the slot at completion of each operation.
experimental::promise
's
type-erased completion handlers.
operator=
implementation for ssl::stream
.
any_io_executor
implementation
to work when both ASIO_USE_TS_EXECUTOR_AS_DEFAULT
and ASIO_SEPARATE_COMPILATION
are defined.
basic_socket::at_mark()
when using the sockatmark()
system call.
dispatch()
, post()
, and defer()
to cover both the old and new executor
forms.
ssl
facilities.
bind_executor
compatibility
with completion tokens.
ASIO_USE_TS_EXECUTOR_AS_DEFAULT
is defined.
awaitable<>
.
experimental::parallel_group
that occured when the execution context was shut down with parallel operations
still pending.
shared_ptr
use
from experimental::coro
co_spawn()
implementation.
async_resume
from being called on experimental::coro
temporaries.
awaitable_operators.hpp
header self-contained.
ssl
certificates
used in examples.
ASIO_HAS_IO_URING
and ASIO_DISABLE_EPOLL
.ASIO_HAS_IO_URING
alone will enable the backend without using it for the existing I/O objects.
This allows it to be used for I/O objects that require io_uring support,
such as files.liburing
library at both compile and link time. Add -luring
to your list of libraries for
linking.
Added support for files. This introduces new classes for stream-oriented
and random-access files. For example, to write to a newly created stream-oriented
file:
asio::stream_file file( my_io_context, "/path/to/file", asio::stream_file::write_only | asio::stream_file::create | asio::stream_file::truncate); file.async_write_some(my_buffer, [](error_code e, size_t n) { // ... });
or to read from a random-access file:
asio::random_access_file file( my_io_context, "/path/to/file", asio::random_access_file::read_only); file.async_read_some_at(1234, my_buffer, [](error_code e, size_t n) { // ... });
This feature currently supports I/O completion ports on Windows,
and io_uring on Linux (define ASIO_HAS_IO_URING
to enable).
Added support for portable pipes. This change add supports for pipes on
POSIX and Windows (when I/O completion ports are available). For example,
to create and use a connected pair of pipe objects:
asio::readable_pipe read_end; asio::writable_pipe write_end; asio::connect_pipe(read_end, write_end); write_end.async_write_some(my_write_buffer, [](error_code e, size_t n) { // ... }); read_end.async_read_some(my_read_buffer, [](error_code e, size_t n) { // ... });
Added support for registered buffers. The mutable_registered_buffer
and const_registered_buffer
classes are buffer sequence types that represent registered buffers. These
buffers are obtained by first performing a buffer registration:
auto my_registration = asio::register_buffers( my_execution_context, my_buffer_sequence);
The registration object must be maintained for as long as the buffer
registration is required. The supplied buffer sequence represents the memory
location or locations that will be registered, and the caller must ensure
they remain valid for as long as they are registered. The registration
is automatically removed when the registration object is destroyed. There
can be at most one active registration per execution context.
The registration object is a container of registered buffers. Buffers may
be obtained from it by iterating over the container, or via direct index
access:
asio::mutable_registered_buffer my_buffer = my_registration[i];
The registered buffers may then be passed directly to operations:
asio::async_read(my_socket, my_buffer, [](error_code ec, size_t n) { // ... });
Buffer registration supports the io_uring backend when used with
read and write operations on descriptors, files, pipes, and sockets. For
portability, the facility may be used on other platforms, but the registered
buffers will behave as normal buffers.
Added experimental support for channels. This adds templates experimental::basic_channel
and experimental::basic_concurrent_channel
,
with aliases experimental::channel
and experimental::concurrent_channel
. Channels may be used
to send completions as messages. For example:
// Create a channel with no buffer space. channel<void(error_code, size_t)> ch(ctx); // The call to try_send fails as there is no buffer // space and no waiting receive operations. bool ok = ch.try_send(asio::error::eof, 123); assert(!ok); // The async_send operation is outstanding until // a receive operation consumes the message. ch.async_send(asio::error::eof, 123, [](error_code ec) { // ... }); // The async_receive consumes the message. Both the // async_send and async_receive operations complete // immediately. ch.async_receive( [](error_code ec, size_t n) { // ... });
experimental::coro
.
co_spawn
for
coro
tasks.
aligned_alloc
on clang
when using an MSVC runtime.
ip::network_v4::canonical()
.
io_context
executors to a single pointer.
execution::any_executor
and any_io_executor
.
gcc
and clang
.
experimental::coro
compatibility with gcc
.
experimental::promise
compatibility with gcc
.
parallel_group
.
experimental::coro
.
parallel_group
to use the recycling allocator for shared state.
awaitable
memory
recycling to use the configurable cache size.
parallel_group
respects operations' associated executors.
boost_
prefix
to namespaces during boostification.
deferred
operator().
deferred
constructors.
push
/pop_options
includes.
awaitable
implementation.
/std:c++latest
.
dev_poll_reactor
backend is used.
posix::basic_stream_descriptor
move operations
to work with non-defaulted executors.
&&
and ||
.
strand<>
to avoid using a potentially moved-from executor.
_aligned_malloc
arguments for MSVC.
cancellation_signal
.
gcc
tests are not used for clang
when detecting compiler features.
clang
shipped with
MSVC.
OPENSSL_NO_SSL_INTERN
is defined.
CancellationSlot
, a lightweight cancellation
channel that is specified through the new associated_cancellation_slot
associator. A concrete CancellationSlot
implementation is provided in the form of the cancellation_signal
and cancellation_slot
classes.
In conjunction with the bind_cancellation_slot
helper function, these may be used to hook cancellation into asynchronous
operations. However, it should be noted that these classes are the low-level
building blocks of cancellation, and most use cases should use a higher
level abstraction for cancellation, such as experimental::parallel_group
or the new logical operators for awaitable
(see below). The ability to cancel individual operations, or composed operations,
is currently supported by:
async_read
and async_write
async_compose
awaitable
experimental::coro
(see below)
experimental::parallel_group
operation (see below)
experimental::promise
class (see below)
Added the associator
trait.
The associator
trait is
used to generically forward associators, such as associated_executor
and associated_allocator
,
through intermediate completion handlers. For example:
template <typename Handler> struct intermediate_handler { Handler handler_; template <typename... Args> void operator()(Args&... args) { // ... } }; namespace asio { template < template <typename, typename> class Associator, typename Handler, typename DefaultCandidate> struct associator< Associator, intermediate_handler<Handler>, DefaultCandidate> { using type = typename Associator<Handler, DefaultCandidate>::type; static type get( const intermediate_handler<Handler>& h, const DefaultCandidate& c = DefaultCandidate()) noexcept { return Associator<Handler, DefaultCandidate>::get( h.handler_, c); } }; } // namespace asio
Added support for asynchronous operations with multiple completion signatures.
Completion signatures may also specify that they are noexcept
,
and whether they are lvalue-invocable (and thus do not "consume"
the completion handler) or rvalue-invocable (and thus do "consume"
the handler, indicating an end to the asynchronous operation). For example:
auto my_async_operation(..., asio::completion_token_for< void(intermediate_result_type) & noexcept, void(final_result_type) && > auto&& token) { // ... }
Added operator&&
and operator||
for awaitable<>
.
The logical operators ||
and
&&
have been overloaded
for awaitable<>
,
to allow coroutines to be trivially awaited in parallel.
When
awaited using &&
,
the co_await
expression
waits until both operations have completed successfully. As a "short-circuit"
evaluation, if one operation fails with an exception, the other is immediately
cancelled. For example:
std::tuple<std::size_t, std::size_t> results = co_await ( async_read(socket, input_buffer, use_awaitable) && async_write(socket, output_buffer, use_awaitable) );
When awaited using ||
,
the co_await
expression
waits until either operation succeeds. As a "short-circuit" evaluation,
if one operation succeeds without throwing an exception, the other is immediately
cancelled. For example:
std::variant<std::size_t, std::monostate> results = co_await ( async_read(socket, input_buffer, use_awaitable) || timer.async_wait(use_awaitable) );
The operators may be enabled by adding the #include
:
#include <asio/experimental/awaitable_operators.hpp>
and then bringing the contents of the experimental::awaitable_operators
namespace into scope:
using namespace asio::experimental::awaitable_operators;
Added the experimental::as_tuple
completion token adapter. The as_tuple
completion token adapter can be used to specify that the completion handler
arguments should be combined into a single tuple argument. The as_tuple
adapter may be used in conjunction
with use_awaitable
and
structured bindings as follows:
auto [e, n] = co_await socket.async_read_some( asio::buffer(data), as_tuple(use_awaitable));
Alternatively, it may be used as a default completion token like
so:
using default_token = as_tuple_t<use_awaitable_t<>>; using tcp_socket = default_token::as_default_on_t<tcp::socket>; // ... awaitable<void> do_read(tcp_socket socket) { // ... auto [e, n] = co_await socket.async_read_some(asio::buffer(data)); // ... }
Added the experimental::append
completion token adapter. The append
completion token adapter can be used to pass additional completion handler
arguments at the end of the completion signature. For example:
timer.async_wait( asio::experimental::append( [](std::error_code ec, int i) { // ... }, 42) ); std::future<int> f = timer.async_wait( asio::experimental::append( asio::use_future, 42 ) );
Added the experimental::prepend
completion token adapter. The prepend
completion token adapter can be used to pass additional arguments before
the existing completion handler arguments. For example:
timer.async_wait( asio::experimental::prepend( [](int i, std::error_code ec) { // ... }, 42) ); std::future<std::tuple<int, std::error_code>> f = timer.async_wait( asio::experimental::prepend( asio::use_future, 42 ) );
Added the experimental::deferred
completion token. The deferred
completion token takes a call to an asynchronous operation's initiating
function and turns it into a function object that accepts a completion
token. For example:
auto deferred_op = timer.async_wait( asio::experimental::deferred); ... std::move(deferred_op)( [](std::error_code ec){ ... });
or:
auto deferred_op = timer.async_wait( asio::experimental::deferred); ... std::future<void> = std::move(deferred_op)( asio::use_future);
The deferred token also supports chaining, to create simple compositions:
auto deferred_op = timer.async_wait( asio::experimental::deferred( [&](std::error_code ec) { timer.expires_after( std::chrono::seconds(1)); return timer.async_wait( asio::experimental::deferred); }); ... std::future<void> = std::move(deferred_op)(asio::use_future);
Added the experimental::parallel_group
class and experimental::make_parallel_group
function. This utility may be used to launch work that is performed in
parallel, and wait for one or all of the operations to complete. A parallel_group
implements automatic cancellation
of incomplete operations. For example:
experimental::make_parallel_group( [&](auto token) { return stream.async_read_some(asio::buffer(data), token); }, [&](auto token) { return timer.async_wait(token); } ).async_wait( experimental::wait_for_one(), []( std::array<std::size_t, 2> completion_order, std::error_code ec1, std::size_t n1, std::error_code ec2 ) { // ... } );
The conditions for completion of the group may be specified using
one of the four provided function objects wait_for_all
,
wait_for_one
, wait_for_one_success
, and wait_for_one_error
, or with a custom
function. The parallel_group
class can also be combined with deferred
as follows:
experimental::make_parallel_group( stream.async_read_some(asio::buffer(data), experimental::deferred), timer.async_wait(experimental::deferred) ).async_wait( // ... );
Note: for maximum flexibility, parallel_group
does not propagate the executor automatically to the operations within
the group.
Added experimental::promise
. The promise
type allows eager execution and synchronisation of async operations. For
example:
auto promise = async_read( stream, asio::buffer(my_buffer), asio::experimental::use_promise); ... do other stuff while the read is going on ... promise.async_wait( // completion the operation [](error_code ec, std::size_t bytes_read) { ... });
Promises can be safely disregarded if the result is no longer required.
Different operations can be combined to either wait for all to complete
or for one to complete (and cancel the rest). For example, to wait for
one to complete:
auto timeout_promise = timer.async_wait( asio::experimental::use_promise); auto read_promise = async_read( stream, asio::buffer(my_buffer), asio::experimental::use_promise); auto promise = asio::experimental::promise<>::race( timeout_promise, read_promise); promise.async_wait( [](std::variant<error_code, std::tuple<error_code, std::size_t>> v) { if (v.index() == 0) {} //timed out else if (v.index() == 1) // completed in time });
or to wait for all to complete:
auto write_promise = async_write( stream, asio::buffer(my_write_buffer), asio::experimental::use_promise); auto read_promise = async_read( stream, asio::buffer(my_buffer), asio::experimental::use_promise); auto promise = asio::experimental::promise<>::all( write_promise, read_promise); promise.async_wait( [](std::tuple<error_code, std::size_t> write_result, std::tuple<error_code, std::size_t> read_result) { });
Thanks go to Klemens Morgenstern for contributing this feature.
Added the experimental::coro
class template. The coro
type is a C++20 coroutine primitive for resumable functions, with the ability
to combine both asynchronous waiting (co_await
)
and yielding (co_yield
)
into a single, stateful control flow. For example:
#include <asio.hpp> #include <asio/experimental/coro.hpp> using asio::ip::tcp; asio::experimental::coro<std::string> reader(tcp::socket& sock) { std::string buf; while (sock.is_open()) { std::size_t n = co_await asio::async_read_until( sock, asio::dynamic_buffer(buf), '\n', asio::experimental::use_coro); co_yield buf.substr(0, n); buf.erase(0, n); } } asio::awaitable<void> consumer(tcp::socket sock) { auto r = reader(sock); auto msg1 = co_await r.async_resume(asio::use_awaitable); std::cout << "Message 1: " << msg1.value_or("\n"); auto msg2 = co_await r.async_resume(asio::use_awaitable); std::cout << "Message 2: " << msg2.value_or("\n"); } asio::awaitable<void> listen(tcp::acceptor& acceptor) { for (;;) { co_spawn( acceptor.get_executor(), consumer(co_await acceptor.async_accept(asio::use_awaitable)), asio::detached); } } int main() { asio::io_context ctx; tcp::acceptor acceptor(ctx, {tcp::v4(), 54321}); co_spawn(ctx, listen(acceptor), asio::detached); ctx.run(); }
Thanks go to Klemens Morgenstern for contributing this feature.
ssl::stream<>
.
co_spawn
to dispatch
the coroutine's initial step
to the executor, and to only post
the completion handler if the coroutine did not otherwise perform a context
switch (i.e. a co_await
on an asynchronous operation).
any_executor
and any_io_executor
when
used with asynchronous operations.
nodiscard
attribute
to awaitable<>
.
ASIO_RECYCLING_ALLOCATOR_CACHE_SIZE
macro.
std::system_error
message workaround for recent
MSVC.
use_awaitable_t::executor_with_default
.
any_io_executor
equality operators to correctly return a result based on the target executor.
ip::scope_id_type
type alias.
ip::port_type
type alias.
std::hash
specialisations for IP addresses.
std::hash
specialisations for ip::basic_endpoint<>
.
any_io_executor
to a "strong typedef"-style class.
experimental::as_single
to work with handler hook deprecation.
errno
is not overwritten
if socket()
fails on macOS/FreeBSD.
io_context
and thread_pool
executors
when move-assigned.
call_stack
objects are accessed only from implementation files.
blocking.always
property from being used with strand<>
, as it did not produce the correct
semantics.
asio/impl/src.cpp
.
connect_pair
function (which will fail with an operation_not_supported error).
ip::basic_resolver
.
Added the experimental::as_single
completion token adapter. The as_single
completion token adapter can be used to specify that the completion handler
arguments should be combined into a single argument. For completion signatures
with a single parameter, the argument is passed through as-is. For signatures
with two or more parameters, the arguments are combined into a tuple. The
as_single
adapter may be
used in conjunction with use_awaitable
and structured bindings as follows:
auto [e, n] = co_await socket.async_read_some( asio::buffer(data), as_single(use_awaitable));
Alternatively, it may be used as a default completion token like
so:
using default_token = as_single_t<use_awaitable_t<>>; using tcp_socket = default_token::as_default_on_t<tcp::socket>; // ... awaitable<void> do_read(tcp_socket socket) { // ... auto [e, n] = co_await socket.async_read_some(asio::buffer(data)); // ... }
MSG_NOSIGNAL
on more platforms by using _POSIX_VERSION
to detect whether it is supported.
executor
concept
to test for a const-qualified execute()
.
any_executor
support
for builds without RTTI support.
thread_pool
unit
test to work without RTTI support.
asio::query
.
push/pop_options.hpp
includes.
select
reactor is used on Windows.
any_executor
comparisons and conversion.
strand<>
adaptation of Networking TS executors when targeting older C++ versions
or less conformant compilers.
basic_socket_acceptor
move constructor as noexcept
.
gcc
10's coroutine
support.
windows::overlapped_ptr
.
execution::receiver_of
concept.
execution::executor
,
execution::operation_state
,execution::sender
,
execution::receiver
, execution::receiver_of
,
and execution::scheduler
concepts and the corresponding
traits. These now test first for well-formed CPO expressions (or, in the
case of senders, a specialised sender_traits
template) and, if not valid, short-circuit the remainder of the evaluation.
This helps prevent recursive template instantiations that can occur in
some contexts.
strand
template's constructor, to prevent template instantiation recursion.
execution::any_executor
template's converting constructors, as per the specification.
execution::sender_traits
specialisation and connect()
member function to the thread_pool
executor, as per the specification.
execution::blocking_t::always_t::is_preferable
to be false as per the
specification.
shape_type
and index_type
to thread_pool
executors, as per the specification.
execution::is_executor
) work with void
.
async_compose
support
for standard executors.
any_io_executor
in asio/ts/netfwd.hpp
.
use_future
compatibility
with older compilers.
gcc
.
clang-cl
on Windows.
io_context
executors,
thread_pool
executors,
system_executor
, and strand<>
.
io_context::executor_type
, thread_pool::executor_type
,
system_executor
,
and strand
executors
now meet the requirements for the proposed standard executors. These
classes also continue to meet the existing requirements for the Networking
TS model of executors.
dispatch
, post
, defer
,
get_associated_executor
,
bind_executor
, make_work_guard
, spawn
, co_spawn
,
async_compose
, use_future
, etc., can interoperate
with both new proposed standard executors, and with existing Networking
TS executors. The implementation determines at compile time which
model a particular executor meets; the proposed standard executor
model is used in preference if both are detected.
any_io_executor
type alias has been introduced as the new default runtime-polymorphic
executor for all I/O objects. This type alias points to the execution::any_executor<>
template with a set of supportable properties specified for use with
I/O. This change may break existing code that directly uses the old
polymorphic wrapper, executor
.
If required for backward compatibility, ASIO_USE_TS_EXECUTOR_AS_DEFAULT
can be defined, which changes the any_io_executor
type alias to instead point to the executor
polymorphic wrapper.
ASIO_NO_TS_EXECUTORS
.
Added converting move construction and assignment to basic_waitable_timer
.
This enables move construction and assignment between different timer types,
provided the executor types are convertible. For example:
basic_waitable_timer< clock_type, traits_type, io_context::executor_type > timer1(my_io_context); basic_waitable_timer< clock_type, traits_type, any_io_executor // polymorphic wrapper > timer2(std::move(timer1));
gcc
10.
Added overloads of co_spawn
that launch an awaitable. This change allows us to write:
co_spawn(executor, echo(std::move(socket)), detached);
instead of:
co_spawn(executor, [socket = std::move(socket)]() mutable { return echo(std::move(socket)); }, detached);
use_awaitable_t
's
default executor adapter, to enable conversion between executor types.
detached_t
as a default completion token, by adding members as_default_on()
and as_default_on_t<>
.
ssl::stream<>
.
ssl::stream<>
write operations to linearise gather-write buffer sequences.
asio_handler_invoke
hook. This hook was deprecated with the introduction of the Networking
TS trait associated_executor
and function get_associated_executor()
. Compiling an application with ASIO_NO_DEPRECATED
will now trigger a
compile error if any handler implements the asio_handler_invoke
hook.
asio_handler_allocate
and asio_handle_deallocate
hooks. These hooks were deprecated with the introduction of the Networking
TS trait associated_allocator
and function get_associated_allocator()
. Compiling an application with ASIO_NO_DEPRECATED
will now trigger a
compile error if any handler implements the asio_handler_allocate
or asio_handler_deallocate
hooks.
recv
rather than recvmsg
,
send
rather than
sendmsg
, read
rather than readv
, and write
rather than writev
.
executor
.
errno
and error codes when on an error path.
io_context::exeutor_type
)
is detected.
Added source location support to handler tracking. The new ASIO_HANDLER_LOCATION((file_name,
line,
function_name))
macro may be used to inform the handler tracking mechanism of a source
location. This macro declares an object that is placed on the stack. Then,
when an asynchronous operation is launched with location information, it
outputs lines using the <action>
n^m
, prior to the n*m
line that signifies
the beginning of the asynchronous operation. For example:
@asio|1589423304.861944|>7|ec=system:0,bytes_transferred=5
@asio|1589423304.861952|7^8|in 'async_write' (...../../include/asio/impl/write.hpp:330)
@asio|1589423304.861952|7^8|called from 'do_write' (handler_tracking/async_tcp_echo_server.cpp:62)
@asio|1589423304.861952|7^8|called from 'operator()' (handler_tracking/async_tcp_echo_server.cpp:51)
@asio|1589423304.861952|7*8|socket@0x7ff61c008230.async_send
@asio|1589423304.861975|.8|non_blocking_send,ec=system:0,bytes_transferred=5
@asio|1589423304.861980|<7|
If std::source_location
or std::experimental::source_location
are available, the use_awaitable_t
token (when default-constructed or used as a default completion token)
will also cause handler tracking to output a source location for each newly
created asynchronous operation. A use_awaitable_t
object may also be explicitly constructed with location information.
handlerviz.pl
tool.
Added the handlerlive.pl
tool, which processes handler
tracking output to produce a list of "live" handlers. Live handlers
are those that are associated with pending asynchronous operations, as
well as handlers that are currently executing. For example:
cat output.txt | perl handlerlive.pl
or:
perl handerlive.pl < output.txt
or:
perl handlerlive.pl output.txt
Added the handlertree.pl
tool, which filters handler
tracking output to include only those events in the tree that produced
the nominated handlers. For example, to filter the output to include only
the events associated with handlers 123
,
456
, and their predecessors:
cat output.txt | perl handlertree.pl 123 456
or:
perl handlertree.pl 123 456 < output.txt
This script may be combined with handerlive.pl and handlerviz.pl
to produce a graph of the "live" asynchronous operation chains.
For example:
cat output.txt | \
perl handlertree.pl perl handlerlive.pl output.txt
| \
perl handlerviz.pl | \
dot -Tsvg > output.svg
async_compose
to
work with copyable handlers when passed by lvalue.
co_spawn
.
Executor
base class from the executor_binder
implementation.
noexcept
.
ssl::host_name_verification
class, which is
a drop-in replacement for ssl::rfc2818_verification
.
The ssl::rfc2818_verification
class has been marked
as deprecated. As a consequence of this change, SSL support now depends
on functions that were introduced in OpenSSL 1.0.2.
ssl::context
constructor to take ownership
of a native handle.
gcc
to use
__cplusplus
macro.
strand<>
converting constructors and assignment operators.
async_read
overloads.
ssl::context
class to propagate non-EOF errors
from the add_certificate_authority
function.
thread_pool
destructor hang that occurred when the pool had an associated I/O object.
select
reactor to recreate the "self
pipe trick" sockets on error. This addresses an issue on some versions
of Windows, where these sockets are discconected after a system sleep.
priority_scheduler
example to demonstrate calls to shutdown()
and destroy()
.
use_awaitable_t::as_default_on
function.
boost::placeholders
namespace.
async_compose
implementation due to incorrect overload selection.
async_initiate
helper function to automatically deduce its return type. This is enabled
for C++11 or later.
return_type
.
async_initiate
.
completion_signature<T>
: Checks if T
is a signature of the form R(Args...)
.
completion_handler_for<T, Signature>
: Checks if T
is usable as a completion handler with the specified signature.
completion_token_for<T, Signature>
: Checks if T
is a completion token that can be used with async_initiate and the
specified signature.
(BOOST_)ASIO_COMPLETION_SIGNATURE
,
(BOOST_)ASIO_COMPLETION_HANDLER_FOR
,
and (BOOST_)ASIO_COMPLETION_TOKEN_FOR
are provided. These macros expand to typename
when concepts are unsupported.
Added the nested template type rebind_executor
to all I/O object types, as a way to generically rebind them to use alternative
I/O executors. For example:
using my_socket_type = tcp::socket::rebind_executor<my_executor_type>::other;
executor_type
and member function get_executor()
. Note that the presence of executor_type
and get_executor()
should be treated as optional, and consequently
it may be preferable to access them via the associated_executor
trait and the get_associated_executor()
helper function.
Added the default_completion_token
trait, so that every I/O executor type now has an associated default completion
token type. This trait may be used in asynchronous operation declarations
as follows:
template < typename IoObject, typename CompletionToken = typename default_completion_token< typename IoObject::executor_type >::type > auto async_xyz( IoObject& io_object, CompletionToken&& token = typename default_completion_token< typename IoObject::executor_type >::type{} );
If not specialised, this trait type is void
,
meaning no default completion token type is available for the given I/O
executor.
Specialised the default_completion_token
trait for the use_awaitable
completion token, so that it may be used as shown in the following example:
auto socket = use_awaitable.as_default_on(tcp::socket(my_context)); // ... co_await socket.async_connect(my_endpoint); // Defaults to use_awaitable.
In this example, the type of the socket
object is transformed from tcp::socket
to have an I/O executor with the default completion token set to use_awaitable
. Alternatively, the socket
type may be computed directly:
using tcp_socket = use_awaitable_t<>::as_default_on_t<tcp::socket>; tcp_socket socket(my_context); // ... co_await socket.async_connect(my_endpoint); // Defaults to use_awaitable.
async_initiate
to the Windows-specific I/O objects' asynchronous operations.
Ensured that the executor type is propagated to newly accepted sockets. When synchronously or asynchronously accepting a new connection, but without specifying an executor or execution context, the accept operation will now correctly propagate the executor type from the acceptor to the socket. For example, if your acceptor type is:
basic_socket_acceptor<ip::tcp, my_executor_type>
then your accepted socket type will be:
basic_stream_socket<ip::tcp, my_executor_type>
Protocol
copy and move operations never throw.
Endpoint
default constructor and move operations never throw.
noexcept
qualifier
to protocol accessors.
noexcept
qualifier
to socket move constructors.
case
fall-through in the free function connect()
implementation.
is_*_buffer_sequence
detection traits for
user-defined sequence types.
CancelIoEx
entry point.
get_option()
member function to be const.
shutdown
function.
is_dynamic_buffer
.
async_accept
between sockets with different executor types.
Executor
template parameter. This template parameter defaults to the asio::executor
type (the polymorphic
executor wrapper) but can be used to specify a user-defined executor
type.
asio::io_context&
now accept either an Executor
or a reference to a concrete ExecutionContext
(such as asio::io_context
or asio::thread_pool
).
Note: One potential source of breakage in existing user code is when
reusing an I/O object's io_context
for constructing another I/O object, as in:
asio::steady_timer my_timer(my_socket.get_executor().context());
To fix this, either construct the second I/O object using
the first I/O object's executor:
asio::steady_timer my_timer(my_socket.get_executor());
or otherwise explicitly pass the io_context
:
asio::steady_timer my_timer(my_io_context);
get_io_context
and get_io_service
member functions have now been removed.
async_result
form with an initiate
static
member function.
The async_result
template now supports a new form:
template <typename CompletionToken, typename Signature> struct async_result { typedef /* ... */ return_type; template <typename Initiation, typename RawCompletionToken, typename... Args> static return_type initiate( Initiation&& initiation, RawCompletionToken&& token, Args&&... args); };
initiate
member
function must: (a) transform the token into a completion handler
object handler
; (b)
cause the invocation of the function object initiation
as if by calling std::forward<Initiation>(initiation)(std::move(handler), std::forward<Args>(args)...)
. Note that the invocation of
initiation
may be
deferred (e.g. lazily evaluated), in which case initiation
and args
must be
decay-copied and moved as required.
async_initiate
has also been added as a wrapper for the invocation of async_result<>::initiate
. For backward compatibility,
this function supports both the old and new async_result
forms.
async_initiate
.
handler_type
trait and single-argument form of async_result
have now been removed.
asio
namespace.
awaitable<>
,
co_spawn
, this_coro
, detached
,
and redirect_error
facilities have been moved from the asio::experimental
namespace to namespace asio
.
As part of this change, the this_coro::token()
awaitable has been superseded by
the asio::use_awaitable
completion token.
use_awaitable
and redirect_error
completion tokens work only with asynchronous operations that use
the new form of async_result
with member function initiate
.
Furthermore, when using use_awaitable
,
please be aware that the asynchronous operation is not initiated
until co_await
is
applied to the awaitable<>
.
DynamicBuffer_v2
concept which is CopyConstructible.
This change adds a new set of type requirements for dynamic buffers,
DynamicBuffer_v2
,
which supports copy construction. These new type requirements enable
dynamic buffers to be used as arguments to user-defined composed
operations, where the same dynamic buffer object is used repeatedly
for multiple underlying operations. For example:
template <typename DynamicBuffer> void echo_line(tcp::socket& sock, DynamicBuffer buf) { n = asio::read_until(sock, buf, '\n'); asio::write(sock, buf, asio::transfer_exactly(n)); }
DynamicBuffer
type requirements have been renamed to DynamicBuffer_v1
.
These requirements continue to be compatible with the Networking
TS.
is_dynamic_buffer_v1
and is_dynamic_buffer_v2
have been added to test for conformance to DynamicBuffer_v1
and DynamicBuffer_v2
respectively. The existing is_dynamic_buffer
trait has been retained and delegates to is_dynamic_buffer_v1
(unless ASIO_NO_DYNAMIC_BUFFER_V1
is explicitly defined, in which case it delegates to is_dynamic_buffer_v2
).
dynamic_string_buffer
and dynamic_vector_buffer
classes conform to both DynamicBuffer_v1
and DynamicBuffer_v2
requirements.
ASIO_NO_DYNAMIC_BUFFER_V1
is defined, all support for DynamicBuffer_v1
types and functions is #ifdef-ed out. Support for using basic_streambuf
with the read
, async_read
,
read_until
, async_read_until
, write
, and async_write
functions is also disabled as a consequence.
async_compose
function that simplifies the implementation of user-defined asynchronous
operations.
make_strand
function,
which creates a strand
with a deduced Executor
template argument.
local::basic_endpoint
that takes a string_view
.
ip::address
, ip::address_v4
,
ip::address_v6
, ip::basic_endpoint
,
and executor_work_guard
classes.
buffer_sequence_begin
and buffer_sequence_end
functions.
ASIO_DISABLE_VISIBILITY
configuration #define
that allows visibility pragmas to be disabled. (Note: If symbols are hidden,
extra care must be taken to ensure that Asio types are not passed across
shared library API boundaries.)
ASIO_STANDALONE
automatically if C++11 or later is detected.
ASIO_ENABLE_BOOST
to explicitly disable standalone mode when compiling with C++11 or
later.
configure
script
now defaults to a standalone build unless Boost is specified or detected.
error::message_size
)
occurs on a datagram-oriented socket.
SO_REUSEPORT
when the reuse_address
option is set.
unistd.h
when
targeting Haiku OS, to fix feature detection.
network_v[46].hpp
headers to the top-level convenience header.
pthread_cond_timedwait
.
EndpointSequence
iterator type rather
than assume the presence of a const_iterator
typedef.
buffer_sequence_begin
and buffer_sequence_end
to prevent implicit conversion. This change addresses an issue where a
call to buffer_sequence_begin
or buffer_sequence_end
could trigger an implicit conversion to const_buffer
or mutable_buffer
. Whenever
this implicit conversion occurred, the return value of buffer_sequence_begin
or buffer_sequence_end
would point to a temporary object.
eof
error
on SSL shutdown as it actually indicates success.
SSL_ERROR_SYSCALL
result without an associated
error.
<atomic>
when targeting apple/clang/libc++ with
recent Xcode versions, even for C++03. This fixes a warning about the deprecation
of OSMemoryBarrier
.
decltype
support for that compiler.
_WIN32_WINNT
to 0x0601
(Windows 7).
dispatch
documentation
to note that it may call the supplied function object in the current thread.
post
and defer
documentation to clarify the the
distinction between them.
std::future
availability with libstdc++.
read_until
.
std::experimental::string_view
and std::string_view
with newer clang/libc++.
std::invoke_result
.
decltype
is available.
size()
, max_size()
or empty()
on default-constructed resolver results.
std::string_view
detection issue when using
clang-cl.
io_context::executor_type::dispatch
.
basic_socket_acceptor::get_option
.
experimental::detached
completion token.
experimental::redirect_error
completion token.
experimental::co_spawn
facility for integration with the coroutines technical specification.
asio::steady_timer
rather than asio::deadline_timer
.
asio::dynamic_buffer
rather than asio::streambuf
.
asio::io_context::run_for()
function for blocking clients.
(BOOST_)ASIO_NO_DEPRECATED
is defined.
(BOOST_)ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM
to enable the old Boost.Date_Time interface in basic_socket_streambuf
and basic_socket_iostream
.
is_dynamic_buffer
trait.
async_result
incompatibility
with deprecated handler_type
.
basic_resolver_results::value_type
typedef.
SSL_OP_NO_COMPRESSION
is defined.
add_certificate_authority
to process multiple certificates in a bundle.
std::invoke_result
rather than std::result_of
.
std::string_view
for C++17 or later, and
std::experimental::string_view
for C++14. Define the preprocessor
macro (BOOST_)ASIO_DISABLE_STD_STRING_VIEW
to force the use of std::experimental::string_view (assuming it is available)
when compiling in C++17 mode.
DynamicBuffer
template
arguments are decayed before using in enable_if
tests.
basic_yield_context
to work with completion signatures containing reference parameters.
spawn()
correctly store decayed copies of their
function and handler arguments.
basic_socket<Protocol, SocketService>
we now have simply basic_socket<Protocol>
.
The old interface can be enabled by defining the (BOOST_)ASIO_ENABLE_OLD_SERVICES
macro.
io_context
basis.
ssl::stream<>
constructor argument.
Executor
type
requirements and classes to support an executor framework, including
the execution_context
base class, the executor_work
class for tracking outstanding work, and the executor
polymorphic wrapper. Free functions dispatch()
, post()
and defer()
have been added and are used to
submit function objects to executors.
wrap()
is used to associate an executor
with a handler or other object. The handler hooks for allocation,
invocation and continuation have been deprecated.
system_executor
class has been added as a default executor.
io_service
class
is now derived from execution_context
and implements the executor type requirements in its nested executor_type
class. The member
functions dispatch()
, post()
, defer()
and wrap()
have been deprecated. The io_service::work
class has been deprecated.
io_service
member
function reset()
has been renamed to restart()
. The old name is retained for backward
compatibility but has been deprecated.
make_service<>()
function is now used to
add a new service to an execution context such as an io_service
. The add_service()
function has been deprecated.
strand<>
template has been added to allow strand functionality to be used
with generic executor types.
io_service
via a context()
member function. The get_io_service()
member function is deprecated.
io_service::post()
, io_service::dispatch()
, io_service::strand::post()
and io_service::strand::dispatch()
functions still require copyable
handlers.
expiry()
member function for obtaining the expiry time. The accessors expires_at()
and expires_after()
have been deprecated, though those
names are retained for the mutating members.
std::packaged_task
class template is
now supported as a completion handler. The initiating operation automatically
returns the future associated with the task. The package()
function has been added as a convenient
factory for packaged tasks.
wait()
and async_wait()
operations that may be used to wait for readiness. The null_buffers
type has been deprecated.
address_cast<>()
, make_address()
, make_address_v4()
and make_address_v6()
free functions. The from_string()
,
to_v4()
,
to_v6()
and v4_mapped()
member functions have been deprecated.
ip::address
now represents an invalid address value that is neither IPv4 nor
IPv6.
buffer()
overloads that generate mutable buffers for non-const string
objects.
asio::streambuf
class. This support includes:
dynamic_string_buffer
and dynamic_vector_buffer
adapter classes that meet the DynamicBufferSequence
type requirements.
dynamic_buffer()
factory functions for creating
a dynamic buffer adapter for a vector
or string
.
read()
, async_read()
, write()
and async_write()
, read_until()
and async_read_until()
free functions that directly
support dynamic buffer sequences.
address_iterator_v4
for iterating across IPv4 addresses
address_iterator_v6
for iterating across IPv6 addresses
address_range_v4
to represent a range of IPv4 addresses
address_range_v6
to represent a range of IPv6 addresses
network_v4
for manipulating IPv4 CIDR addresses, e.g. 1.2.3.0/24
network_v6
for manipulating IPv6 CIDR addresses, e.g. ffe0:/120
<asio/ts/*.hpp>
that correspond to the headers in the proposal.
thread_pool
class.
spawn()
to be executor-aware.
spawn()
overload that takes only a function object.
spawn()
and yield_context
to permit
nested calls to the completion handler.
std::endl
to ensure output is flushed.
ssl::stream<>
bug that may result in spurious 'short read' errors.
ssl::stream<>
constructor argument.
yield_context
object with asynchronous operations.
ConnectEx
function are mapped to their portable equivalents.
join_group
failures as non-fatal.
kqueue
reactor so that it works on FreeBSD.
kqueue
reactor which resulted
in spinning when using serial ports on Mac OS.
kqueue
reactor support for read-only file descriptors.
/dev/poll
reactor.
WSASocketW
,
as WSASocketA
has been
deprecated.
use_future
and spawn()
are not made available when including the asio.hpp
convenience header.
asio::strand
as deprecated. Use asio::io_service::strand
instead.
kqueue
backend that was introduced
in Asio 1.10.2.
gcc
on AIX.
gcc
problem to do with anonymous enums.
HANDLE
backend change to ignore ERROR_MORE_DATA
.
Instead, the error will be propagated as with any other (i.e. in an error_code
or thrown as a system_error
), and the number of bytes
transferred will be returned. For code that needs to handle partial messages,
the error_code
overload
should be used.
signal_set
implementation's signal number check.
SO_UPDATE_CONNECT_CONTEXT
is defined.
VerifyVersionInfo
rather than GetVersionEx
, as GetVersionEx
has been deprecated.
asio::spawn()
to work correctly with new Boost.Coroutine interface.
asio::spawn()
coroutines are correctly unwound when
cleaned up by the io_service
destructor.
io_service::wrap()
and strand::wrap()
.
ConnectEx
,
if available, for connection-oriented IP sockets.
io_service
backend for non-Windows (and non-IOCP Windows) platforms to use a single
condition variable per io_service
instance. This addresses a potential race condition when run_one()
is used from multiple threads.
boost::chrono
and std::chrono
clocks.
EV_CLEAR
handling in the kqueue backend, to address other cases where the close()
system call may hang on Mac OS X.
resolver_query_base::flags::operator~
.
select
reactor
more efficient on Windows for large numbers of sockets.
gcc
.
GetQueuedCompletionStatus
timeout workaround on recent versions of Windows.
FormatMessageW
rather than FormatMessageA
,
as the Windows store does not permit the latter.
io_service
,
strand
, buffers,
composed operations, timers, etc., should all work as normal.
cancel()
function is not supported for sockets. Asynchronous operations may
only be cancelled by closing the socket.
null_buffers
are not supported.
tcp::no_delay
and socket_base::keep_alive
options are supported.
ASIO_STANDALONE
on your compiler command line or as part of the project options. This standalone
configuration has been tested for the following platforms and compilers:
-std=c++11
)
-std=c++11 -stdlib=libc++
)
async_connect
were
not correctly propagated through to the completion handler.
io_service
.
When the bug occurs, the result of an asynchronous operation (error and
bytes tranferred) is incorrectly discarded and zero values used instead.
For TCP sockets this results in spurious end-of-file notifications.
async_wait
on a signal that is already raised.
async_write_at
operations.
HANDLE
backend to treat ERROR_MORE_DATA
as a non-fatal error when returned by GetOverlappedResult
for a synchronous read.
generic
as a keyword. Added a workaround that renames the namespace to cpp_generic
when those language extensions
are in effect.
async_result
support in 1.10.0. In particular,
the buffered stream templates have been updated so that they adhere to
current handler patterns.
use_future
support
for Microsoft Visual Studio 2012.
std::min
in the Windows IOCP backend to avoid
a dependency on the <algorithm>
header.
SSL_CTX_clear_options
function.
handler_type
and async_result
, that
allow the customisation of the return type of an initiating function.
asio::spawn()
function, a high-level wrapper for running stackful coroutines, based on
the Boost.Coroutine library. The spawn()
function enables programs to implement
asynchronous logic in a synchronous manner. For example: size_t n
= my_socket.async_read_some(my_buffer, yield);
. For further information, see Stackful
Coroutines.
asio::use_future
special value, which provides
first-class support for returning a C++11 std::future
from an asynchronous operation's initiating function. For example: future<size_t>
= my_socket.async_read_some(my_buffer, asio::use_future);
. For further information, see Futures.
asio_handler_is_continuation
.
Asynchronous operations may represent a continuation of the asynchronous
control flow associated with the current executing handler. The asio_handler_is_continuation
hook can
be customised to return true
if this is the case, and Asio's implementation can use this knowledge to
optimise scheduling of the new handler. To cover common cases, Asio customises
the hook for strands, spawn()
and composed asynchronous operations.
generic::datagram_protocol
,
generic::raw_protocol
, generic::seq_packet_protocol
and generic::stream_protocol
, which implement the
Protocol
type requirements,
but allow the user to specify the address family (e.g. AF_INET
)
and protocol type (e.g. IPPROTO_TCP
)
at runtime. For further information, see Support
for Other Protocols.
ip::tcp::socket
can be converted into a generic::stream_protocol::socket
via move construction. For further information, see Support
for Other Protocols.
basic_socket_acceptor<>
's accept()
and async_accept()
functions to allow a new connection to
be accepted directly into a socket of a more generic type. For example,
an ip::tcp::acceptor
can be used to accept into a
generic::stream_protocol::socket
object. For further information,
see Support for
Other Protocols.
ASIO_STANDALONE
on your compiler command
line or as part of the project options. This standalone configuration has
currently been tested for the following platforms and compilers:
-std=c++11
)
-std=c++11 -stdlib=libc++
)
ssl::stream<>
class's handshake()
and async_handshake()
functions have been added. These
accept a ConstBufferSequence
to be used as initial input to the ssl engine for the handshake procedure.
ssl::context
objects.
set_verify_depth()
function to the ssl::context
and ssl::stream<>
classes.
add_certificate_authority()
, use_certificate()
, use_certificate_chain()
, use_private_key()
, use_rsa_private_key()
and use_tmp_dh()
, have been added to the ssl::context
class.
ssl::context
to automatically disable
SSL compression by default. To enable, use the new ssl::context::clear_options()
function, as in my_context.clear_options(ssl::context::no_compression)
.
signal_set
implementation.
#warning
directive.
epoll
implementation.
error_code
with an invalid
(i.e. NULL
) error_category
.
basic_waitable_timer
's
underlying implementation so that it can handle any time_point
value without overflowing the intermediate duration objects.
run()
and poll()
on the same io_service
object.
ssl::rfc2818_verification
class.
asio/detail/winsock_init.hpp
for details.
basic_socket::get_option
's
documentation.
long
rather
than int
for SSL_CTX options,
to match OpenSSL.
_snwprintf
to address a compile error due to the changed swprintf
signature in recent versions of MinGW.
io_service
threads due
to running out of work.
accept
as non-fatal.
ip::tcp::iostream
and C++11.
#include <cctype>
, needed for some versions of MinGW.
gcc
's atomic builtins on ARM CPUs, when
available.
io_service
has been destroyed.
epoll_create1()
function but always fail with ENOSYS.
buffered_write_stream
.
epoll_reactor
backend to do lazy registration for EPOLLOUT
events.
epoll_reactor
handling of out-of-band data, which was broken by an incomplete fix in
the last release.
OPENSSL_NO_ENGINE
feature test #define
.
windows::object_handle
so that it works with Windows
compilers that support C++11 move semantics (such as g++
).
g++
4.7 when compiling in C++11 mode.
signal_set
handlers were not being delivered when the io_service
was constructed with a concurrency_hint
of 1.
basic_waitable_timer
based around the C++11 clock type requirements. It may be used with the
clocks from the C++11 <chrono>
library facility or, if those are not available, Boost.Chrono. The typedefs
high_resolution_timer
,
steady_timer
and system_timer
may be used to create timer
objects for the standard clock types.
windows::object_handle
class for performing waits
on Windows kernel objects. Thanks go to Boris Schaeling for contributing
substantially to the development of this feature.
connect()
can return EAGAIN in certain circumstances. Remapped this to another error
so that it doesn't look like a non-blocking operation.
buffered_write_stream
.
io_service
is repeatedly run without
anything to do.
concurrency_hint
is 1) to eliminate a lock/unlock pair.
epoll_reactor
speculative operations to be performed without holding the lock.
epoll_reactor
's
I/O operation immediately before the corresponding handler is called.
This also improves scalability across CPUs when multiple threads
are running the io_service
.
boost::array
or std::array
) of exactly two buffers.
async_read_until
.
signal()
function from the global namespace.
deadline_timer
implementation so that it does not read the clock unless the timer heap
is non-empty.
null_buffers
operations so that they obey the user's non-blocking setting.
fd_set
at runtime when using Windows.
epoll_reactor
initialisation.
(BOOST_)ASIO_STRAND_IMPLEMENTATIONS
to the desired number.
(BOOST_)ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION
flag which switches the allocation of strand implementations to use a round-robin
approach rather than hashing.
strand.post()
is used.
-std=c++0x
mode on g++ 4.5 or higher.
signal()
or sigaction()
.
errno
is preserved across the implementation's signal handler.
io_service
destructor).
OPENSSL_NO_SSL2
is defined.
tick_count_timer
example by making
the duration type signed. Previously, a wait on an already-passed deadline
would not return for a very long time.
(BOOST_)ASIO_ENABLE_OLD_SSL
.
asio::buffer()
overloads for std::array
, when available. The support is
automatically enabled when compiling in -std=c++0x
mode
on g++ 4.3 or higher, or when using MSVC 10. The support may be explicitly
enabled by defining (BOOST_)ASIO_HAS_STD_ARRAY
,
or disabled by defining (BOOST_)ASIO_DISABLE_STD_ARRAY
.
array
,
shared_ptr
, weak_ptr
and atomic
when they are available, rather than the Boost equivalents.
std::error_code
and std::system_error
is no longer enabled by default for g++ 4.5, as that compiler's standard
library does not implement std::system_error::what()
correctly.
fork()
system call. Programs that use fork()
must call io_service.notify_fork()
at the appropriate times. Two new examples have been added showing how
to use this feature.
close()
system call. In particular, assume that
most operating systems won't have close()
fail with EWOULDBLOCK
,
but if it does then set the blocking mode and restart the call. If any
other error occurs, assume the descriptor is closed.
EV_ONESHOT
seems to cause problems on some versions of Mac OS X, with the io_service
destructor getting stuck inside
the close()
system call. Changed the kqueue backend to use EV_CLEAR
instead.
what()
messages.
shutdown_service()
member functions to be private.
signal_set_service::cancel()
.
SignalHandler
example.
signal_set_service.hpp
so that constants like NSIG
may be used.
signal_set_service
implementation so that it doesn't assume that SIGRTMAX
is a compile-time constant.
signal_set
. Programs may add one or more
signals to the set, and then perform an async_wait()
operation. The specified handler will
be called when one of the signals occurs. The same signal number may registered
with multiple signal_set
objects, however the signal number must be used only with Asio.
(BOOST_)ASIO_ENABLE_HANDLER_TRACKING
,
Asio writes debugging output to the standard error stream. The output records
asynchronous operations and the relationships between their handlers. It
may be post-processed using the included handlerviz.pl
tool to create a visual representation of the handlers (requires GraphViz).
asio::streambuf
where the consume()
function did not always update the internal
buffer pointers correctly. The problem may occur when the asio::streambuf
is filled with data using the
standard C++ member functions such as sputn()
. (Note: the problem does not manifest
when the streambuf is populated by the Asio free functions read()
,
async_read()
,
read_until()
or async_read_until()
.)
perform()
function are not correctly re-registered
with kqueue.
std::error_code
and std::system_error
is no longer enabled by default for MSVC10, as that compiler's standard
library does not implement std::system_error::what()
correctly.
buffers_iterator<>
and ip::basic_resolver_iterator
classes so that the value_type typedefs are non-const byte types.
ip::tcp::iostream
.
A timeout is set by calling expires_at()
or expires_from_now()
to establish a deadline. Any socket operations
which occur past the deadline will put the iostream into a bad state.
error()
member function to socket iostreams, for retrieving the error code from
the most recent system call.
basic_deadline_timer::cancel_one()
function. This function lets you cancel
a single waiting handler on a timer. Handlers are cancelled in FIFO order.
transfer_exactly()
completion condition. This can be used
to send or receive a specified number of bytes even if the total size of
the buffer (or buffer sequence) is larger.
connect()
and async_connect()
. These operations try each endpoint in
a list until the socket is successfully connected.
buffer_size()
function so that it works for buffer
sequences in addition to individual buffers.
buffer_copy()
function that can be used to copy the
raw bytes between individual buffers and buffer sequences.
read()
, read_at()
, write()
and write_at()
that do not require a completion condition.
static_assert
is also used to generate an informative error message. This checking may
be disabled by defining (BOOST_)ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS
.
std::error_code
and std::system_error
, when available. The support
is automatically enabled when compiling in -std=c++0x
mode on g++ 4.5 or higher, or when using MSVC 10. The support may be explicitly
enabled by defining ASIO_HAS_STD_SYSTEM_ERROR
,
or disabled by defining ASIO_DISABLE_STD_SYSTEM_ERROR
.
(Available in non-Boost version of Asio only.)
is_loopback()
,
is_unspecified()
and is_multicast()
functions consistently available across the ip::address
,
ip::address_v4
and ip::address_v6
classes.
non_blocking()
functions for managing the non-blocking
behaviour of a socket or descriptor. The io_control()
commands named non_blocking_io
are now deprecated in favour of these new functions.
native_non_blocking()
functions for managing the non-blocking
mode of the underlying socket or descriptor. These functions are intended
to allow the encapsulation of arbitrary non-blocking system calls as asynchronous
operations, in a way that is transparent to the user of the socket object.
The functions have no effect on the behaviour of the synchronous operations
of the socket or descriptor.
io_control()
member function for socket acceptors.
native_type
typedefs in favour of native_handle_type
, and the native()
member functions in favour of native_handle()
.
release()
member function to posix descriptors. This function releases ownership
of the underlying native descriptor to the caller.
SOCK_SEQPACKET
).
io_service::stopped()
function that can be used to determine
whether the io_service
has stopped (i.e. a reset()
call is needed prior to any further calls
to run()
,
run_one()
,
poll()
or poll_one()
).
-std=c++0x
mode on g++ 4.5 or higher, or when using MSVC10.
ip::basic_endpoint<>
objects (such as ip::tcp::endpoint
and ip::udp::endpoint
).
assign()
may have been dup()
-ed,
and so require explicit deregistration from the reactor.
io_service()
. The get_io_service()
member functions should be used instead.
resolver_query
and resolver_iterator
from
the ip::tcp
, ip::udp
and ip::icmp
classes.
FIONBIO
constant to int to suppress a compiler warning on some platforms.
-Wshadow
compiler option.
ip::address_v4::broadcast()
is used on 64-bit platforms.
timerfd
support) that prevents timely
delivery of deadline_timer
handlers, after the program has been running for some time.
deadline_timer
may never fire if the io_service
is running in a background thread.
has_service<>
from compiling.
close()
/closesocket()
failures are correctly propagated.
InitializeCriticalSectionAndSpinCount
.
pselect()
on HP-UX, if it is available.
deadline_timer
objects with expiry times set more than 5 minutes in the future may never
expire.
0
,
as per the documentation.
const_buffers_1
.
Protocol
and
id
to avoid clashing with
Objective-C++ keywords.
vector
reallocation
performance issue that can occur when there are many active deadline_timer
objects.
io_control()
implementation on 64-bit Mac OS X and
BSD platforms.
accept()
are incorrectly treated as successes.
asio/impl/src.cpp
in favour of asio/impl/src.hpp
.
#include
s, e.g. if the
program uses boost::array but does not explicitly include <boost/array.hpp>
.)
deadline_timer
implementation to improve performance.
asio::streambuf
with async_read()
and async_read_until()
.
These read operations now use the existing capacity of the streambuf
when reading, rather than limiting
the read to 512 bytes.
asio/impl/src.cpp
in one source file in a program, then build the program with (BOOST_)ASIO_SEPARATE_COMPILATION
defined in the project/compiler settings. Alternatively, (BOOST_)ASIO_DYN_LINK
may be defined to build a separately-compiled Asio as part of a shared
library.
(BOOST_)ASIO_DISABLE_FENCED_BLOCK
to permit the disabling of memory fences around completion handlers, even
if thread support is enabled.
null_buffers
variant of async_send_to
.
isdigit
in getaddrinfo
emulation.
buffers_iterator
.
null_buffers
operations on Windows.
timerfd
for dispatching timers on Linux, when available.
ip::resolver_query_base::flags
as per the TR2 proposal. This type prevents implicit conversion from int
to flags
,
allowing the compiler to catch cases where users incorrectly pass a numeric
port number as the service name.
#define NOMINMAX
for all Windows compilers. Users can define (BOOST_)ASIO_NO_NOMINMAX
to suppress this definition.
error::eof
result to the completion handler.
io_control()
member functions to always call ioctl
on the underlying descriptor when
modifying blocking mode.
InternetProtocol::resolver_query
and InternetProtocol::resolver_iterator
,
as neither typedef is part of the documented InternetProtocol
requirements. The corresponding typedefs in the ip::tcp
,
ip::udp
and ip::icmp
classes have been deprecated.
select()
.
(BOOST_)ASIO_DISABLE_THREADS
macro that allows Asio's threading support to be independently disabled.
boost::addressof
to get the address of handler objects, rather than applying operator&
directly.
OVERLAPPED
structure
to be valid until both the initiating function call has returned and the
completion packet has been delivered.
boost_
prefix to
the extern "C"
thread entry point function.
getaddrinfo
emulation,
only check the socket type (SOCK_STREAM
or SOCK_DGRAM
) if a service
name has been specified. This should allow the emulation to work with raw
sockets.
buffered*_stream<>
templates to treat 0-byte reads and writes as no-ops, to comply with the
documented type requirements for SyncReadStream
,
AsyncReadStream
, SyncWriteStream
and AsyncWriteStream
.
throw
keyword to boost::throw_exception()
to allow Asio to be used when exception support is disabled. Note that
the SSL wrappers still require exception support.
HANDLE
fails.
_GLIBCXX_DEBUG
is defined.
(BOOST_)ASIO_HASH_MAP_BUCKETS
may be used to tweak the sizes used for the bucket arrays. (N.B. this feature
introduced a bug which was fixed in Asio 1.4.3 / Boost 1.40.)
io_control()
so that it adheres to the documented
type requirements for IoControlCommand.
ReadFile
call fails with ERROR_MORE_DATA
. This enables a hack
where a windows::stream_handle
can be used with a message-oriented
named pipe.
(BOOST_)ASIO_DISABLE_SERIAL_PORT
is defined.
windows::overlapped_ptr::complete()
are correctly passed to the completion
handler.
size_t
CompletionCondition(error_code ec, size_t total)
,
where the return value indicates the maximum number of bytes to be transferred
on the next read or write operation. (The old CompletionCondition signature
is still supported for backwards compatibility).
windows::overlapped_ptr
class to allow arbitrary
overlapped I/O functions (such as TransmitFile
)
to be used with Asio.
eventfd
descriptor is now used (rather than a pipe) to interrupt a blocked select/epoll
reactor.
lowest_layer()
.
io_service
implementations now use lazy initialisation to reduce the memory usage
of an io_service
object
used only as a message queue.
HANDLE
s
such as named pipes (requires HANDLE
s
that work with I/O completion ports).
HANDLE
s
such as files (requires HANDLE
s
that work with I/O completion ports).
null_buffers
type.
read_until()
and async_read_until()
overloads that take a user-defined function object for locating message
boundaries.
(BOOST_)ASIO_ENABLE_TWO_LOCK_QUEUE
)
that may provide better io_service
scalability across many processors.
First stable release of Asio.