diff options
Diffstat (limited to 'src/boost/libs/asio')
423 files changed, 75600 insertions, 0 deletions
diff --git a/src/boost/libs/asio/example/cpp03/allocation/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/allocation/Jamfile.v2 new file mode 100644 index 000000000..f47511bdb --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/allocation/Jamfile.v2 @@ -0,0 +1,30 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe server + : server.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp03/allocation/server.cpp b/src/boost/libs/asio/example/cpp03/allocation/server.cpp new file mode 100644 index 000000000..7a0e4966f --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/allocation/server.cpp @@ -0,0 +1,285 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <iostream> +#include <boost/aligned_storage.hpp> +#include <boost/array.hpp> +#include <boost/bind/bind.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/asio.hpp> + +using boost::asio::ip::tcp; + +// Class to manage the memory to be used for handler-based custom allocation. +// It contains a single block of memory which may be returned for allocation +// requests. If the memory is in use when an allocation request is made, the +// allocator delegates allocation to the global heap. +class handler_memory + : private boost::noncopyable +{ +public: + handler_memory() + : in_use_(false) + { + } + + void* allocate(std::size_t size) + { + if (!in_use_ && size < storage_.size) + { + in_use_ = true; + return storage_.address(); + } + else + { + return ::operator new(size); + } + } + + void deallocate(void* pointer) + { + if (pointer == storage_.address()) + { + in_use_ = false; + } + else + { + ::operator delete(pointer); + } + } + +private: + // Storage space used for handler-based custom memory allocation. + boost::aligned_storage<1024> storage_; + + // Whether the handler-based custom allocation storage has been used. + bool in_use_; +}; + +// The allocator to be associated with the handler objects. This allocator only +// needs to satisfy the C++11 minimal allocator requirements, plus rebind when +// targeting C++03. +template <typename T> +class handler_allocator +{ +public: + typedef T value_type; + + explicit handler_allocator(handler_memory& mem) + : memory_(mem) + { + } + + template <typename U> + handler_allocator(const handler_allocator<U>& other) + : memory_(other.memory_) + { + } + + template <typename U> + struct rebind + { + typedef handler_allocator<U> other; + }; + + bool operator==(const handler_allocator& other) const + { + return &memory_ == &other.memory_; + } + + bool operator!=(const handler_allocator& other) const + { + return &memory_ != &other.memory_; + } + + T* allocate(std::size_t n) const + { + return static_cast<T*>(memory_.allocate(sizeof(T) * n)); + } + + void deallocate(T* p, std::size_t /*n*/) const + { + return memory_.deallocate(p); + } + +//private: + // The underlying memory. + handler_memory& memory_; +}; + +// Wrapper class template for handler objects to allow handler memory +// allocation to be customised. The allocator_type typedef and get_allocator() +// member function are used by the asynchronous operations to obtain the +// allocator. Calls to operator() are forwarded to the encapsulated handler. +template <typename Handler> +class custom_alloc_handler +{ +public: + typedef handler_allocator<Handler> allocator_type; + + custom_alloc_handler(handler_memory& m, Handler h) + : memory_(m), + handler_(h) + { + } + + allocator_type get_allocator() const + { + return allocator_type(memory_); + } + + template <typename Arg1> + void operator()(Arg1 arg1) + { + handler_(arg1); + } + + template <typename Arg1, typename Arg2> + void operator()(Arg1 arg1, Arg2 arg2) + { + handler_(arg1, arg2); + } + +private: + handler_memory& memory_; + Handler handler_; +}; + +// Helper function to wrap a handler object to add custom allocation. +template <typename Handler> +inline custom_alloc_handler<Handler> make_custom_alloc_handler( + handler_memory& m, Handler h) +{ + return custom_alloc_handler<Handler>(m, h); +} + +class session + : public boost::enable_shared_from_this<session> +{ +public: + session(boost::asio::io_context& io_context) + : socket_(io_context) + { + } + + tcp::socket& socket() + { + return socket_; + } + + void start() + { + socket_.async_read_some(boost::asio::buffer(data_), + make_custom_alloc_handler(handler_memory_, + boost::bind(&session::handle_read, + shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred))); + } + + void handle_read(const boost::system::error_code& error, + size_t bytes_transferred) + { + if (!error) + { + boost::asio::async_write(socket_, + boost::asio::buffer(data_, bytes_transferred), + make_custom_alloc_handler(handler_memory_, + boost::bind(&session::handle_write, + shared_from_this(), + boost::asio::placeholders::error))); + } + } + + void handle_write(const boost::system::error_code& error) + { + if (!error) + { + socket_.async_read_some(boost::asio::buffer(data_), + make_custom_alloc_handler(handler_memory_, + boost::bind(&session::handle_read, + shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred))); + } + } + +private: + // The socket used to communicate with the client. + tcp::socket socket_; + + // Buffer used to store data received from the client. + boost::array<char, 1024> data_; + + // The memory to use for handler-based custom memory allocation. + handler_memory handler_memory_; +}; + +typedef boost::shared_ptr<session> session_ptr; + +class server +{ +public: + server(boost::asio::io_context& io_context, short port) + : io_context_(io_context), + acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) + { + session_ptr new_session(new session(io_context_)); + acceptor_.async_accept(new_session->socket(), + boost::bind(&server::handle_accept, this, new_session, + boost::asio::placeholders::error)); + } + + void handle_accept(session_ptr new_session, + const boost::system::error_code& error) + { + if (!error) + { + new_session->start(); + } + + new_session.reset(new session(io_context_)); + acceptor_.async_accept(new_session->socket(), + boost::bind(&server::handle_accept, this, new_session, + boost::asio::placeholders::error)); + } + +private: + boost::asio::io_context& io_context_; + tcp::acceptor acceptor_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: server <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + using namespace std; // For atoi. + server s(io_context, atoi(argv[1])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/buffers/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/buffers/Jamfile.v2 new file mode 100644 index 000000000..f8dde7d80 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/buffers/Jamfile.v2 @@ -0,0 +1,30 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe server + : reference_counted.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp03/buffers/reference_counted.cpp b/src/boost/libs/asio/example/cpp03/buffers/reference_counted.cpp new file mode 100644 index 000000000..d43e27ff4 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/buffers/reference_counted.cpp @@ -0,0 +1,131 @@ +// +// reference_counted.cpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio.hpp> +#include <boost/bind/bind.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/shared_ptr.hpp> +#include <iostream> +#include <vector> + +using boost::asio::ip::tcp; + +// A reference-counted non-modifiable buffer class. +class shared_const_buffer +{ +public: + // Construct from a std::string. + explicit shared_const_buffer(const std::string& data) + : data_(new std::vector<char>(data.begin(), data.end())), + buffer_(boost::asio::buffer(*data_)) + { + } + + // Implement the ConstBufferSequence requirements. + typedef boost::asio::const_buffer value_type; + typedef const boost::asio::const_buffer* const_iterator; + const boost::asio::const_buffer* begin() const { return &buffer_; } + const boost::asio::const_buffer* end() const { return &buffer_ + 1; } + +private: + boost::shared_ptr<std::vector<char> > data_; + boost::asio::const_buffer buffer_; +}; + +class session + : public boost::enable_shared_from_this<session> +{ +public: + session(boost::asio::io_context& io_context) + : socket_(io_context) + { + } + + tcp::socket& socket() + { + return socket_; + } + + void start() + { + using namespace std; // For time_t, time and ctime. + time_t now = time(0); + shared_const_buffer buffer(ctime(&now)); + boost::asio::async_write(socket_, buffer, + boost::bind(&session::handle_write, shared_from_this())); + } + + void handle_write() + { + } + +private: + // The socket used to communicate with the client. + tcp::socket socket_; +}; + +typedef boost::shared_ptr<session> session_ptr; + +class server +{ +public: + server(boost::asio::io_context& io_context, short port) + : io_context_(io_context), + acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) + { + session_ptr new_session(new session(io_context_)); + acceptor_.async_accept(new_session->socket(), + boost::bind(&server::handle_accept, this, new_session, + boost::asio::placeholders::error)); + } + + void handle_accept(session_ptr new_session, + const boost::system::error_code& error) + { + if (!error) + { + new_session->start(); + } + + new_session.reset(new session(io_context_)); + acceptor_.async_accept(new_session->socket(), + boost::bind(&server::handle_accept, this, new_session, + boost::asio::placeholders::error)); + } + +private: + boost::asio::io_context& io_context_; + tcp::acceptor acceptor_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: reference_counted <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + using namespace std; // For atoi. + server s(io_context, atoi(argv[1])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/chat/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/chat/Jamfile.v2 new file mode 100644 index 000000000..342bbdcd4 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/chat/Jamfile.v2 @@ -0,0 +1,35 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <library>/boost/thread//boost_thread + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe chat_server : chat_server.cpp ; +exe chat_client : chat_client.cpp ; +exe posix_chat_client : posix_chat_client.cpp ; diff --git a/src/boost/libs/asio/example/cpp03/chat/chat_client.cpp b/src/boost/libs/asio/example/cpp03/chat/chat_client.cpp new file mode 100644 index 000000000..08b310066 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/chat/chat_client.cpp @@ -0,0 +1,178 @@ +// +// chat_client.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <deque> +#include <iostream> +#include <boost/bind/bind.hpp> +#include <boost/asio.hpp> +#include <boost/thread/thread.hpp> +#include "chat_message.hpp" + +using boost::asio::ip::tcp; + +typedef std::deque<chat_message> chat_message_queue; + +class chat_client +{ +public: + chat_client(boost::asio::io_context& io_context, + const tcp::resolver::results_type& endpoints) + : io_context_(io_context), + socket_(io_context) + { + boost::asio::async_connect(socket_, endpoints, + boost::bind(&chat_client::handle_connect, this, + boost::asio::placeholders::error)); + } + + void write(const chat_message& msg) + { + boost::asio::post(io_context_, + boost::bind(&chat_client::do_write, this, msg)); + } + + void close() + { + boost::asio::post(io_context_, + boost::bind(&chat_client::do_close, this)); + } + +private: + + void handle_connect(const boost::system::error_code& error) + { + if (!error) + { + boost::asio::async_read(socket_, + boost::asio::buffer(read_msg_.data(), chat_message::header_length), + boost::bind(&chat_client::handle_read_header, this, + boost::asio::placeholders::error)); + } + } + + void handle_read_header(const boost::system::error_code& error) + { + if (!error && read_msg_.decode_header()) + { + boost::asio::async_read(socket_, + boost::asio::buffer(read_msg_.body(), read_msg_.body_length()), + boost::bind(&chat_client::handle_read_body, this, + boost::asio::placeholders::error)); + } + else + { + do_close(); + } + } + + void handle_read_body(const boost::system::error_code& error) + { + if (!error) + { + std::cout.write(read_msg_.body(), read_msg_.body_length()); + std::cout << "\n"; + boost::asio::async_read(socket_, + boost::asio::buffer(read_msg_.data(), chat_message::header_length), + boost::bind(&chat_client::handle_read_header, this, + boost::asio::placeholders::error)); + } + else + { + do_close(); + } + } + + void do_write(chat_message msg) + { + bool write_in_progress = !write_msgs_.empty(); + write_msgs_.push_back(msg); + if (!write_in_progress) + { + boost::asio::async_write(socket_, + boost::asio::buffer(write_msgs_.front().data(), + write_msgs_.front().length()), + boost::bind(&chat_client::handle_write, this, + boost::asio::placeholders::error)); + } + } + + void handle_write(const boost::system::error_code& error) + { + if (!error) + { + write_msgs_.pop_front(); + if (!write_msgs_.empty()) + { + boost::asio::async_write(socket_, + boost::asio::buffer(write_msgs_.front().data(), + write_msgs_.front().length()), + boost::bind(&chat_client::handle_write, this, + boost::asio::placeholders::error)); + } + } + else + { + do_close(); + } + } + + void do_close() + { + socket_.close(); + } + +private: + boost::asio::io_context& io_context_; + tcp::socket socket_; + chat_message read_msg_; + chat_message_queue write_msgs_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: chat_client <host> <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + tcp::resolver resolver(io_context); + tcp::resolver::results_type endpoints = resolver.resolve(argv[1], argv[2]); + + chat_client c(io_context, endpoints); + + boost::thread t(boost::bind(&boost::asio::io_context::run, &io_context)); + + char line[chat_message::max_body_length + 1]; + while (std::cin.getline(line, chat_message::max_body_length + 1)) + { + using namespace std; // For strlen and memcpy. + chat_message msg; + msg.body_length(strlen(line)); + memcpy(msg.body(), line, msg.body_length()); + msg.encode_header(); + c.write(msg); + } + + c.close(); + t.join(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/chat/chat_message.hpp b/src/boost/libs/asio/example/cpp03/chat/chat_message.hpp new file mode 100644 index 000000000..0c22c4b23 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/chat/chat_message.hpp @@ -0,0 +1,93 @@ +// +// chat_message.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef CHAT_MESSAGE_HPP +#define CHAT_MESSAGE_HPP + +#include <cstdio> +#include <cstdlib> +#include <cstring> + +class chat_message +{ +public: + enum { header_length = 4 }; + enum { max_body_length = 512 }; + + chat_message() + : body_length_(0) + { + } + + const char* data() const + { + return data_; + } + + char* data() + { + return data_; + } + + size_t length() const + { + return header_length + body_length_; + } + + const char* body() const + { + return data_ + header_length; + } + + char* body() + { + return data_ + header_length; + } + + size_t body_length() const + { + return body_length_; + } + + void body_length(size_t new_length) + { + body_length_ = new_length; + if (body_length_ > max_body_length) + body_length_ = max_body_length; + } + + bool decode_header() + { + using namespace std; // For strncat and atoi. + char header[header_length + 1] = ""; + strncat(header, data_, header_length); + body_length_ = atoi(header); + if (body_length_ > max_body_length) + { + body_length_ = 0; + return false; + } + return true; + } + + void encode_header() + { + using namespace std; // For sprintf and memcpy. + char header[header_length + 1] = ""; + sprintf(header, "%4d", static_cast<int>(body_length_)); + memcpy(data_, header, header_length); + } + +private: + char data_[header_length + max_body_length]; + size_t body_length_; +}; + +#endif // CHAT_MESSAGE_HPP diff --git a/src/boost/libs/asio/example/cpp03/chat/chat_server.cpp b/src/boost/libs/asio/example/cpp03/chat/chat_server.cpp new file mode 100644 index 000000000..9347366fc --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/chat/chat_server.cpp @@ -0,0 +1,249 @@ +// +// chat_server.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <algorithm> +#include <cstdlib> +#include <deque> +#include <iostream> +#include <list> +#include <set> +#include <boost/bind/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/asio.hpp> +#include "chat_message.hpp" + +using boost::asio::ip::tcp; + +//---------------------------------------------------------------------- + +typedef std::deque<chat_message> chat_message_queue; + +//---------------------------------------------------------------------- + +class chat_participant +{ +public: + virtual ~chat_participant() {} + virtual void deliver(const chat_message& msg) = 0; +}; + +typedef boost::shared_ptr<chat_participant> chat_participant_ptr; + +//---------------------------------------------------------------------- + +class chat_room +{ +public: + void join(chat_participant_ptr participant) + { + participants_.insert(participant); + std::for_each(recent_msgs_.begin(), recent_msgs_.end(), + boost::bind(&chat_participant::deliver, + participant, boost::placeholders::_1)); + } + + void leave(chat_participant_ptr participant) + { + participants_.erase(participant); + } + + void deliver(const chat_message& msg) + { + recent_msgs_.push_back(msg); + while (recent_msgs_.size() > max_recent_msgs) + recent_msgs_.pop_front(); + + std::for_each(participants_.begin(), participants_.end(), + boost::bind(&chat_participant::deliver, + boost::placeholders::_1, boost::ref(msg))); + } + +private: + std::set<chat_participant_ptr> participants_; + enum { max_recent_msgs = 100 }; + chat_message_queue recent_msgs_; +}; + +//---------------------------------------------------------------------- + +class chat_session + : public chat_participant, + public boost::enable_shared_from_this<chat_session> +{ +public: + chat_session(boost::asio::io_context& io_context, chat_room& room) + : socket_(io_context), + room_(room) + { + } + + tcp::socket& socket() + { + return socket_; + } + + void start() + { + room_.join(shared_from_this()); + boost::asio::async_read(socket_, + boost::asio::buffer(read_msg_.data(), chat_message::header_length), + boost::bind( + &chat_session::handle_read_header, shared_from_this(), + boost::asio::placeholders::error)); + } + + void deliver(const chat_message& msg) + { + bool write_in_progress = !write_msgs_.empty(); + write_msgs_.push_back(msg); + if (!write_in_progress) + { + boost::asio::async_write(socket_, + boost::asio::buffer(write_msgs_.front().data(), + write_msgs_.front().length()), + boost::bind(&chat_session::handle_write, shared_from_this(), + boost::asio::placeholders::error)); + } + } + + void handle_read_header(const boost::system::error_code& error) + { + if (!error && read_msg_.decode_header()) + { + boost::asio::async_read(socket_, + boost::asio::buffer(read_msg_.body(), read_msg_.body_length()), + boost::bind(&chat_session::handle_read_body, shared_from_this(), + boost::asio::placeholders::error)); + } + else + { + room_.leave(shared_from_this()); + } + } + + void handle_read_body(const boost::system::error_code& error) + { + if (!error) + { + room_.deliver(read_msg_); + boost::asio::async_read(socket_, + boost::asio::buffer(read_msg_.data(), chat_message::header_length), + boost::bind(&chat_session::handle_read_header, shared_from_this(), + boost::asio::placeholders::error)); + } + else + { + room_.leave(shared_from_this()); + } + } + + void handle_write(const boost::system::error_code& error) + { + if (!error) + { + write_msgs_.pop_front(); + if (!write_msgs_.empty()) + { + boost::asio::async_write(socket_, + boost::asio::buffer(write_msgs_.front().data(), + write_msgs_.front().length()), + boost::bind(&chat_session::handle_write, shared_from_this(), + boost::asio::placeholders::error)); + } + } + else + { + room_.leave(shared_from_this()); + } + } + +private: + tcp::socket socket_; + chat_room& room_; + chat_message read_msg_; + chat_message_queue write_msgs_; +}; + +typedef boost::shared_ptr<chat_session> chat_session_ptr; + +//---------------------------------------------------------------------- + +class chat_server +{ +public: + chat_server(boost::asio::io_context& io_context, + const tcp::endpoint& endpoint) + : io_context_(io_context), + acceptor_(io_context, endpoint) + { + start_accept(); + } + + void start_accept() + { + chat_session_ptr new_session(new chat_session(io_context_, room_)); + acceptor_.async_accept(new_session->socket(), + boost::bind(&chat_server::handle_accept, this, new_session, + boost::asio::placeholders::error)); + } + + void handle_accept(chat_session_ptr session, + const boost::system::error_code& error) + { + if (!error) + { + session->start(); + } + + start_accept(); + } + +private: + boost::asio::io_context& io_context_; + tcp::acceptor acceptor_; + chat_room room_; +}; + +typedef boost::shared_ptr<chat_server> chat_server_ptr; +typedef std::list<chat_server_ptr> chat_server_list; + +//---------------------------------------------------------------------- + +int main(int argc, char* argv[]) +{ + try + { + if (argc < 2) + { + std::cerr << "Usage: chat_server <port> [<port> ...]\n"; + return 1; + } + + boost::asio::io_context io_context; + + chat_server_list servers; + for (int i = 1; i < argc; ++i) + { + using namespace std; // For atoi. + tcp::endpoint endpoint(tcp::v4(), atoi(argv[i])); + chat_server_ptr server(new chat_server(io_context, endpoint)); + servers.push_back(server); + } + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/chat/posix_chat_client.cpp b/src/boost/libs/asio/example/cpp03/chat/posix_chat_client.cpp new file mode 100644 index 000000000..85581ef6d --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/chat/posix_chat_client.cpp @@ -0,0 +1,204 @@ +// +// posix_chat_client.cpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <cstring> +#include <iostream> +#include <boost/array.hpp> +#include <boost/bind/bind.hpp> +#include <boost/asio.hpp> +#include "chat_message.hpp" + +#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + +using boost::asio::ip::tcp; +namespace posix = boost::asio::posix; + +class posix_chat_client +{ +public: + posix_chat_client(boost::asio::io_context& io_context, + const tcp::resolver::results_type& endpoints) + : socket_(io_context), + input_(io_context, ::dup(STDIN_FILENO)), + output_(io_context, ::dup(STDOUT_FILENO)), + input_buffer_(chat_message::max_body_length) + { + boost::asio::async_connect(socket_, endpoints, + boost::bind(&posix_chat_client::handle_connect, this, + boost::asio::placeholders::error)); + } + +private: + + void handle_connect(const boost::system::error_code& error) + { + if (!error) + { + // Read the fixed-length header of the next message from the server. + boost::asio::async_read(socket_, + boost::asio::buffer(read_msg_.data(), chat_message::header_length), + boost::bind(&posix_chat_client::handle_read_header, this, + boost::asio::placeholders::error)); + + // Read a line of input entered by the user. + boost::asio::async_read_until(input_, input_buffer_, '\n', + boost::bind(&posix_chat_client::handle_read_input, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + } + + void handle_read_header(const boost::system::error_code& error) + { + if (!error && read_msg_.decode_header()) + { + // Read the variable-length body of the message from the server. + boost::asio::async_read(socket_, + boost::asio::buffer(read_msg_.body(), read_msg_.body_length()), + boost::bind(&posix_chat_client::handle_read_body, this, + boost::asio::placeholders::error)); + } + else + { + close(); + } + } + + void handle_read_body(const boost::system::error_code& error) + { + if (!error) + { + // Write out the message we just received, terminated by a newline. + static char eol[] = { '\n' }; + boost::array<boost::asio::const_buffer, 2> buffers = {{ + boost::asio::buffer(read_msg_.body(), read_msg_.body_length()), + boost::asio::buffer(eol) }}; + boost::asio::async_write(output_, buffers, + boost::bind(&posix_chat_client::handle_write_output, this, + boost::asio::placeholders::error)); + } + else + { + close(); + } + } + + void handle_write_output(const boost::system::error_code& error) + { + if (!error) + { + // Read the fixed-length header of the next message from the server. + boost::asio::async_read(socket_, + boost::asio::buffer(read_msg_.data(), chat_message::header_length), + boost::bind(&posix_chat_client::handle_read_header, this, + boost::asio::placeholders::error)); + } + else + { + close(); + } + } + + void handle_read_input(const boost::system::error_code& error, + std::size_t length) + { + if (!error) + { + // Write the message (minus the newline) to the server. + write_msg_.body_length(length - 1); + input_buffer_.sgetn(write_msg_.body(), length - 1); + input_buffer_.consume(1); // Remove newline from input. + write_msg_.encode_header(); + boost::asio::async_write(socket_, + boost::asio::buffer(write_msg_.data(), write_msg_.length()), + boost::bind(&posix_chat_client::handle_write, this, + boost::asio::placeholders::error)); + } + else if (error == boost::asio::error::not_found) + { + // Didn't get a newline. Send whatever we have. + write_msg_.body_length(input_buffer_.size()); + input_buffer_.sgetn(write_msg_.body(), input_buffer_.size()); + write_msg_.encode_header(); + boost::asio::async_write(socket_, + boost::asio::buffer(write_msg_.data(), write_msg_.length()), + boost::bind(&posix_chat_client::handle_write, this, + boost::asio::placeholders::error)); + } + else + { + close(); + } + } + + void handle_write(const boost::system::error_code& error) + { + if (!error) + { + // Read a line of input entered by the user. + boost::asio::async_read_until(input_, input_buffer_, '\n', + boost::bind(&posix_chat_client::handle_read_input, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + else + { + close(); + } + } + + void close() + { + // Cancel all outstanding asynchronous operations. + socket_.close(); + input_.close(); + output_.close(); + } + +private: + tcp::socket socket_; + posix::stream_descriptor input_; + posix::stream_descriptor output_; + chat_message read_msg_; + chat_message write_msg_; + boost::asio::streambuf input_buffer_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: posix_chat_client <host> <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + tcp::resolver resolver(io_context); + tcp::resolver::results_type endpoints = resolver.resolve(argv[1], argv[2]); + + posix_chat_client c(io_context, endpoints); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} + +#else // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) +int main() {} +#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) diff --git a/src/boost/libs/asio/example/cpp03/echo/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/echo/Jamfile.v2 new file mode 100644 index 000000000..6111d428e --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/echo/Jamfile.v2 @@ -0,0 +1,38 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <library>/boost/thread//boost_thread + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe async_tcp_echo_server : async_tcp_echo_server.cpp ; +exe async_udp_echo_server : async_udp_echo_server.cpp ; +exe blocking_tcp_echo_client : blocking_tcp_echo_client.cpp ; +exe blocking_tcp_echo_server : blocking_tcp_echo_server.cpp ; +exe blocking_udp_echo_client : blocking_udp_echo_client.cpp ; +exe blocking_udp_echo_server : blocking_udp_echo_server.cpp ; diff --git a/src/boost/libs/asio/example/cpp03/echo/async_tcp_echo_server.cpp b/src/boost/libs/asio/example/cpp03/echo/async_tcp_echo_server.cpp new file mode 100644 index 000000000..55c1cb064 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/echo/async_tcp_echo_server.cpp @@ -0,0 +1,137 @@ +// +// async_tcp_echo_server.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <iostream> +#include <boost/bind/bind.hpp> +#include <boost/asio.hpp> + +using boost::asio::ip::tcp; + +class session +{ +public: + session(boost::asio::io_context& io_context) + : socket_(io_context) + { + } + + tcp::socket& socket() + { + return socket_; + } + + void start() + { + socket_.async_read_some(boost::asio::buffer(data_, max_length), + boost::bind(&session::handle_read, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + +private: + void handle_read(const boost::system::error_code& error, + size_t bytes_transferred) + { + if (!error) + { + boost::asio::async_write(socket_, + boost::asio::buffer(data_, bytes_transferred), + boost::bind(&session::handle_write, this, + boost::asio::placeholders::error)); + } + else + { + delete this; + } + } + + void handle_write(const boost::system::error_code& error) + { + if (!error) + { + socket_.async_read_some(boost::asio::buffer(data_, max_length), + boost::bind(&session::handle_read, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + else + { + delete this; + } + } + + tcp::socket socket_; + enum { max_length = 1024 }; + char data_[max_length]; +}; + +class server +{ +public: + server(boost::asio::io_context& io_context, short port) + : io_context_(io_context), + acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) + { + start_accept(); + } + +private: + void start_accept() + { + session* new_session = new session(io_context_); + acceptor_.async_accept(new_session->socket(), + boost::bind(&server::handle_accept, this, new_session, + boost::asio::placeholders::error)); + } + + void handle_accept(session* new_session, + const boost::system::error_code& error) + { + if (!error) + { + new_session->start(); + } + else + { + delete new_session; + } + + start_accept(); + } + + boost::asio::io_context& io_context_; + tcp::acceptor acceptor_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: async_tcp_echo_server <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + using namespace std; // For atoi. + server s(io_context, atoi(argv[1])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/echo/async_udp_echo_server.cpp b/src/boost/libs/asio/example/cpp03/echo/async_udp_echo_server.cpp new file mode 100644 index 000000000..e7d91134e --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/echo/async_udp_echo_server.cpp @@ -0,0 +1,92 @@ +// +// async_udp_echo_server.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <iostream> +#include <boost/bind/bind.hpp> +#include <boost/asio.hpp> + +using boost::asio::ip::udp; + +class server +{ +public: + server(boost::asio::io_context& io_context, short port) + : socket_(io_context, udp::endpoint(udp::v4(), port)) + { + socket_.async_receive_from( + boost::asio::buffer(data_, max_length), sender_endpoint_, + boost::bind(&server::handle_receive_from, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + + void handle_receive_from(const boost::system::error_code& error, + size_t bytes_recvd) + { + if (!error && bytes_recvd > 0) + { + socket_.async_send_to( + boost::asio::buffer(data_, bytes_recvd), sender_endpoint_, + boost::bind(&server::handle_send_to, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + else + { + socket_.async_receive_from( + boost::asio::buffer(data_, max_length), sender_endpoint_, + boost::bind(&server::handle_receive_from, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + } + + void handle_send_to(const boost::system::error_code& /*error*/, + size_t /*bytes_sent*/) + { + socket_.async_receive_from( + boost::asio::buffer(data_, max_length), sender_endpoint_, + boost::bind(&server::handle_receive_from, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + +private: + udp::socket socket_; + udp::endpoint sender_endpoint_; + enum { max_length = 1024 }; + char data_[max_length]; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: async_udp_echo_server <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + using namespace std; // For atoi. + server s(io_context, atoi(argv[1])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/echo/blocking_tcp_echo_client.cpp b/src/boost/libs/asio/example/cpp03/echo/blocking_tcp_echo_client.cpp new file mode 100644 index 000000000..f97d8daaa --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/echo/blocking_tcp_echo_client.cpp @@ -0,0 +1,59 @@ +// +// blocking_tcp_echo_client.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <cstring> +#include <iostream> +#include <boost/asio.hpp> + +using boost::asio::ip::tcp; + +enum { max_length = 1024 }; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: blocking_tcp_echo_client <host> <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + tcp::resolver resolver(io_context); + tcp::resolver::results_type endpoints = + resolver.resolve(tcp::v4(), argv[1], argv[2]); + + tcp::socket s(io_context); + boost::asio::connect(s, endpoints); + + using namespace std; // For strlen. + std::cout << "Enter message: "; + char request[max_length]; + std::cin.getline(request, max_length); + size_t request_length = strlen(request); + boost::asio::write(s, boost::asio::buffer(request, request_length)); + + char reply[max_length]; + size_t reply_length = boost::asio::read(s, + boost::asio::buffer(reply, request_length)); + std::cout << "Reply is: "; + std::cout.write(reply, reply_length); + std::cout << "\n"; + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/echo/blocking_tcp_echo_server.cpp b/src/boost/libs/asio/example/cpp03/echo/blocking_tcp_echo_server.cpp new file mode 100644 index 000000000..b5b364378 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/echo/blocking_tcp_echo_server.cpp @@ -0,0 +1,80 @@ +// +// blocking_tcp_echo_server.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <iostream> +#include <boost/bind/bind.hpp> +#include <boost/smart_ptr.hpp> +#include <boost/asio.hpp> +#include <boost/thread/thread.hpp> + +using boost::asio::ip::tcp; + +const int max_length = 1024; + +typedef boost::shared_ptr<tcp::socket> socket_ptr; + +void session(socket_ptr sock) +{ + try + { + for (;;) + { + char data[max_length]; + + boost::system::error_code error; + size_t length = sock->read_some(boost::asio::buffer(data), error); + if (error == boost::asio::error::eof) + break; // Connection closed cleanly by peer. + else if (error) + throw boost::system::system_error(error); // Some other error. + + boost::asio::write(*sock, boost::asio::buffer(data, length)); + } + } + catch (std::exception& e) + { + std::cerr << "Exception in thread: " << e.what() << "\n"; + } +} + +void server(boost::asio::io_context& io_context, unsigned short port) +{ + tcp::acceptor a(io_context, tcp::endpoint(tcp::v4(), port)); + for (;;) + { + socket_ptr sock(new tcp::socket(io_context)); + a.accept(*sock); + boost::thread t(boost::bind(session, sock)); + } +} + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: blocking_tcp_echo_server <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + using namespace std; // For atoi. + server(io_context, atoi(argv[1])); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/echo/blocking_udp_echo_client.cpp b/src/boost/libs/asio/example/cpp03/echo/blocking_udp_echo_client.cpp new file mode 100644 index 000000000..89afd03bc --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/echo/blocking_udp_echo_client.cpp @@ -0,0 +1,59 @@ +// +// blocking_udp_echo_client.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <cstring> +#include <iostream> +#include <boost/asio.hpp> + +using boost::asio::ip::udp; + +enum { max_length = 1024 }; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: blocking_udp_echo_client <host> <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + udp::socket s(io_context, udp::endpoint(udp::v4(), 0)); + + udp::resolver resolver(io_context); + udp::resolver::results_type endpoints = + resolver.resolve(udp::v4(), argv[1], argv[2]); + + using namespace std; // For strlen. + std::cout << "Enter message: "; + char request[max_length]; + std::cin.getline(request, max_length); + size_t request_length = strlen(request); + s.send_to(boost::asio::buffer(request, request_length), *endpoints.begin()); + + char reply[max_length]; + udp::endpoint sender_endpoint; + size_t reply_length = s.receive_from( + boost::asio::buffer(reply, max_length), sender_endpoint); + std::cout << "Reply is: "; + std::cout.write(reply, reply_length); + std::cout << "\n"; + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/echo/blocking_udp_echo_server.cpp b/src/boost/libs/asio/example/cpp03/echo/blocking_udp_echo_server.cpp new file mode 100644 index 000000000..0db7cd0e1 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/echo/blocking_udp_echo_server.cpp @@ -0,0 +1,53 @@ +// +// blocking_udp_echo_server.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <iostream> +#include <boost/asio.hpp> + +using boost::asio::ip::udp; + +enum { max_length = 1024 }; + +void server(boost::asio::io_context& io_context, unsigned short port) +{ + udp::socket sock(io_context, udp::endpoint(udp::v4(), port)); + for (;;) + { + char data[max_length]; + udp::endpoint sender_endpoint; + size_t length = sock.receive_from( + boost::asio::buffer(data, max_length), sender_endpoint); + sock.send_to(boost::asio::buffer(data, length), sender_endpoint); + } +} + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: blocking_udp_echo_server <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + using namespace std; // For atoi. + server(io_context, atoi(argv[1])); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/fork/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/fork/Jamfile.v2 new file mode 100644 index 000000000..1d93fe89e --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/fork/Jamfile.v2 @@ -0,0 +1,46 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe daemon + : daemon.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe process_per_connection + : process_per_connection.cpp + /boost/system//boost_system + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp03/fork/daemon.cpp b/src/boost/libs/asio/example/cpp03/fork/daemon.cpp new file mode 100644 index 000000000..c69d3a805 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/fork/daemon.cpp @@ -0,0 +1,190 @@ +// +// daemon.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/udp.hpp> +#include <boost/asio/signal_set.hpp> +#include <boost/array.hpp> +#include <boost/bind/bind.hpp> +#include <ctime> +#include <iostream> +#include <syslog.h> +#include <unistd.h> + +using boost::asio::ip::udp; + +class udp_daytime_server +{ +public: + udp_daytime_server(boost::asio::io_context& io_context) + : socket_(io_context, udp::endpoint(udp::v4(), 13)) + { + start_receive(); + } + +private: + void start_receive() + { + socket_.async_receive_from( + boost::asio::buffer(recv_buffer_), remote_endpoint_, + boost::bind(&udp_daytime_server::handle_receive, + this, boost::placeholders::_1)); + } + + void handle_receive(const boost::system::error_code& ec) + { + if (!ec) + { + using namespace std; // For time_t, time and ctime; + time_t now = time(0); + std::string message = ctime(&now); + + boost::system::error_code ignored_ec; + socket_.send_to(boost::asio::buffer(message), + remote_endpoint_, 0, ignored_ec); + } + + start_receive(); + } + + udp::socket socket_; + udp::endpoint remote_endpoint_; + boost::array<char, 1> recv_buffer_; +}; + +int main() +{ + try + { + boost::asio::io_context io_context; + + // Initialise the server before becoming a daemon. If the process is + // started from a shell, this means any errors will be reported back to the + // user. + udp_daytime_server server(io_context); + + // Register signal handlers so that the daemon may be shut down. You may + // also want to register for other signals, such as SIGHUP to trigger a + // re-read of a configuration file. + boost::asio::signal_set signals(io_context, SIGINT, SIGTERM); + signals.async_wait( + boost::bind(&boost::asio::io_context::stop, &io_context)); + + // Inform the io_context that we are about to become a daemon. The + // io_context cleans up any internal resources, such as threads, that may + // interfere with forking. + io_context.notify_fork(boost::asio::io_context::fork_prepare); + + // Fork the process and have the parent exit. If the process was started + // from a shell, this returns control to the user. Forking a new process is + // also a prerequisite for the subsequent call to setsid(). + if (pid_t pid = fork()) + { + if (pid > 0) + { + // We're in the parent process and need to exit. + // + // When the exit() function is used, the program terminates without + // invoking local variables' destructors. Only global variables are + // destroyed. As the io_context object is a local variable, this means + // we do not have to call: + // + // io_context.notify_fork(boost::asio::io_context::fork_parent); + // + // However, this line should be added before each call to exit() if + // using a global io_context object. An additional call: + // + // io_context.notify_fork(boost::asio::io_context::fork_prepare); + // + // should also precede the second fork(). + exit(0); + } + else + { + syslog(LOG_ERR | LOG_USER, "First fork failed: %m"); + return 1; + } + } + + // Make the process a new session leader. This detaches it from the + // terminal. + setsid(); + + // A process inherits its working directory from its parent. This could be + // on a mounted filesystem, which means that the running daemon would + // prevent this filesystem from being unmounted. Changing to the root + // directory avoids this problem. + chdir("/"); + + // The file mode creation mask is also inherited from the parent process. + // We don't want to restrict the permissions on files created by the + // daemon, so the mask is cleared. + umask(0); + + // A second fork ensures the process cannot acquire a controlling terminal. + if (pid_t pid = fork()) + { + if (pid > 0) + { + exit(0); + } + else + { + syslog(LOG_ERR | LOG_USER, "Second fork failed: %m"); + return 1; + } + } + + // Close the standard streams. This decouples the daemon from the terminal + // that started it. + close(0); + close(1); + close(2); + + // We don't want the daemon to have any standard input. + if (open("/dev/null", O_RDONLY) < 0) + { + syslog(LOG_ERR | LOG_USER, "Unable to open /dev/null: %m"); + return 1; + } + + // Send standard output to a log file. + const char* output = "/tmp/asio.daemon.out"; + const int flags = O_WRONLY | O_CREAT | O_APPEND; + const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + if (open(output, flags, mode) < 0) + { + syslog(LOG_ERR | LOG_USER, "Unable to open output file %s: %m", output); + return 1; + } + + // Also send standard error to the same log file. + if (dup(1) < 0) + { + syslog(LOG_ERR | LOG_USER, "Unable to dup output descriptor: %m"); + return 1; + } + + // Inform the io_context that we have finished becoming a daemon. The + // io_context uses this opportunity to create any internal file descriptors + // that need to be private to the new process. + io_context.notify_fork(boost::asio::io_context::fork_child); + + // The io_context can now be used normally. + syslog(LOG_INFO | LOG_USER, "Daemon started"); + io_context.run(); + syslog(LOG_INFO | LOG_USER, "Daemon stopped"); + } + catch (std::exception& e) + { + syslog(LOG_ERR | LOG_USER, "Exception: %s", e.what()); + std::cerr << "Exception: " << e.what() << std::endl; + } +} diff --git a/src/boost/libs/asio/example/cpp03/fork/process_per_connection.cpp b/src/boost/libs/asio/example/cpp03/fork/process_per_connection.cpp new file mode 100644 index 000000000..f7f947222 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/fork/process_per_connection.cpp @@ -0,0 +1,161 @@ +// +// process_per_connection.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/signal_set.hpp> +#include <boost/asio/write.hpp> +#include <boost/array.hpp> +#include <boost/bind/bind.hpp> +#include <cstdlib> +#include <iostream> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +using boost::asio::ip::tcp; + +class server +{ +public: + server(boost::asio::io_context& io_context, unsigned short port) + : io_context_(io_context), + signal_(io_context, SIGCHLD), + acceptor_(io_context, tcp::endpoint(tcp::v4(), port)), + socket_(io_context) + { + start_signal_wait(); + start_accept(); + } + +private: + void start_signal_wait() + { + signal_.async_wait(boost::bind(&server::handle_signal_wait, this)); + } + + void handle_signal_wait() + { + // Only the parent process should check for this signal. We can determine + // whether we are in the parent by checking if the acceptor is still open. + if (acceptor_.is_open()) + { + // Reap completed child processes so that we don't end up with zombies. + int status = 0; + while (waitpid(-1, &status, WNOHANG) > 0) {} + + start_signal_wait(); + } + } + + void start_accept() + { + acceptor_.async_accept(socket_, + boost::bind(&server::handle_accept, this, boost::placeholders::_1)); + } + + void handle_accept(const boost::system::error_code& ec) + { + if (!ec) + { + // Inform the io_context that we are about to fork. The io_context cleans + // up any internal resources, such as threads, that may interfere with + // forking. + io_context_.notify_fork(boost::asio::io_context::fork_prepare); + + if (fork() == 0) + { + // Inform the io_context that the fork is finished and that this is the + // child process. The io_context uses this opportunity to create any + // internal file descriptors that must be private to the new process. + io_context_.notify_fork(boost::asio::io_context::fork_child); + + // The child won't be accepting new connections, so we can close the + // acceptor. It remains open in the parent. + acceptor_.close(); + + // The child process is not interested in processing the SIGCHLD signal. + signal_.cancel(); + + start_read(); + } + else + { + // Inform the io_context that the fork is finished (or failed) and that + // this is the parent process. The io_context uses this opportunity to + // recreate any internal resources that were cleaned up during + // preparation for the fork. + io_context_.notify_fork(boost::asio::io_context::fork_parent); + + socket_.close(); + start_accept(); + } + } + else + { + std::cerr << "Accept error: " << ec.message() << std::endl; + start_accept(); + } + } + + void start_read() + { + socket_.async_read_some(boost::asio::buffer(data_), + boost::bind(&server::handle_read, this, + boost::placeholders::_1, boost::placeholders::_2)); + } + + void handle_read(const boost::system::error_code& ec, std::size_t length) + { + if (!ec) + start_write(length); + } + + void start_write(std::size_t length) + { + boost::asio::async_write(socket_, boost::asio::buffer(data_, length), + boost::bind(&server::handle_write, this, boost::placeholders::_1)); + } + + void handle_write(const boost::system::error_code& ec) + { + if (!ec) + start_read(); + } + + boost::asio::io_context& io_context_; + boost::asio::signal_set signal_; + tcp::acceptor acceptor_; + tcp::socket socket_; + boost::array<char, 1024> data_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: process_per_connection <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + using namespace std; // For atoi. + server s(io_context, atoi(argv[1])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << std::endl; + } +} diff --git a/src/boost/libs/asio/example/cpp03/http/client/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/http/client/Jamfile.v2 new file mode 100644 index 000000000..eedb4068f --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/client/Jamfile.v2 @@ -0,0 +1,33 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe async_client : async_client.cpp ; +exe sync_client : sync_client.cpp ; diff --git a/src/boost/libs/asio/example/cpp03/http/client/async_client.cpp b/src/boost/libs/asio/example/cpp03/http/client/async_client.cpp new file mode 100644 index 000000000..e9bf6baf5 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/client/async_client.cpp @@ -0,0 +1,204 @@ +// +// async_client.cpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <istream> +#include <ostream> +#include <string> +#include <boost/asio.hpp> +#include <boost/bind/bind.hpp> + +using boost::asio::ip::tcp; + +class client +{ +public: + client(boost::asio::io_context& io_context, + const std::string& server, const std::string& path) + : resolver_(io_context), + socket_(io_context) + { + // Form the request. We specify the "Connection: close" header so that the + // server will close the socket after transmitting the response. This will + // allow us to treat all data up until the EOF as the content. + std::ostream request_stream(&request_); + request_stream << "GET " << path << " HTTP/1.0\r\n"; + request_stream << "Host: " << server << "\r\n"; + request_stream << "Accept: */*\r\n"; + request_stream << "Connection: close\r\n\r\n"; + + // Start an asynchronous resolve to translate the server and service names + // into a list of endpoints. + resolver_.async_resolve(server, "http", + boost::bind(&client::handle_resolve, this, + boost::asio::placeholders::error, + boost::asio::placeholders::results)); + } + +private: + void handle_resolve(const boost::system::error_code& err, + const tcp::resolver::results_type& endpoints) + { + if (!err) + { + // Attempt a connection to each endpoint in the list until we + // successfully establish a connection. + boost::asio::async_connect(socket_, endpoints, + boost::bind(&client::handle_connect, this, + boost::asio::placeholders::error)); + } + else + { + std::cout << "Error: " << err.message() << "\n"; + } + } + + void handle_connect(const boost::system::error_code& err) + { + if (!err) + { + // The connection was successful. Send the request. + boost::asio::async_write(socket_, request_, + boost::bind(&client::handle_write_request, this, + boost::asio::placeholders::error)); + } + else + { + std::cout << "Error: " << err.message() << "\n"; + } + } + + void handle_write_request(const boost::system::error_code& err) + { + if (!err) + { + // Read the response status line. The response_ streambuf will + // automatically grow to accommodate the entire line. The growth may be + // limited by passing a maximum size to the streambuf constructor. + boost::asio::async_read_until(socket_, response_, "\r\n", + boost::bind(&client::handle_read_status_line, this, + boost::asio::placeholders::error)); + } + else + { + std::cout << "Error: " << err.message() << "\n"; + } + } + + void handle_read_status_line(const boost::system::error_code& err) + { + if (!err) + { + // Check that response is OK. + std::istream response_stream(&response_); + std::string http_version; + response_stream >> http_version; + unsigned int status_code; + response_stream >> status_code; + std::string status_message; + std::getline(response_stream, status_message); + if (!response_stream || http_version.substr(0, 5) != "HTTP/") + { + std::cout << "Invalid response\n"; + return; + } + if (status_code != 200) + { + std::cout << "Response returned with status code "; + std::cout << status_code << "\n"; + return; + } + + // Read the response headers, which are terminated by a blank line. + boost::asio::async_read_until(socket_, response_, "\r\n\r\n", + boost::bind(&client::handle_read_headers, this, + boost::asio::placeholders::error)); + } + else + { + std::cout << "Error: " << err << "\n"; + } + } + + void handle_read_headers(const boost::system::error_code& err) + { + if (!err) + { + // Process the response headers. + std::istream response_stream(&response_); + std::string header; + while (std::getline(response_stream, header) && header != "\r") + std::cout << header << "\n"; + std::cout << "\n"; + + // Write whatever content we already have to output. + if (response_.size() > 0) + std::cout << &response_; + + // Start reading remaining data until EOF. + boost::asio::async_read(socket_, response_, + boost::asio::transfer_at_least(1), + boost::bind(&client::handle_read_content, this, + boost::asio::placeholders::error)); + } + else + { + std::cout << "Error: " << err << "\n"; + } + } + + void handle_read_content(const boost::system::error_code& err) + { + if (!err) + { + // Write all of the data that has been read so far. + std::cout << &response_; + + // Continue reading remaining data until EOF. + boost::asio::async_read(socket_, response_, + boost::asio::transfer_at_least(1), + boost::bind(&client::handle_read_content, this, + boost::asio::placeholders::error)); + } + else if (err != boost::asio::error::eof) + { + std::cout << "Error: " << err << "\n"; + } + } + + tcp::resolver resolver_; + tcp::socket socket_; + boost::asio::streambuf request_; + boost::asio::streambuf response_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cout << "Usage: async_client <server> <path>\n"; + std::cout << "Example:\n"; + std::cout << " async_client www.boost.org /LICENSE_1_0.txt\n"; + return 1; + } + + boost::asio::io_context io_context; + client c(io_context, argv[1], argv[2]); + io_context.run(); + } + catch (std::exception& e) + { + std::cout << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/http/client/sync_client.cpp b/src/boost/libs/asio/example/cpp03/http/client/sync_client.cpp new file mode 100644 index 000000000..a3b6a5c61 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/client/sync_client.cpp @@ -0,0 +1,106 @@ +// +// sync_client.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <istream> +#include <ostream> +#include <string> +#include <boost/asio.hpp> + +using boost::asio::ip::tcp; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cout << "Usage: sync_client <server> <path>\n"; + std::cout << "Example:\n"; + std::cout << " sync_client www.boost.org /LICENSE_1_0.txt\n"; + return 1; + } + + boost::asio::io_context io_context; + + // Get a list of endpoints corresponding to the server name. + tcp::resolver resolver(io_context); + tcp::resolver::results_type endpoints = resolver.resolve(argv[1], "http"); + + // Try each endpoint until we successfully establish a connection. + tcp::socket socket(io_context); + boost::asio::connect(socket, endpoints); + + // Form the request. We specify the "Connection: close" header so that the + // server will close the socket after transmitting the response. This will + // allow us to treat all data up until the EOF as the content. + boost::asio::streambuf request; + std::ostream request_stream(&request); + request_stream << "GET " << argv[2] << " HTTP/1.0\r\n"; + request_stream << "Host: " << argv[1] << "\r\n"; + request_stream << "Accept: */*\r\n"; + request_stream << "Connection: close\r\n\r\n"; + + // Send the request. + boost::asio::write(socket, request); + + // Read the response status line. The response streambuf will automatically + // grow to accommodate the entire line. The growth may be limited by passing + // a maximum size to the streambuf constructor. + boost::asio::streambuf response; + boost::asio::read_until(socket, response, "\r\n"); + + // Check that response is OK. + std::istream response_stream(&response); + std::string http_version; + response_stream >> http_version; + unsigned int status_code; + response_stream >> status_code; + std::string status_message; + std::getline(response_stream, status_message); + if (!response_stream || http_version.substr(0, 5) != "HTTP/") + { + std::cout << "Invalid response\n"; + return 1; + } + if (status_code != 200) + { + std::cout << "Response returned with status code " << status_code << "\n"; + return 1; + } + + // Read the response headers, which are terminated by a blank line. + boost::asio::read_until(socket, response, "\r\n\r\n"); + + // Process the response headers. + std::string header; + while (std::getline(response_stream, header) && header != "\r") + std::cout << header << "\n"; + std::cout << "\n"; + + // Write whatever content we already have to output. + if (response.size() > 0) + std::cout << &response; + + // Read until EOF, writing data to output as we go. + boost::system::error_code error; + while (boost::asio::read(socket, response, + boost::asio::transfer_at_least(1), error)) + std::cout << &response; + if (error != boost::asio::error::eof) + throw boost::system::system_error(error); + } + catch (std::exception& e) + { + std::cout << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/http/doc_root/data_1K.html b/src/boost/libs/asio/example/cpp03/http/doc_root/data_1K.html new file mode 100644 index 000000000..80e07f009 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/doc_root/data_1K.html @@ -0,0 +1,28 @@ +<!-- +Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) + +Distributed under the Boost Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +--> + +<html> +<body> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the<br/> +</body> +</html> + +<!-- boostinspect:nounlinked --> diff --git a/src/boost/libs/asio/example/cpp03/http/doc_root/data_2K.html b/src/boost/libs/asio/example/cpp03/http/doc_root/data_2K.html new file mode 100644 index 000000000..0584cbe48 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/doc_root/data_2K.html @@ -0,0 +1,49 @@ +<!-- +Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) + +Distributed under the Boost Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +--> + +<html> +<body> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps ove<br/> +</body> +</html> + +<!-- boostinspect:nounlinked --> diff --git a/src/boost/libs/asio/example/cpp03/http/doc_root/data_4K.html b/src/boost/libs/asio/example/cpp03/http/doc_root/data_4K.html new file mode 100644 index 000000000..4c35214d3 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/doc_root/data_4K.html @@ -0,0 +1,91 @@ +<!-- +Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) + +Distributed under the Boost Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +--> + +<html> +<body> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox<br/> +</body> +</html> + +<!-- boostinspect:nounlinked --> diff --git a/src/boost/libs/asio/example/cpp03/http/doc_root/data_8K.html b/src/boost/libs/asio/example/cpp03/http/doc_root/data_8K.html new file mode 100644 index 000000000..fb5624902 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/doc_root/data_8K.html @@ -0,0 +1,175 @@ +<!-- +Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) + +Distributed under the Boost Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +--> + +<html> +<body> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +The quick brown fox jumps over the lazy dog<br/> +.... +</body> +</html> + +<!-- boostinspect:nounlinked --> diff --git a/src/boost/libs/asio/example/cpp03/http/server/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/http/server/Jamfile.v2 new file mode 100644 index 000000000..ed1e3e8ee --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/Jamfile.v2 @@ -0,0 +1,38 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe server + : connection.cpp + connection_manager.cpp + main.cpp + mime_types.cpp + reply.cpp + request_handler.cpp + request_parser.cpp + server.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + /boost/thread//boost_thread + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp03/http/server/connection.cpp b/src/boost/libs/asio/example/cpp03/http/server/connection.cpp new file mode 100644 index 000000000..9bc9a0780 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/connection.cpp @@ -0,0 +1,99 @@ +// +// connection.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "connection.hpp" +#include <vector> +#include <boost/bind/bind.hpp> +#include "connection_manager.hpp" +#include "request_handler.hpp" + +namespace http { +namespace server { + +connection::connection(boost::asio::io_context& io_context, + connection_manager& manager, request_handler& handler) + : socket_(io_context), + connection_manager_(manager), + request_handler_(handler) +{ +} + +boost::asio::ip::tcp::socket& connection::socket() +{ + return socket_; +} + +void connection::start() +{ + socket_.async_read_some(boost::asio::buffer(buffer_), + boost::bind(&connection::handle_read, shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); +} + +void connection::stop() +{ + socket_.close(); +} + +void connection::handle_read(const boost::system::error_code& e, + std::size_t bytes_transferred) +{ + if (!e) + { + boost::tribool result; + boost::tie(result, boost::tuples::ignore) = request_parser_.parse( + request_, buffer_.data(), buffer_.data() + bytes_transferred); + + if (result) + { + request_handler_.handle_request(request_, reply_); + boost::asio::async_write(socket_, reply_.to_buffers(), + boost::bind(&connection::handle_write, shared_from_this(), + boost::asio::placeholders::error)); + } + else if (!result) + { + reply_ = reply::stock_reply(reply::bad_request); + boost::asio::async_write(socket_, reply_.to_buffers(), + boost::bind(&connection::handle_write, shared_from_this(), + boost::asio::placeholders::error)); + } + else + { + socket_.async_read_some(boost::asio::buffer(buffer_), + boost::bind(&connection::handle_read, shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + } + else if (e != boost::asio::error::operation_aborted) + { + connection_manager_.stop(shared_from_this()); + } +} + +void connection::handle_write(const boost::system::error_code& e) +{ + if (!e) + { + // Initiate graceful connection closure. + boost::system::error_code ignored_ec; + socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); + } + + if (e != boost::asio::error::operation_aborted) + { + connection_manager_.stop(shared_from_this()); + } +} + +} // namespace server +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server/connection.hpp b/src/boost/libs/asio/example/cpp03/http/server/connection.hpp new file mode 100644 index 000000000..a701bc68f --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/connection.hpp @@ -0,0 +1,83 @@ +// +// connection.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_CONNECTION_HPP +#define HTTP_CONNECTION_HPP + +#include <boost/asio.hpp> +#include <boost/array.hpp> +#include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include "reply.hpp" +#include "request.hpp" +#include "request_handler.hpp" +#include "request_parser.hpp" + +namespace http { +namespace server { + +class connection_manager; + +/// Represents a single connection from a client. +class connection + : public boost::enable_shared_from_this<connection>, + private boost::noncopyable +{ +public: + /// Construct a connection with the given io_context. + explicit connection(boost::asio::io_context& io_context, + connection_manager& manager, request_handler& handler); + + /// Get the socket associated with the connection. + boost::asio::ip::tcp::socket& socket(); + + /// Start the first asynchronous operation for the connection. + void start(); + + /// Stop all asynchronous operations associated with the connection. + void stop(); + +private: + /// Handle completion of a read operation. + void handle_read(const boost::system::error_code& e, + std::size_t bytes_transferred); + + /// Handle completion of a write operation. + void handle_write(const boost::system::error_code& e); + + /// Socket for the connection. + boost::asio::ip::tcp::socket socket_; + + /// The manager for this connection. + connection_manager& connection_manager_; + + /// The handler used to process the incoming request. + request_handler& request_handler_; + + /// Buffer for incoming data. + boost::array<char, 8192> buffer_; + + /// The incoming request. + request request_; + + /// The parser for the incoming request. + request_parser request_parser_; + + /// The reply to be sent back to the client. + reply reply_; +}; + +typedef boost::shared_ptr<connection> connection_ptr; + +} // namespace server +} // namespace http + +#endif // HTTP_CONNECTION_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server/connection_manager.cpp b/src/boost/libs/asio/example/cpp03/http/server/connection_manager.cpp new file mode 100644 index 000000000..57a509d26 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/connection_manager.cpp @@ -0,0 +1,38 @@ +// +// connection_manager.cpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "connection_manager.hpp" +#include <algorithm> +#include <boost/bind/bind.hpp> + +namespace http { +namespace server { + +void connection_manager::start(connection_ptr c) +{ + connections_.insert(c); + c->start(); +} + +void connection_manager::stop(connection_ptr c) +{ + connections_.erase(c); + c->stop(); +} + +void connection_manager::stop_all() +{ + std::for_each(connections_.begin(), connections_.end(), + boost::bind(&connection::stop, boost::placeholders::_1)); + connections_.clear(); +} + +} // namespace server +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server/connection_manager.hpp b/src/boost/libs/asio/example/cpp03/http/server/connection_manager.hpp new file mode 100644 index 000000000..48c90711f --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/connection_manager.hpp @@ -0,0 +1,44 @@ +// +// connection_manager.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_CONNECTION_MANAGER_HPP +#define HTTP_CONNECTION_MANAGER_HPP + +#include <set> +#include <boost/noncopyable.hpp> +#include "connection.hpp" + +namespace http { +namespace server { + +/// Manages open connections so that they may be cleanly stopped when the server +/// needs to shut down. +class connection_manager + : private boost::noncopyable +{ +public: + /// Add the specified connection to the manager and start it. + void start(connection_ptr c); + + /// Stop the specified connection. + void stop(connection_ptr c); + + /// Stop all connections. + void stop_all(); + +private: + /// The managed connections. + std::set<connection_ptr> connections_; +}; + +} // namespace server +} // namespace http + +#endif // HTTP_CONNECTION_MANAGER_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server/header.hpp b/src/boost/libs/asio/example/cpp03/http/server/header.hpp new file mode 100644 index 000000000..7e176c3b0 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/header.hpp @@ -0,0 +1,28 @@ +// +// header.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_HEADER_HPP +#define HTTP_HEADER_HPP + +#include <string> + +namespace http { +namespace server { + +struct header +{ + std::string name; + std::string value; +}; + +} // namespace server +} // namespace http + +#endif // HTTP_HEADER_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server/main.cpp b/src/boost/libs/asio/example/cpp03/http/server/main.cpp new file mode 100644 index 000000000..a073a7d4d --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/main.cpp @@ -0,0 +1,44 @@ +// +// main.cpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <string> +#include <boost/asio.hpp> +#include <boost/bind/bind.hpp> +#include "server.hpp" + +int main(int argc, char* argv[]) +{ + try + { + // Check command line arguments. + if (argc != 4) + { + std::cerr << "Usage: http_server <address> <port> <doc_root>\n"; + std::cerr << " For IPv4, try:\n"; + std::cerr << " receiver 0.0.0.0 80 .\n"; + std::cerr << " For IPv6, try:\n"; + std::cerr << " receiver 0::0 80 .\n"; + return 1; + } + + // Initialise the server. + http::server::server s(argv[1], argv[2], argv[3]); + + // Run the server until stopped. + s.run(); + } + catch (std::exception& e) + { + std::cerr << "exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/http/server/mime_types.cpp b/src/boost/libs/asio/example/cpp03/http/server/mime_types.cpp new file mode 100644 index 000000000..3964af74c --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/mime_types.cpp @@ -0,0 +1,46 @@ +// +// mime_types.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "mime_types.hpp" + +namespace http { +namespace server { +namespace mime_types { + +struct mapping +{ + const char* extension; + const char* mime_type; +} mappings[] = +{ + { "gif", "image/gif" }, + { "htm", "text/html" }, + { "html", "text/html" }, + { "jpg", "image/jpeg" }, + { "png", "image/png" }, + { 0, 0 } // Marks end of list. +}; + +std::string extension_to_type(const std::string& extension) +{ + for (mapping* m = mappings; m->extension; ++m) + { + if (m->extension == extension) + { + return m->mime_type; + } + } + + return "text/plain"; +} + +} // namespace mime_types +} // namespace server +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server/mime_types.hpp b/src/boost/libs/asio/example/cpp03/http/server/mime_types.hpp new file mode 100644 index 000000000..e9bb88268 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/mime_types.hpp @@ -0,0 +1,27 @@ +// +// mime_types.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_MIME_TYPES_HPP +#define HTTP_MIME_TYPES_HPP + +#include <string> + +namespace http { +namespace server { +namespace mime_types { + +/// Convert a file extension into a MIME type. +std::string extension_to_type(const std::string& extension); + +} // namespace mime_types +} // namespace server +} // namespace http + +#endif // HTTP_MIME_TYPES_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server/reply.cpp b/src/boost/libs/asio/example/cpp03/http/server/reply.cpp new file mode 100644 index 000000000..59eef1cb5 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/reply.cpp @@ -0,0 +1,256 @@ +// +// reply.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "reply.hpp" +#include <string> +#include <boost/lexical_cast.hpp> + +namespace http { +namespace server { + +namespace status_strings { + +const std::string ok = + "HTTP/1.0 200 OK\r\n"; +const std::string created = + "HTTP/1.0 201 Created\r\n"; +const std::string accepted = + "HTTP/1.0 202 Accepted\r\n"; +const std::string no_content = + "HTTP/1.0 204 No Content\r\n"; +const std::string multiple_choices = + "HTTP/1.0 300 Multiple Choices\r\n"; +const std::string moved_permanently = + "HTTP/1.0 301 Moved Permanently\r\n"; +const std::string moved_temporarily = + "HTTP/1.0 302 Moved Temporarily\r\n"; +const std::string not_modified = + "HTTP/1.0 304 Not Modified\r\n"; +const std::string bad_request = + "HTTP/1.0 400 Bad Request\r\n"; +const std::string unauthorized = + "HTTP/1.0 401 Unauthorized\r\n"; +const std::string forbidden = + "HTTP/1.0 403 Forbidden\r\n"; +const std::string not_found = + "HTTP/1.0 404 Not Found\r\n"; +const std::string internal_server_error = + "HTTP/1.0 500 Internal Server Error\r\n"; +const std::string not_implemented = + "HTTP/1.0 501 Not Implemented\r\n"; +const std::string bad_gateway = + "HTTP/1.0 502 Bad Gateway\r\n"; +const std::string service_unavailable = + "HTTP/1.0 503 Service Unavailable\r\n"; + +boost::asio::const_buffer to_buffer(reply::status_type status) +{ + switch (status) + { + case reply::ok: + return boost::asio::buffer(ok); + case reply::created: + return boost::asio::buffer(created); + case reply::accepted: + return boost::asio::buffer(accepted); + case reply::no_content: + return boost::asio::buffer(no_content); + case reply::multiple_choices: + return boost::asio::buffer(multiple_choices); + case reply::moved_permanently: + return boost::asio::buffer(moved_permanently); + case reply::moved_temporarily: + return boost::asio::buffer(moved_temporarily); + case reply::not_modified: + return boost::asio::buffer(not_modified); + case reply::bad_request: + return boost::asio::buffer(bad_request); + case reply::unauthorized: + return boost::asio::buffer(unauthorized); + case reply::forbidden: + return boost::asio::buffer(forbidden); + case reply::not_found: + return boost::asio::buffer(not_found); + case reply::internal_server_error: + return boost::asio::buffer(internal_server_error); + case reply::not_implemented: + return boost::asio::buffer(not_implemented); + case reply::bad_gateway: + return boost::asio::buffer(bad_gateway); + case reply::service_unavailable: + return boost::asio::buffer(service_unavailable); + default: + return boost::asio::buffer(internal_server_error); + } +} + +} // namespace status_strings + +namespace misc_strings { + +const char name_value_separator[] = { ':', ' ' }; +const char crlf[] = { '\r', '\n' }; + +} // namespace misc_strings + +std::vector<boost::asio::const_buffer> reply::to_buffers() +{ + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(status_strings::to_buffer(status)); + for (std::size_t i = 0; i < headers.size(); ++i) + { + header& h = headers[i]; + buffers.push_back(boost::asio::buffer(h.name)); + buffers.push_back(boost::asio::buffer(misc_strings::name_value_separator)); + buffers.push_back(boost::asio::buffer(h.value)); + buffers.push_back(boost::asio::buffer(misc_strings::crlf)); + } + buffers.push_back(boost::asio::buffer(misc_strings::crlf)); + buffers.push_back(boost::asio::buffer(content)); + return buffers; +} + +namespace stock_replies { + +const char ok[] = ""; +const char created[] = + "<html>" + "<head><title>Created</title></head>" + "<body><h1>201 Created</h1></body>" + "</html>"; +const char accepted[] = + "<html>" + "<head><title>Accepted</title></head>" + "<body><h1>202 Accepted</h1></body>" + "</html>"; +const char no_content[] = + "<html>" + "<head><title>No Content</title></head>" + "<body><h1>204 Content</h1></body>" + "</html>"; +const char multiple_choices[] = + "<html>" + "<head><title>Multiple Choices</title></head>" + "<body><h1>300 Multiple Choices</h1></body>" + "</html>"; +const char moved_permanently[] = + "<html>" + "<head><title>Moved Permanently</title></head>" + "<body><h1>301 Moved Permanently</h1></body>" + "</html>"; +const char moved_temporarily[] = + "<html>" + "<head><title>Moved Temporarily</title></head>" + "<body><h1>302 Moved Temporarily</h1></body>" + "</html>"; +const char not_modified[] = + "<html>" + "<head><title>Not Modified</title></head>" + "<body><h1>304 Not Modified</h1></body>" + "</html>"; +const char bad_request[] = + "<html>" + "<head><title>Bad Request</title></head>" + "<body><h1>400 Bad Request</h1></body>" + "</html>"; +const char unauthorized[] = + "<html>" + "<head><title>Unauthorized</title></head>" + "<body><h1>401 Unauthorized</h1></body>" + "</html>"; +const char forbidden[] = + "<html>" + "<head><title>Forbidden</title></head>" + "<body><h1>403 Forbidden</h1></body>" + "</html>"; +const char not_found[] = + "<html>" + "<head><title>Not Found</title></head>" + "<body><h1>404 Not Found</h1></body>" + "</html>"; +const char internal_server_error[] = + "<html>" + "<head><title>Internal Server Error</title></head>" + "<body><h1>500 Internal Server Error</h1></body>" + "</html>"; +const char not_implemented[] = + "<html>" + "<head><title>Not Implemented</title></head>" + "<body><h1>501 Not Implemented</h1></body>" + "</html>"; +const char bad_gateway[] = + "<html>" + "<head><title>Bad Gateway</title></head>" + "<body><h1>502 Bad Gateway</h1></body>" + "</html>"; +const char service_unavailable[] = + "<html>" + "<head><title>Service Unavailable</title></head>" + "<body><h1>503 Service Unavailable</h1></body>" + "</html>"; + +std::string to_string(reply::status_type status) +{ + switch (status) + { + case reply::ok: + return ok; + case reply::created: + return created; + case reply::accepted: + return accepted; + case reply::no_content: + return no_content; + case reply::multiple_choices: + return multiple_choices; + case reply::moved_permanently: + return moved_permanently; + case reply::moved_temporarily: + return moved_temporarily; + case reply::not_modified: + return not_modified; + case reply::bad_request: + return bad_request; + case reply::unauthorized: + return unauthorized; + case reply::forbidden: + return forbidden; + case reply::not_found: + return not_found; + case reply::internal_server_error: + return internal_server_error; + case reply::not_implemented: + return not_implemented; + case reply::bad_gateway: + return bad_gateway; + case reply::service_unavailable: + return service_unavailable; + default: + return internal_server_error; + } +} + +} // namespace stock_replies + +reply reply::stock_reply(reply::status_type status) +{ + reply rep; + rep.status = status; + rep.content = stock_replies::to_string(status); + rep.headers.resize(2); + rep.headers[0].name = "Content-Length"; + rep.headers[0].value = boost::lexical_cast<std::string>(rep.content.size()); + rep.headers[1].name = "Content-Type"; + rep.headers[1].value = "text/html"; + return rep; +} + +} // namespace server +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server/reply.hpp b/src/boost/libs/asio/example/cpp03/http/server/reply.hpp new file mode 100644 index 000000000..6a3240e2d --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/reply.hpp @@ -0,0 +1,64 @@ +// +// reply.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_REPLY_HPP +#define HTTP_REPLY_HPP + +#include <string> +#include <vector> +#include <boost/asio.hpp> +#include "header.hpp" + +namespace http { +namespace server { + +/// A reply to be sent to a client. +struct reply +{ + /// The status of the reply. + enum status_type + { + ok = 200, + created = 201, + accepted = 202, + no_content = 204, + multiple_choices = 300, + moved_permanently = 301, + moved_temporarily = 302, + not_modified = 304, + bad_request = 400, + unauthorized = 401, + forbidden = 403, + not_found = 404, + internal_server_error = 500, + not_implemented = 501, + bad_gateway = 502, + service_unavailable = 503 + } status; + + /// The headers to be included in the reply. + std::vector<header> headers; + + /// The content to be sent in the reply. + std::string content; + + /// Convert the reply into a vector of buffers. The buffers do not own the + /// underlying memory blocks, therefore the reply object must remain valid and + /// not be changed until the write operation has completed. + std::vector<boost::asio::const_buffer> to_buffers(); + + /// Get a stock reply. + static reply stock_reply(status_type status); +}; + +} // namespace server +} // namespace http + +#endif // HTTP_REPLY_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server/request.hpp b/src/boost/libs/asio/example/cpp03/http/server/request.hpp new file mode 100644 index 000000000..358133512 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/request.hpp @@ -0,0 +1,34 @@ +// +// request.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_REQUEST_HPP +#define HTTP_REQUEST_HPP + +#include <string> +#include <vector> +#include "header.hpp" + +namespace http { +namespace server { + +/// A request received from a client. +struct request +{ + std::string method; + std::string uri; + int http_version_major; + int http_version_minor; + std::vector<header> headers; +}; + +} // namespace server +} // namespace http + +#endif // HTTP_REQUEST_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server/request_handler.cpp b/src/boost/libs/asio/example/cpp03/http/server/request_handler.cpp new file mode 100644 index 000000000..2e38447b3 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/request_handler.cpp @@ -0,0 +1,122 @@ +// +// request_handler.cpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "request_handler.hpp" +#include <fstream> +#include <sstream> +#include <string> +#include <boost/lexical_cast.hpp> +#include "mime_types.hpp" +#include "reply.hpp" +#include "request.hpp" + +namespace http { +namespace server { + +request_handler::request_handler(const std::string& doc_root) + : doc_root_(doc_root) +{ +} + +void request_handler::handle_request(const request& req, reply& rep) +{ + // Decode url to path. + std::string request_path; + if (!url_decode(req.uri, request_path)) + { + rep = reply::stock_reply(reply::bad_request); + return; + } + + // Request path must be absolute and not contain "..". + if (request_path.empty() || request_path[0] != '/' + || request_path.find("..") != std::string::npos) + { + rep = reply::stock_reply(reply::bad_request); + return; + } + + // If path ends in slash (i.e. is a directory) then add "index.html". + if (request_path[request_path.size() - 1] == '/') + { + request_path += "index.html"; + } + + // Determine the file extension. + std::size_t last_slash_pos = request_path.find_last_of("/"); + std::size_t last_dot_pos = request_path.find_last_of("."); + std::string extension; + if (last_dot_pos != std::string::npos && last_dot_pos > last_slash_pos) + { + extension = request_path.substr(last_dot_pos + 1); + } + + // Open the file to send back. + std::string full_path = doc_root_ + request_path; + std::ifstream is(full_path.c_str(), std::ios::in | std::ios::binary); + if (!is) + { + rep = reply::stock_reply(reply::not_found); + return; + } + + // Fill out the reply to be sent to the client. + rep.status = reply::ok; + char buf[512]; + while (is.read(buf, sizeof(buf)).gcount() > 0) + rep.content.append(buf, is.gcount()); + rep.headers.resize(2); + rep.headers[0].name = "Content-Length"; + rep.headers[0].value = boost::lexical_cast<std::string>(rep.content.size()); + rep.headers[1].name = "Content-Type"; + rep.headers[1].value = mime_types::extension_to_type(extension); +} + +bool request_handler::url_decode(const std::string& in, std::string& out) +{ + out.clear(); + out.reserve(in.size()); + for (std::size_t i = 0; i < in.size(); ++i) + { + if (in[i] == '%') + { + if (i + 3 <= in.size()) + { + int value = 0; + std::istringstream is(in.substr(i + 1, 2)); + if (is >> std::hex >> value) + { + out += static_cast<char>(value); + i += 2; + } + else + { + return false; + } + } + else + { + return false; + } + } + else if (in[i] == '+') + { + out += ' '; + } + else + { + out += in[i]; + } + } + return true; +} + +} // namespace server +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server/request_handler.hpp b/src/boost/libs/asio/example/cpp03/http/server/request_handler.hpp new file mode 100644 index 000000000..2f542a1e4 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/request_handler.hpp @@ -0,0 +1,46 @@ +// +// request_handler.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_REQUEST_HANDLER_HPP +#define HTTP_REQUEST_HANDLER_HPP + +#include <string> +#include <boost/noncopyable.hpp> + +namespace http { +namespace server { + +struct reply; +struct request; + +/// The common handler for all incoming requests. +class request_handler + : private boost::noncopyable +{ +public: + /// Construct with a directory containing files to be served. + explicit request_handler(const std::string& doc_root); + + /// Handle a request and produce a reply. + void handle_request(const request& req, reply& rep); + +private: + /// The directory containing the files to be served. + std::string doc_root_; + + /// Perform URL-decoding on a string. Returns false if the encoding was + /// invalid. + static bool url_decode(const std::string& in, std::string& out); +}; + +} // namespace server +} // namespace http + +#endif // HTTP_REQUEST_HANDLER_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server/request_parser.cpp b/src/boost/libs/asio/example/cpp03/http/server/request_parser.cpp new file mode 100644 index 000000000..acfdf311b --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/request_parser.cpp @@ -0,0 +1,315 @@ +// +// request_parser.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "request_parser.hpp" +#include "request.hpp" + +namespace http { +namespace server { + +request_parser::request_parser() + : state_(method_start) +{ +} + +void request_parser::reset() +{ + state_ = method_start; +} + +boost::tribool request_parser::consume(request& req, char input) +{ + switch (state_) + { + case method_start: + if (!is_char(input) || is_ctl(input) || is_tspecial(input)) + { + return false; + } + else + { + state_ = method; + req.method.push_back(input); + return boost::indeterminate; + } + case method: + if (input == ' ') + { + state_ = uri; + return boost::indeterminate; + } + else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) + { + return false; + } + else + { + req.method.push_back(input); + return boost::indeterminate; + } + case uri: + if (input == ' ') + { + state_ = http_version_h; + return boost::indeterminate; + } + else if (is_ctl(input)) + { + return false; + } + else + { + req.uri.push_back(input); + return boost::indeterminate; + } + case http_version_h: + if (input == 'H') + { + state_ = http_version_t_1; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_t_1: + if (input == 'T') + { + state_ = http_version_t_2; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_t_2: + if (input == 'T') + { + state_ = http_version_p; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_p: + if (input == 'P') + { + state_ = http_version_slash; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_slash: + if (input == '/') + { + req.http_version_major = 0; + req.http_version_minor = 0; + state_ = http_version_major_start; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_major_start: + if (is_digit(input)) + { + req.http_version_major = req.http_version_major * 10 + input - '0'; + state_ = http_version_major; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_major: + if (input == '.') + { + state_ = http_version_minor_start; + return boost::indeterminate; + } + else if (is_digit(input)) + { + req.http_version_major = req.http_version_major * 10 + input - '0'; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_minor_start: + if (is_digit(input)) + { + req.http_version_minor = req.http_version_minor * 10 + input - '0'; + state_ = http_version_minor; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_minor: + if (input == '\r') + { + state_ = expecting_newline_1; + return boost::indeterminate; + } + else if (is_digit(input)) + { + req.http_version_minor = req.http_version_minor * 10 + input - '0'; + return boost::indeterminate; + } + else + { + return false; + } + case expecting_newline_1: + if (input == '\n') + { + state_ = header_line_start; + return boost::indeterminate; + } + else + { + return false; + } + case header_line_start: + if (input == '\r') + { + state_ = expecting_newline_3; + return boost::indeterminate; + } + else if (!req.headers.empty() && (input == ' ' || input == '\t')) + { + state_ = header_lws; + return boost::indeterminate; + } + else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) + { + return false; + } + else + { + req.headers.push_back(header()); + req.headers.back().name.push_back(input); + state_ = header_name; + return boost::indeterminate; + } + case header_lws: + if (input == '\r') + { + state_ = expecting_newline_2; + return boost::indeterminate; + } + else if (input == ' ' || input == '\t') + { + return boost::indeterminate; + } + else if (is_ctl(input)) + { + return false; + } + else + { + state_ = header_value; + req.headers.back().value.push_back(input); + return boost::indeterminate; + } + case header_name: + if (input == ':') + { + state_ = space_before_header_value; + return boost::indeterminate; + } + else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) + { + return false; + } + else + { + req.headers.back().name.push_back(input); + return boost::indeterminate; + } + case space_before_header_value: + if (input == ' ') + { + state_ = header_value; + return boost::indeterminate; + } + else + { + return false; + } + case header_value: + if (input == '\r') + { + state_ = expecting_newline_2; + return boost::indeterminate; + } + else if (is_ctl(input)) + { + return false; + } + else + { + req.headers.back().value.push_back(input); + return boost::indeterminate; + } + case expecting_newline_2: + if (input == '\n') + { + state_ = header_line_start; + return boost::indeterminate; + } + else + { + return false; + } + case expecting_newline_3: + return (input == '\n'); + default: + return false; + } +} + +bool request_parser::is_char(int c) +{ + return c >= 0 && c <= 127; +} + +bool request_parser::is_ctl(int c) +{ + return (c >= 0 && c <= 31) || (c == 127); +} + +bool request_parser::is_tspecial(int c) +{ + switch (c) + { + case '(': case ')': case '<': case '>': case '@': + case ',': case ';': case ':': case '\\': case '"': + case '/': case '[': case ']': case '?': case '=': + case '{': case '}': case ' ': case '\t': + return true; + default: + return false; + } +} + +bool request_parser::is_digit(int c) +{ + return c >= '0' && c <= '9'; +} + +} // namespace server +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server/request_parser.hpp b/src/boost/libs/asio/example/cpp03/http/server/request_parser.hpp new file mode 100644 index 000000000..e13a13181 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/request_parser.hpp @@ -0,0 +1,95 @@ +// +// request_parser.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_REQUEST_PARSER_HPP +#define HTTP_REQUEST_PARSER_HPP + +#include <boost/logic/tribool.hpp> +#include <boost/tuple/tuple.hpp> + +namespace http { +namespace server { + +struct request; + +/// Parser for incoming requests. +class request_parser +{ +public: + /// Construct ready to parse the request method. + request_parser(); + + /// Reset to initial parser state. + void reset(); + + /// Parse some data. The tribool return value is true when a complete request + /// has been parsed, false if the data is invalid, indeterminate when more + /// data is required. The InputIterator return value indicates how much of the + /// input has been consumed. + template <typename InputIterator> + boost::tuple<boost::tribool, InputIterator> parse(request& req, + InputIterator begin, InputIterator end) + { + while (begin != end) + { + boost::tribool result = consume(req, *begin++); + if (result || !result) + return boost::make_tuple(result, begin); + } + boost::tribool result = boost::indeterminate; + return boost::make_tuple(result, begin); + } + +private: + /// Handle the next character of input. + boost::tribool consume(request& req, char input); + + /// Check if a byte is an HTTP character. + static bool is_char(int c); + + /// Check if a byte is an HTTP control character. + static bool is_ctl(int c); + + /// Check if a byte is defined as an HTTP tspecial character. + static bool is_tspecial(int c); + + /// Check if a byte is a digit. + static bool is_digit(int c); + + /// The current state of the parser. + enum state + { + method_start, + method, + uri, + http_version_h, + http_version_t_1, + http_version_t_2, + http_version_p, + http_version_slash, + http_version_major_start, + http_version_major, + http_version_minor_start, + http_version_minor, + expecting_newline_1, + header_line_start, + header_lws, + header_name, + space_before_header_value, + header_value, + expecting_newline_2, + expecting_newline_3 + } state_; +}; + +} // namespace server +} // namespace http + +#endif // HTTP_REQUEST_PARSER_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server/server.cpp b/src/boost/libs/asio/example/cpp03/http/server/server.cpp new file mode 100644 index 000000000..42253d878 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/server.cpp @@ -0,0 +1,94 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "server.hpp" +#include <boost/bind/bind.hpp> +#include <signal.h> + +namespace http { +namespace server { + +server::server(const std::string& address, const std::string& port, + const std::string& doc_root) + : io_context_(), + signals_(io_context_), + acceptor_(io_context_), + connection_manager_(), + new_connection_(), + request_handler_(doc_root) +{ + // Register to handle the signals that indicate when the server should exit. + // It is safe to register for the same signal multiple times in a program, + // provided all registration for the specified signal is made through Asio. + signals_.add(SIGINT); + signals_.add(SIGTERM); +#if defined(SIGQUIT) + signals_.add(SIGQUIT); +#endif // defined(SIGQUIT) + signals_.async_wait(boost::bind(&server::handle_stop, this)); + + // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). + boost::asio::ip::tcp::resolver resolver(io_context_); + boost::asio::ip::tcp::endpoint endpoint = + *resolver.resolve(address, port).begin(); + acceptor_.open(endpoint.protocol()); + acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + acceptor_.bind(endpoint); + acceptor_.listen(); + + start_accept(); +} + +void server::run() +{ + // The io_context::run() call will block until all asynchronous operations + // have finished. While the server is running, there is always at least one + // asynchronous operation outstanding: the asynchronous accept call waiting + // for new incoming connections. + io_context_.run(); +} + +void server::start_accept() +{ + new_connection_.reset(new connection(io_context_, + connection_manager_, request_handler_)); + acceptor_.async_accept(new_connection_->socket(), + boost::bind(&server::handle_accept, this, + boost::asio::placeholders::error)); +} + +void server::handle_accept(const boost::system::error_code& e) +{ + // Check whether the server was stopped by a signal before this completion + // handler had a chance to run. + if (!acceptor_.is_open()) + { + return; + } + + if (!e) + { + connection_manager_.start(new_connection_); + } + + start_accept(); +} + +void server::handle_stop() +{ + // The server is stopped by cancelling all outstanding asynchronous + // operations. Once all operations have finished the io_context::run() call + // will exit. + acceptor_.close(); + connection_manager_.stop_all(); +} + +} // namespace server +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server/server.hpp b/src/boost/libs/asio/example/cpp03/http/server/server.hpp new file mode 100644 index 000000000..e91b3d5fd --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server/server.hpp @@ -0,0 +1,69 @@ +// +// server.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER_HPP +#define HTTP_SERVER_HPP + +#include <boost/asio.hpp> +#include <string> +#include <boost/noncopyable.hpp> +#include "connection.hpp" +#include "connection_manager.hpp" +#include "request_handler.hpp" + +namespace http { +namespace server { + +/// The top-level class of the HTTP server. +class server + : private boost::noncopyable +{ +public: + /// Construct the server to listen on the specified TCP address and port, and + /// serve up files from the given directory. + explicit server(const std::string& address, const std::string& port, + const std::string& doc_root); + + /// Run the server's io_context loop. + void run(); + +private: + /// Initiate an asynchronous accept operation. + void start_accept(); + + /// Handle completion of an asynchronous accept operation. + void handle_accept(const boost::system::error_code& e); + + /// Handle a request to stop the server. + void handle_stop(); + + /// The io_context used to perform asynchronous operations. + boost::asio::io_context io_context_; + + /// The signal_set is used to register for process termination notifications. + boost::asio::signal_set signals_; + + /// Acceptor used to listen for incoming connections. + boost::asio::ip::tcp::acceptor acceptor_; + + /// The connection manager which owns all live connections. + connection_manager connection_manager_; + + /// The next connection to be accepted. + connection_ptr new_connection_; + + /// The handler for all incoming requests. + request_handler request_handler_; +}; + +} // namespace server +} // namespace http + +#endif // HTTP_SERVER_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server2/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/http/server2/Jamfile.v2 new file mode 100644 index 000000000..dc049c811 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/Jamfile.v2 @@ -0,0 +1,38 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe server + : connection.cpp + io_context_pool.cpp + main.cpp + mime_types.cpp + reply.cpp + request_handler.cpp + request_parser.cpp + server.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + /boost/thread//boost_thread + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp03/http/server2/connection.cpp b/src/boost/libs/asio/example/cpp03/http/server2/connection.cpp new file mode 100644 index 000000000..6f8b02e26 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/connection.cpp @@ -0,0 +1,93 @@ +// +// connection.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "connection.hpp" +#include <vector> +#include <boost/bind/bind.hpp> +#include "request_handler.hpp" + +namespace http { +namespace server2 { + +connection::connection(boost::asio::io_context& io_context, + request_handler& handler) + : socket_(io_context), + request_handler_(handler) +{ +} + +boost::asio::ip::tcp::socket& connection::socket() +{ + return socket_; +} + +void connection::start() +{ + socket_.async_read_some(boost::asio::buffer(buffer_), + boost::bind(&connection::handle_read, shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); +} + +void connection::handle_read(const boost::system::error_code& e, + std::size_t bytes_transferred) +{ + if (!e) + { + boost::tribool result; + boost::tie(result, boost::tuples::ignore) = request_parser_.parse( + request_, buffer_.data(), buffer_.data() + bytes_transferred); + + if (result) + { + request_handler_.handle_request(request_, reply_); + boost::asio::async_write(socket_, reply_.to_buffers(), + boost::bind(&connection::handle_write, shared_from_this(), + boost::asio::placeholders::error)); + } + else if (!result) + { + reply_ = reply::stock_reply(reply::bad_request); + boost::asio::async_write(socket_, reply_.to_buffers(), + boost::bind(&connection::handle_write, shared_from_this(), + boost::asio::placeholders::error)); + } + else + { + socket_.async_read_some(boost::asio::buffer(buffer_), + boost::bind(&connection::handle_read, shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + } + + // If an error occurs then no new asynchronous operations are started. This + // means that all shared_ptr references to the connection object will + // disappear and the object will be destroyed automatically after this + // handler returns. The connection class's destructor closes the socket. +} + +void connection::handle_write(const boost::system::error_code& e) +{ + if (!e) + { + // Initiate graceful connection closure. + boost::system::error_code ignored_ec; + socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); + } + + // No new asynchronous operations are started. This means that all shared_ptr + // references to the connection object will disappear and the object will be + // destroyed automatically after this handler returns. The connection class's + // destructor closes the socket. +} + +} // namespace server2 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server2/connection.hpp b/src/boost/libs/asio/example/cpp03/http/server2/connection.hpp new file mode 100644 index 000000000..c949c64c3 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/connection.hpp @@ -0,0 +1,75 @@ +// +// connection.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER2_CONNECTION_HPP +#define HTTP_SERVER2_CONNECTION_HPP + +#include <boost/asio.hpp> +#include <boost/array.hpp> +#include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include "reply.hpp" +#include "request.hpp" +#include "request_handler.hpp" +#include "request_parser.hpp" + +namespace http { +namespace server2 { + +/// Represents a single connection from a client. +class connection + : public boost::enable_shared_from_this<connection>, + private boost::noncopyable +{ +public: + /// Construct a connection with the given io_context. + explicit connection(boost::asio::io_context& io_context, + request_handler& handler); + + /// Get the socket associated with the connection. + boost::asio::ip::tcp::socket& socket(); + + /// Start the first asynchronous operation for the connection. + void start(); + +private: + /// Handle completion of a read operation. + void handle_read(const boost::system::error_code& e, + std::size_t bytes_transferred); + + /// Handle completion of a write operation. + void handle_write(const boost::system::error_code& e); + + /// Socket for the connection. + boost::asio::ip::tcp::socket socket_; + + /// The handler used to process the incoming request. + request_handler& request_handler_; + + /// Buffer for incoming data. + boost::array<char, 8192> buffer_; + + /// The incoming request. + request request_; + + /// The parser for the incoming request. + request_parser request_parser_; + + /// The reply to be sent back to the client. + reply reply_; +}; + +typedef boost::shared_ptr<connection> connection_ptr; + +} // namespace server2 +} // namespace http + +#endif // HTTP_SERVER2_CONNECTION_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server2/header.hpp b/src/boost/libs/asio/example/cpp03/http/server2/header.hpp new file mode 100644 index 000000000..80efc6cc6 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/header.hpp @@ -0,0 +1,28 @@ +// +// header.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER2_HEADER_HPP +#define HTTP_SERVER2_HEADER_HPP + +#include <string> + +namespace http { +namespace server2 { + +struct header +{ + std::string name; + std::string value; +}; + +} // namespace server2 +} // namespace http + +#endif // HTTP_SERVER2_HEADER_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server2/io_context_pool.cpp b/src/boost/libs/asio/example/cpp03/http/server2/io_context_pool.cpp new file mode 100644 index 000000000..427c22600 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/io_context_pool.cpp @@ -0,0 +1,70 @@ +// +// io_context_pool.cpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "server.hpp" +#include <stdexcept> +#include <boost/thread/thread.hpp> +#include <boost/bind/bind.hpp> +#include <boost/shared_ptr.hpp> + +namespace http { +namespace server2 { + +io_context_pool::io_context_pool(std::size_t pool_size) + : next_io_context_(0) +{ + if (pool_size == 0) + throw std::runtime_error("io_context_pool size is 0"); + + // Give all the io_contexts work to do so that their run() functions will not + // exit until they are explicitly stopped. + for (std::size_t i = 0; i < pool_size; ++i) + { + io_context_ptr io_context(new boost::asio::io_context); + io_contexts_.push_back(io_context); + work_.push_back(boost::asio::make_work_guard(*io_context)); + } +} + +void io_context_pool::run() +{ + // Create a pool of threads to run all of the io_contexts. + std::vector<boost::shared_ptr<boost::thread> > threads; + for (std::size_t i = 0; i < io_contexts_.size(); ++i) + { + boost::shared_ptr<boost::thread> thread(new boost::thread( + boost::bind(&boost::asio::io_context::run, io_contexts_[i]))); + threads.push_back(thread); + } + + // Wait for all threads in the pool to exit. + for (std::size_t i = 0; i < threads.size(); ++i) + threads[i]->join(); +} + +void io_context_pool::stop() +{ + // Explicitly stop all io_contexts. + for (std::size_t i = 0; i < io_contexts_.size(); ++i) + io_contexts_[i]->stop(); +} + +boost::asio::io_context& io_context_pool::get_io_context() +{ + // Use a round-robin scheme to choose the next io_context to use. + boost::asio::io_context& io_context = *io_contexts_[next_io_context_]; + ++next_io_context_; + if (next_io_context_ == io_contexts_.size()) + next_io_context_ = 0; + return io_context; +} + +} // namespace server2 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server2/io_context_pool.hpp b/src/boost/libs/asio/example/cpp03/http/server2/io_context_pool.hpp new file mode 100644 index 000000000..86bd5b45a --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/io_context_pool.hpp @@ -0,0 +1,58 @@ +// +// io_context_pool.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER2_IO_SERVICE_POOL_HPP +#define HTTP_SERVER2_IO_SERVICE_POOL_HPP + +#include <boost/asio.hpp> +#include <list> +#include <vector> +#include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> + +namespace http { +namespace server2 { + +/// A pool of io_context objects. +class io_context_pool + : private boost::noncopyable +{ +public: + /// Construct the io_context pool. + explicit io_context_pool(std::size_t pool_size); + + /// Run all io_context objects in the pool. + void run(); + + /// Stop all io_context objects in the pool. + void stop(); + + /// Get an io_context to use. + boost::asio::io_context& get_io_context(); + +private: + typedef boost::shared_ptr<boost::asio::io_context> io_context_ptr; + typedef boost::asio::executor_work_guard< + boost::asio::io_context::executor_type> io_context_work; + + /// The pool of io_contexts. + std::vector<io_context_ptr> io_contexts_; + + /// The work that keeps the io_contexts running. + std::list<io_context_work> work_; + + /// The next io_context to use for a connection. + std::size_t next_io_context_; +}; + +} // namespace server2 +} // namespace http + +#endif // HTTP_SERVER2_IO_SERVICE_POOL_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server2/main.cpp b/src/boost/libs/asio/example/cpp03/http/server2/main.cpp new file mode 100644 index 000000000..18be4184e --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/main.cpp @@ -0,0 +1,46 @@ +// +// main.cpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <string> +#include <boost/asio.hpp> +#include <boost/bind/bind.hpp> +#include <boost/lexical_cast.hpp> +#include "server.hpp" + +int main(int argc, char* argv[]) +{ + try + { + // Check command line arguments. + if (argc != 5) + { + std::cerr << "Usage: http_server <address> <port> <threads> <doc_root>\n"; + std::cerr << " For IPv4, try:\n"; + std::cerr << " receiver 0.0.0.0 80 1 .\n"; + std::cerr << " For IPv6, try:\n"; + std::cerr << " receiver 0::0 80 1 .\n"; + return 1; + } + + // Initialise the server. + std::size_t num_threads = boost::lexical_cast<std::size_t>(argv[3]); + http::server2::server s(argv[1], argv[2], argv[4], num_threads); + + // Run the server until stopped. + s.run(); + } + catch (std::exception& e) + { + std::cerr << "exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/http/server2/mime_types.cpp b/src/boost/libs/asio/example/cpp03/http/server2/mime_types.cpp new file mode 100644 index 000000000..b2fc5e7aa --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/mime_types.cpp @@ -0,0 +1,46 @@ +// +// mime_types.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "mime_types.hpp" + +namespace http { +namespace server2 { +namespace mime_types { + +struct mapping +{ + const char* extension; + const char* mime_type; +} mappings[] = +{ + { "gif", "image/gif" }, + { "htm", "text/html" }, + { "html", "text/html" }, + { "jpg", "image/jpeg" }, + { "png", "image/png" }, + { 0, 0 } // Marks end of list. +}; + +std::string extension_to_type(const std::string& extension) +{ + for (mapping* m = mappings; m->extension; ++m) + { + if (m->extension == extension) + { + return m->mime_type; + } + } + + return "text/plain"; +} + +} // namespace mime_types +} // namespace server2 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server2/mime_types.hpp b/src/boost/libs/asio/example/cpp03/http/server2/mime_types.hpp new file mode 100644 index 000000000..56e3fd57b --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/mime_types.hpp @@ -0,0 +1,27 @@ +// +// mime_types.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER2_MIME_TYPES_HPP +#define HTTP_SERVER2_MIME_TYPES_HPP + +#include <string> + +namespace http { +namespace server2 { +namespace mime_types { + +/// Convert a file extension into a MIME type. +std::string extension_to_type(const std::string& extension); + +} // namespace mime_types +} // namespace server2 +} // namespace http + +#endif // HTTP_SERVER2_MIME_TYPES_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server2/reply.cpp b/src/boost/libs/asio/example/cpp03/http/server2/reply.cpp new file mode 100644 index 000000000..524cb65e9 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/reply.cpp @@ -0,0 +1,256 @@ +// +// reply.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "reply.hpp" +#include <string> +#include <boost/lexical_cast.hpp> + +namespace http { +namespace server2 { + +namespace status_strings { + +const std::string ok = + "HTTP/1.0 200 OK\r\n"; +const std::string created = + "HTTP/1.0 201 Created\r\n"; +const std::string accepted = + "HTTP/1.0 202 Accepted\r\n"; +const std::string no_content = + "HTTP/1.0 204 No Content\r\n"; +const std::string multiple_choices = + "HTTP/1.0 300 Multiple Choices\r\n"; +const std::string moved_permanently = + "HTTP/1.0 301 Moved Permanently\r\n"; +const std::string moved_temporarily = + "HTTP/1.0 302 Moved Temporarily\r\n"; +const std::string not_modified = + "HTTP/1.0 304 Not Modified\r\n"; +const std::string bad_request = + "HTTP/1.0 400 Bad Request\r\n"; +const std::string unauthorized = + "HTTP/1.0 401 Unauthorized\r\n"; +const std::string forbidden = + "HTTP/1.0 403 Forbidden\r\n"; +const std::string not_found = + "HTTP/1.0 404 Not Found\r\n"; +const std::string internal_server_error = + "HTTP/1.0 500 Internal Server Error\r\n"; +const std::string not_implemented = + "HTTP/1.0 501 Not Implemented\r\n"; +const std::string bad_gateway = + "HTTP/1.0 502 Bad Gateway\r\n"; +const std::string service_unavailable = + "HTTP/1.0 503 Service Unavailable\r\n"; + +boost::asio::const_buffer to_buffer(reply::status_type status) +{ + switch (status) + { + case reply::ok: + return boost::asio::buffer(ok); + case reply::created: + return boost::asio::buffer(created); + case reply::accepted: + return boost::asio::buffer(accepted); + case reply::no_content: + return boost::asio::buffer(no_content); + case reply::multiple_choices: + return boost::asio::buffer(multiple_choices); + case reply::moved_permanently: + return boost::asio::buffer(moved_permanently); + case reply::moved_temporarily: + return boost::asio::buffer(moved_temporarily); + case reply::not_modified: + return boost::asio::buffer(not_modified); + case reply::bad_request: + return boost::asio::buffer(bad_request); + case reply::unauthorized: + return boost::asio::buffer(unauthorized); + case reply::forbidden: + return boost::asio::buffer(forbidden); + case reply::not_found: + return boost::asio::buffer(not_found); + case reply::internal_server_error: + return boost::asio::buffer(internal_server_error); + case reply::not_implemented: + return boost::asio::buffer(not_implemented); + case reply::bad_gateway: + return boost::asio::buffer(bad_gateway); + case reply::service_unavailable: + return boost::asio::buffer(service_unavailable); + default: + return boost::asio::buffer(internal_server_error); + } +} + +} // namespace status_strings + +namespace misc_strings { + +const char name_value_separator[] = { ':', ' ' }; +const char crlf[] = { '\r', '\n' }; + +} // namespace misc_strings + +std::vector<boost::asio::const_buffer> reply::to_buffers() +{ + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(status_strings::to_buffer(status)); + for (std::size_t i = 0; i < headers.size(); ++i) + { + header& h = headers[i]; + buffers.push_back(boost::asio::buffer(h.name)); + buffers.push_back(boost::asio::buffer(misc_strings::name_value_separator)); + buffers.push_back(boost::asio::buffer(h.value)); + buffers.push_back(boost::asio::buffer(misc_strings::crlf)); + } + buffers.push_back(boost::asio::buffer(misc_strings::crlf)); + buffers.push_back(boost::asio::buffer(content)); + return buffers; +} + +namespace stock_replies { + +const char ok[] = ""; +const char created[] = + "<html>" + "<head><title>Created</title></head>" + "<body><h1>201 Created</h1></body>" + "</html>"; +const char accepted[] = + "<html>" + "<head><title>Accepted</title></head>" + "<body><h1>202 Accepted</h1></body>" + "</html>"; +const char no_content[] = + "<html>" + "<head><title>No Content</title></head>" + "<body><h1>204 Content</h1></body>" + "</html>"; +const char multiple_choices[] = + "<html>" + "<head><title>Multiple Choices</title></head>" + "<body><h1>300 Multiple Choices</h1></body>" + "</html>"; +const char moved_permanently[] = + "<html>" + "<head><title>Moved Permanently</title></head>" + "<body><h1>301 Moved Permanently</h1></body>" + "</html>"; +const char moved_temporarily[] = + "<html>" + "<head><title>Moved Temporarily</title></head>" + "<body><h1>302 Moved Temporarily</h1></body>" + "</html>"; +const char not_modified[] = + "<html>" + "<head><title>Not Modified</title></head>" + "<body><h1>304 Not Modified</h1></body>" + "</html>"; +const char bad_request[] = + "<html>" + "<head><title>Bad Request</title></head>" + "<body><h1>400 Bad Request</h1></body>" + "</html>"; +const char unauthorized[] = + "<html>" + "<head><title>Unauthorized</title></head>" + "<body><h1>401 Unauthorized</h1></body>" + "</html>"; +const char forbidden[] = + "<html>" + "<head><title>Forbidden</title></head>" + "<body><h1>403 Forbidden</h1></body>" + "</html>"; +const char not_found[] = + "<html>" + "<head><title>Not Found</title></head>" + "<body><h1>404 Not Found</h1></body>" + "</html>"; +const char internal_server_error[] = + "<html>" + "<head><title>Internal Server Error</title></head>" + "<body><h1>500 Internal Server Error</h1></body>" + "</html>"; +const char not_implemented[] = + "<html>" + "<head><title>Not Implemented</title></head>" + "<body><h1>501 Not Implemented</h1></body>" + "</html>"; +const char bad_gateway[] = + "<html>" + "<head><title>Bad Gateway</title></head>" + "<body><h1>502 Bad Gateway</h1></body>" + "</html>"; +const char service_unavailable[] = + "<html>" + "<head><title>Service Unavailable</title></head>" + "<body><h1>503 Service Unavailable</h1></body>" + "</html>"; + +std::string to_string(reply::status_type status) +{ + switch (status) + { + case reply::ok: + return ok; + case reply::created: + return created; + case reply::accepted: + return accepted; + case reply::no_content: + return no_content; + case reply::multiple_choices: + return multiple_choices; + case reply::moved_permanently: + return moved_permanently; + case reply::moved_temporarily: + return moved_temporarily; + case reply::not_modified: + return not_modified; + case reply::bad_request: + return bad_request; + case reply::unauthorized: + return unauthorized; + case reply::forbidden: + return forbidden; + case reply::not_found: + return not_found; + case reply::internal_server_error: + return internal_server_error; + case reply::not_implemented: + return not_implemented; + case reply::bad_gateway: + return bad_gateway; + case reply::service_unavailable: + return service_unavailable; + default: + return internal_server_error; + } +} + +} // namespace stock_replies + +reply reply::stock_reply(reply::status_type status) +{ + reply rep; + rep.status = status; + rep.content = stock_replies::to_string(status); + rep.headers.resize(2); + rep.headers[0].name = "Content-Length"; + rep.headers[0].value = boost::lexical_cast<std::string>(rep.content.size()); + rep.headers[1].name = "Content-Type"; + rep.headers[1].value = "text/html"; + return rep; +} + +} // namespace server2 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server2/reply.hpp b/src/boost/libs/asio/example/cpp03/http/server2/reply.hpp new file mode 100644 index 000000000..bff15b0db --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/reply.hpp @@ -0,0 +1,64 @@ +// +// reply.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER2_REPLY_HPP +#define HTTP_SERVER2_REPLY_HPP + +#include <string> +#include <vector> +#include <boost/asio.hpp> +#include "header.hpp" + +namespace http { +namespace server2 { + +/// A reply to be sent to a client. +struct reply +{ + /// The status of the reply. + enum status_type + { + ok = 200, + created = 201, + accepted = 202, + no_content = 204, + multiple_choices = 300, + moved_permanently = 301, + moved_temporarily = 302, + not_modified = 304, + bad_request = 400, + unauthorized = 401, + forbidden = 403, + not_found = 404, + internal_server_error = 500, + not_implemented = 501, + bad_gateway = 502, + service_unavailable = 503 + } status; + + /// The headers to be included in the reply. + std::vector<header> headers; + + /// The content to be sent in the reply. + std::string content; + + /// Convert the reply into a vector of buffers. The buffers do not own the + /// underlying memory blocks, therefore the reply object must remain valid and + /// not be changed until the write operation has completed. + std::vector<boost::asio::const_buffer> to_buffers(); + + /// Get a stock reply. + static reply stock_reply(status_type status); +}; + +} // namespace server2 +} // namespace http + +#endif // HTTP_SERVER2_REPLY_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server2/request.hpp b/src/boost/libs/asio/example/cpp03/http/server2/request.hpp new file mode 100644 index 000000000..197afe34a --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/request.hpp @@ -0,0 +1,34 @@ +// +// request.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER2_REQUEST_HPP +#define HTTP_SERVER2_REQUEST_HPP + +#include <string> +#include <vector> +#include "header.hpp" + +namespace http { +namespace server2 { + +/// A request received from a client. +struct request +{ + std::string method; + std::string uri; + int http_version_major; + int http_version_minor; + std::vector<header> headers; +}; + +} // namespace server2 +} // namespace http + +#endif // HTTP_SERVER2_REQUEST_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server2/request_handler.cpp b/src/boost/libs/asio/example/cpp03/http/server2/request_handler.cpp new file mode 100644 index 000000000..ca3728b58 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/request_handler.cpp @@ -0,0 +1,122 @@ +// +// request_handler.cpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "request_handler.hpp" +#include <fstream> +#include <sstream> +#include <string> +#include <boost/lexical_cast.hpp> +#include "mime_types.hpp" +#include "reply.hpp" +#include "request.hpp" + +namespace http { +namespace server2 { + +request_handler::request_handler(const std::string& doc_root) + : doc_root_(doc_root) +{ +} + +void request_handler::handle_request(const request& req, reply& rep) +{ + // Decode url to path. + std::string request_path; + if (!url_decode(req.uri, request_path)) + { + rep = reply::stock_reply(reply::bad_request); + return; + } + + // Request path must be absolute and not contain "..". + if (request_path.empty() || request_path[0] != '/' + || request_path.find("..") != std::string::npos) + { + rep = reply::stock_reply(reply::bad_request); + return; + } + + // If path ends in slash (i.e. is a directory) then add "index.html". + if (request_path[request_path.size() - 1] == '/') + { + request_path += "index.html"; + } + + // Determine the file extension. + std::size_t last_slash_pos = request_path.find_last_of("/"); + std::size_t last_dot_pos = request_path.find_last_of("."); + std::string extension; + if (last_dot_pos != std::string::npos && last_dot_pos > last_slash_pos) + { + extension = request_path.substr(last_dot_pos + 1); + } + + // Open the file to send back. + std::string full_path = doc_root_ + request_path; + std::ifstream is(full_path.c_str(), std::ios::in | std::ios::binary); + if (!is) + { + rep = reply::stock_reply(reply::not_found); + return; + } + + // Fill out the reply to be sent to the client. + rep.status = reply::ok; + char buf[512]; + while (is.read(buf, sizeof(buf)).gcount() > 0) + rep.content.append(buf, is.gcount()); + rep.headers.resize(2); + rep.headers[0].name = "Content-Length"; + rep.headers[0].value = boost::lexical_cast<std::string>(rep.content.size()); + rep.headers[1].name = "Content-Type"; + rep.headers[1].value = mime_types::extension_to_type(extension); +} + +bool request_handler::url_decode(const std::string& in, std::string& out) +{ + out.clear(); + out.reserve(in.size()); + for (std::size_t i = 0; i < in.size(); ++i) + { + if (in[i] == '%') + { + if (i + 3 <= in.size()) + { + int value = 0; + std::istringstream is(in.substr(i + 1, 2)); + if (is >> std::hex >> value) + { + out += static_cast<char>(value); + i += 2; + } + else + { + return false; + } + } + else + { + return false; + } + } + else if (in[i] == '+') + { + out += ' '; + } + else + { + out += in[i]; + } + } + return true; +} + +} // namespace server2 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server2/request_handler.hpp b/src/boost/libs/asio/example/cpp03/http/server2/request_handler.hpp new file mode 100644 index 000000000..dc327fdb4 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/request_handler.hpp @@ -0,0 +1,46 @@ +// +// request_handler.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER2_REQUEST_HANDLER_HPP +#define HTTP_SERVER2_REQUEST_HANDLER_HPP + +#include <string> +#include <boost/noncopyable.hpp> + +namespace http { +namespace server2 { + +struct reply; +struct request; + +/// The common handler for all incoming requests. +class request_handler + : private boost::noncopyable +{ +public: + /// Construct with a directory containing files to be served. + explicit request_handler(const std::string& doc_root); + + /// Handle a request and produce a reply. + void handle_request(const request& req, reply& rep); + +private: + /// The directory containing the files to be served. + std::string doc_root_; + + /// Perform URL-decoding on a string. Returns false if the encoding was + /// invalid. + static bool url_decode(const std::string& in, std::string& out); +}; + +} // namespace server2 +} // namespace http + +#endif // HTTP_SERVER2_REQUEST_HANDLER_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server2/request_parser.cpp b/src/boost/libs/asio/example/cpp03/http/server2/request_parser.cpp new file mode 100644 index 000000000..8533e8873 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/request_parser.cpp @@ -0,0 +1,315 @@ +// +// request_parser.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "request_parser.hpp" +#include "request.hpp" + +namespace http { +namespace server2 { + +request_parser::request_parser() + : state_(method_start) +{ +} + +void request_parser::reset() +{ + state_ = method_start; +} + +boost::tribool request_parser::consume(request& req, char input) +{ + switch (state_) + { + case method_start: + if (!is_char(input) || is_ctl(input) || is_tspecial(input)) + { + return false; + } + else + { + state_ = method; + req.method.push_back(input); + return boost::indeterminate; + } + case method: + if (input == ' ') + { + state_ = uri; + return boost::indeterminate; + } + else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) + { + return false; + } + else + { + req.method.push_back(input); + return boost::indeterminate; + } + case uri: + if (input == ' ') + { + state_ = http_version_h; + return boost::indeterminate; + } + else if (is_ctl(input)) + { + return false; + } + else + { + req.uri.push_back(input); + return boost::indeterminate; + } + case http_version_h: + if (input == 'H') + { + state_ = http_version_t_1; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_t_1: + if (input == 'T') + { + state_ = http_version_t_2; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_t_2: + if (input == 'T') + { + state_ = http_version_p; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_p: + if (input == 'P') + { + state_ = http_version_slash; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_slash: + if (input == '/') + { + req.http_version_major = 0; + req.http_version_minor = 0; + state_ = http_version_major_start; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_major_start: + if (is_digit(input)) + { + req.http_version_major = req.http_version_major * 10 + input - '0'; + state_ = http_version_major; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_major: + if (input == '.') + { + state_ = http_version_minor_start; + return boost::indeterminate; + } + else if (is_digit(input)) + { + req.http_version_major = req.http_version_major * 10 + input - '0'; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_minor_start: + if (is_digit(input)) + { + req.http_version_minor = req.http_version_minor * 10 + input - '0'; + state_ = http_version_minor; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_minor: + if (input == '\r') + { + state_ = expecting_newline_1; + return boost::indeterminate; + } + else if (is_digit(input)) + { + req.http_version_minor = req.http_version_minor * 10 + input - '0'; + return boost::indeterminate; + } + else + { + return false; + } + case expecting_newline_1: + if (input == '\n') + { + state_ = header_line_start; + return boost::indeterminate; + } + else + { + return false; + } + case header_line_start: + if (input == '\r') + { + state_ = expecting_newline_3; + return boost::indeterminate; + } + else if (!req.headers.empty() && (input == ' ' || input == '\t')) + { + state_ = header_lws; + return boost::indeterminate; + } + else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) + { + return false; + } + else + { + req.headers.push_back(header()); + req.headers.back().name.push_back(input); + state_ = header_name; + return boost::indeterminate; + } + case header_lws: + if (input == '\r') + { + state_ = expecting_newline_2; + return boost::indeterminate; + } + else if (input == ' ' || input == '\t') + { + return boost::indeterminate; + } + else if (is_ctl(input)) + { + return false; + } + else + { + state_ = header_value; + req.headers.back().value.push_back(input); + return boost::indeterminate; + } + case header_name: + if (input == ':') + { + state_ = space_before_header_value; + return boost::indeterminate; + } + else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) + { + return false; + } + else + { + req.headers.back().name.push_back(input); + return boost::indeterminate; + } + case space_before_header_value: + if (input == ' ') + { + state_ = header_value; + return boost::indeterminate; + } + else + { + return false; + } + case header_value: + if (input == '\r') + { + state_ = expecting_newline_2; + return boost::indeterminate; + } + else if (is_ctl(input)) + { + return false; + } + else + { + req.headers.back().value.push_back(input); + return boost::indeterminate; + } + case expecting_newline_2: + if (input == '\n') + { + state_ = header_line_start; + return boost::indeterminate; + } + else + { + return false; + } + case expecting_newline_3: + return (input == '\n'); + default: + return false; + } +} + +bool request_parser::is_char(int c) +{ + return c >= 0 && c <= 127; +} + +bool request_parser::is_ctl(int c) +{ + return (c >= 0 && c <= 31) || (c == 127); +} + +bool request_parser::is_tspecial(int c) +{ + switch (c) + { + case '(': case ')': case '<': case '>': case '@': + case ',': case ';': case ':': case '\\': case '"': + case '/': case '[': case ']': case '?': case '=': + case '{': case '}': case ' ': case '\t': + return true; + default: + return false; + } +} + +bool request_parser::is_digit(int c) +{ + return c >= '0' && c <= '9'; +} + +} // namespace server2 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server2/request_parser.hpp b/src/boost/libs/asio/example/cpp03/http/server2/request_parser.hpp new file mode 100644 index 000000000..3d9aae7a9 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/request_parser.hpp @@ -0,0 +1,95 @@ +// +// request_parser.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER2_REQUEST_PARSER_HPP +#define HTTP_SERVER2_REQUEST_PARSER_HPP + +#include <boost/logic/tribool.hpp> +#include <boost/tuple/tuple.hpp> + +namespace http { +namespace server2 { + +struct request; + +/// Parser for incoming requests. +class request_parser +{ +public: + /// Construct ready to parse the request method. + request_parser(); + + /// Reset to initial parser state. + void reset(); + + /// Parse some data. The tribool return value is true when a complete request + /// has been parsed, false if the data is invalid, indeterminate when more + /// data is required. The InputIterator return value indicates how much of the + /// input has been consumed. + template <typename InputIterator> + boost::tuple<boost::tribool, InputIterator> parse(request& req, + InputIterator begin, InputIterator end) + { + while (begin != end) + { + boost::tribool result = consume(req, *begin++); + if (result || !result) + return boost::make_tuple(result, begin); + } + boost::tribool result = boost::indeterminate; + return boost::make_tuple(result, begin); + } + +private: + /// Handle the next character of input. + boost::tribool consume(request& req, char input); + + /// Check if a byte is an HTTP character. + static bool is_char(int c); + + /// Check if a byte is an HTTP control character. + static bool is_ctl(int c); + + /// Check if a byte is defined as an HTTP tspecial character. + static bool is_tspecial(int c); + + /// Check if a byte is a digit. + static bool is_digit(int c); + + /// The current state of the parser. + enum state + { + method_start, + method, + uri, + http_version_h, + http_version_t_1, + http_version_t_2, + http_version_p, + http_version_slash, + http_version_major_start, + http_version_major, + http_version_minor_start, + http_version_minor, + expecting_newline_1, + header_line_start, + header_lws, + header_name, + space_before_header_value, + header_value, + expecting_newline_2, + expecting_newline_3 + } state_; +}; + +} // namespace server2 +} // namespace http + +#endif // HTTP_SERVER2_REQUEST_PARSER_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server2/server.cpp b/src/boost/libs/asio/example/cpp03/http/server2/server.cpp new file mode 100644 index 000000000..c6fa33ca1 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/server.cpp @@ -0,0 +1,77 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "server.hpp" +#include <boost/bind/bind.hpp> + +namespace http { +namespace server2 { + +server::server(const std::string& address, const std::string& port, + const std::string& doc_root, std::size_t io_context_pool_size) + : io_context_pool_(io_context_pool_size), + signals_(io_context_pool_.get_io_context()), + acceptor_(io_context_pool_.get_io_context()), + new_connection_(), + request_handler_(doc_root) +{ + // Register to handle the signals that indicate when the server should exit. + // It is safe to register for the same signal multiple times in a program, + // provided all registration for the specified signal is made through Asio. + signals_.add(SIGINT); + signals_.add(SIGTERM); +#if defined(SIGQUIT) + signals_.add(SIGQUIT); +#endif // defined(SIGQUIT) + signals_.async_wait(boost::bind(&server::handle_stop, this)); + + // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). + boost::asio::ip::tcp::resolver resolver(acceptor_.get_executor()); + boost::asio::ip::tcp::endpoint endpoint = + *resolver.resolve(address, port).begin(); + acceptor_.open(endpoint.protocol()); + acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + acceptor_.bind(endpoint); + acceptor_.listen(); + + start_accept(); +} + +void server::run() +{ + io_context_pool_.run(); +} + +void server::start_accept() +{ + new_connection_.reset(new connection( + io_context_pool_.get_io_context(), request_handler_)); + acceptor_.async_accept(new_connection_->socket(), + boost::bind(&server::handle_accept, this, + boost::asio::placeholders::error)); +} + +void server::handle_accept(const boost::system::error_code& e) +{ + if (!e) + { + new_connection_->start(); + } + + start_accept(); +} + +void server::handle_stop() +{ + io_context_pool_.stop(); +} + +} // namespace server2 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server2/server.hpp b/src/boost/libs/asio/example/cpp03/http/server2/server.hpp new file mode 100644 index 000000000..90b921f4e --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server2/server.hpp @@ -0,0 +1,68 @@ +// +// server.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER2_SERVER_HPP +#define HTTP_SERVER2_SERVER_HPP + +#include <boost/asio.hpp> +#include <string> +#include <vector> +#include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> +#include "connection.hpp" +#include "io_context_pool.hpp" +#include "request_handler.hpp" + +namespace http { +namespace server2 { + +/// The top-level class of the HTTP server. +class server + : private boost::noncopyable +{ +public: + /// Construct the server to listen on the specified TCP address and port, and + /// serve up files from the given directory. + explicit server(const std::string& address, const std::string& port, + const std::string& doc_root, std::size_t io_context_pool_size); + + /// Run the server's io_context loop. + void run(); + +private: + /// Initiate an asynchronous accept operation. + void start_accept(); + + /// Handle completion of an asynchronous accept operation. + void handle_accept(const boost::system::error_code& e); + + /// Handle a request to stop the server. + void handle_stop(); + + /// The pool of io_context objects used to perform asynchronous operations. + io_context_pool io_context_pool_; + + /// The signal_set is used to register for process termination notifications. + boost::asio::signal_set signals_; + + /// Acceptor used to listen for incoming connections. + boost::asio::ip::tcp::acceptor acceptor_; + + /// The next connection to be accepted. + connection_ptr new_connection_; + + /// The handler for all incoming requests. + request_handler request_handler_; +}; + +} // namespace server2 +} // namespace http + +#endif // HTTP_SERVER2_SERVER_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server3/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/http/server3/Jamfile.v2 new file mode 100644 index 000000000..e49656ec5 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server3/Jamfile.v2 @@ -0,0 +1,37 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe server + : connection.cpp + main.cpp + mime_types.cpp + reply.cpp + request_handler.cpp + request_parser.cpp + server.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + /boost/thread//boost_thread + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp03/http/server3/connection.cpp b/src/boost/libs/asio/example/cpp03/http/server3/connection.cpp new file mode 100644 index 000000000..fa6f828a9 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server3/connection.cpp @@ -0,0 +1,94 @@ +// +// connection.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "connection.hpp" +#include <vector> +#include <boost/bind/bind.hpp> +#include "request_handler.hpp" + +namespace http { +namespace server3 { + +connection::connection(boost::asio::io_context& io_context, + request_handler& handler) + : strand_(boost::asio::make_strand(io_context)), + socket_(strand_), + request_handler_(handler) +{ +} + +boost::asio::ip::tcp::socket& connection::socket() +{ + return socket_; +} + +void connection::start() +{ + socket_.async_read_some(boost::asio::buffer(buffer_), + boost::bind(&connection::handle_read, shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); +} + +void connection::handle_read(const boost::system::error_code& e, + std::size_t bytes_transferred) +{ + if (!e) + { + boost::tribool result; + boost::tie(result, boost::tuples::ignore) = request_parser_.parse( + request_, buffer_.data(), buffer_.data() + bytes_transferred); + + if (result) + { + request_handler_.handle_request(request_, reply_); + boost::asio::async_write(socket_, reply_.to_buffers(), + boost::bind(&connection::handle_write, shared_from_this(), + boost::asio::placeholders::error)); + } + else if (!result) + { + reply_ = reply::stock_reply(reply::bad_request); + boost::asio::async_write(socket_, reply_.to_buffers(), + boost::bind(&connection::handle_write, shared_from_this(), + boost::asio::placeholders::error)); + } + else + { + socket_.async_read_some(boost::asio::buffer(buffer_), + boost::bind(&connection::handle_read, shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + } + + // If an error occurs then no new asynchronous operations are started. This + // means that all shared_ptr references to the connection object will + // disappear and the object will be destroyed automatically after this + // handler returns. The connection class's destructor closes the socket. +} + +void connection::handle_write(const boost::system::error_code& e) +{ + if (!e) + { + // Initiate graceful connection closure. + boost::system::error_code ignored_ec; + socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); + } + + // No new asynchronous operations are started. This means that all shared_ptr + // references to the connection object will disappear and the object will be + // destroyed automatically after this handler returns. The connection class's + // destructor closes the socket. +} + +} // namespace server3 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server3/connection.hpp b/src/boost/libs/asio/example/cpp03/http/server3/connection.hpp new file mode 100644 index 000000000..f5583d02f --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server3/connection.hpp @@ -0,0 +1,78 @@ +// +// connection.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER3_CONNECTION_HPP +#define HTTP_SERVER3_CONNECTION_HPP + +#include <boost/asio.hpp> +#include <boost/array.hpp> +#include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include "reply.hpp" +#include "request.hpp" +#include "request_handler.hpp" +#include "request_parser.hpp" + +namespace http { +namespace server3 { + +/// Represents a single connection from a client. +class connection + : public boost::enable_shared_from_this<connection>, + private boost::noncopyable +{ +public: + /// Construct a connection with the given io_context. + explicit connection(boost::asio::io_context& io_context, + request_handler& handler); + + /// Get the socket associated with the connection. + boost::asio::ip::tcp::socket& socket(); + + /// Start the first asynchronous operation for the connection. + void start(); + +private: + /// Handle completion of a read operation. + void handle_read(const boost::system::error_code& e, + std::size_t bytes_transferred); + + /// Handle completion of a write operation. + void handle_write(const boost::system::error_code& e); + + /// Strand to ensure the connection's handlers are not called concurrently. + boost::asio::strand<boost::asio::io_context::executor_type> strand_; + + /// Socket for the connection. + boost::asio::ip::tcp::socket socket_; + + /// The handler used to process the incoming request. + request_handler& request_handler_; + + /// Buffer for incoming data. + boost::array<char, 8192> buffer_; + + /// The incoming request. + request request_; + + /// The parser for the incoming request. + request_parser request_parser_; + + /// The reply to be sent back to the client. + reply reply_; +}; + +typedef boost::shared_ptr<connection> connection_ptr; + +} // namespace server3 +} // namespace http + +#endif // HTTP_SERVER3_CONNECTION_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server3/header.hpp b/src/boost/libs/asio/example/cpp03/http/server3/header.hpp new file mode 100644 index 000000000..45a98a4bb --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server3/header.hpp @@ -0,0 +1,28 @@ +// +// header.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER3_HEADER_HPP +#define HTTP_SERVER3_HEADER_HPP + +#include <string> + +namespace http { +namespace server3 { + +struct header +{ + std::string name; + std::string value; +}; + +} // namespace server3 +} // namespace http + +#endif // HTTP_SERVER3_HEADER_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server3/main.cpp b/src/boost/libs/asio/example/cpp03/http/server3/main.cpp new file mode 100644 index 000000000..4f181c573 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server3/main.cpp @@ -0,0 +1,46 @@ +// +// main.cpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <string> +#include <boost/asio.hpp> +#include <boost/bind/bind.hpp> +#include <boost/lexical_cast.hpp> +#include "server.hpp" + +int main(int argc, char* argv[]) +{ + try + { + // Check command line arguments. + if (argc != 5) + { + std::cerr << "Usage: http_server <address> <port> <threads> <doc_root>\n"; + std::cerr << " For IPv4, try:\n"; + std::cerr << " receiver 0.0.0.0 80 1 .\n"; + std::cerr << " For IPv6, try:\n"; + std::cerr << " receiver 0::0 80 1 .\n"; + return 1; + } + + // Initialise the server. + std::size_t num_threads = boost::lexical_cast<std::size_t>(argv[3]); + http::server3::server s(argv[1], argv[2], argv[4], num_threads); + + // Run the server until stopped. + s.run(); + } + catch (std::exception& e) + { + std::cerr << "exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/http/server3/mime_types.cpp b/src/boost/libs/asio/example/cpp03/http/server3/mime_types.cpp new file mode 100644 index 000000000..028970c10 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server3/mime_types.cpp @@ -0,0 +1,46 @@ +// +// mime_types.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "mime_types.hpp" + +namespace http { +namespace server3 { +namespace mime_types { + +struct mapping +{ + const char* extension; + const char* mime_type; +} mappings[] = +{ + { "gif", "image/gif" }, + { "htm", "text/html" }, + { "html", "text/html" }, + { "jpg", "image/jpeg" }, + { "png", "image/png" }, + { 0, 0 } // Marks end of list. +}; + +std::string extension_to_type(const std::string& extension) +{ + for (mapping* m = mappings; m->extension; ++m) + { + if (m->extension == extension) + { + return m->mime_type; + } + } + + return "text/plain"; +} + +} // namespace mime_types +} // namespace server3 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server3/mime_types.hpp b/src/boost/libs/asio/example/cpp03/http/server3/mime_types.hpp new file mode 100644 index 000000000..9558f5e83 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server3/mime_types.hpp @@ -0,0 +1,27 @@ +// +// mime_types.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER3_MIME_TYPES_HPP +#define HTTP_SERVER3_MIME_TYPES_HPP + +#include <string> + +namespace http { +namespace server3 { +namespace mime_types { + +/// Convert a file extension into a MIME type. +std::string extension_to_type(const std::string& extension); + +} // namespace mime_types +} // namespace server3 +} // namespace http + +#endif // HTTP_SERVER3_MIME_TYPES_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server3/reply.cpp b/src/boost/libs/asio/example/cpp03/http/server3/reply.cpp new file mode 100644 index 000000000..0d4639200 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server3/reply.cpp @@ -0,0 +1,256 @@ +// +// reply.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "reply.hpp" +#include <string> +#include <boost/lexical_cast.hpp> + +namespace http { +namespace server3 { + +namespace status_strings { + +const std::string ok = + "HTTP/1.0 200 OK\r\n"; +const std::string created = + "HTTP/1.0 201 Created\r\n"; +const std::string accepted = + "HTTP/1.0 202 Accepted\r\n"; +const std::string no_content = + "HTTP/1.0 204 No Content\r\n"; +const std::string multiple_choices = + "HTTP/1.0 300 Multiple Choices\r\n"; +const std::string moved_permanently = + "HTTP/1.0 301 Moved Permanently\r\n"; +const std::string moved_temporarily = + "HTTP/1.0 302 Moved Temporarily\r\n"; +const std::string not_modified = + "HTTP/1.0 304 Not Modified\r\n"; +const std::string bad_request = + "HTTP/1.0 400 Bad Request\r\n"; +const std::string unauthorized = + "HTTP/1.0 401 Unauthorized\r\n"; +const std::string forbidden = + "HTTP/1.0 403 Forbidden\r\n"; +const std::string not_found = + "HTTP/1.0 404 Not Found\r\n"; +const std::string internal_server_error = + "HTTP/1.0 500 Internal Server Error\r\n"; +const std::string not_implemented = + "HTTP/1.0 501 Not Implemented\r\n"; +const std::string bad_gateway = + "HTTP/1.0 502 Bad Gateway\r\n"; +const std::string service_unavailable = + "HTTP/1.0 503 Service Unavailable\r\n"; + +boost::asio::const_buffer to_buffer(reply::status_type status) +{ + switch (status) + { + case reply::ok: + return boost::asio::buffer(ok); + case reply::created: + return boost::asio::buffer(created); + case reply::accepted: + return boost::asio::buffer(accepted); + case reply::no_content: + return boost::asio::buffer(no_content); + case reply::multiple_choices: + return boost::asio::buffer(multiple_choices); + case reply::moved_permanently: + return boost::asio::buffer(moved_permanently); + case reply::moved_temporarily: + return boost::asio::buffer(moved_temporarily); + case reply::not_modified: + return boost::asio::buffer(not_modified); + case reply::bad_request: + return boost::asio::buffer(bad_request); + case reply::unauthorized: + return boost::asio::buffer(unauthorized); + case reply::forbidden: + return boost::asio::buffer(forbidden); + case reply::not_found: + return boost::asio::buffer(not_found); + case reply::internal_server_error: + return boost::asio::buffer(internal_server_error); + case reply::not_implemented: + return boost::asio::buffer(not_implemented); + case reply::bad_gateway: + return boost::asio::buffer(bad_gateway); + case reply::service_unavailable: + return boost::asio::buffer(service_unavailable); + default: + return boost::asio::buffer(internal_server_error); + } +} + +} // namespace status_strings + +namespace misc_strings { + +const char name_value_separator[] = { ':', ' ' }; +const char crlf[] = { '\r', '\n' }; + +} // namespace misc_strings + +std::vector<boost::asio::const_buffer> reply::to_buffers() +{ + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(status_strings::to_buffer(status)); + for (std::size_t i = 0; i < headers.size(); ++i) + { + header& h = headers[i]; + buffers.push_back(boost::asio::buffer(h.name)); + buffers.push_back(boost::asio::buffer(misc_strings::name_value_separator)); + buffers.push_back(boost::asio::buffer(h.value)); + buffers.push_back(boost::asio::buffer(misc_strings::crlf)); + } + buffers.push_back(boost::asio::buffer(misc_strings::crlf)); + buffers.push_back(boost::asio::buffer(content)); + return buffers; +} + +namespace stock_replies { + +const char ok[] = ""; +const char created[] = + "<html>" + "<head><title>Created</title></head>" + "<body><h1>201 Created</h1></body>" + "</html>"; +const char accepted[] = + "<html>" + "<head><title>Accepted</title></head>" + "<body><h1>202 Accepted</h1></body>" + "</html>"; +const char no_content[] = + "<html>" + "<head><title>No Content</title></head>" + "<body><h1>204 Content</h1></body>" + "</html>"; +const char multiple_choices[] = + "<html>" + "<head><title>Multiple Choices</title></head>" + "<body><h1>300 Multiple Choices</h1></body>" + "</html>"; +const char moved_permanently[] = + "<html>" + "<head><title>Moved Permanently</title></head>" + "<body><h1>301 Moved Permanently</h1></body>" + "</html>"; +const char moved_temporarily[] = + "<html>" + "<head><title>Moved Temporarily</title></head>" + "<body><h1>302 Moved Temporarily</h1></body>" + "</html>"; +const char not_modified[] = + "<html>" + "<head><title>Not Modified</title></head>" + "<body><h1>304 Not Modified</h1></body>" + "</html>"; +const char bad_request[] = + "<html>" + "<head><title>Bad Request</title></head>" + "<body><h1>400 Bad Request</h1></body>" + "</html>"; +const char unauthorized[] = + "<html>" + "<head><title>Unauthorized</title></head>" + "<body><h1>401 Unauthorized</h1></body>" + "</html>"; +const char forbidden[] = + "<html>" + "<head><title>Forbidden</title></head>" + "<body><h1>403 Forbidden</h1></body>" + "</html>"; +const char not_found[] = + "<html>" + "<head><title>Not Found</title></head>" + "<body><h1>404 Not Found</h1></body>" + "</html>"; +const char internal_server_error[] = + "<html>" + "<head><title>Internal Server Error</title></head>" + "<body><h1>500 Internal Server Error</h1></body>" + "</html>"; +const char not_implemented[] = + "<html>" + "<head><title>Not Implemented</title></head>" + "<body><h1>501 Not Implemented</h1></body>" + "</html>"; +const char bad_gateway[] = + "<html>" + "<head><title>Bad Gateway</title></head>" + "<body><h1>502 Bad Gateway</h1></body>" + "</html>"; +const char service_unavailable[] = + "<html>" + "<head><title>Service Unavailable</title></head>" + "<body><h1>503 Service Unavailable</h1></body>" + "</html>"; + +std::string to_string(reply::status_type status) +{ + switch (status) + { + case reply::ok: + return ok; + case reply::created: + return created; + case reply::accepted: + return accepted; + case reply::no_content: + return no_content; + case reply::multiple_choices: + return multiple_choices; + case reply::moved_permanently: + return moved_permanently; + case reply::moved_temporarily: + return moved_temporarily; + case reply::not_modified: + return not_modified; + case reply::bad_request: + return bad_request; + case reply::unauthorized: + return unauthorized; + case reply::forbidden: + return forbidden; + case reply::not_found: + return not_found; + case reply::internal_server_error: + return internal_server_error; + case reply::not_implemented: + return not_implemented; + case reply::bad_gateway: + return bad_gateway; + case reply::service_unavailable: + return service_unavailable; + default: + return internal_server_error; + } +} + +} // namespace stock_replies + +reply reply::stock_reply(reply::status_type status) +{ + reply rep; + rep.status = status; + rep.content = stock_replies::to_string(status); + rep.headers.resize(2); + rep.headers[0].name = "Content-Length"; + rep.headers[0].value = boost::lexical_cast<std::string>(rep.content.size()); + rep.headers[1].name = "Content-Type"; + rep.headers[1].value = "text/html"; + return rep; +} + +} // namespace server3 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server3/reply.hpp b/src/boost/libs/asio/example/cpp03/http/server3/reply.hpp new file mode 100644 index 000000000..201578576 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server3/reply.hpp @@ -0,0 +1,64 @@ +// +// reply.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER3_REPLY_HPP +#define HTTP_SERVER3_REPLY_HPP + +#include <string> +#include <vector> +#include <boost/asio.hpp> +#include "header.hpp" + +namespace http { +namespace server3 { + +/// A reply to be sent to a client. +struct reply +{ + /// The status of the reply. + enum status_type + { + ok = 200, + created = 201, + accepted = 202, + no_content = 204, + multiple_choices = 300, + moved_permanently = 301, + moved_temporarily = 302, + not_modified = 304, + bad_request = 400, + unauthorized = 401, + forbidden = 403, + not_found = 404, + internal_server_error = 500, + not_implemented = 501, + bad_gateway = 502, + service_unavailable = 503 + } status; + + /// The headers to be included in the reply. + std::vector<header> headers; + + /// The content to be sent in the reply. + std::string content; + + /// Convert the reply into a vector of buffers. The buffers do not own the + /// underlying memory blocks, therefore the reply object must remain valid and + /// not be changed until the write operation has completed. + std::vector<boost::asio::const_buffer> to_buffers(); + + /// Get a stock reply. + static reply stock_reply(status_type status); +}; + +} // namespace server3 +} // namespace http + +#endif // HTTP_SERVER3_REPLY_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server3/request.hpp b/src/boost/libs/asio/example/cpp03/http/server3/request.hpp new file mode 100644 index 000000000..300d379cc --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server3/request.hpp @@ -0,0 +1,34 @@ +// +// request.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER3_REQUEST_HPP +#define HTTP_SERVER3_REQUEST_HPP + +#include <string> +#include <vector> +#include "header.hpp" + +namespace http { +namespace server3 { + +/// A request received from a client. +struct request +{ + std::string method; + std::string uri; + int http_version_major; + int http_version_minor; + std::vector<header> headers; +}; + +} // namespace server3 +} // namespace http + +#endif // HTTP_SERVER3_REQUEST_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server3/request_handler.cpp b/src/boost/libs/asio/example/cpp03/http/server3/request_handler.cpp new file mode 100644 index 000000000..3046989f4 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server3/request_handler.cpp @@ -0,0 +1,122 @@ +// +// request_handler.cpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "request_handler.hpp" +#include <fstream> +#include <sstream> +#include <string> +#include <boost/lexical_cast.hpp> +#include "mime_types.hpp" +#include "reply.hpp" +#include "request.hpp" + +namespace http { +namespace server3 { + +request_handler::request_handler(const std::string& doc_root) + : doc_root_(doc_root) +{ +} + +void request_handler::handle_request(const request& req, reply& rep) +{ + // Decode url to path. + std::string request_path; + if (!url_decode(req.uri, request_path)) + { + rep = reply::stock_reply(reply::bad_request); + return; + } + + // Request path must be absolute and not contain "..". + if (request_path.empty() || request_path[0] != '/' + || request_path.find("..") != std::string::npos) + { + rep = reply::stock_reply(reply::bad_request); + return; + } + + // If path ends in slash (i.e. is a directory) then add "index.html". + if (request_path[request_path.size() - 1] == '/') + { + request_path += "index.html"; + } + + // Determine the file extension. + std::size_t last_slash_pos = request_path.find_last_of("/"); + std::size_t last_dot_pos = request_path.find_last_of("."); + std::string extension; + if (last_dot_pos != std::string::npos && last_dot_pos > last_slash_pos) + { + extension = request_path.substr(last_dot_pos + 1); + } + + // Open the file to send back. + std::string full_path = doc_root_ + request_path; + std::ifstream is(full_path.c_str(), std::ios::in | std::ios::binary); + if (!is) + { + rep = reply::stock_reply(reply::not_found); + return; + } + + // Fill out the reply to be sent to the client. + rep.status = reply::ok; + char buf[512]; + while (is.read(buf, sizeof(buf)).gcount() > 0) + rep.content.append(buf, is.gcount()); + rep.headers.resize(2); + rep.headers[0].name = "Content-Length"; + rep.headers[0].value = boost::lexical_cast<std::string>(rep.content.size()); + rep.headers[1].name = "Content-Type"; + rep.headers[1].value = mime_types::extension_to_type(extension); +} + +bool request_handler::url_decode(const std::string& in, std::string& out) +{ + out.clear(); + out.reserve(in.size()); + for (std::size_t i = 0; i < in.size(); ++i) + { + if (in[i] == '%') + { + if (i + 3 <= in.size()) + { + int value = 0; + std::istringstream is(in.substr(i + 1, 2)); + if (is >> std::hex >> value) + { + out += static_cast<char>(value); + i += 2; + } + else + { + return false; + } + } + else + { + return false; + } + } + else if (in[i] == '+') + { + out += ' '; + } + else + { + out += in[i]; + } + } + return true; +} + +} // namespace server3 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server3/request_handler.hpp b/src/boost/libs/asio/example/cpp03/http/server3/request_handler.hpp new file mode 100644 index 000000000..75d415716 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server3/request_handler.hpp @@ -0,0 +1,46 @@ +// +// request_handler.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER3_REQUEST_HANDLER_HPP +#define HTTP_SERVER3_REQUEST_HANDLER_HPP + +#include <string> +#include <boost/noncopyable.hpp> + +namespace http { +namespace server3 { + +struct reply; +struct request; + +/// The common handler for all incoming requests. +class request_handler + : private boost::noncopyable +{ +public: + /// Construct with a directory containing files to be served. + explicit request_handler(const std::string& doc_root); + + /// Handle a request and produce a reply. + void handle_request(const request& req, reply& rep); + +private: + /// The directory containing the files to be served. + std::string doc_root_; + + /// Perform URL-decoding on a string. Returns false if the encoding was + /// invalid. + static bool url_decode(const std::string& in, std::string& out); +}; + +} // namespace server3 +} // namespace http + +#endif // HTTP_SERVER3_REQUEST_HANDLER_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server3/request_parser.cpp b/src/boost/libs/asio/example/cpp03/http/server3/request_parser.cpp new file mode 100644 index 000000000..d70645512 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server3/request_parser.cpp @@ -0,0 +1,315 @@ +// +// request_parser.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "request_parser.hpp" +#include "request.hpp" + +namespace http { +namespace server3 { + +request_parser::request_parser() + : state_(method_start) +{ +} + +void request_parser::reset() +{ + state_ = method_start; +} + +boost::tribool request_parser::consume(request& req, char input) +{ + switch (state_) + { + case method_start: + if (!is_char(input) || is_ctl(input) || is_tspecial(input)) + { + return false; + } + else + { + state_ = method; + req.method.push_back(input); + return boost::indeterminate; + } + case method: + if (input == ' ') + { + state_ = uri; + return boost::indeterminate; + } + else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) + { + return false; + } + else + { + req.method.push_back(input); + return boost::indeterminate; + } + case uri: + if (input == ' ') + { + state_ = http_version_h; + return boost::indeterminate; + } + else if (is_ctl(input)) + { + return false; + } + else + { + req.uri.push_back(input); + return boost::indeterminate; + } + case http_version_h: + if (input == 'H') + { + state_ = http_version_t_1; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_t_1: + if (input == 'T') + { + state_ = http_version_t_2; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_t_2: + if (input == 'T') + { + state_ = http_version_p; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_p: + if (input == 'P') + { + state_ = http_version_slash; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_slash: + if (input == '/') + { + req.http_version_major = 0; + req.http_version_minor = 0; + state_ = http_version_major_start; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_major_start: + if (is_digit(input)) + { + req.http_version_major = req.http_version_major * 10 + input - '0'; + state_ = http_version_major; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_major: + if (input == '.') + { + state_ = http_version_minor_start; + return boost::indeterminate; + } + else if (is_digit(input)) + { + req.http_version_major = req.http_version_major * 10 + input - '0'; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_minor_start: + if (is_digit(input)) + { + req.http_version_minor = req.http_version_minor * 10 + input - '0'; + state_ = http_version_minor; + return boost::indeterminate; + } + else + { + return false; + } + case http_version_minor: + if (input == '\r') + { + state_ = expecting_newline_1; + return boost::indeterminate; + } + else if (is_digit(input)) + { + req.http_version_minor = req.http_version_minor * 10 + input - '0'; + return boost::indeterminate; + } + else + { + return false; + } + case expecting_newline_1: + if (input == '\n') + { + state_ = header_line_start; + return boost::indeterminate; + } + else + { + return false; + } + case header_line_start: + if (input == '\r') + { + state_ = expecting_newline_3; + return boost::indeterminate; + } + else if (!req.headers.empty() && (input == ' ' || input == '\t')) + { + state_ = header_lws; + return boost::indeterminate; + } + else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) + { + return false; + } + else + { + req.headers.push_back(header()); + req.headers.back().name.push_back(input); + state_ = header_name; + return boost::indeterminate; + } + case header_lws: + if (input == '\r') + { + state_ = expecting_newline_2; + return boost::indeterminate; + } + else if (input == ' ' || input == '\t') + { + return boost::indeterminate; + } + else if (is_ctl(input)) + { + return false; + } + else + { + state_ = header_value; + req.headers.back().value.push_back(input); + return boost::indeterminate; + } + case header_name: + if (input == ':') + { + state_ = space_before_header_value; + return boost::indeterminate; + } + else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) + { + return false; + } + else + { + req.headers.back().name.push_back(input); + return boost::indeterminate; + } + case space_before_header_value: + if (input == ' ') + { + state_ = header_value; + return boost::indeterminate; + } + else + { + return false; + } + case header_value: + if (input == '\r') + { + state_ = expecting_newline_2; + return boost::indeterminate; + } + else if (is_ctl(input)) + { + return false; + } + else + { + req.headers.back().value.push_back(input); + return boost::indeterminate; + } + case expecting_newline_2: + if (input == '\n') + { + state_ = header_line_start; + return boost::indeterminate; + } + else + { + return false; + } + case expecting_newline_3: + return (input == '\n'); + default: + return false; + } +} + +bool request_parser::is_char(int c) +{ + return c >= 0 && c <= 127; +} + +bool request_parser::is_ctl(int c) +{ + return (c >= 0 && c <= 31) || (c == 127); +} + +bool request_parser::is_tspecial(int c) +{ + switch (c) + { + case '(': case ')': case '<': case '>': case '@': + case ',': case ';': case ':': case '\\': case '"': + case '/': case '[': case ']': case '?': case '=': + case '{': case '}': case ' ': case '\t': + return true; + default: + return false; + } +} + +bool request_parser::is_digit(int c) +{ + return c >= '0' && c <= '9'; +} + +} // namespace server3 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server3/request_parser.hpp b/src/boost/libs/asio/example/cpp03/http/server3/request_parser.hpp new file mode 100644 index 000000000..f3ae654f4 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server3/request_parser.hpp @@ -0,0 +1,95 @@ +// +// request_parser.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER3_REQUEST_PARSER_HPP +#define HTTP_SERVER3_REQUEST_PARSER_HPP + +#include <boost/logic/tribool.hpp> +#include <boost/tuple/tuple.hpp> + +namespace http { +namespace server3 { + +struct request; + +/// Parser for incoming requests. +class request_parser +{ +public: + /// Construct ready to parse the request method. + request_parser(); + + /// Reset to initial parser state. + void reset(); + + /// Parse some data. The tribool return value is true when a complete request + /// has been parsed, false if the data is invalid, indeterminate when more + /// data is required. The InputIterator return value indicates how much of the + /// input has been consumed. + template <typename InputIterator> + boost::tuple<boost::tribool, InputIterator> parse(request& req, + InputIterator begin, InputIterator end) + { + while (begin != end) + { + boost::tribool result = consume(req, *begin++); + if (result || !result) + return boost::make_tuple(result, begin); + } + boost::tribool result = boost::indeterminate; + return boost::make_tuple(result, begin); + } + +private: + /// Handle the next character of input. + boost::tribool consume(request& req, char input); + + /// Check if a byte is an HTTP character. + static bool is_char(int c); + + /// Check if a byte is an HTTP control character. + static bool is_ctl(int c); + + /// Check if a byte is defined as an HTTP tspecial character. + static bool is_tspecial(int c); + + /// Check if a byte is a digit. + static bool is_digit(int c); + + /// The current state of the parser. + enum state + { + method_start, + method, + uri, + http_version_h, + http_version_t_1, + http_version_t_2, + http_version_p, + http_version_slash, + http_version_major_start, + http_version_major, + http_version_minor_start, + http_version_minor, + expecting_newline_1, + header_line_start, + header_lws, + header_name, + space_before_header_value, + header_value, + expecting_newline_2, + expecting_newline_3 + } state_; +}; + +} // namespace server3 +} // namespace http + +#endif // HTTP_SERVER3_REQUEST_PARSER_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server3/server.cpp b/src/boost/libs/asio/example/cpp03/http/server3/server.cpp new file mode 100644 index 000000000..8035d3167 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server3/server.cpp @@ -0,0 +1,90 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "server.hpp" +#include <boost/thread/thread.hpp> +#include <boost/bind/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <vector> + +namespace http { +namespace server3 { + +server::server(const std::string& address, const std::string& port, + const std::string& doc_root, std::size_t thread_pool_size) + : thread_pool_size_(thread_pool_size), + signals_(io_context_), + acceptor_(io_context_), + new_connection_(), + request_handler_(doc_root) +{ + // Register to handle the signals that indicate when the server should exit. + // It is safe to register for the same signal multiple times in a program, + // provided all registration for the specified signal is made through Asio. + signals_.add(SIGINT); + signals_.add(SIGTERM); +#if defined(SIGQUIT) + signals_.add(SIGQUIT); +#endif // defined(SIGQUIT) + signals_.async_wait(boost::bind(&server::handle_stop, this)); + + // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). + boost::asio::ip::tcp::resolver resolver(io_context_); + boost::asio::ip::tcp::endpoint endpoint = + *resolver.resolve(address, port).begin(); + acceptor_.open(endpoint.protocol()); + acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + acceptor_.bind(endpoint); + acceptor_.listen(); + + start_accept(); +} + +void server::run() +{ + // Create a pool of threads to run all of the io_contexts. + std::vector<boost::shared_ptr<boost::thread> > threads; + for (std::size_t i = 0; i < thread_pool_size_; ++i) + { + boost::shared_ptr<boost::thread> thread(new boost::thread( + boost::bind(&boost::asio::io_context::run, &io_context_))); + threads.push_back(thread); + } + + // Wait for all threads in the pool to exit. + for (std::size_t i = 0; i < threads.size(); ++i) + threads[i]->join(); +} + +void server::start_accept() +{ + new_connection_.reset(new connection(io_context_, request_handler_)); + acceptor_.async_accept(new_connection_->socket(), + boost::bind(&server::handle_accept, this, + boost::asio::placeholders::error)); +} + +void server::handle_accept(const boost::system::error_code& e) +{ + if (!e) + { + new_connection_->start(); + } + + start_accept(); +} + +void server::handle_stop() +{ + io_context_.stop(); +} + +} // namespace server3 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server3/server.hpp b/src/boost/libs/asio/example/cpp03/http/server3/server.hpp new file mode 100644 index 000000000..fc7c21d37 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server3/server.hpp @@ -0,0 +1,70 @@ +// +// server.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER3_SERVER_HPP +#define HTTP_SERVER3_SERVER_HPP + +#include <boost/asio.hpp> +#include <string> +#include <vector> +#include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> +#include "connection.hpp" +#include "request_handler.hpp" + +namespace http { +namespace server3 { + +/// The top-level class of the HTTP server. +class server + : private boost::noncopyable +{ +public: + /// Construct the server to listen on the specified TCP address and port, and + /// serve up files from the given directory. + explicit server(const std::string& address, const std::string& port, + const std::string& doc_root, std::size_t thread_pool_size); + + /// Run the server's io_context loop. + void run(); + +private: + /// Initiate an asynchronous accept operation. + void start_accept(); + + /// Handle completion of an asynchronous accept operation. + void handle_accept(const boost::system::error_code& e); + + /// Handle a request to stop the server. + void handle_stop(); + + /// The number of threads that will call io_context::run(). + std::size_t thread_pool_size_; + + /// The io_context used to perform asynchronous operations. + boost::asio::io_context io_context_; + + /// The signal_set is used to register for process termination notifications. + boost::asio::signal_set signals_; + + /// Acceptor used to listen for incoming connections. + boost::asio::ip::tcp::acceptor acceptor_; + + /// The next connection to be accepted. + connection_ptr new_connection_; + + /// The handler for all incoming requests. + request_handler request_handler_; +}; + +} // namespace server3 +} // namespace http + +#endif // HTTP_SERVER3_SERVER_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server4/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/http/server4/Jamfile.v2 new file mode 100644 index 000000000..c103f1217 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server4/Jamfile.v2 @@ -0,0 +1,36 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe server + : file_handler.cpp + main.cpp + mime_types.cpp + reply.cpp + request_parser.cpp + server.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + /boost/thread//boost_thread + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp03/http/server4/file_handler.cpp b/src/boost/libs/asio/example/cpp03/http/server4/file_handler.cpp new file mode 100644 index 000000000..49537f9b6 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server4/file_handler.cpp @@ -0,0 +1,122 @@ +// +// file_handler.cpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "file_handler.hpp" +#include <fstream> +#include <sstream> +#include <string> +#include <boost/lexical_cast.hpp> +#include "mime_types.hpp" +#include "reply.hpp" +#include "request.hpp" + +namespace http { +namespace server4 { + +file_handler::file_handler(const std::string& doc_root) + : doc_root_(doc_root) +{ +} + +void file_handler::operator()(const request& req, reply& rep) +{ + // Decode url to path. + std::string request_path; + if (!url_decode(req.uri, request_path)) + { + rep = reply::stock_reply(reply::bad_request); + return; + } + + // Request path must be absolute and not contain "..". + if (request_path.empty() || request_path[0] != '/' + || request_path.find("..") != std::string::npos) + { + rep = reply::stock_reply(reply::bad_request); + return; + } + + // If path ends in slash (i.e. is a directory) then add "index.html". + if (request_path[request_path.size() - 1] == '/') + { + request_path += "index.html"; + } + + // Determine the file extension. + std::size_t last_slash_pos = request_path.find_last_of("/"); + std::size_t last_dot_pos = request_path.find_last_of("."); + std::string extension; + if (last_dot_pos != std::string::npos && last_dot_pos > last_slash_pos) + { + extension = request_path.substr(last_dot_pos + 1); + } + + // Open the file to send back. + std::string full_path = doc_root_ + request_path; + std::ifstream is(full_path.c_str(), std::ios::in | std::ios::binary); + if (!is) + { + rep = reply::stock_reply(reply::not_found); + return; + } + + // Fill out the reply to be sent to the client. + rep.status = reply::ok; + char buf[512]; + while (is.read(buf, sizeof(buf)).gcount() > 0) + rep.content.append(buf, is.gcount()); + rep.headers.resize(2); + rep.headers[0].name = "Content-Length"; + rep.headers[0].value = boost::lexical_cast<std::string>(rep.content.size()); + rep.headers[1].name = "Content-Type"; + rep.headers[1].value = mime_types::extension_to_type(extension); +} + +bool file_handler::url_decode(const std::string& in, std::string& out) +{ + out.clear(); + out.reserve(in.size()); + for (std::size_t i = 0; i < in.size(); ++i) + { + if (in[i] == '%') + { + if (i + 3 <= in.size()) + { + int value = 0; + std::istringstream is(in.substr(i + 1, 2)); + if (is >> std::hex >> value) + { + out += static_cast<char>(value); + i += 2; + } + else + { + return false; + } + } + else + { + return false; + } + } + else if (in[i] == '+') + { + out += ' '; + } + else + { + out += in[i]; + } + } + return true; +} + +} // namespace server4 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server4/file_handler.hpp b/src/boost/libs/asio/example/cpp03/http/server4/file_handler.hpp new file mode 100644 index 000000000..ff9f0f887 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server4/file_handler.hpp @@ -0,0 +1,44 @@ +// +// file_handler.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER4_FILE_HANDLER_HPP +#define HTTP_SERVER4_FILE_HANDLER_HPP + +#include <string> + +namespace http { +namespace server4 { + +struct reply; +struct request; + +/// The common handler for all incoming requests. +class file_handler +{ +public: + /// Construct with a directory containing files to be served. + explicit file_handler(const std::string& doc_root); + + /// Handle a request and produce a reply. + void operator()(const request& req, reply& rep); + +private: + /// The directory containing the files to be served. + std::string doc_root_; + + /// Perform URL-decoding on a string. Returns false if the encoding was + /// invalid. + static bool url_decode(const std::string& in, std::string& out); +}; + +} // namespace server4 +} // namespace http + +#endif // HTTP_SERVER4_FILE_HANDLER_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server4/header.hpp b/src/boost/libs/asio/example/cpp03/http/server4/header.hpp new file mode 100644 index 000000000..5a1373e21 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server4/header.hpp @@ -0,0 +1,28 @@ +// +// header.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER4_HEADER_HPP +#define HTTP_SERVER4_HEADER_HPP + +#include <string> + +namespace http { +namespace server4 { + +struct header +{ + std::string name; + std::string value; +}; + +} // namespace server4 +} // namespace http + +#endif // HTTP_SERVER4_HEADER_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server4/main.cpp b/src/boost/libs/asio/example/cpp03/http/server4/main.cpp new file mode 100644 index 000000000..50efacd22 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server4/main.cpp @@ -0,0 +1,58 @@ +// +// main.cpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <boost/asio.hpp> +#include <boost/bind/bind.hpp> +#include <signal.h> +#include "server.hpp" +#include "file_handler.hpp" + +int main(int argc, char* argv[]) +{ + try + { + // Check command line arguments. + if (argc != 4) + { + std::cerr << "Usage: http_server <address> <port> <doc_root>\n"; + std::cerr << " For IPv4, try:\n"; + std::cerr << " receiver 0.0.0.0 80 .\n"; + std::cerr << " For IPv6, try:\n"; + std::cerr << " receiver 0::0 80 .\n"; + return 1; + } + + boost::asio::io_context io_context; + + // Launch the initial server coroutine. + http::server4::server(io_context, argv[1], argv[2], + http::server4::file_handler(argv[3]))(); + + // Wait for signals indicating time to shut down. + boost::asio::signal_set signals(io_context); + signals.add(SIGINT); + signals.add(SIGTERM); +#if defined(SIGQUIT) + signals.add(SIGQUIT); +#endif // defined(SIGQUIT) + signals.async_wait(boost::bind( + &boost::asio::io_context::stop, &io_context)); + + // Run the server. + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/http/server4/mime_types.cpp b/src/boost/libs/asio/example/cpp03/http/server4/mime_types.cpp new file mode 100644 index 000000000..0d8ea5d5a --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server4/mime_types.cpp @@ -0,0 +1,46 @@ +// +// mime_types.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "mime_types.hpp" + +namespace http { +namespace server4 { +namespace mime_types { + +struct mapping +{ + const char* extension; + const char* mime_type; +} mappings[] = +{ + { "gif", "image/gif" }, + { "htm", "text/html" }, + { "html", "text/html" }, + { "jpg", "image/jpeg" }, + { "png", "image/png" }, + { 0, 0 } // Marks end of list. +}; + +std::string extension_to_type(const std::string& extension) +{ + for (mapping* m = mappings; m->extension; ++m) + { + if (m->extension == extension) + { + return m->mime_type; + } + } + + return "text/plain"; +} + +} // namespace mime_types +} // namespace server4 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server4/mime_types.hpp b/src/boost/libs/asio/example/cpp03/http/server4/mime_types.hpp new file mode 100644 index 000000000..d92ba1283 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server4/mime_types.hpp @@ -0,0 +1,27 @@ +// +// mime_types.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER4_MIME_TYPES_HPP +#define HTTP_SERVER4_MIME_TYPES_HPP + +#include <string> + +namespace http { +namespace server4 { +namespace mime_types { + +/// Convert a file extension into a MIME type. +std::string extension_to_type(const std::string& extension); + +} // namespace mime_types +} // namespace server4 +} // namespace http + +#endif // HTTP_SERVER4_MIME_TYPES_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server4/reply.cpp b/src/boost/libs/asio/example/cpp03/http/server4/reply.cpp new file mode 100644 index 000000000..be9481aeb --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server4/reply.cpp @@ -0,0 +1,256 @@ +// +// reply.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "reply.hpp" +#include <string> +#include <boost/lexical_cast.hpp> + +namespace http { +namespace server4 { + +namespace status_strings { + +const std::string ok = + "HTTP/1.0 200 OK\r\n"; +const std::string created = + "HTTP/1.0 201 Created\r\n"; +const std::string accepted = + "HTTP/1.0 202 Accepted\r\n"; +const std::string no_content = + "HTTP/1.0 204 No Content\r\n"; +const std::string multiple_choices = + "HTTP/1.0 300 Multiple Choices\r\n"; +const std::string moved_permanently = + "HTTP/1.0 301 Moved Permanently\r\n"; +const std::string moved_temporarily = + "HTTP/1.0 302 Moved Temporarily\r\n"; +const std::string not_modified = + "HTTP/1.0 304 Not Modified\r\n"; +const std::string bad_request = + "HTTP/1.0 400 Bad Request\r\n"; +const std::string unauthorized = + "HTTP/1.0 401 Unauthorized\r\n"; +const std::string forbidden = + "HTTP/1.0 403 Forbidden\r\n"; +const std::string not_found = + "HTTP/1.0 404 Not Found\r\n"; +const std::string internal_server_error = + "HTTP/1.0 500 Internal Server Error\r\n"; +const std::string not_implemented = + "HTTP/1.0 501 Not Implemented\r\n"; +const std::string bad_gateway = + "HTTP/1.0 502 Bad Gateway\r\n"; +const std::string service_unavailable = + "HTTP/1.0 503 Service Unavailable\r\n"; + +boost::asio::const_buffer to_buffer(reply::status_type status) +{ + switch (status) + { + case reply::ok: + return boost::asio::buffer(ok); + case reply::created: + return boost::asio::buffer(created); + case reply::accepted: + return boost::asio::buffer(accepted); + case reply::no_content: + return boost::asio::buffer(no_content); + case reply::multiple_choices: + return boost::asio::buffer(multiple_choices); + case reply::moved_permanently: + return boost::asio::buffer(moved_permanently); + case reply::moved_temporarily: + return boost::asio::buffer(moved_temporarily); + case reply::not_modified: + return boost::asio::buffer(not_modified); + case reply::bad_request: + return boost::asio::buffer(bad_request); + case reply::unauthorized: + return boost::asio::buffer(unauthorized); + case reply::forbidden: + return boost::asio::buffer(forbidden); + case reply::not_found: + return boost::asio::buffer(not_found); + case reply::internal_server_error: + return boost::asio::buffer(internal_server_error); + case reply::not_implemented: + return boost::asio::buffer(not_implemented); + case reply::bad_gateway: + return boost::asio::buffer(bad_gateway); + case reply::service_unavailable: + return boost::asio::buffer(service_unavailable); + default: + return boost::asio::buffer(internal_server_error); + } +} + +} // namespace status_strings + +namespace misc_strings { + +const char name_value_separator[] = { ':', ' ' }; +const char crlf[] = { '\r', '\n' }; + +} // namespace misc_strings + +std::vector<boost::asio::const_buffer> reply::to_buffers() +{ + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(status_strings::to_buffer(status)); + for (std::size_t i = 0; i < headers.size(); ++i) + { + header& h = headers[i]; + buffers.push_back(boost::asio::buffer(h.name)); + buffers.push_back(boost::asio::buffer(misc_strings::name_value_separator)); + buffers.push_back(boost::asio::buffer(h.value)); + buffers.push_back(boost::asio::buffer(misc_strings::crlf)); + } + buffers.push_back(boost::asio::buffer(misc_strings::crlf)); + buffers.push_back(boost::asio::buffer(content)); + return buffers; +} + +namespace stock_replies { + +const char ok[] = ""; +const char created[] = + "<html>" + "<head><title>Created</title></head>" + "<body><h1>201 Created</h1></body>" + "</html>"; +const char accepted[] = + "<html>" + "<head><title>Accepted</title></head>" + "<body><h1>202 Accepted</h1></body>" + "</html>"; +const char no_content[] = + "<html>" + "<head><title>No Content</title></head>" + "<body><h1>204 Content</h1></body>" + "</html>"; +const char multiple_choices[] = + "<html>" + "<head><title>Multiple Choices</title></head>" + "<body><h1>300 Multiple Choices</h1></body>" + "</html>"; +const char moved_permanently[] = + "<html>" + "<head><title>Moved Permanently</title></head>" + "<body><h1>301 Moved Permanently</h1></body>" + "</html>"; +const char moved_temporarily[] = + "<html>" + "<head><title>Moved Temporarily</title></head>" + "<body><h1>302 Moved Temporarily</h1></body>" + "</html>"; +const char not_modified[] = + "<html>" + "<head><title>Not Modified</title></head>" + "<body><h1>304 Not Modified</h1></body>" + "</html>"; +const char bad_request[] = + "<html>" + "<head><title>Bad Request</title></head>" + "<body><h1>400 Bad Request</h1></body>" + "</html>"; +const char unauthorized[] = + "<html>" + "<head><title>Unauthorized</title></head>" + "<body><h1>401 Unauthorized</h1></body>" + "</html>"; +const char forbidden[] = + "<html>" + "<head><title>Forbidden</title></head>" + "<body><h1>403 Forbidden</h1></body>" + "</html>"; +const char not_found[] = + "<html>" + "<head><title>Not Found</title></head>" + "<body><h1>404 Not Found</h1></body>" + "</html>"; +const char internal_server_error[] = + "<html>" + "<head><title>Internal Server Error</title></head>" + "<body><h1>500 Internal Server Error</h1></body>" + "</html>"; +const char not_implemented[] = + "<html>" + "<head><title>Not Implemented</title></head>" + "<body><h1>501 Not Implemented</h1></body>" + "</html>"; +const char bad_gateway[] = + "<html>" + "<head><title>Bad Gateway</title></head>" + "<body><h1>502 Bad Gateway</h1></body>" + "</html>"; +const char service_unavailable[] = + "<html>" + "<head><title>Service Unavailable</title></head>" + "<body><h1>503 Service Unavailable</h1></body>" + "</html>"; + +std::string to_string(reply::status_type status) +{ + switch (status) + { + case reply::ok: + return ok; + case reply::created: + return created; + case reply::accepted: + return accepted; + case reply::no_content: + return no_content; + case reply::multiple_choices: + return multiple_choices; + case reply::moved_permanently: + return moved_permanently; + case reply::moved_temporarily: + return moved_temporarily; + case reply::not_modified: + return not_modified; + case reply::bad_request: + return bad_request; + case reply::unauthorized: + return unauthorized; + case reply::forbidden: + return forbidden; + case reply::not_found: + return not_found; + case reply::internal_server_error: + return internal_server_error; + case reply::not_implemented: + return not_implemented; + case reply::bad_gateway: + return bad_gateway; + case reply::service_unavailable: + return service_unavailable; + default: + return internal_server_error; + } +} + +} // namespace stock_replies + +reply reply::stock_reply(reply::status_type status) +{ + reply rep; + rep.status = status; + rep.content = stock_replies::to_string(status); + rep.headers.resize(2); + rep.headers[0].name = "Content-Length"; + rep.headers[0].value = boost::lexical_cast<std::string>(rep.content.size()); + rep.headers[1].name = "Content-Type"; + rep.headers[1].value = "text/html"; + return rep; +} + +} // namespace server4 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server4/reply.hpp b/src/boost/libs/asio/example/cpp03/http/server4/reply.hpp new file mode 100644 index 000000000..6ca1d635d --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server4/reply.hpp @@ -0,0 +1,64 @@ +// +// reply.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER4_REPLY_HPP +#define HTTP_SERVER4_REPLY_HPP + +#include <string> +#include <vector> +#include <boost/asio.hpp> +#include "header.hpp" + +namespace http { +namespace server4 { + +/// A reply to be sent to a client. +struct reply +{ + /// The status of the reply. + enum status_type + { + ok = 200, + created = 201, + accepted = 202, + no_content = 204, + multiple_choices = 300, + moved_permanently = 301, + moved_temporarily = 302, + not_modified = 304, + bad_request = 400, + unauthorized = 401, + forbidden = 403, + not_found = 404, + internal_server_error = 500, + not_implemented = 501, + bad_gateway = 502, + service_unavailable = 503 + } status; + + /// The headers to be included in the reply. + std::vector<header> headers; + + /// The content to be sent in the reply. + std::string content; + + /// Convert the reply into a vector of buffers. The buffers do not own the + /// underlying memory blocks, therefore the reply object must remain valid and + /// not be changed until the write operation has completed. + std::vector<boost::asio::const_buffer> to_buffers(); + + /// Get a stock reply. + static reply stock_reply(status_type status); +}; + +} // namespace server4 +} // namespace http + +#endif // HTTP_SERVER4_REPLY_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server4/request.hpp b/src/boost/libs/asio/example/cpp03/http/server4/request.hpp new file mode 100644 index 000000000..a50a21fd2 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server4/request.hpp @@ -0,0 +1,46 @@ +// +// request.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER4_REQUEST_HPP +#define HTTP_SERVER4_REQUEST_HPP + +#include <string> +#include <vector> +#include "header.hpp" + +namespace http { +namespace server4 { + +/// A request received from a client. +struct request +{ + /// The request method, e.g. "GET", "POST". + std::string method; + + /// The requested URI, such as a path to a file. + std::string uri; + + /// Major version number, usually 1. + int http_version_major; + + /// Minor version number, usually 0 or 1. + int http_version_minor; + + /// The headers included with the request. + std::vector<header> headers; + + /// The optional content sent with the request. + std::string content; +}; + +} // namespace server4 +} // namespace http + +#endif // HTTP_SERVER4_REQUEST_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server4/request_parser.cpp b/src/boost/libs/asio/example/cpp03/http/server4/request_parser.cpp new file mode 100644 index 000000000..17f0abb1c --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server4/request_parser.cpp @@ -0,0 +1,226 @@ +// +// request_parser.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "request_parser.hpp" +#include <algorithm> +#include <cctype> +#include <boost/lexical_cast.hpp> +#include "request.hpp" + +namespace http { +namespace server4 { + +// Enable the pseudo-keywords reenter, yield and fork. +#include <boost/asio/yield.hpp> + +std::string request_parser::content_length_name_ = "Content-Length"; + +boost::tribool request_parser::consume(request& req, char c) +{ + reenter (this) + { + req.method.clear(); + req.uri.clear(); + req.http_version_major = 0; + req.http_version_minor = 0; + req.headers.clear(); + req.content.clear(); + content_length_ = 0; + + // Request method. + while (is_char(c) && !is_ctl(c) && !is_tspecial(c) && c != ' ') + { + req.method.push_back(c); + yield return boost::indeterminate; + } + if (req.method.empty()) + return false; + + // Space. + if (c != ' ') return false; + yield return boost::indeterminate; + + // URI. + while (!is_ctl(c) && c != ' ') + { + req.uri.push_back(c); + yield return boost::indeterminate; + } + if (req.uri.empty()) return false; + + // Space. + if (c != ' ') return false; + yield return boost::indeterminate; + + // HTTP protocol identifier. + if (c != 'H') return false; + yield return boost::indeterminate; + if (c != 'T') return false; + yield return boost::indeterminate; + if (c != 'T') return false; + yield return boost::indeterminate; + if (c != 'P') return false; + yield return boost::indeterminate; + + // Slash. + if (c != '/') return false; + yield return boost::indeterminate; + + // Major version number. + if (!is_digit(c)) return false; + while (is_digit(c)) + { + req.http_version_major = req.http_version_major * 10 + c - '0'; + yield return boost::indeterminate; + } + + // Dot. + if (c != '.') return false; + yield return boost::indeterminate; + + // Minor version number. + if (!is_digit(c)) return false; + while (is_digit(c)) + { + req.http_version_minor = req.http_version_minor * 10 + c - '0'; + yield return boost::indeterminate; + } + + // CRLF. + if (c != '\r') return false; + yield return boost::indeterminate; + if (c != '\n') return false; + yield return boost::indeterminate; + + // Headers. + while ((is_char(c) && !is_ctl(c) && !is_tspecial(c) && c != '\r') + || (c == ' ' || c == '\t')) + { + if (c == ' ' || c == '\t') + { + // Leading whitespace. Must be continuation of previous header's value. + if (req.headers.empty()) return false; + while (c == ' ' || c == '\t') + yield return boost::indeterminate; + } + else + { + // Start the next header. + req.headers.push_back(header()); + + // Header name. + while (is_char(c) && !is_ctl(c) && !is_tspecial(c) && c != ':') + { + req.headers.back().name.push_back(c); + yield return boost::indeterminate; + } + + // Colon and space separates the header name from the header value. + if (c != ':') return false; + yield return boost::indeterminate; + if (c != ' ') return false; + yield return boost::indeterminate; + } + + // Header value. + while (is_char(c) && !is_ctl(c) && c != '\r') + { + req.headers.back().value.push_back(c); + yield return boost::indeterminate; + } + + // CRLF. + if (c != '\r') return false; + yield return boost::indeterminate; + if (c != '\n') return false; + yield return boost::indeterminate; + } + + // CRLF. + if (c != '\r') return false; + yield return boost::indeterminate; + if (c != '\n') return false; + + // Check for optional Content-Length header. + for (std::size_t i = 0; i < req.headers.size(); ++i) + { + if (headers_equal(req.headers[i].name, content_length_name_)) + { + try + { + content_length_ = + boost::lexical_cast<std::size_t>(req.headers[i].value); + } + catch (boost::bad_lexical_cast&) + { + return false; + } + } + } + + // Content. + while (req.content.size() < content_length_) + { + yield return boost::indeterminate; + req.content.push_back(c); + } + } + + return true; +} + +// Disable the pseudo-keywords reenter, yield and fork. +#include <boost/asio/unyield.hpp> + +bool request_parser::is_char(int c) +{ + return c >= 0 && c <= 127; +} + +bool request_parser::is_ctl(int c) +{ + return (c >= 0 && c <= 31) || (c == 127); +} + +bool request_parser::is_tspecial(int c) +{ + switch (c) + { + case '(': case ')': case '<': case '>': case '@': + case ',': case ';': case ':': case '\\': case '"': + case '/': case '[': case ']': case '?': case '=': + case '{': case '}': case ' ': case '\t': + return true; + default: + return false; + } +} + +bool request_parser::is_digit(int c) +{ + return c >= '0' && c <= '9'; +} + +bool request_parser::tolower_compare(char a, char b) +{ + return std::tolower(a) == std::tolower(b); +} + +bool request_parser::headers_equal(const std::string& a, const std::string& b) +{ + if (a.length() != b.length()) + return false; + + return std::equal(a.begin(), a.end(), b.begin(), + &request_parser::tolower_compare); +} + +} // namespace server4 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server4/request_parser.hpp b/src/boost/libs/asio/example/cpp03/http/server4/request_parser.hpp new file mode 100644 index 000000000..f7beaebd4 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server4/request_parser.hpp @@ -0,0 +1,78 @@ +// +// request_parser.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER4_REQUEST_PARSER_HPP +#define HTTP_SERVER4_REQUEST_PARSER_HPP + +#include <string> +#include <boost/logic/tribool.hpp> +#include <boost/tuple/tuple.hpp> +#include <boost/asio/coroutine.hpp> + +namespace http { +namespace server4 { + +struct request; + +/// Parser for incoming requests. +class request_parser : boost::asio::coroutine +{ +public: + /// Parse some data. The tribool return value is true when a complete request + /// has been parsed, false if the data is invalid, indeterminate when more + /// data is required. The InputIterator return value indicates how much of the + /// input has been consumed. + template <typename InputIterator> + boost::tuple<boost::tribool, InputIterator> parse(request& req, + InputIterator begin, InputIterator end) + { + while (begin != end) + { + boost::tribool result = consume(req, *begin++); + if (result || !result) + return boost::make_tuple(result, begin); + } + boost::tribool result = boost::indeterminate; + return boost::make_tuple(result, begin); + } + +private: + /// The name of the content length header. + static std::string content_length_name_; + + /// Content length as decoded from headers. Defaults to 0. + std::size_t content_length_; + + /// Handle the next character of input. + boost::tribool consume(request& req, char input); + + /// Check if a byte is an HTTP character. + static bool is_char(int c); + + /// Check if a byte is an HTTP control character. + static bool is_ctl(int c); + + /// Check if a byte is defined as an HTTP tspecial character. + static bool is_tspecial(int c); + + /// Check if a byte is a digit. + static bool is_digit(int c); + + /// Check if two characters are equal, without regard to case. + static bool tolower_compare(char a, char b); + + /// Check whether the two request header names match. + bool headers_equal(const std::string& a, const std::string& b); +}; + +} // namespace server4 +} // namespace http + +#endif // HTTP_SERVER4_REQUEST_PARSER_HPP diff --git a/src/boost/libs/asio/example/cpp03/http/server4/server.cpp b/src/boost/libs/asio/example/cpp03/http/server4/server.cpp new file mode 100644 index 000000000..b6d109cad --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server4/server.cpp @@ -0,0 +1,122 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "server.hpp" +#include "request.hpp" +#include "reply.hpp" + +namespace http { +namespace server4 { + +server::server(boost::asio::io_context& io_context, + const std::string& address, const std::string& port, + boost::function<void(const request&, reply&)> request_handler) + : request_handler_(request_handler) +{ + tcp::resolver resolver(io_context); + boost::asio::ip::tcp::endpoint endpoint = + *resolver.resolve(address, port).begin(); + acceptor_.reset(new tcp::acceptor(io_context, endpoint)); +} + +// Enable the pseudo-keywords reenter, yield and fork. +#include <boost/asio/yield.hpp> + +void server::operator()(boost::system::error_code ec, std::size_t length) +{ + // In this example we keep the error handling code in one place by + // hoisting it outside the coroutine. An alternative approach would be to + // check the value of ec after each yield for an asynchronous operation. + if (!ec) + { + // On reentering a coroutine, control jumps to the location of the last + // yield or fork. The argument to the "reenter" pseudo-keyword can be a + // pointer or reference to an object of type coroutine. + reenter (this) + { + // Loop to accept incoming connections. + do + { + // Create a new socket for the next incoming connection. + socket_.reset(new tcp::socket(acceptor_->get_executor())); + + // Accept a new connection. The "yield" pseudo-keyword saves the current + // line number and exits the coroutine's "reenter" block. We use the + // server coroutine as the completion handler for the async_accept + // operation. When the asynchronous operation completes, the io_context + // invokes the function call operator, we "reenter" the coroutine, and + // then control resumes at the following line. + yield acceptor_->async_accept(*socket_, *this); + + // We "fork" by cloning a new server coroutine to handle the connection. + // After forking we have a parent coroutine and a child coroutine. Both + // parent and child continue execution at the following line. They can + // be distinguished using the functions coroutine::is_parent() and + // coroutine::is_child(). + fork server(*this)(); + + // The parent continues looping to accept the next incoming connection. + // The child exits the loop and processes the connection. + } while (is_parent()); + + // Create the objects needed to receive a request on the connection. + buffer_.reset(new boost::array<char, 8192>); + request_.reset(new request); + + // Loop until a complete request (or an invalid one) has been received. + do + { + // Receive some more data. When control resumes at the following line, + // the ec and length parameters reflect the result of the asynchronous + // operation. + yield socket_->async_read_some(boost::asio::buffer(*buffer_), *this); + + // Parse the data we just received. + boost::tie(valid_request_, boost::tuples::ignore) + = request_parser_.parse(*request_, + buffer_->data(), buffer_->data() + length); + + // An indeterminate result means we need more data, so keep looping. + } while (boost::indeterminate(valid_request_)); + + // Create the reply object that will be sent back to the client. + reply_.reset(new reply); + + if (valid_request_) + { + // A valid request was received. Call the user-supplied function object + // to process the request and compose a reply. + request_handler_(*request_, *reply_); + } + else + { + // The request was invalid. + *reply_ = reply::stock_reply(reply::bad_request); + } + + // Send the reply back to the client. + yield boost::asio::async_write(*socket_, reply_->to_buffers(), *this); + + // Initiate graceful connection closure. + socket_->shutdown(tcp::socket::shutdown_both, ec); + } + } + + // If an error occurs then the coroutine is not reentered. Consequently, no + // new asynchronous operations are started. This means that all shared_ptr + // references will disappear and the resources associated with the coroutine + // will be destroyed automatically after this function call returns. +} + +// Disable the pseudo-keywords reenter, yield and fork. +#include <boost/asio/unyield.hpp> + +} // namespace server4 +} // namespace http diff --git a/src/boost/libs/asio/example/cpp03/http/server4/server.hpp b/src/boost/libs/asio/example/cpp03/http/server4/server.hpp new file mode 100644 index 000000000..5be1f250a --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/http/server4/server.hpp @@ -0,0 +1,73 @@ +// +// server.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER4_SERVER_HPP +#define HTTP_SERVER4_SERVER_HPP + +#include <boost/asio.hpp> +#include <string> +#include <boost/array.hpp> +#include <boost/function.hpp> +#include <boost/shared_ptr.hpp> +#include "request_parser.hpp" + +namespace http { +namespace server4 { + +struct request; +struct reply; + +/// The top-level coroutine of the HTTP server. +class server : boost::asio::coroutine +{ +public: + /// Construct the server to listen on the specified TCP address and port, and + /// serve up files from the given directory. + explicit server(boost::asio::io_context& io_context, + const std::string& address, const std::string& port, + boost::function<void(const request&, reply&)> request_handler); + + /// Perform work associated with the server. + void operator()( + boost::system::error_code ec = boost::system::error_code(), + std::size_t length = 0); + +private: + typedef boost::asio::ip::tcp tcp; + + /// The user-supplied handler for all incoming requests. + boost::function<void(const request&, reply&)> request_handler_; + + /// Acceptor used to listen for incoming connections. + boost::shared_ptr<tcp::acceptor> acceptor_; + + /// The current connection from a client. + boost::shared_ptr<tcp::socket> socket_; + + /// Buffer for incoming data. + boost::shared_ptr<boost::array<char, 8192> > buffer_; + + /// The incoming request. + boost::shared_ptr<request> request_; + + /// Whether the request is valid or not. + boost::tribool valid_request_; + + /// The parser for the incoming request. + request_parser request_parser_; + + /// The reply to be sent back to the client. + boost::shared_ptr<reply> reply_; +}; + +} // namespace server4 +} // namespace http + +#endif // HTTP_SERVER4_SERVER_HPP diff --git a/src/boost/libs/asio/example/cpp03/icmp/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/icmp/Jamfile.v2 new file mode 100644 index 000000000..a7a2ac60d --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/icmp/Jamfile.v2 @@ -0,0 +1,30 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe ping + : ping.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp03/icmp/icmp_header.hpp b/src/boost/libs/asio/example/cpp03/icmp/icmp_header.hpp new file mode 100644 index 000000000..ddb992e62 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/icmp/icmp_header.hpp @@ -0,0 +1,94 @@ +// +// icmp_header.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ICMP_HEADER_HPP +#define ICMP_HEADER_HPP + +#include <istream> +#include <ostream> +#include <algorithm> + +// ICMP header for both IPv4 and IPv6. +// +// The wire format of an ICMP header is: +// +// 0 8 16 31 +// +---------------+---------------+------------------------------+ --- +// | | | | ^ +// | type | code | checksum | | +// | | | | | +// +---------------+---------------+------------------------------+ 8 bytes +// | | | | +// | identifier | sequence number | | +// | | | v +// +-------------------------------+------------------------------+ --- + +class icmp_header +{ +public: + enum { echo_reply = 0, destination_unreachable = 3, source_quench = 4, + redirect = 5, echo_request = 8, time_exceeded = 11, parameter_problem = 12, + timestamp_request = 13, timestamp_reply = 14, info_request = 15, + info_reply = 16, address_request = 17, address_reply = 18 }; + + icmp_header() { std::fill(rep_, rep_ + sizeof(rep_), 0); } + + unsigned char type() const { return rep_[0]; } + unsigned char code() const { return rep_[1]; } + unsigned short checksum() const { return decode(2, 3); } + unsigned short identifier() const { return decode(4, 5); } + unsigned short sequence_number() const { return decode(6, 7); } + + void type(unsigned char n) { rep_[0] = n; } + void code(unsigned char n) { rep_[1] = n; } + void checksum(unsigned short n) { encode(2, 3, n); } + void identifier(unsigned short n) { encode(4, 5, n); } + void sequence_number(unsigned short n) { encode(6, 7, n); } + + friend std::istream& operator>>(std::istream& is, icmp_header& header) + { return is.read(reinterpret_cast<char*>(header.rep_), 8); } + + friend std::ostream& operator<<(std::ostream& os, const icmp_header& header) + { return os.write(reinterpret_cast<const char*>(header.rep_), 8); } + +private: + unsigned short decode(int a, int b) const + { return (rep_[a] << 8) + rep_[b]; } + + void encode(int a, int b, unsigned short n) + { + rep_[a] = static_cast<unsigned char>(n >> 8); + rep_[b] = static_cast<unsigned char>(n & 0xFF); + } + + unsigned char rep_[8]; +}; + +template <typename Iterator> +void compute_checksum(icmp_header& header, + Iterator body_begin, Iterator body_end) +{ + unsigned int sum = (header.type() << 8) + header.code() + + header.identifier() + header.sequence_number(); + + Iterator body_iter = body_begin; + while (body_iter != body_end) + { + sum += (static_cast<unsigned char>(*body_iter++) << 8); + if (body_iter != body_end) + sum += static_cast<unsigned char>(*body_iter++); + } + + sum = (sum >> 16) + (sum & 0xFFFF); + sum += (sum >> 16); + header.checksum(static_cast<unsigned short>(~sum)); +} + +#endif // ICMP_HEADER_HPP diff --git a/src/boost/libs/asio/example/cpp03/icmp/ipv4_header.hpp b/src/boost/libs/asio/example/cpp03/icmp/ipv4_header.hpp new file mode 100644 index 000000000..56adc2494 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/icmp/ipv4_header.hpp @@ -0,0 +1,102 @@ +// +// ipv4_header.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef IPV4_HEADER_HPP +#define IPV4_HEADER_HPP + +#include <algorithm> +#include <boost/asio/ip/address_v4.hpp> + +// Packet header for IPv4. +// +// The wire format of an IPv4 header is: +// +// 0 8 16 31 +// +-------+-------+---------------+------------------------------+ --- +// | | | | | ^ +// |version|header | type of | total length in bytes | | +// | (4) | length| service | | | +// +-------+-------+---------------+-+-+-+------------------------+ | +// | | | | | | | +// | identification |0|D|M| fragment offset | | +// | | |F|F| | | +// +---------------+---------------+-+-+-+------------------------+ | +// | | | | | +// | time to live | protocol | header checksum | 20 bytes +// | | | | | +// +---------------+---------------+------------------------------+ | +// | | | +// | source IPv4 address | | +// | | | +// +--------------------------------------------------------------+ | +// | | | +// | destination IPv4 address | | +// | | v +// +--------------------------------------------------------------+ --- +// | | ^ +// | | | +// / options (if any) / 0 - 40 +// / / bytes +// | | | +// | | v +// +--------------------------------------------------------------+ --- + +class ipv4_header +{ +public: + ipv4_header() { std::fill(rep_, rep_ + sizeof(rep_), 0); } + + unsigned char version() const { return (rep_[0] >> 4) & 0xF; } + unsigned short header_length() const { return (rep_[0] & 0xF) * 4; } + unsigned char type_of_service() const { return rep_[1]; } + unsigned short total_length() const { return decode(2, 3); } + unsigned short identification() const { return decode(4, 5); } + bool dont_fragment() const { return (rep_[6] & 0x40) != 0; } + bool more_fragments() const { return (rep_[6] & 0x20) != 0; } + unsigned short fragment_offset() const { return decode(6, 7) & 0x1FFF; } + unsigned int time_to_live() const { return rep_[8]; } + unsigned char protocol() const { return rep_[9]; } + unsigned short header_checksum() const { return decode(10, 11); } + + boost::asio::ip::address_v4 source_address() const + { + boost::asio::ip::address_v4::bytes_type bytes + = { { rep_[12], rep_[13], rep_[14], rep_[15] } }; + return boost::asio::ip::address_v4(bytes); + } + + boost::asio::ip::address_v4 destination_address() const + { + boost::asio::ip::address_v4::bytes_type bytes + = { { rep_[16], rep_[17], rep_[18], rep_[19] } }; + return boost::asio::ip::address_v4(bytes); + } + + friend std::istream& operator>>(std::istream& is, ipv4_header& header) + { + is.read(reinterpret_cast<char*>(header.rep_), 20); + if (header.version() != 4) + is.setstate(std::ios::failbit); + std::streamsize options_length = header.header_length() - 20; + if (options_length < 0 || options_length > 40) + is.setstate(std::ios::failbit); + else + is.read(reinterpret_cast<char*>(header.rep_) + 20, options_length); + return is; + } + +private: + unsigned short decode(int a, int b) const + { return (rep_[a] << 8) + rep_[b]; } + + unsigned char rep_[60]; +}; + +#endif // IPV4_HEADER_HPP diff --git a/src/boost/libs/asio/example/cpp03/icmp/ping.cpp b/src/boost/libs/asio/example/cpp03/icmp/ping.cpp new file mode 100644 index 000000000..7a3bfea21 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/icmp/ping.cpp @@ -0,0 +1,163 @@ +// +// ping.cpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio.hpp> +#include <boost/bind/bind.hpp> +#include <istream> +#include <iostream> +#include <ostream> + +#include "icmp_header.hpp" +#include "ipv4_header.hpp" + +using boost::asio::ip::icmp; +using boost::asio::steady_timer; +namespace chrono = boost::asio::chrono; + +class pinger +{ +public: + pinger(boost::asio::io_context& io_context, const char* destination) + : resolver_(io_context), socket_(io_context, icmp::v4()), + timer_(io_context), sequence_number_(0), num_replies_(0) + { + destination_ = *resolver_.resolve(icmp::v4(), destination, "").begin(); + + start_send(); + start_receive(); + } + +private: + void start_send() + { + std::string body("\"Hello!\" from Asio ping."); + + // Create an ICMP header for an echo request. + icmp_header echo_request; + echo_request.type(icmp_header::echo_request); + echo_request.code(0); + echo_request.identifier(get_identifier()); + echo_request.sequence_number(++sequence_number_); + compute_checksum(echo_request, body.begin(), body.end()); + + // Encode the request packet. + boost::asio::streambuf request_buffer; + std::ostream os(&request_buffer); + os << echo_request << body; + + // Send the request. + time_sent_ = steady_timer::clock_type::now(); + socket_.send_to(request_buffer.data(), destination_); + + // Wait up to five seconds for a reply. + num_replies_ = 0; + timer_.expires_at(time_sent_ + chrono::seconds(5)); + timer_.async_wait(boost::bind(&pinger::handle_timeout, this)); + } + + void handle_timeout() + { + if (num_replies_ == 0) + std::cout << "Request timed out" << std::endl; + + // Requests must be sent no less than one second apart. + timer_.expires_at(time_sent_ + chrono::seconds(1)); + timer_.async_wait(boost::bind(&pinger::start_send, this)); + } + + void start_receive() + { + // Discard any data already in the buffer. + reply_buffer_.consume(reply_buffer_.size()); + + // Wait for a reply. We prepare the buffer to receive up to 64KB. + socket_.async_receive(reply_buffer_.prepare(65536), + boost::bind(&pinger::handle_receive, this, boost::placeholders::_2)); + } + + void handle_receive(std::size_t length) + { + // The actual number of bytes received is committed to the buffer so that we + // can extract it using a std::istream object. + reply_buffer_.commit(length); + + // Decode the reply packet. + std::istream is(&reply_buffer_); + ipv4_header ipv4_hdr; + icmp_header icmp_hdr; + is >> ipv4_hdr >> icmp_hdr; + + // We can receive all ICMP packets received by the host, so we need to + // filter out only the echo replies that match the our identifier and + // expected sequence number. + if (is && icmp_hdr.type() == icmp_header::echo_reply + && icmp_hdr.identifier() == get_identifier() + && icmp_hdr.sequence_number() == sequence_number_) + { + // If this is the first reply, interrupt the five second timeout. + if (num_replies_++ == 0) + timer_.cancel(); + + // Print out some information about the reply packet. + chrono::steady_clock::time_point now = chrono::steady_clock::now(); + chrono::steady_clock::duration elapsed = now - time_sent_; + std::cout << length - ipv4_hdr.header_length() + << " bytes from " << ipv4_hdr.source_address() + << ": icmp_seq=" << icmp_hdr.sequence_number() + << ", ttl=" << ipv4_hdr.time_to_live() + << ", time=" + << chrono::duration_cast<chrono::milliseconds>(elapsed).count() + << std::endl; + } + + start_receive(); + } + + static unsigned short get_identifier() + { +#if defined(BOOST_ASIO_WINDOWS) + return static_cast<unsigned short>(::GetCurrentProcessId()); +#else + return static_cast<unsigned short>(::getpid()); +#endif + } + + icmp::resolver resolver_; + icmp::endpoint destination_; + icmp::socket socket_; + steady_timer timer_; + unsigned short sequence_number_; + chrono::steady_clock::time_point time_sent_; + boost::asio::streambuf reply_buffer_; + std::size_t num_replies_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: ping <host>" << std::endl; +#if !defined(BOOST_ASIO_WINDOWS) + std::cerr << "(You may need to run this program as root.)" << std::endl; +#endif + return 1; + } + + boost::asio::io_context io_context; + pinger p(io_context, argv[1]); + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << std::endl; + } +} diff --git a/src/boost/libs/asio/example/cpp03/invocation/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/invocation/Jamfile.v2 new file mode 100644 index 000000000..56beb37f0 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/invocation/Jamfile.v2 @@ -0,0 +1,30 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe prioritised_handlers + : prioritised_handlers.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp03/invocation/prioritised_handlers.cpp b/src/boost/libs/asio/example/cpp03/invocation/prioritised_handlers.cpp new file mode 100644 index 000000000..f0d201d83 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/invocation/prioritised_handlers.cpp @@ -0,0 +1,171 @@ +// +// prioritised_handlers.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio.hpp> +#include <boost/function.hpp> +#include <iostream> +#include <queue> + +using boost::asio::ip::tcp; + +class handler_priority_queue : public boost::asio::execution_context +{ +public: + void add(int priority, boost::function<void()> function) + { + handlers_.push(queued_handler(priority, function)); + } + + void execute_all() + { + while (!handlers_.empty()) + { + queued_handler handler = handlers_.top(); + handler.execute(); + handlers_.pop(); + } + } + + class executor + { + public: + executor(handler_priority_queue& q, int p) + : context_(q), priority_(p) + { + } + + handler_priority_queue& context() const + { + return context_; + } + + template <typename Function, typename Allocator> + void dispatch(const Function& f, const Allocator&) const + { + context_.add(priority_, f); + } + + template <typename Function, typename Allocator> + void post(const Function& f, const Allocator&) const + { + context_.add(priority_, f); + } + + template <typename Function, typename Allocator> + void defer(const Function& f, const Allocator&) const + { + context_.add(priority_, f); + } + + void on_work_started() const {} + void on_work_finished() const {} + + bool operator==(const executor& other) const + { + return &context_ == &other.context_ && priority_ == other.priority_; + } + + bool operator!=(const executor& other) const + { + return !operator==(other); + } + + private: + handler_priority_queue& context_; + int priority_; + }; + + template <typename Handler> + boost::asio::executor_binder<Handler, executor> + wrap(int priority, Handler handler) + { + return boost::asio::bind_executor(executor(*this, priority), handler); + } + +private: + class queued_handler + { + public: + queued_handler(int p, boost::function<void()> f) + : priority_(p), function_(f) + { + } + + void execute() + { + function_(); + } + + friend bool operator<(const queued_handler& a, + const queued_handler& b) + { + return a.priority_ < b.priority_; + } + + private: + int priority_; + boost::function<void()> function_; + }; + + std::priority_queue<queued_handler> handlers_; +}; + +//---------------------------------------------------------------------- + +void high_priority_handler(const boost::system::error_code& /*ec*/) +{ + std::cout << "High priority handler\n"; +} + +void middle_priority_handler(const boost::system::error_code& /*ec*/) +{ + std::cout << "Middle priority handler\n"; +} + +void low_priority_handler() +{ + std::cout << "Low priority handler\n"; +} + +int main() +{ + boost::asio::io_context io_context; + + handler_priority_queue pri_queue; + + // Post a completion handler to be run immediately. + boost::asio::post(io_context, pri_queue.wrap(0, low_priority_handler)); + + // Start an asynchronous accept that will complete immediately. + tcp::endpoint endpoint(boost::asio::ip::address_v4::loopback(), 0); + tcp::acceptor acceptor(io_context, endpoint); + tcp::socket server_socket(io_context); + acceptor.async_accept(server_socket, + pri_queue.wrap(100, high_priority_handler)); + tcp::socket client_socket(io_context); + client_socket.connect(acceptor.local_endpoint()); + + // Set a deadline timer to expire immediately. + boost::asio::steady_timer timer(io_context); + timer.expires_at(boost::asio::steady_timer::time_point::min()); + timer.async_wait(pri_queue.wrap(42, middle_priority_handler)); + + while (io_context.run_one()) + { + // The custom invocation hook adds the handlers to the priority queue + // rather than executing them from within the poll_one() call. + while (io_context.poll_one()) + ; + + pri_queue.execute_all(); + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/iostreams/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/iostreams/Jamfile.v2 new file mode 100644 index 000000000..ece413e23 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/iostreams/Jamfile.v2 @@ -0,0 +1,34 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe daytime_client : daytime_client.cpp ; +exe daytime_server : daytime_server.cpp ; +exe http_client : http_client.cpp ; diff --git a/src/boost/libs/asio/example/cpp03/iostreams/daytime_client.cpp b/src/boost/libs/asio/example/cpp03/iostreams/daytime_client.cpp new file mode 100644 index 000000000..7abd1115f --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/iostreams/daytime_client.cpp @@ -0,0 +1,44 @@ +// +// daytime_client.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <string> +#include <boost/asio.hpp> + +using boost::asio::ip::tcp; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: daytime_client <host>" << std::endl; + return 1; + } + + tcp::iostream s(argv[1], "daytime"); + if (!s) + { + std::cout << "Unable to connect: " << s.error().message() << std::endl; + return 1; + } + + std::string line; + std::getline(s, line); + std::cout << line << std::endl; + } + catch (std::exception& e) + { + std::cout << "Exception: " << e.what() << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/iostreams/daytime_server.cpp b/src/boost/libs/asio/example/cpp03/iostreams/daytime_server.cpp new file mode 100644 index 000000000..bcc0b1605 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/iostreams/daytime_server.cpp @@ -0,0 +1,51 @@ +// +// daytime_server.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <ctime> +#include <iostream> +#include <string> +#include <boost/asio.hpp> + +using boost::asio::ip::tcp; + +std::string make_daytime_string() +{ + using namespace std; // For time_t, time and ctime; + time_t now = time(0); + return ctime(&now); +} + +int main() +{ + try + { + boost::asio::io_context io_context; + + tcp::endpoint endpoint(tcp::v4(), 13); + tcp::acceptor acceptor(io_context, endpoint); + + for (;;) + { + tcp::iostream stream; + boost::system::error_code ec; + acceptor.accept(stream.socket(), ec); + if (!ec) + { + stream << make_daytime_string(); + } + } + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/iostreams/http_client.cpp b/src/boost/libs/asio/example/cpp03/iostreams/http_client.cpp new file mode 100644 index 000000000..bc5613a03 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/iostreams/http_client.cpp @@ -0,0 +1,91 @@ +// +// http_client.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <istream> +#include <ostream> +#include <string> +#include <boost/asio/ip/tcp.hpp> + +using boost::asio::ip::tcp; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cout << "Usage: http_client <server> <path>\n"; + std::cout << "Example:\n"; + std::cout << " http_client www.boost.org /LICENSE_1_0.txt\n"; + return 1; + } + + boost::asio::ip::tcp::iostream s; + + // The entire sequence of I/O operations must complete within 60 seconds. + // If an expiry occurs, the socket is automatically closed and the stream + // becomes bad. + s.expires_after(boost::asio::chrono::seconds(60)); + + // Establish a connection to the server. + s.connect(argv[1], "http"); + if (!s) + { + std::cout << "Unable to connect: " << s.error().message() << "\n"; + return 1; + } + + // Send the request. We specify the "Connection: close" header so that the + // server will close the socket after transmitting the response. This will + // allow us to treat all data up until the EOF as the content. + s << "GET " << argv[2] << " HTTP/1.0\r\n"; + s << "Host: " << argv[1] << "\r\n"; + s << "Accept: */*\r\n"; + s << "Connection: close\r\n\r\n"; + + // By default, the stream is tied with itself. This means that the stream + // automatically flush the buffered output before attempting a read. It is + // not necessary not explicitly flush the stream at this point. + + // Check that response is OK. + std::string http_version; + s >> http_version; + unsigned int status_code; + s >> status_code; + std::string status_message; + std::getline(s, status_message); + if (!s || http_version.substr(0, 5) != "HTTP/") + { + std::cout << "Invalid response\n"; + return 1; + } + if (status_code != 200) + { + std::cout << "Response returned with status code " << status_code << "\n"; + return 1; + } + + // Process the response headers, which are terminated by a blank line. + std::string header; + while (std::getline(s, header) && header != "\r") + std::cout << header << "\n"; + std::cout << "\n"; + + // Write the remaining data to output. + std::cout << s.rdbuf(); + } + catch (std::exception& e) + { + std::cout << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/local/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/local/Jamfile.v2 new file mode 100644 index 000000000..05ef40b90 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/local/Jamfile.v2 @@ -0,0 +1,82 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe connect_pair + : connect_pair.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + /boost/thread//boost_thread + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe iostream_client + : iostream_client.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe stream_client + : stream_client.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe stream_server + : stream_server.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp03/local/connect_pair.cpp b/src/boost/libs/asio/example/cpp03/local/connect_pair.cpp new file mode 100644 index 000000000..7901783b6 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/local/connect_pair.cpp @@ -0,0 +1,142 @@ +// +// connect_pair.cpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <string> +#include <cctype> +#include <boost/asio.hpp> +#include <boost/thread/thread.hpp> +#include <boost/array.hpp> +#include <boost/bind/bind.hpp> + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +using boost::asio::local::stream_protocol; + +class uppercase_filter +{ +public: + uppercase_filter(boost::asio::io_context& io_context) + : socket_(io_context) + { + } + + stream_protocol::socket& socket() + { + return socket_; + } + + void start() + { + // Wait for request. + socket_.async_read_some(boost::asio::buffer(data_), + boost::bind(&uppercase_filter::handle_read, + this, boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + +private: + void handle_read(const boost::system::error_code& ec, std::size_t size) + { + if (!ec) + { + // Compute result. + for (std::size_t i = 0; i < size; ++i) + data_[i] = std::toupper(data_[i]); + + // Send result. + boost::asio::async_write(socket_, boost::asio::buffer(data_, size), + boost::bind(&uppercase_filter::handle_write, + this, boost::asio::placeholders::error)); + } + else + { + throw boost::system::system_error(ec); + } + } + + void handle_write(const boost::system::error_code& ec) + { + if (!ec) + { + // Wait for request. + socket_.async_read_some(boost::asio::buffer(data_), + boost::bind(&uppercase_filter::handle_read, + this, boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + else + { + throw boost::system::system_error(ec); + } + } + + stream_protocol::socket socket_; + boost::array<char, 512> data_; +}; + +void run(boost::asio::io_context* io_context) +{ + try + { + io_context->run(); + } + catch (std::exception& e) + { + std::cerr << "Exception in thread: " << e.what() << "\n"; + std::exit(1); + } +} + +int main() +{ + try + { + boost::asio::io_context io_context; + + // Create filter and establish a connection to it. + uppercase_filter filter(io_context); + stream_protocol::socket socket(io_context); + boost::asio::local::connect_pair(socket, filter.socket()); + filter.start(); + + // The io_context runs in a background thread to perform filtering. + boost::thread thread(boost::bind(run, &io_context)); + + for (;;) + { + // Collect request from user. + std::cout << "Enter a string: "; + std::string request; + std::getline(std::cin, request); + + // Send request to filter. + boost::asio::write(socket, boost::asio::buffer(request)); + + // Wait for reply from filter. + std::vector<char> reply(request.size()); + boost::asio::read(socket, boost::asio::buffer(reply)); + + // Show reply to user. + std::cout << "Result: "; + std::cout.write(&reply[0], request.size()); + std::cout << std::endl; + } + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + std::exit(1); + } +} + +#else // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +# error Local sockets not available on this platform. +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) diff --git a/src/boost/libs/asio/example/cpp03/local/iostream_client.cpp b/src/boost/libs/asio/example/cpp03/local/iostream_client.cpp new file mode 100644 index 000000000..4e61abb47 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/local/iostream_client.cpp @@ -0,0 +1,62 @@ +// +// stream_client.cpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstring> +#include <iostream> +#include <boost/asio.hpp> + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +using boost::asio::local::stream_protocol; + +enum { max_length = 1024 }; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: iostream_client <file>\n"; + return 1; + } + + stream_protocol::endpoint ep(argv[1]); + stream_protocol::iostream s(ep); + if (!s) + { + std::cerr << "Unable to connect: " << s.error().message() << std::endl; + return 1; + } + + using namespace std; // For strlen. + std::cout << "Enter message: "; + char request[max_length]; + std::cin.getline(request, max_length); + size_t length = strlen(request); + s << request; + + char reply[max_length]; + s.read(reply, length); + std::cout << "Reply is: "; + std::cout.write(reply, length); + std::cout << "\n"; + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} + +#else // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +# error Local sockets not available on this platform. +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) diff --git a/src/boost/libs/asio/example/cpp03/local/stream_client.cpp b/src/boost/libs/asio/example/cpp03/local/stream_client.cpp new file mode 100644 index 000000000..2a62bdee2 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/local/stream_client.cpp @@ -0,0 +1,61 @@ +// +// stream_client.cpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <cstring> +#include <iostream> +#include <boost/asio.hpp> + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +using boost::asio::local::stream_protocol; + +enum { max_length = 1024 }; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: stream_client <file>\n"; + return 1; + } + + boost::asio::io_context io_context; + + stream_protocol::socket s(io_context); + s.connect(stream_protocol::endpoint(argv[1])); + + using namespace std; // For strlen. + std::cout << "Enter message: "; + char request[max_length]; + std::cin.getline(request, max_length); + size_t request_length = strlen(request); + boost::asio::write(s, boost::asio::buffer(request, request_length)); + + char reply[max_length]; + size_t reply_length = boost::asio::read(s, + boost::asio::buffer(reply, request_length)); + std::cout << "Reply is: "; + std::cout.write(reply, reply_length); + std::cout << "\n"; + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} + +#else // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +# error Local sockets not available on this platform. +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) diff --git a/src/boost/libs/asio/example/cpp03/local/stream_server.cpp b/src/boost/libs/asio/example/cpp03/local/stream_server.cpp new file mode 100644 index 000000000..7d309ef2a --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/local/stream_server.cpp @@ -0,0 +1,141 @@ +// +// stream_server.cpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdio> +#include <iostream> +#include <boost/array.hpp> +#include <boost/bind/bind.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/asio.hpp> + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +using boost::asio::local::stream_protocol; + +class session + : public boost::enable_shared_from_this<session> +{ +public: + session(boost::asio::io_context& io_context) + : socket_(io_context) + { + } + + stream_protocol::socket& socket() + { + return socket_; + } + + void start() + { + socket_.async_read_some(boost::asio::buffer(data_), + boost::bind(&session::handle_read, + shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + + void handle_read(const boost::system::error_code& error, + size_t bytes_transferred) + { + if (!error) + { + boost::asio::async_write(socket_, + boost::asio::buffer(data_, bytes_transferred), + boost::bind(&session::handle_write, + shared_from_this(), + boost::asio::placeholders::error)); + } + } + + void handle_write(const boost::system::error_code& error) + { + if (!error) + { + socket_.async_read_some(boost::asio::buffer(data_), + boost::bind(&session::handle_read, + shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + } + +private: + // The socket used to communicate with the client. + stream_protocol::socket socket_; + + // Buffer used to store data received from the client. + boost::array<char, 1024> data_; +}; + +typedef boost::shared_ptr<session> session_ptr; + +class server +{ +public: + server(boost::asio::io_context& io_context, const std::string& file) + : io_context_(io_context), + acceptor_(io_context, stream_protocol::endpoint(file)) + { + session_ptr new_session(new session(io_context_)); + acceptor_.async_accept(new_session->socket(), + boost::bind(&server::handle_accept, this, new_session, + boost::asio::placeholders::error)); + } + + void handle_accept(session_ptr new_session, + const boost::system::error_code& error) + { + if (!error) + { + new_session->start(); + } + + new_session.reset(new session(io_context_)); + acceptor_.async_accept(new_session->socket(), + boost::bind(&server::handle_accept, this, new_session, + boost::asio::placeholders::error)); + } + +private: + boost::asio::io_context& io_context_; + stream_protocol::acceptor acceptor_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: stream_server <file>\n"; + std::cerr << "*** WARNING: existing file is removed ***\n"; + return 1; + } + + boost::asio::io_context io_context; + + std::remove(argv[1]); + server s(io_context, argv[1]); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} + +#else // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +# error Local sockets not available on this platform. +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) diff --git a/src/boost/libs/asio/example/cpp03/multicast/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/multicast/Jamfile.v2 new file mode 100644 index 000000000..909903a79 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/multicast/Jamfile.v2 @@ -0,0 +1,33 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe receiver : receiver.cpp ; +exe sender : sender.cpp ; diff --git a/src/boost/libs/asio/example/cpp03/multicast/receiver.cpp b/src/boost/libs/asio/example/cpp03/multicast/receiver.cpp new file mode 100644 index 000000000..f6da0138d --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/multicast/receiver.cpp @@ -0,0 +1,93 @@ +// +// receiver.cpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <string> +#include <boost/asio.hpp> +#include "boost/bind/bind.hpp" + +const short multicast_port = 30001; + +class receiver +{ +public: + receiver(boost::asio::io_context& io_context, + const boost::asio::ip::address& listen_address, + const boost::asio::ip::address& multicast_address) + : socket_(io_context) + { + // Create the socket so that multiple may be bound to the same address. + boost::asio::ip::udp::endpoint listen_endpoint( + listen_address, multicast_port); + socket_.open(listen_endpoint.protocol()); + socket_.set_option(boost::asio::ip::udp::socket::reuse_address(true)); + socket_.bind(listen_endpoint); + + // Join the multicast group. + socket_.set_option( + boost::asio::ip::multicast::join_group(multicast_address)); + + socket_.async_receive_from( + boost::asio::buffer(data_, max_length), sender_endpoint_, + boost::bind(&receiver::handle_receive_from, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + + void handle_receive_from(const boost::system::error_code& error, + size_t bytes_recvd) + { + if (!error) + { + std::cout.write(data_, bytes_recvd); + std::cout << std::endl; + + socket_.async_receive_from( + boost::asio::buffer(data_, max_length), sender_endpoint_, + boost::bind(&receiver::handle_receive_from, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + } + +private: + boost::asio::ip::udp::socket socket_; + boost::asio::ip::udp::endpoint sender_endpoint_; + enum { max_length = 1024 }; + char data_[max_length]; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: receiver <listen_address> <multicast_address>\n"; + std::cerr << " For IPv4, try:\n"; + std::cerr << " receiver 0.0.0.0 239.255.0.1\n"; + std::cerr << " For IPv6, try:\n"; + std::cerr << " receiver 0::0 ff31::8000:1234\n"; + return 1; + } + + boost::asio::io_context io_context; + receiver r(io_context, + boost::asio::ip::make_address(argv[1]), + boost::asio::ip::make_address(argv[2])); + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/multicast/sender.cpp b/src/boost/libs/asio/example/cpp03/multicast/sender.cpp new file mode 100644 index 000000000..256eb482f --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/multicast/sender.cpp @@ -0,0 +1,98 @@ +// +// sender.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <sstream> +#include <string> +#include <boost/asio.hpp> +#include "boost/bind/bind.hpp" + +const short multicast_port = 30001; +const int max_message_count = 10; + +class sender +{ +public: + sender(boost::asio::io_context& io_context, + const boost::asio::ip::address& multicast_address) + : endpoint_(multicast_address, multicast_port), + socket_(io_context, endpoint_.protocol()), + timer_(io_context), + message_count_(0) + { + std::ostringstream os; + os << "Message " << message_count_++; + message_ = os.str(); + + socket_.async_send_to( + boost::asio::buffer(message_), endpoint_, + boost::bind(&sender::handle_send_to, this, + boost::asio::placeholders::error)); + } + + void handle_send_to(const boost::system::error_code& error) + { + if (!error && message_count_ < max_message_count) + { + timer_.expires_after(boost::asio::chrono::seconds(1)); + timer_.async_wait( + boost::bind(&sender::handle_timeout, this, + boost::asio::placeholders::error)); + } + } + + void handle_timeout(const boost::system::error_code& error) + { + if (!error) + { + std::ostringstream os; + os << "Message " << message_count_++; + message_ = os.str(); + + socket_.async_send_to( + boost::asio::buffer(message_), endpoint_, + boost::bind(&sender::handle_send_to, this, + boost::asio::placeholders::error)); + } + } + +private: + boost::asio::ip::udp::endpoint endpoint_; + boost::asio::ip::udp::socket socket_; + boost::asio::steady_timer timer_; + int message_count_; + std::string message_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: sender <multicast_address>\n"; + std::cerr << " For IPv4, try:\n"; + std::cerr << " sender 239.255.0.1\n"; + std::cerr << " For IPv6, try:\n"; + std::cerr << " sender ff31::8000:1234\n"; + return 1; + } + + boost::asio::io_context io_context; + sender s(io_context, boost::asio::ip::make_address(argv[1])); + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/nonblocking/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/nonblocking/Jamfile.v2 new file mode 100644 index 000000000..0c4c30bae --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/nonblocking/Jamfile.v2 @@ -0,0 +1,30 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe third_party_lib + : third_party_lib.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp03/nonblocking/third_party_lib.cpp b/src/boost/libs/asio/example/cpp03/nonblocking/third_party_lib.cpp new file mode 100644 index 000000000..86b11c6dd --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/nonblocking/third_party_lib.cpp @@ -0,0 +1,240 @@ +// +// third_party_lib.cpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio.hpp> +#include <boost/array.hpp> +#include <boost/bind/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <iostream> + +using boost::asio::ip::tcp; + +namespace third_party_lib { + +// Simulation of a third party library that wants to perform read and write +// operations directly on a socket. It needs to be polled to determine whether +// it requires a read or write operation, and notified when the socket is ready +// for reading or writing. +class session +{ +public: + session(tcp::socket& socket) + : socket_(socket), + state_(reading) + { + } + + // Returns true if the third party library wants to be notified when the + // socket is ready for reading. + bool want_read() const + { + return state_ == reading; + } + + // Notify that third party library that it should perform its read operation. + void do_read(boost::system::error_code& ec) + { + if (std::size_t len = socket_.read_some(boost::asio::buffer(data_), ec)) + { + write_buffer_ = boost::asio::buffer(data_, len); + state_ = writing; + } + } + + // Returns true if the third party library wants to be notified when the + // socket is ready for writing. + bool want_write() const + { + return state_ == writing; + } + + // Notify that third party library that it should perform its write operation. + void do_write(boost::system::error_code& ec) + { + if (std::size_t len = socket_.write_some( + boost::asio::buffer(write_buffer_), ec)) + { + write_buffer_ = write_buffer_ + len; + state_ = boost::asio::buffer_size(write_buffer_) > 0 ? writing : reading; + } + } + +private: + tcp::socket& socket_; + enum { reading, writing } state_; + boost::array<char, 128> data_; + boost::asio::const_buffer write_buffer_; +}; + +} // namespace third_party_lib + +// The glue between asio's sockets and the third party library. +class connection + : public boost::enable_shared_from_this<connection> +{ +public: + typedef boost::shared_ptr<connection> pointer; + + static pointer create(const boost::asio::executor& ex) + { + return pointer(new connection(ex)); + } + + tcp::socket& socket() + { + return socket_; + } + + void start() + { + // Put the socket into non-blocking mode. + socket_.non_blocking(true); + + start_operations(); + } + +private: + connection(const boost::asio::executor& ex) + : socket_(ex), + session_impl_(socket_), + read_in_progress_(false), + write_in_progress_(false) + { + } + + void start_operations() + { + // Start a read operation if the third party library wants one. + if (session_impl_.want_read() && !read_in_progress_) + { + read_in_progress_ = true; + socket_.async_wait(tcp::socket::wait_read, + boost::bind(&connection::handle_read, + shared_from_this(), + boost::asio::placeholders::error)); + } + + // Start a write operation if the third party library wants one. + if (session_impl_.want_write() && !write_in_progress_) + { + write_in_progress_ = true; + socket_.async_wait(tcp::socket::wait_write, + boost::bind(&connection::handle_write, + shared_from_this(), + boost::asio::placeholders::error)); + } + } + + void handle_read(boost::system::error_code ec) + { + read_in_progress_ = false; + + // Notify third party library that it can perform a read. + if (!ec) + session_impl_.do_read(ec); + + // The third party library successfully performed a read on the socket. + // Start new read or write operations based on what it now wants. + if (!ec || ec == boost::asio::error::would_block) + start_operations(); + + // Otherwise, an error occurred. Closing the socket cancels any outstanding + // asynchronous read or write operations. The connection object will be + // destroyed automatically once those outstanding operations complete. + else + socket_.close(); + } + + void handle_write(boost::system::error_code ec) + { + write_in_progress_ = false; + + // Notify third party library that it can perform a write. + if (!ec) + session_impl_.do_write(ec); + + // The third party library successfully performed a write on the socket. + // Start new read or write operations based on what it now wants. + if (!ec || ec == boost::asio::error::would_block) + start_operations(); + + // Otherwise, an error occurred. Closing the socket cancels any outstanding + // asynchronous read or write operations. The connection object will be + // destroyed automatically once those outstanding operations complete. + else + socket_.close(); + } + +private: + tcp::socket socket_; + third_party_lib::session session_impl_; + bool read_in_progress_; + bool write_in_progress_; +}; + +class server +{ +public: + server(boost::asio::io_context& io_context, unsigned short port) + : acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) + { + start_accept(); + } + +private: + void start_accept() + { + connection::pointer new_connection = + connection::create(acceptor_.get_executor()); + + acceptor_.async_accept(new_connection->socket(), + boost::bind(&server::handle_accept, this, new_connection, + boost::asio::placeholders::error)); + } + + void handle_accept(connection::pointer new_connection, + const boost::system::error_code& error) + { + if (!error) + { + new_connection->start(); + } + + start_accept(); + } + + tcp::acceptor acceptor_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: third_party_lib <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + using namespace std; // For atoi. + server s(io_context, atoi(argv[1])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/porthopper/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/porthopper/Jamfile.v2 new file mode 100644 index 000000000..64d070c28 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/porthopper/Jamfile.v2 @@ -0,0 +1,33 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe client : client.cpp ; +exe server : server.cpp ; diff --git a/src/boost/libs/asio/example/cpp03/porthopper/client.cpp b/src/boost/libs/asio/example/cpp03/porthopper/client.cpp new file mode 100644 index 000000000..fc258515d --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/porthopper/client.cpp @@ -0,0 +1,192 @@ +// +// client.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio.hpp> +#include <boost/lambda/lambda.hpp> +#include <boost/lambda/bind.hpp> +#include <boost/lambda/if.hpp> +#include <boost/shared_ptr.hpp> +#include <algorithm> +#include <cstdlib> +#include <exception> +#include <iostream> +#include <string> +#include "protocol.hpp" + +using namespace boost; +using boost::asio::ip::tcp; +using boost::asio::ip::udp; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: client <host> <port>\n"; + return 1; + } + using namespace std; // For atoi. + std::string host_name = argv[1]; + std::string port = argv[2]; + + boost::asio::io_context io_context; + + // Determine the location of the server. + tcp::resolver resolver(io_context); + tcp::endpoint remote_endpoint = *resolver.resolve(host_name, port).begin(); + + // Establish the control connection to the server. + tcp::socket control_socket(io_context); + control_socket.connect(remote_endpoint); + + // Create a datagram socket to receive data from the server. + boost::shared_ptr<udp::socket> data_socket( + new udp::socket(io_context, udp::endpoint(udp::v4(), 0))); + + // Determine what port we will receive data on. + udp::endpoint data_endpoint = data_socket->local_endpoint(); + + // Ask the server to start sending us data. + control_request start = control_request::start(data_endpoint.port()); + boost::asio::write(control_socket, start.to_buffers()); + + unsigned long last_frame_number = 0; + for (;;) + { + // Receive 50 messages on the current data socket. + for (int i = 0; i < 50; ++i) + { + // Receive a frame from the server. + frame f; + data_socket->receive(f.to_buffers(), 0); + if (f.number() > last_frame_number) + { + last_frame_number = f.number(); + std::cout << "\n" << f.payload(); + } + } + + // Time to switch to a new socket. To ensure seamless handover we will + // continue to receive packets using the old socket until data arrives on + // the new one. + std::cout << " Starting renegotiation"; + + // Create the new data socket. + boost::shared_ptr<udp::socket> new_data_socket( + new udp::socket(io_context, udp::endpoint(udp::v4(), 0))); + + // Determine the new port we will use to receive data. + udp::endpoint new_data_endpoint = new_data_socket->local_endpoint(); + + // Ask the server to switch over to the new port. + control_request change = control_request::change( + data_endpoint.port(), new_data_endpoint.port()); + boost::system::error_code control_result; + boost::asio::async_write(control_socket, change.to_buffers(), + ( + lambda::var(control_result) = lambda::_1 + )); + + // Try to receive a frame from the server on the new data socket. If we + // successfully receive a frame on this new data socket we can consider + // the renegotation complete. In that case we will close the old data + // socket, which will cause any outstanding receive operation on it to be + // cancelled. + frame f1; + boost::system::error_code new_data_socket_result; + new_data_socket->async_receive(f1.to_buffers(), + ( + // Note: lambda::_1 is the first argument to the callback handler, + // which in this case is the error code for the operation. + lambda::var(new_data_socket_result) = lambda::_1, + lambda::if_(!lambda::_1) + [ + // We have successfully received a frame on the new data socket, + // so we can close the old data socket. This will cancel any + // outstanding receive operation on the old data socket. + lambda::var(data_socket) = boost::shared_ptr<udp::socket>() + ] + )); + + // This loop will continue until we have successfully completed the + // renegotiation (i.e. received a frame on the new data socket), or some + // unrecoverable error occurs. + bool done = false; + while (!done) + { + // Even though we're performing a renegotation, we want to continue + // receiving data as smoothly as possible. Therefore we will continue to + // try to receive a frame from the server on the old data socket. If we + // receive a frame on this socket we will interrupt the io_context, + // print the frame, and resume waiting for the other operations to + // complete. + frame f2; + done = true; // Let's be optimistic. + if (data_socket) // Might have been closed by new_data_socket's handler. + { + data_socket->async_receive(f2.to_buffers(), 0, + ( + lambda::if_(!lambda::_1) + [ + // We have successfully received a frame on the old data + // socket. Stop the io_context so that we can print it. + lambda::bind(&boost::asio::io_context::stop, &io_context), + lambda::var(done) = false + ] + )); + } + + // Run the operations in parallel. This will block until all operations + // have finished, or until the io_context is interrupted. (No threads!) + io_context.restart(); + io_context.run(); + + // If the io_context.run() was interrupted then we have received a frame + // on the old data socket. We need to keep waiting for the renegotation + // operations to complete. + if (!done) + { + if (f2.number() > last_frame_number) + { + last_frame_number = f2.number(); + std::cout << "\n" << f2.payload(); + } + } + } + + // Since the loop has finished, we have either successfully completed + // the renegotation, or an error has occurred. First we'll check for + // errors. + if (control_result) + throw boost::system::system_error(control_result); + if (new_data_socket_result) + throw boost::system::system_error(new_data_socket_result); + + // If we get here it means we have successfully started receiving data on + // the new data socket. This new data socket will be used from now on + // (until the next time we renegotiate). + std::cout << " Renegotiation complete"; + data_socket = new_data_socket; + data_endpoint = new_data_endpoint; + if (f1.number() > last_frame_number) + { + last_frame_number = f1.number(); + std::cout << "\n" << f1.payload(); + } + } + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/porthopper/protocol.hpp b/src/boost/libs/asio/example/cpp03/porthopper/protocol.hpp new file mode 100644 index 000000000..38e2ee896 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/porthopper/protocol.hpp @@ -0,0 +1,156 @@ +// +// protocol.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef PORTHOPPER_PROTOCOL_HPP +#define PORTHOPPER_PROTOCOL_HPP + +#include <boost/array.hpp> +#include <boost/asio.hpp> +#include <cstring> +#include <iomanip> +#include <string> +#include <strstream> + +// This request is sent by the client to the server over a TCP connection. +// The client uses it to perform three functions: +// - To request that data start being sent to a given port. +// - To request that data is no longer sent to a given port. +// - To change the target port to another. +class control_request +{ +public: + // Construct an empty request. Used when receiving. + control_request() + { + } + + // Create a request to start sending data to a given port. + static const control_request start(unsigned short port) + { + return control_request(0, port); + } + + // Create a request to stop sending data to a given port. + static const control_request stop(unsigned short port) + { + return control_request(port, 0); + } + + // Create a request to change the port that data is sent to. + static const control_request change( + unsigned short old_port, unsigned short new_port) + { + return control_request(old_port, new_port); + } + + // Get the old port. Returns 0 for start requests. + unsigned short old_port() const + { + std::istrstream is(data_, encoded_port_size); + unsigned short port = 0; + is >> std::setw(encoded_port_size) >> std::hex >> port; + return port; + } + + // Get the new port. Returns 0 for stop requests. + unsigned short new_port() const + { + std::istrstream is(data_ + encoded_port_size, encoded_port_size); + unsigned short port = 0; + is >> std::setw(encoded_port_size) >> std::hex >> port; + return port; + } + + // Obtain buffers for reading from or writing to a socket. + boost::array<boost::asio::mutable_buffer, 1> to_buffers() + { + boost::array<boost::asio::mutable_buffer, 1> buffers + = { { boost::asio::buffer(data_) } }; + return buffers; + } + +private: + // Construct with specified old and new ports. + control_request(unsigned short old_port_number, + unsigned short new_port_number) + { + std::ostrstream os(data_, control_request_size); + os << std::setw(encoded_port_size) << std::hex << old_port_number; + os << std::setw(encoded_port_size) << std::hex << new_port_number; + } + + // The length in bytes of a control_request and its components. + enum + { + encoded_port_size = 4, // 16-bit port in hex. + control_request_size = encoded_port_size * 2 + }; + + // The encoded request data. + char data_[control_request_size]; +}; + +// This frame is sent from the server to subscribed clients over UDP. +class frame +{ +public: + // The maximum allowable length of the payload. + enum { payload_size = 32 }; + + // Construct an empty frame. Used when receiving. + frame() + { + } + + // Construct a frame with specified frame number and payload. + frame(unsigned long frame_number, const std::string& payload_data) + { + std::ostrstream os(data_, frame_size); + os << std::setw(encoded_number_size) << std::hex << frame_number; + os << std::setw(payload_size) + << std::setfill(' ') << payload_data.substr(0, payload_size); + } + + // Get the frame number. + unsigned long number() const + { + std::istrstream is(data_, encoded_number_size); + unsigned long frame_number = 0; + is >> std::setw(encoded_number_size) >> std::hex >> frame_number; + return frame_number; + } + + // Get the payload data. + const std::string payload() const + { + return std::string(data_ + encoded_number_size, payload_size); + } + + // Obtain buffers for reading from or writing to a socket. + boost::array<boost::asio::mutable_buffer, 1> to_buffers() + { + boost::array<boost::asio::mutable_buffer, 1> buffers + = { { boost::asio::buffer(data_) } }; + return buffers; + } + +private: + // The length in bytes of a frame and its components. + enum + { + encoded_number_size = 8, // Frame number in hex. + frame_size = encoded_number_size + payload_size + }; + + // The encoded frame data. + char data_[frame_size]; +}; + +#endif // PORTHOPPER_PROTOCOL_HPP diff --git a/src/boost/libs/asio/example/cpp03/porthopper/server.cpp b/src/boost/libs/asio/example/cpp03/porthopper/server.cpp new file mode 100644 index 000000000..191f62088 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/porthopper/server.cpp @@ -0,0 +1,187 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio.hpp> +#include <boost/bind/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <cmath> +#include <cstdlib> +#include <exception> +#include <iostream> +#include <set> +#include "protocol.hpp" + +using boost::asio::ip::tcp; +using boost::asio::ip::udp; + +typedef boost::shared_ptr<tcp::socket> tcp_socket_ptr; +typedef boost::shared_ptr<boost::asio::steady_timer> timer_ptr; +typedef boost::shared_ptr<control_request> control_request_ptr; + +class server +{ +public: + // Construct the server to wait for incoming control connections. + server(boost::asio::io_context& io_context, unsigned short port) + : acceptor_(io_context, tcp::endpoint(tcp::v4(), port)), + timer_(io_context), + udp_socket_(io_context, udp::endpoint(udp::v4(), 0)), + next_frame_number_(1) + { + // Start waiting for a new control connection. + tcp_socket_ptr new_socket(new tcp::socket(acceptor_.get_executor())); + acceptor_.async_accept(*new_socket, + boost::bind(&server::handle_accept, this, + boost::asio::placeholders::error, new_socket)); + + // Start the timer used to generate outgoing frames. + timer_.expires_after(boost::asio::chrono::milliseconds(100)); + timer_.async_wait(boost::bind(&server::handle_timer, this)); + } + + // Handle a new control connection. + void handle_accept(const boost::system::error_code& ec, tcp_socket_ptr socket) + { + if (!ec) + { + // Start receiving control requests on the connection. + control_request_ptr request(new control_request); + boost::asio::async_read(*socket, request->to_buffers(), + boost::bind(&server::handle_control_request, this, + boost::asio::placeholders::error, socket, request)); + } + + // Start waiting for a new control connection. + tcp_socket_ptr new_socket(new tcp::socket(acceptor_.get_executor())); + acceptor_.async_accept(*new_socket, + boost::bind(&server::handle_accept, this, + boost::asio::placeholders::error, new_socket)); + } + + // Handle a new control request. + void handle_control_request(const boost::system::error_code& ec, + tcp_socket_ptr socket, control_request_ptr request) + { + if (!ec) + { + // Delay handling of the control request to simulate network latency. + timer_ptr delay_timer( + new boost::asio::steady_timer(acceptor_.get_executor())); + delay_timer->expires_after(boost::asio::chrono::seconds(2)); + delay_timer->async_wait( + boost::bind(&server::handle_control_request_timer, this, + socket, request, delay_timer)); + } + } + + void handle_control_request_timer(tcp_socket_ptr socket, + control_request_ptr request, timer_ptr /*delay_timer*/) + { + // Determine what address this client is connected from, since + // subscriptions must be stored on the server as a complete endpoint, not + // just a port. We use the non-throwing overload of remote_endpoint() since + // it may fail if the socket is no longer connected. + boost::system::error_code ec; + tcp::endpoint remote_endpoint = socket->remote_endpoint(ec); + if (!ec) + { + // Remove old port subscription, if any. + if (unsigned short old_port = request->old_port()) + { + udp::endpoint old_endpoint(remote_endpoint.address(), old_port); + subscribers_.erase(old_endpoint); + std::cout << "Removing subscription " << old_endpoint << std::endl; + } + + // Add new port subscription, if any. + if (unsigned short new_port = request->new_port()) + { + udp::endpoint new_endpoint(remote_endpoint.address(), new_port); + subscribers_.insert(new_endpoint); + std::cout << "Adding subscription " << new_endpoint << std::endl; + } + } + + // Wait for next control request on this connection. + boost::asio::async_read(*socket, request->to_buffers(), + boost::bind(&server::handle_control_request, this, + boost::asio::placeholders::error, socket, request)); + } + + // Every time the timer fires we will generate a new frame and send it to all + // subscribers. + void handle_timer() + { + // Generate payload. + double x = next_frame_number_ * 0.2; + double y = std::sin(x); + int char_index = static_cast<int>((y + 1.0) * (frame::payload_size / 2)); + std::string payload; + for (int i = 0; i < frame::payload_size; ++i) + payload += (i == char_index ? '*' : '.'); + + // Create the frame to be sent to all subscribers. + frame f(next_frame_number_++, payload); + + // Send frame to all subscribers. We can use synchronous calls here since + // UDP send operations typically do not block. + std::set<udp::endpoint>::iterator j; + for (j = subscribers_.begin(); j != subscribers_.end(); ++j) + { + boost::system::error_code ec; + udp_socket_.send_to(f.to_buffers(), *j, 0, ec); + } + + // Wait for next timeout. + timer_.expires_after(boost::asio::chrono::milliseconds(100)); + timer_.async_wait(boost::bind(&server::handle_timer, this)); + } + +private: + // The acceptor used to accept incoming control connections. + tcp::acceptor acceptor_; + + // The timer used for generating data. + boost::asio::steady_timer timer_; + + // The socket used to send data to subscribers. + udp::socket udp_socket_; + + // The next frame number. + unsigned long next_frame_number_; + + // The set of endpoints that are subscribed. + std::set<udp::endpoint> subscribers_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: server <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + using namespace std; // For atoi. + server s(io_context, atoi(argv[1])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/serialization/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/serialization/Jamfile.v2 new file mode 100644 index 000000000..c0231b8b7 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/serialization/Jamfile.v2 @@ -0,0 +1,34 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/serialization//boost_serialization + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe client : client.cpp ; +exe server : server.cpp ; diff --git a/src/boost/libs/asio/example/cpp03/serialization/client.cpp b/src/boost/libs/asio/example/cpp03/serialization/client.cpp new file mode 100644 index 000000000..f4b9b8efd --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/serialization/client.cpp @@ -0,0 +1,125 @@ +// +// client.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio.hpp> +#include <boost/bind/bind.hpp> +#include <iostream> +#include <vector> +#include "connection.hpp" // Must come before boost/serialization headers. +#include <boost/serialization/vector.hpp> +#include "stock.hpp" + +namespace s11n_example { + +/// Downloads stock quote information from a server. +class client +{ +public: + /// Constructor starts the asynchronous connect operation. + client(boost::asio::io_context& io_context, + const std::string& host, const std::string& service) + : connection_(io_context.get_executor()) + { + // Resolve the host name into an IP address. + boost::asio::ip::tcp::resolver resolver(io_context); + boost::asio::ip::tcp::resolver::query query(host, service); + boost::asio::ip::tcp::resolver::iterator endpoint_iterator = + resolver.resolve(query); + + // Start an asynchronous connect operation. + boost::asio::async_connect(connection_.socket(), endpoint_iterator, + boost::bind(&client::handle_connect, this, + boost::asio::placeholders::error)); + } + + /// Handle completion of a connect operation. + void handle_connect(const boost::system::error_code& e) + { + if (!e) + { + // Successfully established connection. Start operation to read the list + // of stocks. The connection::async_read() function will automatically + // decode the data that is read from the underlying socket. + connection_.async_read(stocks_, + boost::bind(&client::handle_read, this, + boost::asio::placeholders::error)); + } + else + { + // An error occurred. Log it and return. Since we are not starting a new + // operation the io_context will run out of work to do and the client will + // exit. + std::cerr << e.message() << std::endl; + } + } + + /// Handle completion of a read operation. + void handle_read(const boost::system::error_code& e) + { + if (!e) + { + // Print out the data that was received. + for (std::size_t i = 0; i < stocks_.size(); ++i) + { + std::cout << "Stock number " << i << "\n"; + std::cout << " code: " << stocks_[i].code << "\n"; + std::cout << " name: " << stocks_[i].name << "\n"; + std::cout << " open_price: " << stocks_[i].open_price << "\n"; + std::cout << " high_price: " << stocks_[i].high_price << "\n"; + std::cout << " low_price: " << stocks_[i].low_price << "\n"; + std::cout << " last_price: " << stocks_[i].last_price << "\n"; + std::cout << " buy_price: " << stocks_[i].buy_price << "\n"; + std::cout << " buy_quantity: " << stocks_[i].buy_quantity << "\n"; + std::cout << " sell_price: " << stocks_[i].sell_price << "\n"; + std::cout << " sell_quantity: " << stocks_[i].sell_quantity << "\n"; + } + } + else + { + // An error occurred. + std::cerr << e.message() << std::endl; + } + + // Since we are not starting a new operation the io_context will run out of + // work to do and the client will exit. + } + +private: + /// The connection to the server. + connection connection_; + + /// The data received from the server. + std::vector<stock> stocks_; +}; + +} // namespace s11n_example + +int main(int argc, char* argv[]) +{ + try + { + // Check command line arguments. + if (argc != 3) + { + std::cerr << "Usage: client <host> <port>" << std::endl; + return 1; + } + + boost::asio::io_context io_context; + s11n_example::client client(io_context, argv[1], argv[2]); + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/serialization/connection.hpp b/src/boost/libs/asio/example/cpp03/serialization/connection.hpp new file mode 100644 index 000000000..e6801614d --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/serialization/connection.hpp @@ -0,0 +1,188 @@ +// +// connection.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef SERIALIZATION_CONNECTION_HPP +#define SERIALIZATION_CONNECTION_HPP + +#include <boost/asio.hpp> +#include <boost/archive/text_iarchive.hpp> +#include <boost/archive/text_oarchive.hpp> +#include <boost/bind/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/tuple/tuple.hpp> +#include <iomanip> +#include <string> +#include <sstream> +#include <vector> + +namespace s11n_example { + +/// The connection class provides serialization primitives on top of a socket. +/** + * Each message sent using this class consists of: + * @li An 8-byte header containing the length of the serialized data in + * hexadecimal. + * @li The serialized data. + */ +class connection +{ +public: + /// Constructor. + connection(const boost::asio::executor& ex) + : socket_(ex) + { + } + + /// Get the underlying socket. Used for making a connection or for accepting + /// an incoming connection. + boost::asio::ip::tcp::socket& socket() + { + return socket_; + } + + /// Asynchronously write a data structure to the socket. + template <typename T, typename Handler> + void async_write(const T& t, Handler handler) + { + // Serialize the data first so we know how large it is. + std::ostringstream archive_stream; + boost::archive::text_oarchive archive(archive_stream); + archive << t; + outbound_data_ = archive_stream.str(); + + // Format the header. + std::ostringstream header_stream; + header_stream << std::setw(header_length) + << std::hex << outbound_data_.size(); + if (!header_stream || header_stream.str().size() != header_length) + { + // Something went wrong, inform the caller. + boost::system::error_code error(boost::asio::error::invalid_argument); + boost::asio::post(socket_.get_executor(), boost::bind(handler, error)); + return; + } + outbound_header_ = header_stream.str(); + + // Write the serialized data to the socket. We use "gather-write" to send + // both the header and the data in a single write operation. + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(boost::asio::buffer(outbound_header_)); + buffers.push_back(boost::asio::buffer(outbound_data_)); + boost::asio::async_write(socket_, buffers, handler); + } + + /// Asynchronously read a data structure from the socket. + template <typename T, typename Handler> + void async_read(T& t, Handler handler) + { + // Issue a read operation to read exactly the number of bytes in a header. + void (connection::*f)( + const boost::system::error_code&, + T&, boost::tuple<Handler>) + = &connection::handle_read_header<T, Handler>; + boost::asio::async_read(socket_, boost::asio::buffer(inbound_header_), + boost::bind(f, + this, boost::asio::placeholders::error, boost::ref(t), + boost::make_tuple(handler))); + } + + /// Handle a completed read of a message header. The handler is passed using + /// a tuple since boost::bind seems to have trouble binding a function object + /// created using boost::bind as a parameter. + template <typename T, typename Handler> + void handle_read_header(const boost::system::error_code& e, + T& t, boost::tuple<Handler> handler) + { + if (e) + { + boost::get<0>(handler)(e); + } + else + { + // Determine the length of the serialized data. + std::istringstream is(std::string(inbound_header_, header_length)); + std::size_t inbound_data_size = 0; + if (!(is >> std::hex >> inbound_data_size)) + { + // Header doesn't seem to be valid. Inform the caller. + boost::system::error_code error(boost::asio::error::invalid_argument); + boost::get<0>(handler)(error); + return; + } + + // Start an asynchronous call to receive the data. + inbound_data_.resize(inbound_data_size); + void (connection::*f)( + const boost::system::error_code&, + T&, boost::tuple<Handler>) + = &connection::handle_read_data<T, Handler>; + boost::asio::async_read(socket_, boost::asio::buffer(inbound_data_), + boost::bind(f, this, + boost::asio::placeholders::error, boost::ref(t), handler)); + } + } + + /// Handle a completed read of message data. + template <typename T, typename Handler> + void handle_read_data(const boost::system::error_code& e, + T& t, boost::tuple<Handler> handler) + { + if (e) + { + boost::get<0>(handler)(e); + } + else + { + // Extract the data structure from the data just received. + try + { + std::string archive_data(&inbound_data_[0], inbound_data_.size()); + std::istringstream archive_stream(archive_data); + boost::archive::text_iarchive archive(archive_stream); + archive >> t; + } + catch (std::exception& e) + { + // Unable to decode data. + boost::system::error_code error(boost::asio::error::invalid_argument); + boost::get<0>(handler)(error); + return; + } + + // Inform caller that data has been received ok. + boost::get<0>(handler)(e); + } + } + +private: + /// The underlying socket. + boost::asio::ip::tcp::socket socket_; + + /// The size of a fixed length header. + enum { header_length = 8 }; + + /// Holds an outbound header. + std::string outbound_header_; + + /// Holds the outbound data. + std::string outbound_data_; + + /// Holds an inbound header. + char inbound_header_[header_length]; + + /// Holds the inbound data. + std::vector<char> inbound_data_; +}; + +typedef boost::shared_ptr<connection> connection_ptr; + +} // namespace s11n_example + +#endif // SERIALIZATION_CONNECTION_HPP diff --git a/src/boost/libs/asio/example/cpp03/serialization/server.cpp b/src/boost/libs/asio/example/cpp03/serialization/server.cpp new file mode 100644 index 000000000..4e527cf27 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/serialization/server.cpp @@ -0,0 +1,123 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio.hpp> +#include <boost/bind/bind.hpp> +#include <boost/lexical_cast.hpp> +#include <iostream> +#include <vector> +#include "connection.hpp" // Must come before boost/serialization headers. +#include <boost/serialization/vector.hpp> +#include "stock.hpp" + +namespace s11n_example { + +/// Serves stock quote information to any client that connects to it. +class server +{ +public: + /// Constructor opens the acceptor and starts waiting for the first incoming + /// connection. + server(boost::asio::io_context& io_context, unsigned short port) + : acceptor_(io_context, + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)) + { + // Create the data to be sent to each client. + stock s; + s.code = "ABC"; + s.name = "A Big Company"; + s.open_price = 4.56; + s.high_price = 5.12; + s.low_price = 4.33; + s.last_price = 4.98; + s.buy_price = 4.96; + s.buy_quantity = 1000; + s.sell_price = 4.99; + s.sell_quantity = 2000; + stocks_.push_back(s); + s.code = "DEF"; + s.name = "Developer Entertainment Firm"; + s.open_price = 20.24; + s.high_price = 22.88; + s.low_price = 19.50; + s.last_price = 19.76; + s.buy_price = 19.72; + s.buy_quantity = 34000; + s.sell_price = 19.85; + s.sell_quantity = 45000; + stocks_.push_back(s); + + // Start an accept operation for a new connection. + connection_ptr new_conn(new connection(acceptor_.get_executor())); + acceptor_.async_accept(new_conn->socket(), + boost::bind(&server::handle_accept, this, + boost::asio::placeholders::error, new_conn)); + } + + /// Handle completion of a accept operation. + void handle_accept(const boost::system::error_code& e, connection_ptr conn) + { + if (!e) + { + // Successfully accepted a new connection. Send the list of stocks to the + // client. The connection::async_write() function will automatically + // serialize the data structure for us. + conn->async_write(stocks_, + boost::bind(&server::handle_write, this, + boost::asio::placeholders::error, conn)); + } + + // Start an accept operation for a new connection. + connection_ptr new_conn(new connection(acceptor_.get_executor())); + acceptor_.async_accept(new_conn->socket(), + boost::bind(&server::handle_accept, this, + boost::asio::placeholders::error, new_conn)); + } + + /// Handle completion of a write operation. + void handle_write(const boost::system::error_code& e, connection_ptr conn) + { + // Nothing to do. The socket will be closed automatically when the last + // reference to the connection object goes away. + } + +private: + /// The acceptor object used to accept incoming socket connections. + boost::asio::ip::tcp::acceptor acceptor_; + + /// The data to be sent to each client. + std::vector<stock> stocks_; +}; + +} // namespace s11n_example + +int main(int argc, char* argv[]) +{ + try + { + // Check command line arguments. + if (argc != 2) + { + std::cerr << "Usage: server <port>" << std::endl; + return 1; + } + unsigned short port = boost::lexical_cast<unsigned short>(argv[1]); + + boost::asio::io_context io_context; + s11n_example::server server(io_context, port); + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/serialization/stock.hpp b/src/boost/libs/asio/example/cpp03/serialization/stock.hpp new file mode 100644 index 000000000..ca5a1c957 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/serialization/stock.hpp @@ -0,0 +1,50 @@ +// +// stock.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef SERIALIZATION_STOCK_HPP +#define SERIALIZATION_STOCK_HPP + +#include <string> + +namespace s11n_example { + +/// Structure to hold information about a single stock. +struct stock +{ + std::string code; + std::string name; + double open_price; + double high_price; + double low_price; + double last_price; + double buy_price; + int buy_quantity; + double sell_price; + int sell_quantity; + + template <typename Archive> + void serialize(Archive& ar, const unsigned int version) + { + ar & code; + ar & name; + ar & open_price; + ar & high_price; + ar & low_price; + ar & last_price; + ar & buy_price; + ar & buy_quantity; + ar & sell_price; + ar & sell_quantity; + } +}; + +} // namespace s11n_example + +#endif // SERIALIZATION_STOCK_HPP diff --git a/src/boost/libs/asio/example/cpp03/services/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/services/Jamfile.v2 new file mode 100644 index 000000000..3a2634d74 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/services/Jamfile.v2 @@ -0,0 +1,32 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe daytime_client + : daytime_client.cpp + logger_service.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + /boost/thread//boost_thread + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp03/services/basic_logger.hpp b/src/boost/libs/asio/example/cpp03/services/basic_logger.hpp new file mode 100644 index 000000000..d7cc42579 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/services/basic_logger.hpp @@ -0,0 +1,83 @@ +// +// basic_logger.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef SERVICES_BASIC_LOGGER_HPP +#define SERVICES_BASIC_LOGGER_HPP + +#include <boost/asio.hpp> +#include <boost/noncopyable.hpp> +#include <string> + +namespace services { + +/// Class to provide simple logging functionality. Use the services::logger +/// typedef. +template <typename Service> +class basic_logger + : private boost::noncopyable +{ +public: + /// The type of the service that will be used to provide timer operations. + typedef Service service_type; + + /// The native implementation type of the timer. + typedef typename service_type::impl_type impl_type; + + /// Constructor. + /** + * This constructor creates a logger. + * + * @param context The execution context used to locate the logger service. + * + * @param identifier An identifier for this logger. + */ + explicit basic_logger(boost::asio::execution_context& context, + const std::string& identifier) + : service_(boost::asio::use_service<Service>(context)), + impl_(service_.null()) + { + service_.create(impl_, identifier); + } + + /// Destructor. + ~basic_logger() + { + service_.destroy(impl_); + } + + /// Get the io_context associated with the object. + boost::asio::io_context& get_io_context() + { + return service_.get_io_context(); + } + + /// Set the output file for all logger instances. + void use_file(const std::string& file) + { + service_.use_file(impl_, file); + } + + /// Log a message. + void log(const std::string& message) + { + service_.log(impl_, message); + } + +private: + /// The backend service implementation. + service_type& service_; + + /// The underlying native implementation. + impl_type impl_; +}; + +} // namespace services + +#endif // SERVICES_BASIC_LOGGER_HPP diff --git a/src/boost/libs/asio/example/cpp03/services/daytime_client.cpp b/src/boost/libs/asio/example/cpp03/services/daytime_client.cpp new file mode 100644 index 000000000..59a0a6269 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/services/daytime_client.cpp @@ -0,0 +1,97 @@ +// +// daytime_client.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio.hpp> +#include <boost/bind/bind.hpp> +#include <iostream> +#include "logger.hpp" + +using boost::asio::ip::tcp; + +char read_buffer[1024]; + +void read_handler(const boost::system::error_code& e, + std::size_t bytes_transferred, tcp::socket* s) +{ + if (!e) + { + std::cout.write(read_buffer, bytes_transferred); + + s->async_read_some(boost::asio::buffer(read_buffer), + boost::bind(read_handler, boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, s)); + } + else + { + services::logger logger(s->get_executor().context(), "read_handler"); + + std::string msg = "Read error: "; + msg += e.message(); + logger.log(msg); + } +} + +void connect_handler(const boost::system::error_code& e, tcp::socket* s) +{ + services::logger logger(s->get_executor().context(), "connect_handler"); + + if (!e) + { + logger.log("Connection established"); + + s->async_read_some(boost::asio::buffer(read_buffer), + boost::bind(read_handler, boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred, s)); + } + else + { + std::string msg = "Unable to establish connection: "; + msg += e.message(); + logger.log(msg); + } +} + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: daytime_client <host>" << std::endl; + return 1; + } + + boost::asio::io_context io_context; + + // Set the name of the file that all logger instances will use. + services::logger logger(io_context, ""); + logger.use_file("log.txt"); + + // Resolve the address corresponding to the given host. + tcp::resolver resolver(io_context); + tcp::resolver::results_type endpoints = + resolver.resolve(argv[1], "daytime"); + + // Start an asynchronous connect. + tcp::socket socket(io_context); + boost::asio::async_connect(socket, endpoints, + boost::bind(connect_handler, + boost::asio::placeholders::error, &socket)); + + // Run the io_context until all operations have finished. + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/services/logger.hpp b/src/boost/libs/asio/example/cpp03/services/logger.hpp new file mode 100644 index 000000000..4eb00268a --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/services/logger.hpp @@ -0,0 +1,24 @@ +// +// logger.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef SERVICES_LOGGER_HPP +#define SERVICES_LOGGER_HPP + +#include "basic_logger.hpp" +#include "logger_service.hpp" + +namespace services { + +/// Typedef for typical logger usage. +typedef basic_logger<logger_service> logger; + +} // namespace services + +#endif // SERVICES_LOGGER_HPP diff --git a/src/boost/libs/asio/example/cpp03/services/logger_service.cpp b/src/boost/libs/asio/example/cpp03/services/logger_service.cpp new file mode 100644 index 000000000..c1c9ac4e5 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/services/logger_service.cpp @@ -0,0 +1,11 @@ +// +// logger_service.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "logger_service.hpp" diff --git a/src/boost/libs/asio/example/cpp03/services/logger_service.hpp b/src/boost/libs/asio/example/cpp03/services/logger_service.hpp new file mode 100644 index 000000000..4f439c5e1 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/services/logger_service.hpp @@ -0,0 +1,146 @@ +// +// logger_service.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef SERVICES_LOGGER_SERVICE_HPP +#define SERVICES_LOGGER_SERVICE_HPP + +#include <boost/asio.hpp> +#include <boost/thread/thread.hpp> +#include <boost/bind/bind.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/noncopyable.hpp> +#include <boost/scoped_ptr.hpp> +#include <fstream> +#include <sstream> +#include <string> + +namespace services { + +/// Service implementation for the logger. +class logger_service + : public boost::asio::execution_context::service +{ +public: + /// The type used to identify this service in the execution context. + typedef logger_service key_type; + + /// The backend implementation of a logger. + struct logger_impl + { + explicit logger_impl(const std::string& ident) : identifier(ident) {} + std::string identifier; + }; + + /// The type for an implementation of the logger. + typedef logger_impl* impl_type; + + /// Constructor creates a thread to run a private io_context. + logger_service(boost::asio::execution_context& context) + : boost::asio::execution_context::service(context), + work_io_context_(), + work_(boost::asio::make_work_guard(work_io_context_)), + work_thread_(new boost::thread( + boost::bind(&boost::asio::io_context::run, &work_io_context_))) + { + } + + /// Destructor shuts down the private io_context. + ~logger_service() + { + /// Indicate that we have finished with the private io_context. Its + /// io_context::run() function will exit once all other work has completed. + work_.reset(); + if (work_thread_) + work_thread_->join(); + } + + /// Destroy all user-defined handler objects owned by the service. + void shutdown() + { + } + + /// Return a null logger implementation. + impl_type null() const + { + return 0; + } + + /// Create a new logger implementation. + void create(impl_type& impl, const std::string& identifier) + { + impl = new logger_impl(identifier); + } + + /// Destroy a logger implementation. + void destroy(impl_type& impl) + { + delete impl; + impl = null(); + } + + /// Set the output file for the logger. The current implementation sets the + /// output file for all logger instances, and so the impl parameter is not + /// actually needed. It is retained here to illustrate how service functions + /// are typically defined. + void use_file(impl_type& /*impl*/, const std::string& file) + { + // Pass the work of opening the file to the background thread. + boost::asio::post(work_io_context_, boost::bind( + &logger_service::use_file_impl, this, file)); + } + + /// Log a message. + void log(impl_type& impl, const std::string& message) + { + // Format the text to be logged. + std::ostringstream os; + os << impl->identifier << ": " << message; + + // Pass the work of writing to the file to the background thread. + boost::asio::post(work_io_context_, boost::bind( + &logger_service::log_impl, this, os.str())); + } + +private: + /// Helper function used to open the output file from within the private + /// io_context's thread. + void use_file_impl(const std::string& file) + { + ofstream_.close(); + ofstream_.clear(); + ofstream_.open(file.c_str()); + } + + /// Helper function used to log a message from within the private io_context's + /// thread. + void log_impl(const std::string& text) + { + ofstream_ << text << std::endl; + } + + /// Private io_context used for performing logging operations. + boost::asio::io_context work_io_context_; + + /// Work for the private io_context to perform. If we do not give the + /// io_context some work to do then the io_context::run() function will exit + /// immediately. + boost::asio::executor_work_guard< + boost::asio::io_context::executor_type> work_; + + /// Thread used for running the work io_context's run loop. + boost::scoped_ptr<boost::thread> work_thread_; + + /// The file to which log messages will be written. + std::ofstream ofstream_; +}; + +} // namespace services + +#endif // SERVICES_LOGGER_SERVICE_HPP diff --git a/src/boost/libs/asio/example/cpp03/socks4/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/socks4/Jamfile.v2 new file mode 100644 index 000000000..aa1492bad --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/socks4/Jamfile.v2 @@ -0,0 +1,30 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe server + : sync_client.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp03/socks4/socks4.hpp b/src/boost/libs/asio/example/cpp03/socks4/socks4.hpp new file mode 100644 index 000000000..ad72b120f --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/socks4/socks4.hpp @@ -0,0 +1,144 @@ +// +// socks4.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef SOCKS4_HPP +#define SOCKS4_HPP + +#include <string> +#include <boost/asio.hpp> +#include <boost/array.hpp> + +namespace socks4 { + +const unsigned char version = 0x04; + +class request +{ +public: + enum command_type + { + connect = 0x01, + bind = 0x02 + }; + + request(command_type cmd, const boost::asio::ip::tcp::endpoint& endpoint, + const std::string& user_id) + : version_(version), + command_(cmd), + user_id_(user_id), + null_byte_(0) + { + // Only IPv4 is supported by the SOCKS 4 protocol. + if (endpoint.protocol() != boost::asio::ip::tcp::v4()) + { + throw boost::system::system_error( + boost::asio::error::address_family_not_supported); + } + + // Convert port number to network byte order. + unsigned short port = endpoint.port(); + port_high_byte_ = (port >> 8) & 0xff; + port_low_byte_ = port & 0xff; + + // Save IP address in network byte order. + address_ = endpoint.address().to_v4().to_bytes(); + } + + boost::array<boost::asio::const_buffer, 7> buffers() const + { + boost::array<boost::asio::const_buffer, 7> bufs = + { + { + boost::asio::buffer(&version_, 1), + boost::asio::buffer(&command_, 1), + boost::asio::buffer(&port_high_byte_, 1), + boost::asio::buffer(&port_low_byte_, 1), + boost::asio::buffer(address_), + boost::asio::buffer(user_id_), + boost::asio::buffer(&null_byte_, 1) + } + }; + return bufs; + } + +private: + unsigned char version_; + unsigned char command_; + unsigned char port_high_byte_; + unsigned char port_low_byte_; + boost::asio::ip::address_v4::bytes_type address_; + std::string user_id_; + unsigned char null_byte_; +}; + +class reply +{ +public: + enum status_type + { + request_granted = 0x5a, + request_failed = 0x5b, + request_failed_no_identd = 0x5c, + request_failed_bad_user_id = 0x5d + }; + + reply() + : null_byte_(0), + status_() + { + } + + boost::array<boost::asio::mutable_buffer, 5> buffers() + { + boost::array<boost::asio::mutable_buffer, 5> bufs = + { + { + boost::asio::buffer(&null_byte_, 1), + boost::asio::buffer(&status_, 1), + boost::asio::buffer(&port_high_byte_, 1), + boost::asio::buffer(&port_low_byte_, 1), + boost::asio::buffer(address_) + } + }; + return bufs; + } + + bool success() const + { + return null_byte_ == 0 && status_ == request_granted; + } + + unsigned char status() const + { + return status_; + } + + boost::asio::ip::tcp::endpoint endpoint() const + { + unsigned short port = port_high_byte_; + port = (port << 8) & 0xff00; + port = port | port_low_byte_; + + boost::asio::ip::address_v4 address(address_); + + return boost::asio::ip::tcp::endpoint(address, port); + } + +private: + unsigned char null_byte_; + unsigned char status_; + unsigned char port_high_byte_; + unsigned char port_low_byte_; + boost::asio::ip::address_v4::bytes_type address_; +}; + +} // namespace socks4 + +#endif // SOCKS4_HPP diff --git a/src/boost/libs/asio/example/cpp03/socks4/sync_client.cpp b/src/boost/libs/asio/example/cpp03/socks4/sync_client.cpp new file mode 100644 index 000000000..a2edd89cd --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/socks4/sync_client.cpp @@ -0,0 +1,94 @@ +// +// sync_client.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <iomanip> +#include <ostream> +#include <string> +#include <boost/asio.hpp> +#include <boost/array.hpp> +#include "socks4.hpp" + +using boost::asio::ip::tcp; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 4) + { + std::cout << "Usage: sync_client <socks4server> <socks4port> <user>\n"; + std::cout << "Examples:\n"; + std::cout << " sync_client 127.0.0.1 1080 chris\n"; + std::cout << " sync_client localhost socks chris\n"; + return 1; + } + + boost::asio::io_context io_context; + + // Get a list of endpoints corresponding to the SOCKS 4 server name. + tcp::resolver resolver(io_context); + tcp::resolver::results_type endpoints = resolver.resolve(argv[1], argv[2]); + + // Try each endpoint until we successfully establish a connection to the + // SOCKS 4 server. + tcp::socket socket(io_context); + boost::asio::connect(socket, endpoints); + + // Get an endpoint for the Boost website. This will be passed to the SOCKS + // 4 server. Explicitly specify IPv4 since SOCKS 4 does not support IPv6. + tcp::endpoint http_endpoint = + *resolver.resolve(tcp::v4(), "www.boost.org", "http").begin(); + + // Send the request to the SOCKS 4 server. + socks4::request socks_request( + socks4::request::connect, http_endpoint, argv[3]); + boost::asio::write(socket, socks_request.buffers()); + + // Receive a response from the SOCKS 4 server. + socks4::reply socks_reply; + boost::asio::read(socket, socks_reply.buffers()); + + // Check whether we successfully negotiated with the SOCKS 4 server. + if (!socks_reply.success()) + { + std::cout << "Connection failed.\n"; + std::cout << "status = 0x" << std::hex << socks_reply.status(); + return 1; + } + + // Form the HTTP request. We specify the "Connection: close" header so that + // the server will close the socket after transmitting the response. This + // will allow us to treat all data up until the EOF as the response. + std::string request = + "GET / HTTP/1.0\r\n" + "Host: www.boost.org\r\n" + "Accept: */*\r\n" + "Connection: close\r\n\r\n"; + + // Send the HTTP request. + boost::asio::write(socket, boost::asio::buffer(request)); + + // Read until EOF, writing data to output as we go. + boost::array<char, 512> response; + boost::system::error_code error; + while (std::size_t s = socket.read_some( + boost::asio::buffer(response), error)) + std::cout.write(response.data(), s); + if (error != boost::asio::error::eof) + throw boost::system::system_error(error); + } + catch (std::exception& e) + { + std::cout << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/spawn/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/spawn/Jamfile.v2 new file mode 100644 index 000000000..7e4b320ef --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/spawn/Jamfile.v2 @@ -0,0 +1,50 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe server + : echo_server.cpp + /boost/context//boost_context + /boost/coroutine//boost_coroutine + /boost/system//boost_system + /boost/chrono//boost_chrono + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe parallel_grep + : parallel_grep.cpp + /boost/context//boost_context + /boost/coroutine//boost_coroutine + /boost/system//boost_system + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp03/spawn/echo_server.cpp b/src/boost/libs/asio/example/cpp03/spawn/echo_server.cpp new file mode 100644 index 000000000..9efe62b92 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/spawn/echo_server.cpp @@ -0,0 +1,122 @@ +// +// echo_server.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/spawn.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/asio/write.hpp> +#include <boost/bind/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <iostream> + +using boost::asio::ip::tcp; + +class session : public boost::enable_shared_from_this<session> +{ +public: + explicit session(boost::asio::io_context& io_context) + : strand_(boost::asio::make_strand(io_context)), + socket_(io_context), + timer_(io_context) + { + } + + tcp::socket& socket() + { + return socket_; + } + + void go() + { + boost::asio::spawn(strand_, + boost::bind(&session::echo, + shared_from_this(), boost::placeholders::_1)); + boost::asio::spawn(strand_, + boost::bind(&session::timeout, + shared_from_this(), boost::placeholders::_1)); + } + +private: + void echo(boost::asio::yield_context yield) + { + try + { + char data[128]; + for (;;) + { + timer_.expires_after(boost::asio::chrono::seconds(10)); + std::size_t n = socket_.async_read_some(boost::asio::buffer(data), yield); + boost::asio::async_write(socket_, boost::asio::buffer(data, n), yield); + } + } + catch (std::exception& e) + { + socket_.close(); + timer_.cancel(); + } + } + + void timeout(boost::asio::yield_context yield) + { + while (socket_.is_open()) + { + boost::system::error_code ignored_ec; + timer_.async_wait(yield[ignored_ec]); + if (timer_.expiry() <= boost::asio::steady_timer::clock_type::now()) + socket_.close(); + } + } + + boost::asio::strand<boost::asio::io_context::executor_type> strand_; + tcp::socket socket_; + boost::asio::steady_timer timer_; +}; + +void do_accept(boost::asio::io_context& io_context, + unsigned short port, boost::asio::yield_context yield) +{ + tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), port)); + + for (;;) + { + boost::system::error_code ec; + boost::shared_ptr<session> new_session(new session(io_context)); + acceptor.async_accept(new_session->socket(), yield[ec]); + if (!ec) new_session->go(); + } +} + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: echo_server <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + boost::asio::spawn(io_context, + boost::bind(do_accept, + boost::ref(io_context), atoi(argv[1]), boost::placeholders::_1)); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/spawn/parallel_grep.cpp b/src/boost/libs/asio/example/cpp03/spawn/parallel_grep.cpp new file mode 100644 index 000000000..832b09ab6 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/spawn/parallel_grep.cpp @@ -0,0 +1,90 @@ +// +// parallel_grep.cpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/dispatch.hpp> +#include <boost/asio/post.hpp> +#include <boost/asio/spawn.hpp> +#include <boost/asio/strand.hpp> +#include <boost/asio/thread_pool.hpp> +#include <boost/thread/thread.hpp> +#include <boost/bind/bind.hpp> +#include <fstream> +#include <iostream> +#include <string> + +using boost::asio::dispatch; +using boost::asio::spawn; +using boost::asio::strand; +using boost::asio::thread_pool; +using boost::asio::yield_context; + +void print_match(std::string input_file, std::string line) +{ + std::cout << input_file << ':' << line << std::endl; +} + +void search_file(std::string search_string, std::string input_file, + strand<thread_pool::executor_type> output_strand, yield_context yield) +{ + std::ifstream is(input_file.c_str()); + std::string line; + std::size_t line_num = 0; + while (std::getline(is, line)) + { + // If we find a match, send a message to the output. + if (line.find(search_string) != std::string::npos) + { + dispatch(output_strand, boost::bind(&print_match, input_file, line)); + } + + // Every so often we yield control to another coroutine. + if (++line_num % 10 == 0) + post(yield); + } +} + +int main(int argc, char* argv[]) +{ + try + { + if (argc < 2) + { + std::cerr << "Usage: parallel_grep <string> <files...>\n"; + return 1; + } + + // We use a fixed size pool of threads for reading the input files. The + // number of threads is automatically determined based on the number of + // CPUs available in the system. + thread_pool pool; + + // To prevent the output from being garbled, we use a strand to synchronise + // printing. + strand<thread_pool::executor_type> output_strand(pool.get_executor()); + + // Spawn a new coroutine for each file specified on the command line. + std::string search_string = argv[1]; + for (int argn = 2; argn < argc; ++argn) + { + std::string input_file = argv[argn]; + spawn(pool, boost::bind(&search_file, search_string, + input_file, output_strand, boost::placeholders::_1)); + } + + // Join the thread pool to wait for all the spawned tasks to complete. + pool.join(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/ssl/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/ssl/Jamfile.v2 new file mode 100644 index 000000000..a7805abb8 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/ssl/Jamfile.v2 @@ -0,0 +1,48 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +import os ; + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +if [ os.name ] = NT +{ + lib ssl : : <name>ssleay32 ; + lib crypto : : <name>libeay32 ; +} +else +{ + lib ssl ; + lib crypto ; +} + +project + : requirements + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + <library>ssl + <library>crypto + ; + +exe client : client.cpp ; +exe server : server.cpp ; diff --git a/src/boost/libs/asio/example/cpp03/ssl/README b/src/boost/libs/asio/example/cpp03/ssl/README new file mode 100644 index 000000000..7dea8cc9b --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/ssl/README @@ -0,0 +1,8 @@ +The passphrase for both the CA and server private keys is "test". + + +------------------------------------------------------------------------------- +Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) + +Distributed under the Boost Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/src/boost/libs/asio/example/cpp03/ssl/ca.pem b/src/boost/libs/asio/example/cpp03/ssl/ca.pem new file mode 100644 index 000000000..1ee5f2ca4 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/ssl/ca.pem @@ -0,0 +1,49 @@ +-----BEGIN CERTIFICATE----- +MIIDlzCCAn+gAwIBAgIJAMJYU3U6A0IRMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNV +BAYTAkFVMQwwCgYDVQQIEwNOU1cxDzANBgNVBAcTBlN5ZG5leTENMAsGA1UEChME +YXNpbzAeFw0xNTExMTgyMjMzNDhaFw0yMDExMTYyMjMzNDhaMDsxCzAJBgNVBAYT +AkFVMQwwCgYDVQQIEwNOU1cxDzANBgNVBAcTBlN5ZG5leTENMAsGA1UEChMEYXNp +bzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMcRJocHdVMdLUJ/pypY +QVSTC0t3IIgjwjazrK3kAaoIMvzPmDFxEXWcDx+nyz8kQ/E38Ir/ef2BCNGci5hu +wkfMSuMoW9l2N4hx3QCcF46tTDEZztFxWAH7QbE2wYMlMgKZSxWimNfq0YjxEEXb +QM0lGPLFh7Xoko29H0F3LKaaQV9u/vop3Hs0h12HeWlY4PiLp7QQTNGqbWcXycA0 +NZ/fyismireyEvPAgo6L8iXuAi7g0TVKVNlrticGGjMcMq6IMvxzEpSMkuMQ5rWj +pZjWOoBjSYBuXdblcBRvXhOr2Ws8jJLMZfehKq9q1reQfoGV6xMnbwmumSXbWRWT +0vkCAwEAAaOBnTCBmjAdBgNVHQ4EFgQUK/Zv/AVtfIeucJw8VEtux1dhI1YwawYD +VR0jBGQwYoAUK/Zv/AVtfIeucJw8VEtux1dhI1ahP6Q9MDsxCzAJBgNVBAYTAkFV +MQwwCgYDVQQIEwNOU1cxDzANBgNVBAcTBlN5ZG5leTENMAsGA1UEChMEYXNpb4IJ +AMJYU3U6A0IRMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBABLYXimq +v/HLyIJi7Xn8AJUsICj8LKF/J24nwwiF+ibf7UkoChJURs4nN78bod/lpDVPTEVl +gTBdV/vBJs416sCEFfsGjqB9OBYj4gb0VaJDsQd0+NMvXp0faKv2y9wgScxG9/cg +aM7eRmyfMn1qjb6tpNxVOPpe/nFi8Vx/1orejBRaZr4zF5TkoPepfwLWQeXDUIdE ++QHZ60jZAkR5RXTVU4u3kOKcJs839pmJYyxM4H2VxpR18vy4/YdIVWkREIUM2OgT +5iznIQIIgR56QRGP85uef+I6n0BHzrBk6du69bkQFxrFjLVGlal4bIQqSg4KGWgx +dEdymMWzmMxpO9s= +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIIEpgIBAAKCAQEAxxEmhwd1Ux0tQn+nKlhBVJMLS3cgiCPCNrOsreQBqggy/M+Y +MXERdZwPH6fLPyRD8Tfwiv95/YEI0ZyLmG7CR8xK4yhb2XY3iHHdAJwXjq1MMRnO +0XFYAftBsTbBgyUyAplLFaKY1+rRiPEQRdtAzSUY8sWHteiSjb0fQXcspppBX27+ ++incezSHXYd5aVjg+IuntBBM0aptZxfJwDQ1n9/KKyaKt7IS88CCjovyJe4CLuDR +NUpU2Wu2JwYaMxwyrogy/HMSlIyS4xDmtaOlmNY6gGNJgG5d1uVwFG9eE6vZazyM +ksxl96Eqr2rWt5B+gZXrEydvCa6ZJdtZFZPS+QIDAQABAoIBAQCOma+SvPoDzvvU +DiPOxqgOEMPfjHfGbm86xl0luBalGfiEd6WbjVanfGKtF4MWOUFec+chez+FJMEP +fufVC0qrKiJfNVMOpYvEd2SMgkSx1VymM8me6WXVDYsSipn2+1cm228ZEYAR9Emj +oqQ4loaGLlP/3RaJbhBF7ruMJvXaZZQ4fZy74Z4tyRaaE1B659ua7Rjne7eNhQE8 +cR7cQDkxsNNN3LTbfLRwEc/gcDXWgLe5JlR/K4ZrdKc3lyivm+Uew3ubKs+fgkyY +kHmuI3RJGIjpnsZW0/So+pHm3b/fo6lmlhTXtNNd+tkkKn2K9ttbXT3Sc13Pc+4w +c4MLyUpdAoGBAOxTtGDpeF6U4s+GPuOCzHCwKQyzfOyCL/UTZv1UJX7Kn1FYycJH +eOjtBRtS661cGkGd1MPfjdX2VV84AmBGDUmRqJ2KfTI1NjLAEJ115ANTpmSTm3lF +UYncgbzl6aflLpjE1mgY+JTJykYeN5jhhO0r2bsdY7S+zaMCSI5NLuznAoGBANej +aMtqLg2qKoq+fUkNBHHLXelR5dBXFnKgSrTj++H4yeW9pYbl8bK3gTF3I5+dSjHW +DdC4+X09iPqY7p8vm8Gq/vgO8Bu+EnKNVr80PJSj7AzFGd6mk/CVrAzoY2XJWbAp +YFwpo1WfHjS5wBfQzBlXY7kWVB7fj32kk14PYmUfAoGBAJXfd7NGHPoOfdCSGGv8 +VV7ZuQ6+/WiYH4XS6iuaI7VHFsZmAn3dCcbeGbD8Y04r7NLUH0yhB7g7YmTihk87 +3c1cPIy8eS1QJbEFsQPK8fFSKWH7YkwEM/O0DesX+5hodaaYnkiiHXNujYLuQuAH +lV87wfcyajsEDjFkj1L/i9TdAoGBAKYfRUQv8HqmdU+doHb+iEYCHb75UMpHzQtR +YTwpxoo3V5Kdnz9lNeYwaF7rIY59ZgMunEYHumw5U6V625nW228/hF0lZOR6cUu+ +hu2WGHWKMvdDgMJ+IcpeA8WN4cUwcN+9gHZ/vUzg4CxOTSYLvLBpGnIkOXnvUGPC +vaTgxTSRAoGBAOHcuZ9hcUrPuVI1HVkjQQLu5mLZ3tz6linEbe/RCdJMK8JrRX4w +ubB7gFclMYGbLlDNAJVYkydJaCy/2NAI3rfsOda+VmDqGx6z4BbSGceHhomyU1Oo +1H7YaXsuzDkzl23HRsyp0pKJpTdghZdbVsGF8vAB8ygK3ehM233neSln +-----END RSA PRIVATE KEY----- diff --git a/src/boost/libs/asio/example/cpp03/ssl/client.cpp b/src/boost/libs/asio/example/cpp03/ssl/client.cpp new file mode 100644 index 000000000..d00e15eb1 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/ssl/client.cpp @@ -0,0 +1,157 @@ +// +// client.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <iostream> +#include <boost/bind/bind.hpp> +#include <boost/asio.hpp> +#include <boost/asio/ssl.hpp> + +enum { max_length = 1024 }; + +class client +{ +public: + client(boost::asio::io_context& io_context, + boost::asio::ssl::context& context, + boost::asio::ip::tcp::resolver::results_type endpoints) + : socket_(io_context, context) + { + socket_.set_verify_mode(boost::asio::ssl::verify_peer); + socket_.set_verify_callback( + boost::bind(&client::verify_certificate, this, + boost::placeholders::_1, boost::placeholders::_2)); + + boost::asio::async_connect(socket_.lowest_layer(), endpoints, + boost::bind(&client::handle_connect, this, + boost::asio::placeholders::error)); + } + + bool verify_certificate(bool preverified, + boost::asio::ssl::verify_context& ctx) + { + // The verify callback can be used to check whether the certificate that is + // being presented is valid for the peer. For example, RFC 2818 describes + // the steps involved in doing this for HTTPS. Consult the OpenSSL + // documentation for more details. Note that the callback is called once + // for each certificate in the certificate chain, starting from the root + // certificate authority. + + // In this example we will simply print the certificate's subject name. + char subject_name[256]; + X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); + X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256); + std::cout << "Verifying " << subject_name << "\n"; + + return preverified; + } + + void handle_connect(const boost::system::error_code& error) + { + if (!error) + { + socket_.async_handshake(boost::asio::ssl::stream_base::client, + boost::bind(&client::handle_handshake, this, + boost::asio::placeholders::error)); + } + else + { + std::cout << "Connect failed: " << error.message() << "\n"; + } + } + + void handle_handshake(const boost::system::error_code& error) + { + if (!error) + { + std::cout << "Enter message: "; + std::cin.getline(request_, max_length); + size_t request_length = strlen(request_); + + boost::asio::async_write(socket_, + boost::asio::buffer(request_, request_length), + boost::bind(&client::handle_write, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + else + { + std::cout << "Handshake failed: " << error.message() << "\n"; + } + } + + void handle_write(const boost::system::error_code& error, + size_t bytes_transferred) + { + if (!error) + { + boost::asio::async_read(socket_, + boost::asio::buffer(reply_, bytes_transferred), + boost::bind(&client::handle_read, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + else + { + std::cout << "Write failed: " << error.message() << "\n"; + } + } + + void handle_read(const boost::system::error_code& error, + size_t bytes_transferred) + { + if (!error) + { + std::cout << "Reply: "; + std::cout.write(reply_, bytes_transferred); + std::cout << "\n"; + } + else + { + std::cout << "Read failed: " << error.message() << "\n"; + } + } + +private: + boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_; + char request_[max_length]; + char reply_[max_length]; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: client <host> <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + boost::asio::ip::tcp::resolver resolver(io_context); + boost::asio::ip::tcp::resolver::results_type endpoints = + resolver.resolve(argv[1], argv[2]); + + boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23); + ctx.load_verify_file("ca.pem"); + + client c(io_context, ctx, endpoints); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/ssl/dh2048.pem b/src/boost/libs/asio/example/cpp03/ssl/dh2048.pem new file mode 100644 index 000000000..07250cca6 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/ssl/dh2048.pem @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEAyNnxZSYc6J89mDNnqOH8bnwBiAJxcaUS3PkIEcwW8D9o2BlNq6EO +XKMIbdfwPFZi80GMpNu3YP2A2B42sAHmb7w7ZA92QDv3JjqzR0QuS/CkMv4CEjha +QBFwBDDWnnHBSj4w/t54ii0SH34mWcjBItI2eMtnM9J6fnvNiWqJxdt4iA4mZjZD +qZTjIRyjgKAevzkqAlBqQRoVUUgu+9Cf29wXjVl3bE+0VU5CdFeyT+Y9yunz88mq +rGyx1uPt+zbIfxuNLH+coY67y1ht7iZEL5WLd3wGCycRT+lYy2AL/rxGBPxStFIT +2bOkQao6sAfb4UdGEUlwHUXZrAV51oM30wIBAg== +-----END DH PARAMETERS----- diff --git a/src/boost/libs/asio/example/cpp03/ssl/server.cpp b/src/boost/libs/asio/example/cpp03/ssl/server.cpp new file mode 100644 index 000000000..fde441505 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/ssl/server.cpp @@ -0,0 +1,170 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <iostream> +#include <boost/bind/bind.hpp> +#include <boost/asio.hpp> +#include <boost/asio/ssl.hpp> + +typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket; + +class session +{ +public: + session(boost::asio::io_context& io_context, + boost::asio::ssl::context& context) + : socket_(io_context, context) + { + } + + ssl_socket::lowest_layer_type& socket() + { + return socket_.lowest_layer(); + } + + void start() + { + socket_.async_handshake(boost::asio::ssl::stream_base::server, + boost::bind(&session::handle_handshake, this, + boost::asio::placeholders::error)); + } + + void handle_handshake(const boost::system::error_code& error) + { + if (!error) + { + socket_.async_read_some(boost::asio::buffer(data_, max_length), + boost::bind(&session::handle_read, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + else + { + delete this; + } + } + + void handle_read(const boost::system::error_code& error, + size_t bytes_transferred) + { + if (!error) + { + boost::asio::async_write(socket_, + boost::asio::buffer(data_, bytes_transferred), + boost::bind(&session::handle_write, this, + boost::asio::placeholders::error)); + } + else + { + delete this; + } + } + + void handle_write(const boost::system::error_code& error) + { + if (!error) + { + socket_.async_read_some(boost::asio::buffer(data_, max_length), + boost::bind(&session::handle_read, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + else + { + delete this; + } + } + +private: + ssl_socket socket_; + enum { max_length = 1024 }; + char data_[max_length]; +}; + +class server +{ +public: + server(boost::asio::io_context& io_context, unsigned short port) + : io_context_(io_context), + acceptor_(io_context, + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)), + context_(boost::asio::ssl::context::sslv23) + { + context_.set_options( + boost::asio::ssl::context::default_workarounds + | boost::asio::ssl::context::no_sslv2 + | boost::asio::ssl::context::single_dh_use); + context_.set_password_callback(boost::bind(&server::get_password, this)); + context_.use_certificate_chain_file("server.pem"); + context_.use_private_key_file("server.pem", boost::asio::ssl::context::pem); + context_.use_tmp_dh_file("dh2048.pem"); + + start_accept(); + } + + std::string get_password() const + { + return "test"; + } + + void start_accept() + { + session* new_session = new session(io_context_, context_); + acceptor_.async_accept(new_session->socket(), + boost::bind(&server::handle_accept, this, new_session, + boost::asio::placeholders::error)); + } + + void handle_accept(session* new_session, + const boost::system::error_code& error) + { + if (!error) + { + new_session->start(); + } + else + { + delete new_session; + } + + start_accept(); + } + +private: + boost::asio::io_context& io_context_; + boost::asio::ip::tcp::acceptor acceptor_; + boost::asio::ssl::context context_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: server <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + using namespace std; // For atoi. + server s(io_context, atoi(argv[1])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/ssl/server.pem b/src/boost/libs/asio/example/cpp03/ssl/server.pem new file mode 100644 index 000000000..37ea6e267 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/ssl/server.pem @@ -0,0 +1,71 @@ +-----BEGIN CERTIFICATE----- +MIIDAzCCAesCCQD9QcRiWk0y9TANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJB +VTEMMAoGA1UECBMDTlNXMQ8wDQYDVQQHEwZTeWRuZXkxDTALBgNVBAoTBGFzaW8w +HhcNMTUxMTE4MjIzNzMxWhcNMjAxMTE2MjIzNzMxWjBMMQswCQYDVQQGEwJBVTEM +MAoGA1UECBMDTlNXMQ8wDQYDVQQHEwZTeWRuZXkxDTALBgNVBAoTBGFzaW8xDzAN +BgNVBAsTBnNlcnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALr0 ++NXSklsGJR7HYHP/H4V5+KpYrmFKva/K7iiqi+XyWEjGnj+/iImJW26phhg9GouN +JJxdrP7/0LwpMsEC/9v09dMNAEewtYhPgD4kiUH/E/79wVmayMZZZGrpF9Rw+wWv +q58y3L1wKge3qilX6slVDdNhqU3vBiMKEJfsjE4PKcEVjPCjVJG2562eHK9FxyjQ +DykyH61lQKBQOiElilPQKzAO7U36yTvs+chWuUfK47B8EC+PJ5KcLEppli4ljlwE +w01HnGxwvjDLobKm2jL6CWi3aYGWudyTsNAd7YC5C7psktBypQLBcfp7uUrrR5Bb +PEjFHJUWIlyoYvm2OjMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAtceVW6tixFsB +ZRhjL5aRCcbx2iMwEXd54lcP6BWe1qOcDPHoSYI1zvvGzohbEvBfqUv78S9MtzaT +gMe5rIU9M1ZM09PyaM6ZutGpKHE8L4qcOslTt41GQFsSqPFdcbgSV20MvBzjGayR +AI/WV0avW3oasdetJPZCR7bRbCbMbWTgclUfv5F25ENcR+BhNuilfL15owL0s4sS +Wb4jOOHhXV9iXeS2dH0snFqv4BmQ9ZoA7zbM9lG3EU5DuxHESYkCnzJyEqqY3vWv +PFRViCxLp5LQLmkTQ3dglVQA4x6ZaonaewdPtdhjkLUuIqDvQx5+kIaOELbSws+c +bREYlnGrFw== +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,D459676347D389E9135496D8AAFA7953 + +wbrjxr9NHur8kgxDsgXOY9qFGKpONIQLxkuahUrDD/H+s/l7ugsLWOPsOXbjNL/7 +QYUBAx85HKm9D8BQ5g78Y82qfArap3/3IIuysDfQDh4fQodhVtmGTFiCOvudlGEp +lq1niQRLThlxeRoFphH8KKiOTO9a/d8tdL7zRmiFwnVnhK4014mgVmgcSefA1AF5 +RbJAeMclUKddG6ltQK00ptg84CDXiMWQXFBGGmQ1av2lyFzC+xLP+qDqZAYTM9lZ +NFRo2oEZP1ozfOVNSbXTanJgZ0DSSmhGE1PcVrHSeE/v+k1kPh3oVKi9GV51kIDC +Zd9f/XltuDOzy1Ybn6gRy4nzNpzcwjSCIHEdSD5nxU5JfHfQ3OtnsEab7qf989iP +s2LbCSp5uGTMvfesMIkixIZAQp2FeahZTAgU2Vx+wi5Kks68rOqeywEfzACL/Um5 +7XZu8gDs4MgRRWnxK1BbJDPifICLvSJZvgB9FKX/hk4FHFF+MtcrkalehCuLooDV +3rfHNvRSbg7J97XQ3QC+k9ZDaumpy6n+LhaVv7BIJRBnBBtZ5Eg3DmPg6flqaHAU +Y/8d82wb/pCmbvR3B1/Ebgs84DPJ+uZnY9M5Iwx19oqlVSR2ts/Tx619LGAm+BiQ +7YDoC4CFmpAA8Uw0xnUbNgx94NdNmlnLeLtS50b0XlWpHKbVzmVbNYEjY6NHMlLt +aqxWHTYTa7g/c1bg2/nxF1Lbfu5VSTROGBUuer1c3yzVuyBrjcX92Jp4BJH78qOp +N6lY6MnH4HYRXHjzlt/S0ZzO0faPPe18Q8SWvnDVuE3fYzzL772B56d2t8eodc+/ +t6M3qJ60eXdsmgYOaPRLRUovN2xT2UUr0+biuguHyqfaVfcEU/adw+b9oUVE+5Nw +nZHI5qhPnhLxChyZqbBl68zMUyKlfff4OyLvRGpfcHwBw6DTGjduB+DDsqqkcIB9 +2VL6nps7ZVCwMPI18siUd6cttEOf6ZXrVqHg9wfDvJOlh2NNKNLxSAFubHc90Jlj +KejrWenXo2w6YkSUeTV4t4cWu7U8rXIkTJXDl1S6NO8DWqNDo5KjgJ2SK5NlSOJ7 +jgECn390ooneJOxxytPVQO2xppXQZZS65RHrvhB+ss5xUknly9q+ICyt6xTR9nqA +PKkeSE6qVY0J4JgFXpkgQxgwMnjSED3LKr3jlz28pr5cC6tsc5SSlekHjT2fcSrX +uccaVahaJRigf+q+4XzmJtdwbZU+YWGZRVMlQLA5yzPHQHDYkPpOeYU4WReND8S4 +TZRkPHaxOZ2lKQwJB93V8Vbt2MvwRy392452a33S4TcQLaWzoOljXjmZjrp2rvRz +prBaNe8LnO4V8Oliv+H+E0UWiWFDuI+HBy4X4O9plsbw/gk64Phl9qLiBwaX/AIR +66FXvC/czABo9oSt2jekcMtJofYr8Gr2bsJlt5ZX+GEOxz4jMv7xvz5/L3W7jVav +pHGIv4xfN9FrXzL47O7UuUF9xZg4Rp/fxwpgEDNZmX/3DnP0ewZQUcgUX0pdqNGQ +YVqJXcRF7KqG2NSQFuwPESZQnxU0WzSgRyUae7xg1WKfSuN8NVAzKhOgeqlD2IAo +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDlzCCAn+gAwIBAgIJAMJYU3U6A0IRMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNV +BAYTAkFVMQwwCgYDVQQIEwNOU1cxDzANBgNVBAcTBlN5ZG5leTENMAsGA1UEChME +YXNpbzAeFw0xNTExMTgyMjMzNDhaFw0yMDExMTYyMjMzNDhaMDsxCzAJBgNVBAYT +AkFVMQwwCgYDVQQIEwNOU1cxDzANBgNVBAcTBlN5ZG5leTENMAsGA1UEChMEYXNp +bzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMcRJocHdVMdLUJ/pypY +QVSTC0t3IIgjwjazrK3kAaoIMvzPmDFxEXWcDx+nyz8kQ/E38Ir/ef2BCNGci5hu +wkfMSuMoW9l2N4hx3QCcF46tTDEZztFxWAH7QbE2wYMlMgKZSxWimNfq0YjxEEXb +QM0lGPLFh7Xoko29H0F3LKaaQV9u/vop3Hs0h12HeWlY4PiLp7QQTNGqbWcXycA0 +NZ/fyismireyEvPAgo6L8iXuAi7g0TVKVNlrticGGjMcMq6IMvxzEpSMkuMQ5rWj +pZjWOoBjSYBuXdblcBRvXhOr2Ws8jJLMZfehKq9q1reQfoGV6xMnbwmumSXbWRWT +0vkCAwEAAaOBnTCBmjAdBgNVHQ4EFgQUK/Zv/AVtfIeucJw8VEtux1dhI1YwawYD +VR0jBGQwYoAUK/Zv/AVtfIeucJw8VEtux1dhI1ahP6Q9MDsxCzAJBgNVBAYTAkFV +MQwwCgYDVQQIEwNOU1cxDzANBgNVBAcTBlN5ZG5leTENMAsGA1UEChMEYXNpb4IJ +AMJYU3U6A0IRMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBABLYXimq +v/HLyIJi7Xn8AJUsICj8LKF/J24nwwiF+ibf7UkoChJURs4nN78bod/lpDVPTEVl +gTBdV/vBJs416sCEFfsGjqB9OBYj4gb0VaJDsQd0+NMvXp0faKv2y9wgScxG9/cg +aM7eRmyfMn1qjb6tpNxVOPpe/nFi8Vx/1orejBRaZr4zF5TkoPepfwLWQeXDUIdE ++QHZ60jZAkR5RXTVU4u3kOKcJs839pmJYyxM4H2VxpR18vy4/YdIVWkREIUM2OgT +5iznIQIIgR56QRGP85uef+I6n0BHzrBk6du69bkQFxrFjLVGlal4bIQqSg4KGWgx +dEdymMWzmMxpO9s= +-----END CERTIFICATE----- diff --git a/src/boost/libs/asio/example/cpp03/timeouts/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/timeouts/Jamfile.v2 new file mode 100644 index 000000000..dcc83c435 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/timeouts/Jamfile.v2 @@ -0,0 +1,36 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe async_tcp_client : async_tcp_client.cpp ; +exe blocking_tcp_client : blocking_tcp_client.cpp ; +exe blocking_token_tcp_client : blocking_token_tcp_client.cpp ; +exe blocking_udp_client : blocking_udp_client.cpp ; +exe server : server.cpp ; diff --git a/src/boost/libs/asio/example/cpp03/timeouts/async_tcp_client.cpp b/src/boost/libs/asio/example/cpp03/timeouts/async_tcp_client.cpp new file mode 100644 index 000000000..1f8ba01ed --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/timeouts/async_tcp_client.cpp @@ -0,0 +1,311 @@ +// +// async_tcp_client.cpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/buffer.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/read_until.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/asio/write.hpp> +#include <boost/bind/bind.hpp> +#include <iostream> +#include <string> + +using boost::asio::steady_timer; +using boost::asio::ip::tcp; + +// +// This class manages socket timeouts by applying the concept of a deadline. +// Some asynchronous operations are given deadlines by which they must complete. +// Deadlines are enforced by an "actor" that persists for the lifetime of the +// client object: +// +// +----------------+ +// | | +// | check_deadline |<---+ +// | | | +// +----------------+ | async_wait() +// | | +// +---------+ +// +// If the deadline actor determines that the deadline has expired, the socket +// is closed and any outstanding operations are consequently cancelled. +// +// Connection establishment involves trying each endpoint in turn until a +// connection is successful, or the available endpoints are exhausted. If the +// deadline actor closes the socket, the connect actor is woken up and moves to +// the next endpoint. +// +// +---------------+ +// | | +// | start_connect |<---+ +// | | | +// +---------------+ | +// | | +// async_- | +----------------+ +// connect() | | | +// +--->| handle_connect | +// | | +// +----------------+ +// : +// Once a connection is : +// made, the connect : +// actor forks in two - : +// : +// an actor for reading : and an actor for +// inbound messages: : sending heartbeats: +// : +// +------------+ : +-------------+ +// | |<- - - - -+- - - - ->| | +// | start_read | | start_write |<---+ +// | |<---+ | | | +// +------------+ | +-------------+ | async_wait() +// | | | | +// async_- | +-------------+ async_- | +--------------+ +// read_- | | | write() | | | +// until() +--->| handle_read | +--->| handle_write | +// | | | | +// +-------------+ +--------------+ +// +// The input actor reads messages from the socket, where messages are delimited +// by the newline character. The deadline for a complete message is 30 seconds. +// +// The heartbeat actor sends a heartbeat (a message that consists of a single +// newline character) every 10 seconds. In this example, no deadline is applied +// to message sending. +// +class client +{ +public: + client(boost::asio::io_context& io_context) + : stopped_(false), + socket_(io_context), + deadline_(io_context), + heartbeat_timer_(io_context) + { + } + + // Called by the user of the client class to initiate the connection process. + // The endpoints will have been obtained using a tcp::resolver. + void start(tcp::resolver::results_type endpoints) + { + // Start the connect actor. + endpoints_ = endpoints; + start_connect(endpoints_.begin()); + + // Start the deadline actor. You will note that we're not setting any + // particular deadline here. Instead, the connect and input actors will + // update the deadline prior to each asynchronous operation. + deadline_.async_wait(boost::bind(&client::check_deadline, this)); + } + + // This function terminates all the actors to shut down the connection. It + // may be called by the user of the client class, or by the class itself in + // response to graceful termination or an unrecoverable error. + void stop() + { + stopped_ = true; + boost::system::error_code ignored_ec; + socket_.close(ignored_ec); + deadline_.cancel(); + heartbeat_timer_.cancel(); + } + +private: + void start_connect(tcp::resolver::results_type::iterator endpoint_iter) + { + if (endpoint_iter != endpoints_.end()) + { + std::cout << "Trying " << endpoint_iter->endpoint() << "...\n"; + + // Set a deadline for the connect operation. + deadline_.expires_after(boost::asio::chrono::seconds(60)); + + // Start the asynchronous connect operation. + socket_.async_connect(endpoint_iter->endpoint(), + boost::bind(&client::handle_connect, this, + boost::placeholders::_1, endpoint_iter)); + } + else + { + // There are no more endpoints to try. Shut down the client. + stop(); + } + } + + void handle_connect(const boost::system::error_code& ec, + tcp::resolver::results_type::iterator endpoint_iter) + { + if (stopped_) + return; + + // The async_connect() function automatically opens the socket at the start + // of the asynchronous operation. If the socket is closed at this time then + // the timeout handler must have run first. + if (!socket_.is_open()) + { + std::cout << "Connect timed out\n"; + + // Try the next available endpoint. + start_connect(++endpoint_iter); + } + + // Check if the connect operation failed before the deadline expired. + else if (ec) + { + std::cout << "Connect error: " << ec.message() << "\n"; + + // We need to close the socket used in the previous connection attempt + // before starting a new one. + socket_.close(); + + // Try the next available endpoint. + start_connect(++endpoint_iter); + } + + // Otherwise we have successfully established a connection. + else + { + std::cout << "Connected to " << endpoint_iter->endpoint() << "\n"; + + // Start the input actor. + start_read(); + + // Start the heartbeat actor. + start_write(); + } + } + + void start_read() + { + // Set a deadline for the read operation. + deadline_.expires_after(boost::asio::chrono::seconds(30)); + + // Start an asynchronous operation to read a newline-delimited message. + boost::asio::async_read_until(socket_, + boost::asio::dynamic_buffer(input_buffer_), '\n', + boost::bind(&client::handle_read, this, + boost::placeholders::_1, boost::placeholders::_2)); + } + + void handle_read(const boost::system::error_code& ec, std::size_t n) + { + if (stopped_) + return; + + if (!ec) + { + // Extract the newline-delimited message from the buffer. + std::string line(input_buffer_.substr(0, n - 1)); + input_buffer_.erase(0, n); + + // Empty messages are heartbeats and so ignored. + if (!line.empty()) + { + std::cout << "Received: " << line << "\n"; + } + + start_read(); + } + else + { + std::cout << "Error on receive: " << ec.message() << "\n"; + + stop(); + } + } + + void start_write() + { + if (stopped_) + return; + + // Start an asynchronous operation to send a heartbeat message. + boost::asio::async_write(socket_, boost::asio::buffer("\n", 1), + boost::bind(&client::handle_write, this, boost::placeholders::_1)); + } + + void handle_write(const boost::system::error_code& ec) + { + if (stopped_) + return; + + if (!ec) + { + // Wait 10 seconds before sending the next heartbeat. + heartbeat_timer_.expires_after(boost::asio::chrono::seconds(10)); + heartbeat_timer_.async_wait(boost::bind(&client::start_write, this)); + } + else + { + std::cout << "Error on heartbeat: " << ec.message() << "\n"; + + stop(); + } + } + + void check_deadline() + { + if (stopped_) + return; + + // Check whether the deadline has passed. We compare the deadline against + // the current time since a new asynchronous operation may have moved the + // deadline before this actor had a chance to run. + if (deadline_.expiry() <= steady_timer::clock_type::now()) + { + // The deadline has passed. The socket is closed so that any outstanding + // asynchronous operations are cancelled. + socket_.close(); + + // There is no longer an active deadline. The expiry is set to the + // maximum time point so that the actor takes no action until a new + // deadline is set. + deadline_.expires_at(steady_timer::time_point::max()); + } + + // Put the actor back to sleep. + deadline_.async_wait(boost::bind(&client::check_deadline, this)); + } + +private: + bool stopped_; + tcp::resolver::results_type endpoints_; + tcp::socket socket_; + std::string input_buffer_; + steady_timer deadline_; + steady_timer heartbeat_timer_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: client <host> <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + tcp::resolver r(io_context); + client c(io_context); + + c.start(r.resolve(argv[1], argv[2])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/timeouts/blocking_tcp_client.cpp b/src/boost/libs/asio/example/cpp03/timeouts/blocking_tcp_client.cpp new file mode 100644 index 000000000..a0bbaeac6 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/timeouts/blocking_tcp_client.cpp @@ -0,0 +1,191 @@ +// +// blocking_tcp_client.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/buffer.hpp> +#include <boost/asio/connect.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/read_until.hpp> +#include <boost/system/system_error.hpp> +#include <boost/asio/write.hpp> +#include <cstdlib> +#include <iostream> +#include <string> +#include <boost/lambda/bind.hpp> +#include <boost/lambda/lambda.hpp> + +using boost::asio::ip::tcp; +using boost::lambda::bind; +using boost::lambda::var; +using boost::lambda::_1; +using boost::lambda::_2; + +//---------------------------------------------------------------------- + +// +// This class manages socket timeouts by running the io_context using the timed +// io_context::run_for() member function. Each asynchronous operation is given +// a timeout within which it must complete. The socket operations themselves +// use boost::lambda function objects as completion handlers. For a given +// socket operation, the client object runs the io_context to block thread +// execution until the operation completes or the timeout is reached. If the +// io_context::run_for() function times out, the socket is closed and the +// outstanding asynchronous operation is cancelled. +// +class client +{ +public: + client() + : socket_(io_context_) + { + } + + void connect(const std::string& host, const std::string& service, + boost::asio::chrono::steady_clock::duration timeout) + { + // Resolve the host name and service to a list of endpoints. + tcp::resolver::results_type endpoints = + tcp::resolver(io_context_).resolve(host, service); + + // Start the asynchronous operation itself. The boost::lambda function + // object is used as a callback and will update the ec variable when the + // operation completes. The blocking_udp_client.cpp example shows how you + // can use boost::bind rather than boost::lambda. + boost::system::error_code ec; + boost::asio::async_connect(socket_, endpoints, var(ec) = _1); + + // Run the operation until it completes, or until the timeout. + run(timeout); + + // Determine whether a connection was successfully established. + if (ec) + throw boost::system::system_error(ec); + } + + std::string read_line(boost::asio::chrono::steady_clock::duration timeout) + { + // Start the asynchronous operation. The boost::lambda function object is + // used as a callback and will update the ec variable when the operation + // completes. The blocking_udp_client.cpp example shows how you can use + // boost::bind rather than boost::lambda. + boost::system::error_code ec; + std::size_t n = 0; + boost::asio::async_read_until(socket_, + boost::asio::dynamic_buffer(input_buffer_), + '\n', (var(ec) = _1, var(n) = _2)); + + // Run the operation until it completes, or until the timeout. + run(timeout); + + // Determine whether the read completed successfully. + if (ec) + throw boost::system::system_error(ec); + + std::string line(input_buffer_.substr(0, n - 1)); + input_buffer_.erase(0, n); + return line; + } + + void write_line(const std::string& line, + boost::asio::chrono::steady_clock::duration timeout) + { + std::string data = line + "\n"; + + // Start the asynchronous operation. The boost::lambda function object is + // used as a callback and will update the ec variable when the operation + // completes. The blocking_udp_client.cpp example shows how you can use + // boost::bind rather than boost::lambda. + boost::system::error_code ec; + boost::asio::async_write(socket_, boost::asio::buffer(data), var(ec) = _1); + + // Run the operation until it completes, or until the timeout. + run(timeout); + + // Determine whether the read completed successfully. + if (ec) + throw boost::system::system_error(ec); + } + +private: + void run(boost::asio::chrono::steady_clock::duration timeout) + { + // Restart the io_context, as it may have been left in the "stopped" state + // by a previous operation. + io_context_.restart(); + + // Block until the asynchronous operation has completed, or timed out. If + // the pending asynchronous operation is a composed operation, the deadline + // applies to the entire operation, rather than individual operations on + // the socket. + io_context_.run_for(timeout); + + // If the asynchronous operation completed successfully then the io_context + // would have been stopped due to running out of work. If it was not + // stopped, then the io_context::run_for call must have timed out. + if (!io_context_.stopped()) + { + // Close the socket to cancel the outstanding asynchronous operation. + socket_.close(); + + // Run the io_context again until the operation completes. + io_context_.run(); + } + } + + boost::asio::io_context io_context_; + tcp::socket socket_; + std::string input_buffer_; +}; + +//---------------------------------------------------------------------- + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 4) + { + std::cerr << "Usage: blocking_tcp_client <host> <port> <message>\n"; + return 1; + } + + client c; + c.connect(argv[1], argv[2], boost::asio::chrono::seconds(10)); + + boost::asio::chrono::steady_clock::time_point time_sent = + boost::asio::chrono::steady_clock::now(); + + c.write_line(argv[3], boost::asio::chrono::seconds(10)); + + for (;;) + { + std::string line = c.read_line(boost::asio::chrono::seconds(10)); + + // Keep going until we get back the line that was sent. + if (line == argv[3]) + break; + } + + boost::asio::chrono::steady_clock::time_point time_received = + boost::asio::chrono::steady_clock::now(); + + std::cout << "Round trip time: "; + std::cout << boost::asio::chrono::duration_cast< + boost::asio::chrono::microseconds>( + time_received - time_sent).count(); + std::cout << " microseconds\n"; + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/timeouts/blocking_token_tcp_client.cpp b/src/boost/libs/asio/example/cpp03/timeouts/blocking_token_tcp_client.cpp new file mode 100644 index 000000000..effb491c2 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/timeouts/blocking_token_tcp_client.cpp @@ -0,0 +1,202 @@ +// +// blocking_token_tcp_client.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/connect.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/read_until.hpp> +#include <boost/asio/streambuf.hpp> +#include <boost/system/system_error.hpp> +#include <boost/asio/write.hpp> +#include <cstdlib> +#include <iostream> +#include <memory> +#include <string> + +using boost::asio::ip::tcp; + +// We will use our sockets only with an io_context. +typedef boost::asio::basic_stream_socket<tcp, + boost::asio::io_context::executor_type> tcp_socket; + +//---------------------------------------------------------------------- + +// A custom completion token that makes asynchronous operations behave as +// though they are blocking calls with a timeout. +struct close_after +{ + close_after(boost::asio::chrono::steady_clock::duration t, tcp_socket& s) + : timeout_(t), socket_(s) + { + } + + // The maximum time to wait for an asynchronous operation to complete. + boost::asio::chrono::steady_clock::duration timeout_; + + // The socket to be closed if the operation does not complete in time. + tcp_socket& socket_; +}; + +namespace boost { +namespace asio { + +// The async_result template is specialised to allow the close_after token to +// be used with asynchronous operations that have a completion signature of +// void(error_code, T). Generalising this for all completion signature forms is +// left as an exercise for the reader. +template <typename T> +class async_result<close_after, void(boost::system::error_code, T)> +{ +public: + // An asynchronous operation's initiating function automatically creates an + // completion_handler_type object from the token. This function object is + // then called on completion of the asynchronous operation. + class completion_handler_type + { + public: + completion_handler_type(const close_after& token) + : token_(token) + { + } + + void operator()(boost::system::error_code ec, T t) + { + *ec_ = ec; + *t_ = t; + } + + private: + friend class async_result; + close_after token_; + boost::system::error_code* ec_; + T* t_; + }; + + // The async_result constructor associates the completion handler object with + // the result of the initiating function. + explicit async_result(completion_handler_type& h) + : timeout_(h.token_.timeout_), + socket_(h.token_.socket_) + { + h.ec_ = &ec_; + h.t_ = &t_; + } + + // The return_type typedef determines the result type of the asynchronous + // operation's initiating function. + typedef T return_type; + + // The get() function is used to obtain the result of the asynchronous + // operation's initiating function. For the close_after completion token, we + // use this function to run the io_context until the operation is complete. + return_type get() + { + boost::asio::io_context& io_context = socket_.get_executor().context(); + + // Restart the io_context, as it may have been left in the "stopped" state + // by a previous operation. + io_context.restart(); + + // Block until the asynchronous operation has completed, or timed out. If + // the pending asynchronous operation is a composed operation, the deadline + // applies to the entire operation, rather than individual operations on + // the socket. + io_context.run_for(timeout_); + + // If the asynchronous operation completed successfully then the io_context + // would have been stopped due to running out of work. If it was not + // stopped, then the io_context::run_for call must have timed out and the + // operation is still incomplete. + if (!io_context.stopped()) + { + // Close the socket to cancel the outstanding asynchronous operation. + socket_.close(); + + // Run the io_context again until the operation completes. + io_context.run(); + } + + // If the operation failed, throw an exception. Otherwise return the result. + return ec_ ? throw boost::system::system_error(ec_) : t_; + } + +private: + boost::asio::chrono::steady_clock::duration timeout_; + tcp_socket& socket_; + boost::system::error_code ec_; + T t_; +}; + +} // namespace asio +} // namespace boost + +//---------------------------------------------------------------------- + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 4) + { + std::cerr << "Usage: blocking_tcp_client <host> <port> <message>\n"; + return 1; + } + + boost::asio::io_context io_context; + + // Resolve the host name and service to a list of endpoints. + tcp::resolver::results_type endpoints = + tcp::resolver(io_context).resolve(argv[1], argv[2]); + + tcp_socket socket(io_context); + + // Run an asynchronous connect operation with a timeout. + boost::asio::async_connect(socket, endpoints, + close_after(boost::asio::chrono::seconds(10), socket)); + + boost::asio::chrono::steady_clock::time_point time_sent = + boost::asio::chrono::steady_clock::now(); + + // Run an asynchronous write operation with a timeout. + std::string msg = argv[3] + std::string("\n"); + boost::asio::async_write(socket, boost::asio::buffer(msg), + close_after(boost::asio::chrono::seconds(10), socket)); + + for (std::string input_buffer;;) + { + // Run an asynchronous read operation with a timeout. + std::size_t n = boost::asio::async_read_until(socket, + boost::asio::dynamic_buffer(input_buffer), '\n', + close_after(boost::asio::chrono::seconds(10), socket)); + + std::string line(input_buffer.substr(0, n - 1)); + input_buffer.erase(0, n); + + // Keep going until we get back the line that was sent. + if (line == argv[3]) + break; + } + + boost::asio::chrono::steady_clock::time_point time_received = + boost::asio::chrono::steady_clock::now(); + + std::cout << "Round trip time: "; + std::cout << boost::asio::chrono::duration_cast< + boost::asio::chrono::microseconds>( + time_received - time_sent).count(); + std::cout << " microseconds\n"; + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/timeouts/blocking_udp_client.cpp b/src/boost/libs/asio/example/cpp03/timeouts/blocking_udp_client.cpp new file mode 100644 index 000000000..95c3480c1 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/timeouts/blocking_udp_client.cpp @@ -0,0 +1,154 @@ +// +// blocking_udp_client.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/buffer.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/udp.hpp> +#include <cstdlib> +#include <boost/bind/bind.hpp> +#include <iostream> + +using boost::asio::ip::udp; + +//---------------------------------------------------------------------- + +// +// This class manages socket timeouts by running the io_context using the timed +// io_context::run_for() member function. Each asynchronous operation is given +// a timeout within which it must complete. The socket operations themselves +// use boost::bind to specify the completion handler: +// +// +---------------+ +// | | +// | receive | +// | | +// +---------------+ +// | +// async_- | +----------------+ +// receive() | | | +// +--->| handle_receive | +// | | +// +----------------+ +// +// For a given socket operation, the client object runs the io_context to block +// thread execution until the operation completes or the timeout is reached. If +// the io_context::run_for() function times out, the socket is closed and the +// outstanding asynchronous operation is cancelled. +// +class client +{ +public: + client(const udp::endpoint& listen_endpoint) + : socket_(io_context_, listen_endpoint) + { + } + + std::size_t receive(const boost::asio::mutable_buffer& buffer, + boost::asio::chrono::steady_clock::duration timeout, + boost::system::error_code& ec) + { + // Start the asynchronous operation. The handle_receive function used as a + // callback will update the ec and length variables. + std::size_t length = 0; + socket_.async_receive(boost::asio::buffer(buffer), + boost::bind(&client::handle_receive, + boost::placeholders::_1, boost::placeholders::_2, &ec, &length)); + + // Run the operation until it completes, or until the timeout. + run(timeout); + + return length; + } + +private: + void run(boost::asio::chrono::steady_clock::duration timeout) + { + // Restart the io_context, as it may have been left in the "stopped" state + // by a previous operation. + io_context_.restart(); + + // Block until the asynchronous operation has completed, or timed out. If + // the pending asynchronous operation is a composed operation, the deadline + // applies to the entire operation, rather than individual operations on + // the socket. + io_context_.run_for(timeout); + + // If the asynchronous operation completed successfully then the io_context + // would have been stopped due to running out of work. If it was not + // stopped, then the io_context::run_for call must have timed out. + if (!io_context_.stopped()) + { + // Cancel the outstanding asynchronous operation. + socket_.cancel(); + + // Run the io_context again until the operation completes. + io_context_.run(); + } + } + + static void handle_receive( + const boost::system::error_code& ec, std::size_t length, + boost::system::error_code* out_ec, std::size_t* out_length) + { + *out_ec = ec; + *out_length = length; + } + +private: + boost::asio::io_context io_context_; + udp::socket socket_; +}; + +//---------------------------------------------------------------------- + +int main(int argc, char* argv[]) +{ + try + { + using namespace std; // For atoi. + + if (argc != 3) + { + std::cerr << "Usage: blocking_udp_client <listen_addr> <listen_port>\n"; + return 1; + } + + udp::endpoint listen_endpoint( + boost::asio::ip::make_address(argv[1]), + std::atoi(argv[2])); + + client c(listen_endpoint); + + for (;;) + { + char data[1024]; + boost::system::error_code ec; + std::size_t n = c.receive(boost::asio::buffer(data), + boost::asio::chrono::seconds(10), ec); + + if (ec) + { + std::cout << "Receive error: " << ec.message() << "\n"; + } + else + { + std::cout << "Received: "; + std::cout.write(data, n); + std::cout << "\n"; + } + } + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/timeouts/server.cpp b/src/boost/libs/asio/example/cpp03/timeouts/server.cpp new file mode 100644 index 000000000..0b48ea01d --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/timeouts/server.cpp @@ -0,0 +1,433 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <algorithm> +#include <cstdlib> +#include <deque> +#include <iostream> +#include <set> +#include <string> +#include <boost/bind/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/asio/buffer.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/ip/udp.hpp> +#include <boost/asio/read_until.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/asio/write.hpp> + +using boost::asio::steady_timer; +using boost::asio::ip::tcp; +using boost::asio::ip::udp; + +//---------------------------------------------------------------------- + +class subscriber +{ +public: + virtual ~subscriber() {} + virtual void deliver(const std::string& msg) = 0; +}; + +typedef boost::shared_ptr<subscriber> subscriber_ptr; + +//---------------------------------------------------------------------- + +class channel +{ +public: + void join(subscriber_ptr subscriber) + { + subscribers_.insert(subscriber); + } + + void leave(subscriber_ptr subscriber) + { + subscribers_.erase(subscriber); + } + + void deliver(const std::string& msg) + { + std::for_each(subscribers_.begin(), subscribers_.end(), + boost::bind(&subscriber::deliver, + boost::placeholders::_1, boost::ref(msg))); + } + +private: + std::set<subscriber_ptr> subscribers_; +}; + +//---------------------------------------------------------------------- + +// +// This class manages socket timeouts by applying the concept of a deadline. +// Some asynchronous operations are given deadlines by which they must complete. +// Deadlines are enforced by two "actors" that persist for the lifetime of the +// session object, one for input and one for output: +// +// +----------------+ +----------------+ +// | | | | +// | check_deadline |<---+ | check_deadline |<---+ +// | | | async_wait() | | | async_wait() +// +----------------+ | on input +----------------+ | on output +// | | deadline | | deadline +// +---------+ +---------+ +// +// If either deadline actor determines that the corresponding deadline has +// expired, the socket is closed and any outstanding operations are cancelled. +// +// The input actor reads messages from the socket, where messages are delimited +// by the newline character: +// +// +------------+ +// | | +// | start_read |<---+ +// | | | +// +------------+ | +// | | +// async_- | +-------------+ +// read_- | | | +// until() +--->| handle_read | +// | | +// +-------------+ +// +// The deadline for receiving a complete message is 30 seconds. If a non-empty +// message is received, it is delivered to all subscribers. If a heartbeat (a +// message that consists of a single newline character) is received, a heartbeat +// is enqueued for the client, provided there are no other messages waiting to +// be sent. +// +// The output actor is responsible for sending messages to the client: +// +// +--------------+ +// | |<---------------------+ +// | await_output | | +// | |<---+ | +// +--------------+ | | +// | | | async_wait() | +// | +--------+ | +// V | +// +-------------+ +--------------+ +// | | async_write() | | +// | start_write |-------------->| handle_write | +// | | | | +// +-------------+ +--------------+ +// +// The output actor first waits for an output message to be enqueued. It does +// this by using a steady_timer as an asynchronous condition variable. The +// steady_timer will be signalled whenever the output queue is non-empty. +// +// Once a message is available, it is sent to the client. The deadline for +// sending a complete message is 30 seconds. After the message is successfully +// sent, the output actor again waits for the output queue to become non-empty. +// +class tcp_session + : public subscriber, + public boost::enable_shared_from_this<tcp_session> +{ +public: + tcp_session(boost::asio::io_context& io_context, channel& ch) + : channel_(ch), + socket_(io_context), + input_deadline_(io_context), + non_empty_output_queue_(io_context), + output_deadline_(io_context) + { + input_deadline_.expires_at(steady_timer::time_point::max()); + output_deadline_.expires_at(steady_timer::time_point::max()); + + // The non_empty_output_queue_ steady_timer is set to the maximum time + // point whenever the output queue is empty. This ensures that the output + // actor stays asleep until a message is put into the queue. + non_empty_output_queue_.expires_at(steady_timer::time_point::max()); + } + + tcp::socket& socket() + { + return socket_; + } + + // Called by the server object to initiate the four actors. + void start() + { + channel_.join(shared_from_this()); + + start_read(); + + input_deadline_.async_wait( + boost::bind(&tcp_session::check_deadline, + shared_from_this(), &input_deadline_)); + + await_output(); + + output_deadline_.async_wait( + boost::bind(&tcp_session::check_deadline, + shared_from_this(), &output_deadline_)); + } + +private: + void stop() + { + channel_.leave(shared_from_this()); + + boost::system::error_code ignored_ec; + socket_.close(ignored_ec); + input_deadline_.cancel(); + non_empty_output_queue_.cancel(); + output_deadline_.cancel(); + } + + bool stopped() const + { + return !socket_.is_open(); + } + + void deliver(const std::string& msg) + { + output_queue_.push_back(msg + "\n"); + + // Signal that the output queue contains messages. Modifying the expiry + // will wake the output actor, if it is waiting on the timer. + non_empty_output_queue_.expires_at(steady_timer::time_point::min()); + } + + void start_read() + { + // Set a deadline for the read operation. + input_deadline_.expires_after(boost::asio::chrono::seconds(30)); + + // Start an asynchronous operation to read a newline-delimited message. + boost::asio::async_read_until(socket_, + boost::asio::dynamic_buffer(input_buffer_), '\n', + boost::bind(&tcp_session::handle_read, shared_from_this(), + boost::placeholders::_1, boost::placeholders::_2)); + } + + void handle_read(const boost::system::error_code& ec, std::size_t n) + { + if (stopped()) + return; + + if (!ec) + { + // Extract the newline-delimited message from the buffer. + std::string msg(input_buffer_.substr(0, n - 1)); + input_buffer_.erase(0, n); + + if (!msg.empty()) + { + channel_.deliver(msg); + } + else + { + // We received a heartbeat message from the client. If there's nothing + // else being sent or ready to be sent, send a heartbeat right back. + if (output_queue_.empty()) + { + output_queue_.push_back("\n"); + + // Signal that the output queue contains messages. Modifying the + // expiry will wake the output actor, if it is waiting on the timer. + non_empty_output_queue_.expires_at(steady_timer::time_point::min()); + } + } + + start_read(); + } + else + { + stop(); + } + } + + void await_output() + { + if (stopped()) + return; + + if (output_queue_.empty()) + { + // There are no messages that are ready to be sent. The actor goes to + // sleep by waiting on the non_empty_output_queue_ timer. When a new + // message is added, the timer will be modified and the actor will wake. + non_empty_output_queue_.expires_at(steady_timer::time_point::max()); + non_empty_output_queue_.async_wait( + boost::bind(&tcp_session::await_output, shared_from_this())); + } + else + { + start_write(); + } + } + + void start_write() + { + // Set a deadline for the write operation. + output_deadline_.expires_after(boost::asio::chrono::seconds(30)); + + // Start an asynchronous operation to send a message. + boost::asio::async_write(socket_, + boost::asio::buffer(output_queue_.front()), + boost::bind(&tcp_session::handle_write, + shared_from_this(), boost::placeholders::_1)); + } + + void handle_write(const boost::system::error_code& ec) + { + if (stopped()) + return; + + if (!ec) + { + output_queue_.pop_front(); + + await_output(); + } + else + { + stop(); + } + } + + void check_deadline(steady_timer* deadline) + { + if (stopped()) + return; + + // Check whether the deadline has passed. We compare the deadline against + // the current time since a new asynchronous operation may have moved the + // deadline before this actor had a chance to run. + if (deadline->expiry() <= steady_timer::clock_type::now()) + { + // The deadline has passed. Stop the session. The other actors will + // terminate as soon as possible. + stop(); + } + else + { + // Put the actor back to sleep. + deadline->async_wait( + boost::bind(&tcp_session::check_deadline, + shared_from_this(), deadline)); + } + } + + channel& channel_; + tcp::socket socket_; + std::string input_buffer_; + steady_timer input_deadline_; + std::deque<std::string> output_queue_; + steady_timer non_empty_output_queue_; + steady_timer output_deadline_; +}; + +typedef boost::shared_ptr<tcp_session> tcp_session_ptr; + +//---------------------------------------------------------------------- + +class udp_broadcaster + : public subscriber +{ +public: + udp_broadcaster(boost::asio::io_context& io_context, + const udp::endpoint& broadcast_endpoint) + : socket_(io_context) + { + socket_.connect(broadcast_endpoint); + socket_.set_option(udp::socket::broadcast(true)); + } + +private: + void deliver(const std::string& msg) + { + boost::system::error_code ignored_ec; + socket_.send(boost::asio::buffer(msg), 0, ignored_ec); + } + + udp::socket socket_; +}; + +//---------------------------------------------------------------------- + +class server +{ +public: + server(boost::asio::io_context& io_context, + const tcp::endpoint& listen_endpoint, + const udp::endpoint& broadcast_endpoint) + : io_context_(io_context), + acceptor_(io_context, listen_endpoint) + { + subscriber_ptr bc(new udp_broadcaster(io_context_, broadcast_endpoint)); + channel_.join(bc); + + start_accept(); + } + + void start_accept() + { + tcp_session_ptr new_session(new tcp_session(io_context_, channel_)); + + acceptor_.async_accept(new_session->socket(), + boost::bind(&server::handle_accept, + this, new_session, boost::placeholders::_1)); + } + + void handle_accept(tcp_session_ptr session, + const boost::system::error_code& ec) + { + if (!ec) + { + session->start(); + } + + start_accept(); + } + +private: + boost::asio::io_context& io_context_; + tcp::acceptor acceptor_; + channel channel_; +}; + +//---------------------------------------------------------------------- + +int main(int argc, char* argv[]) +{ + try + { + using namespace std; // For atoi. + + if (argc != 4) + { + std::cerr << "Usage: server <listen_port> <bcast_address> <bcast_port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + tcp::endpoint listen_endpoint(tcp::v4(), atoi(argv[1])); + + udp::endpoint broadcast_endpoint( + boost::asio::ip::make_address(argv[2]), atoi(argv[3])); + + server s(io_context, listen_endpoint, broadcast_endpoint); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/timers/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/timers/Jamfile.v2 new file mode 100644 index 000000000..7c57391ed --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/timers/Jamfile.v2 @@ -0,0 +1,30 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe time_t_timer + : time_t_timer.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp03/timers/time_t_timer.cpp b/src/boost/libs/asio/example/cpp03/timers/time_t_timer.cpp new file mode 100644 index 000000000..6efc29ebc --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/timers/time_t_timer.cpp @@ -0,0 +1,106 @@ +// +// time_t_timer.cpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio.hpp> +#include <ctime> +#include <iostream> + +// A custom implementation of the Clock concept from the standard C++ library. +struct time_t_clock +{ + // The duration type. + typedef boost::asio::chrono::steady_clock::duration duration; + + // The duration's underlying arithmetic representation. + typedef duration::rep rep; + + // The ratio representing the duration's tick period. + typedef duration::period period; + + // An absolute time point represented using the clock. + typedef boost::asio::chrono::time_point<time_t_clock> time_point; + + // The clock is not monotonically increasing. + static const bool is_steady = false; + + // Get the current time. + static time_point now() + { + return time_point() + boost::asio::chrono::seconds(std::time(0)); + } +}; + +// The boost::asio::basic_waitable_timer template accepts an optional WaitTraits +// template parameter. The underlying time_t clock has one-second granularity, +// so these traits may be customised to reduce the latency between the clock +// ticking over and a wait operation's completion. When the timeout is near +// (less than one second away) we poll the clock more frequently to detect the +// time change closer to when it occurs. The user can select the appropriate +// trade off between accuracy and the increased CPU cost of polling. In extreme +// cases, a zero duration may be returned to make the timers as accurate as +// possible, albeit with 100% CPU usage. +struct time_t_wait_traits +{ + // Determine how long until the clock should be next polled to determine + // whether the duration has elapsed. + static time_t_clock::duration to_wait_duration( + const time_t_clock::duration& d) + { + if (d > boost::asio::chrono::seconds(1)) + return d - boost::asio::chrono::seconds(1); + else if (d > boost::asio::chrono::seconds(0)) + return boost::asio::chrono::milliseconds(10); + else + return boost::asio::chrono::seconds(0); + } + + // Determine how long until the clock should be next polled to determine + // whether the absoluate time has been reached. + static time_t_clock::duration to_wait_duration( + const time_t_clock::time_point& t) + { + return to_wait_duration(t - time_t_clock::now()); + } +}; + +typedef boost::asio::basic_waitable_timer< + time_t_clock, time_t_wait_traits> time_t_timer; + +void handle_timeout(const boost::system::error_code&) +{ + std::cout << "handle_timeout\n"; +} + +int main() +{ + try + { + boost::asio::io_context io_context; + + time_t_timer timer(io_context); + + timer.expires_after(boost::asio::chrono::seconds(5)); + std::cout << "Starting synchronous wait\n"; + timer.wait(); + std::cout << "Finished synchronous wait\n"; + + timer.expires_after(boost::asio::chrono::seconds(5)); + std::cout << "Starting asynchronous wait\n"; + timer.async_wait(&handle_timeout); + io_context.run(); + std::cout << "Finished asynchronous wait\n"; + } + catch (std::exception& e) + { + std::cout << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/tutorial/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/tutorial/Jamfile.v2 new file mode 100644 index 000000000..3cc39ec0e --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/tutorial/Jamfile.v2 @@ -0,0 +1,67 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <library>/boost/thread//boost_thread + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +obj timer1.obj : timer1/timer.cpp ; +exe timer1 : timer1.obj ; + +obj timer2.obj : timer2/timer.cpp ; +exe timer2 : timer2.obj ; + +obj timer3.obj : timer3/timer.cpp ; +exe timer3 : timer3.obj ; + +obj timer4.obj : timer4/timer.cpp ; +exe timer4 : timer4.obj ; + +obj timer5.obj : timer5/timer.cpp ; +exe timer5 : timer5.obj ; + +obj daytime1_client.obj : daytime1/client.cpp ; +exe daytime1_client : daytime1_client.obj ; + +obj daytime2_server.obj : daytime2/server.cpp ; +exe daytime2_server : daytime2_server.obj ; + +obj daytime3_server.obj : daytime3/server.cpp ; +exe daytime3_server : daytime3_server.obj ; + +obj daytime4_client.obj : daytime4/client.cpp ; +exe daytime4_client : daytime4_client.obj ; + +obj daytime5_server.obj : daytime5/server.cpp ; +exe daytime5_server : daytime5_server.obj ; + +obj daytime6_server.obj : daytime6/server.cpp ; +exe daytime6_server : daytime6_server.obj ; + +obj daytime7_server.obj : daytime7/server.cpp ; +exe daytime7_server : daytime7_server.obj ; diff --git a/src/boost/libs/asio/example/cpp03/tutorial/daytime1/client.cpp b/src/boost/libs/asio/example/cpp03/tutorial/daytime1/client.cpp new file mode 100644 index 000000000..42acecaef --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/tutorial/daytime1/client.cpp @@ -0,0 +1,57 @@ +// +// client.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <boost/array.hpp> +#include <boost/asio.hpp> + +using boost::asio::ip::tcp; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: client <host>" << std::endl; + return 1; + } + + boost::asio::io_context io_context; + + tcp::resolver resolver(io_context); + tcp::resolver::results_type endpoints = + resolver.resolve(argv[1], "daytime"); + + tcp::socket socket(io_context); + boost::asio::connect(socket, endpoints); + + for (;;) + { + boost::array<char, 128> buf; + boost::system::error_code error; + + size_t len = socket.read_some(boost::asio::buffer(buf), error); + + if (error == boost::asio::error::eof) + break; // Connection closed cleanly by peer. + else if (error) + throw boost::system::system_error(error); // Some other error. + + std::cout.write(buf.data(), len); + } + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/tutorial/daytime2/server.cpp b/src/boost/libs/asio/example/cpp03/tutorial/daytime2/server.cpp new file mode 100644 index 000000000..332eb159f --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/tutorial/daytime2/server.cpp @@ -0,0 +1,50 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <ctime> +#include <iostream> +#include <string> +#include <boost/asio.hpp> + +using boost::asio::ip::tcp; + +std::string make_daytime_string() +{ + using namespace std; // For time_t, time and ctime; + time_t now = time(0); + return ctime(&now); +} + +int main() +{ + try + { + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), 13)); + + for (;;) + { + tcp::socket socket(io_context); + acceptor.accept(socket); + + std::string message = make_daytime_string(); + + boost::system::error_code ignored_error; + boost::asio::write(socket, boost::asio::buffer(message), ignored_error); + } + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/tutorial/daytime3/server.cpp b/src/boost/libs/asio/example/cpp03/tutorial/daytime3/server.cpp new file mode 100644 index 000000000..01a2a8838 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/tutorial/daytime3/server.cpp @@ -0,0 +1,119 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <ctime> +#include <iostream> +#include <string> +#include <boost/bind/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/asio.hpp> + +using boost::asio::ip::tcp; + +std::string make_daytime_string() +{ + using namespace std; // For time_t, time and ctime; + time_t now = time(0); + return ctime(&now); +} + +class tcp_connection + : public boost::enable_shared_from_this<tcp_connection> +{ +public: + typedef boost::shared_ptr<tcp_connection> pointer; + + static pointer create(boost::asio::io_context& io_context) + { + return pointer(new tcp_connection(io_context)); + } + + tcp::socket& socket() + { + return socket_; + } + + void start() + { + message_ = make_daytime_string(); + + boost::asio::async_write(socket_, boost::asio::buffer(message_), + boost::bind(&tcp_connection::handle_write, shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + +private: + tcp_connection(boost::asio::io_context& io_context) + : socket_(io_context) + { + } + + void handle_write(const boost::system::error_code& /*error*/, + size_t /*bytes_transferred*/) + { + } + + tcp::socket socket_; + std::string message_; +}; + +class tcp_server +{ +public: + tcp_server(boost::asio::io_context& io_context) + : io_context_(io_context), + acceptor_(io_context, tcp::endpoint(tcp::v4(), 13)) + { + start_accept(); + } + +private: + void start_accept() + { + tcp_connection::pointer new_connection = + tcp_connection::create(io_context_); + + acceptor_.async_accept(new_connection->socket(), + boost::bind(&tcp_server::handle_accept, this, new_connection, + boost::asio::placeholders::error)); + } + + void handle_accept(tcp_connection::pointer new_connection, + const boost::system::error_code& error) + { + if (!error) + { + new_connection->start(); + } + + start_accept(); + } + + boost::asio::io_context& io_context_; + tcp::acceptor acceptor_; +}; + +int main() +{ + try + { + boost::asio::io_context io_context; + tcp_server server(io_context); + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/tutorial/daytime4/client.cpp b/src/boost/libs/asio/example/cpp03/tutorial/daytime4/client.cpp new file mode 100644 index 000000000..df3092da6 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/tutorial/daytime4/client.cpp @@ -0,0 +1,52 @@ +// +// client.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <boost/array.hpp> +#include <boost/asio.hpp> + +using boost::asio::ip::udp; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: client <host>" << std::endl; + return 1; + } + + boost::asio::io_context io_context; + + udp::resolver resolver(io_context); + udp::endpoint receiver_endpoint = + *resolver.resolve(udp::v4(), argv[1], "daytime").begin(); + + udp::socket socket(io_context); + socket.open(udp::v4()); + + boost::array<char, 1> send_buf = {{ 0 }}; + socket.send_to(boost::asio::buffer(send_buf), receiver_endpoint); + + boost::array<char, 128> recv_buf; + udp::endpoint sender_endpoint; + size_t len = socket.receive_from( + boost::asio::buffer(recv_buf), sender_endpoint); + + std::cout.write(recv_buf.data(), len); + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/tutorial/daytime5/server.cpp b/src/boost/libs/asio/example/cpp03/tutorial/daytime5/server.cpp new file mode 100644 index 000000000..316a72923 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/tutorial/daytime5/server.cpp @@ -0,0 +1,53 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <ctime> +#include <iostream> +#include <string> +#include <boost/array.hpp> +#include <boost/asio.hpp> + +using boost::asio::ip::udp; + +std::string make_daytime_string() +{ + using namespace std; // For time_t, time and ctime; + time_t now = time(0); + return ctime(&now); +} + +int main() +{ + try + { + boost::asio::io_context io_context; + + udp::socket socket(io_context, udp::endpoint(udp::v4(), 13)); + + for (;;) + { + boost::array<char, 1> recv_buf; + udp::endpoint remote_endpoint; + socket.receive_from(boost::asio::buffer(recv_buf), remote_endpoint); + + std::string message = make_daytime_string(); + + boost::system::error_code ignored_error; + socket.send_to(boost::asio::buffer(message), + remote_endpoint, 0, ignored_error); + } + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/tutorial/daytime6/server.cpp b/src/boost/libs/asio/example/cpp03/tutorial/daytime6/server.cpp new file mode 100644 index 000000000..df1f2fa47 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/tutorial/daytime6/server.cpp @@ -0,0 +1,89 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <ctime> +#include <iostream> +#include <string> +#include <boost/array.hpp> +#include <boost/bind/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/asio.hpp> + +using boost::asio::ip::udp; + +std::string make_daytime_string() +{ + using namespace std; // For time_t, time and ctime; + time_t now = time(0); + return ctime(&now); +} + +class udp_server +{ +public: + udp_server(boost::asio::io_context& io_context) + : socket_(io_context, udp::endpoint(udp::v4(), 13)) + { + start_receive(); + } + +private: + void start_receive() + { + socket_.async_receive_from( + boost::asio::buffer(recv_buffer_), remote_endpoint_, + boost::bind(&udp_server::handle_receive, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + + void handle_receive(const boost::system::error_code& error, + std::size_t /*bytes_transferred*/) + { + if (!error) + { + boost::shared_ptr<std::string> message( + new std::string(make_daytime_string())); + + socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_, + boost::bind(&udp_server::handle_send, this, message, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + + start_receive(); + } + } + + void handle_send(boost::shared_ptr<std::string> /*message*/, + const boost::system::error_code& /*error*/, + std::size_t /*bytes_transferred*/) + { + } + + udp::socket socket_; + udp::endpoint remote_endpoint_; + boost::array<char, 1> recv_buffer_; +}; + +int main() +{ + try + { + boost::asio::io_context io_context; + udp_server server(io_context); + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/tutorial/daytime7/server.cpp b/src/boost/libs/asio/example/cpp03/tutorial/daytime7/server.cpp new file mode 100644 index 000000000..f52b25754 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/tutorial/daytime7/server.cpp @@ -0,0 +1,160 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <ctime> +#include <iostream> +#include <string> +#include <boost/array.hpp> +#include <boost/bind/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/asio.hpp> + +using boost::asio::ip::tcp; +using boost::asio::ip::udp; + +std::string make_daytime_string() +{ + using namespace std; // For time_t, time and ctime; + time_t now = time(0); + return ctime(&now); +} + +class tcp_connection + : public boost::enable_shared_from_this<tcp_connection> +{ +public: + typedef boost::shared_ptr<tcp_connection> pointer; + + static pointer create(boost::asio::io_context& io_context) + { + return pointer(new tcp_connection(io_context)); + } + + tcp::socket& socket() + { + return socket_; + } + + void start() + { + message_ = make_daytime_string(); + + boost::asio::async_write(socket_, boost::asio::buffer(message_), + boost::bind(&tcp_connection::handle_write, shared_from_this())); + } + +private: + tcp_connection(boost::asio::io_context& io_context) + : socket_(io_context) + { + } + + void handle_write() + { + } + + tcp::socket socket_; + std::string message_; +}; + +class tcp_server +{ +public: + tcp_server(boost::asio::io_context& io_context) + : io_context_(io_context), + acceptor_(io_context, tcp::endpoint(tcp::v4(), 13)) + { + start_accept(); + } + +private: + void start_accept() + { + tcp_connection::pointer new_connection = + tcp_connection::create(io_context_); + + acceptor_.async_accept(new_connection->socket(), + boost::bind(&tcp_server::handle_accept, this, new_connection, + boost::asio::placeholders::error)); + } + + void handle_accept(tcp_connection::pointer new_connection, + const boost::system::error_code& error) + { + if (!error) + { + new_connection->start(); + } + + start_accept(); + } + + boost::asio::io_context& io_context_; + tcp::acceptor acceptor_; +}; + +class udp_server +{ +public: + udp_server(boost::asio::io_context& io_context) + : socket_(io_context, udp::endpoint(udp::v4(), 13)) + { + start_receive(); + } + +private: + void start_receive() + { + socket_.async_receive_from( + boost::asio::buffer(recv_buffer_), remote_endpoint_, + boost::bind(&udp_server::handle_receive, this, + boost::asio::placeholders::error)); + } + + void handle_receive(const boost::system::error_code& error) + { + if (!error) + { + boost::shared_ptr<std::string> message( + new std::string(make_daytime_string())); + + socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_, + boost::bind(&udp_server::handle_send, this, message)); + + start_receive(); + } + } + + void handle_send(boost::shared_ptr<std::string> /*message*/) + { + } + + udp::socket socket_; + udp::endpoint remote_endpoint_; + boost::array<char, 1> recv_buffer_; +}; + +int main() +{ + try + { + boost::asio::io_context io_context; + tcp_server server1(io_context); + udp_server server2(io_context); + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/tutorial/daytime_dox.txt b/src/boost/libs/asio/example/cpp03/tutorial/daytime_dox.txt new file mode 100644 index 000000000..5ec49c67c --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/tutorial/daytime_dox.txt @@ -0,0 +1,500 @@ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** +\page tutdaytime1 Daytime.1 - A synchronous TCP daytime client + +This tutorial program shows how to use asio to implement a client application +with TCP. + +\dontinclude daytime1/client.cpp +\skip #include + +We start by including the necessary header files. + +\until asio.hpp + +The purpose of this application is to access a daytime service, +so we need the user to specify the server. + +\until } + +All programs that use asio need to have at least one boost::asio::io_context +object. + +\until boost::asio::io_context + +We need to turn the server name that was specified as a parameter to the +application, into a TCP endpoint. To do this we use an +boost::asio::ip::tcp::resolver object. + +\until tcp::resolver + +A resolver takes a host name and service name and turns them into a list of +endpoints. We perform a resolve call using the name of the server, specified in +<tt>argv[1]</tt>, and the name of the service, in this case <tt>"daytime"</tt>. + +The list of endpoints is returned using an object of type +boost::asio::ip::tcp::resolver::results_type. This object is a range, with begin() and +end() member functions that may be used for iterating over the results. + +\until resolver.resolve + +Now we create and connect the socket. The list of endpoints obtained above may +contain both IPv4 and IPv6 endpoints, so we need to try each of them until we +find one that works. This keeps the client program independent of a specific IP +version. The boost::asio::connect() function does this for us automatically. + +\until boost::asio::connect + +The connection is open. All we need to do now is read the response from the +daytime service. + +We use a <tt>boost::array</tt> to hold the received data. The boost::asio::buffer() +function automatically determines the size of the array to help prevent buffer +overruns. Instead of a <tt>boost::array</tt>, we could have used a <tt>char +[]</tt> or <tt>std::vector</tt>. + +\until read_some + +When the server closes the connection, the boost::asio::ip::tcp::socket::read_some() +function will exit with the boost::asio::error::eof error, which is how we know to +exit the loop. + +\until } + +Finally, handle any exceptions that may have been thrown. + +\until } +\until } + +See the \ref tutdaytime1src "full source listing" \n +Return to the \ref index "tutorial index" \n +Next: \ref tutdaytime2 + +*/ + +/** +\page tutdaytime1src Source listing for Daytime.1 +\include daytime1/client.cpp +Return to \ref tutdaytime1 +*/ + +/** +\page tutdaytime2 Daytime.2 - A synchronous TCP daytime server + +This tutorial program shows how to use asio to implement a server application +with TCP. + +\dontinclude daytime2/server.cpp +\skip #include + +\until using + +We define the function <tt>make_daytime_string()</tt> to create the string to +be sent back to the client. This function will be reused in all of our daytime +server applications. + +\until boost::asio::io_context + +A boost::asio::ip::tcp::acceptor object needs to be created to listen +for new connections. It is initialised to listen on TCP port 13, for IP version 4. + +\until tcp::acceptor + +This is an iterative server, which means that it will handle one +connection at a time. Create a socket that will represent the connection to the +client, and then wait for a connection. + +\until acceptor.accept + +A client is accessing our service. Determine the current time +and transfer this information to the client. + +\until } +\until } + +Finally, handle any exceptions. + +\until } +\until } + +See the \ref tutdaytime2src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tutdaytime1 \n +Next: \ref tutdaytime3 + +*/ + +/** +\page tutdaytime2src Source listing for Daytime.2 +\include daytime2/server.cpp +Return to \ref tutdaytime2 +*/ + +/** +\page tutdaytime3 Daytime.3 - An asynchronous TCP daytime server + +\section tutdaytime3funcmain The main() function + +\dontinclude daytime3/server.cpp +\skip int main() +\until try +\until { + +We need to create a server object to accept incoming client connections. The +boost::asio::io_context object provides I/O services, such as sockets, that the +server object will use. + +\until tcp_server + +Run the boost::asio::io_context object so that it will perform asynchronous operations +on your behalf. + +\until return 0; +\until } + +\section tutdaytime3classtcp_server The tcp_server class + +\dontinclude daytime3/server.cpp +\skip class tcp_server +\until public: + +The constructor initialises an acceptor to listen on TCP port 13. + +\until private: + +The function <tt>start_accept()</tt> creates a socket and initiates an +asynchronous accept operation to wait for a new connection. + +\until } + +The function <tt>handle_accept()</tt> is called when the asynchronous accept +operation initiated by <tt>start_accept()</tt> finishes. It services the client +request, and then calls <tt>start_accept()</tt> to initiate the next accept +operation. + +\until } +\until } + +\section tutdaytime3classtcp_connection The tcp_connection class + +We will use <tt>shared_ptr</tt> and <tt>enable_shared_from_this</tt> because we +want to keep the <tt>tcp_connection</tt> object alive as long as there is an +operation that refers to it. + +\dontinclude daytime3/server.cpp +\skip class tcp_connection +\until shared_ptr +\until } +\until } + +In the function <tt>start()</tt>, we call boost::asio::async_write() to serve the data +to the client. Note that we are using boost::asio::async_write(), rather than +boost::asio::ip::tcp::socket::async_write_some(), to ensure that the entire block of +data is sent. + +\until { + +The data to be sent is stored in the class member <tt>message_</tt> as we need +to keep the data valid until the asynchronous operation is complete. + +\until message_ + +When initiating the asynchronous operation, and if using boost::bind(), you +must specify only the arguments that match the handler's parameter list. In +this program, both of the argument placeholders (boost::asio::placeholders::error and +boost::asio::placeholders::bytes_transferred) could potentially have been removed, +since they are not being used in <tt>handle_write()</tt>. + +\until placeholders::bytes_transferred + +Any further actions for this client connection are now the responsibility of +<tt>handle_write()</tt>. + +\until }; + +\section tutdaytime3remunused Removing unused handler parameters + +You may have noticed that the <tt>error</tt>, and <tt>bytes_transferred</tt> +parameters are not used in the body of the <tt>handle_write()</tt> function. If +parameters are not needed, it is possible to remove them from the function so +that it looks like: + +\code + void handle_write() + { + } +\endcode + +The boost::asio::async_write() call used to initiate the call can then be changed to +just: + +\code + boost::asio::async_write(socket_, boost::asio::buffer(message_), + boost::bind(&tcp_connection::handle_write, shared_from_this())); +\endcode + +See the \ref tutdaytime3src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tutdaytime2 \n +Next: \ref tutdaytime4 + +*/ + +/** +\page tutdaytime3src Source listing for Daytime.3 +\include daytime3/server.cpp +Return to \ref tutdaytime3 +*/ + +/** +\page tutdaytime4 Daytime.4 - A synchronous UDP daytime client + +This tutorial program shows how to use asio to implement a client application +with UDP. + +\dontinclude daytime4/client.cpp +\skip #include +\until using boost::asio::ip::udp; + +The start of the application is essentially the same as for the TCP daytime +client. + +\until boost::asio::io_context + +We use an boost::asio::ip::udp::resolver object to find the correct remote endpoint to +use based on the host and service names. The query is restricted to return only +IPv4 endpoints by the boost::asio::ip::udp::v4() argument. + +\until udp::v4 + +The boost::asio::ip::udp::resolver::resolve() function is guaranteed to return at +least one endpoint in the list if it does not fail. This means it is safe to +dereference the return value directly. + +\until udp::endpoint + +Since UDP is datagram-oriented, we will not be using a stream socket. Create an +boost::asio::ip::udp::socket and initiate contact with the remote endpoint. + +\until receiver_endpoint + +Now we need to be ready to accept whatever the server sends back to us. The +endpoint on our side that receives the server's response will be initialised by +boost::asio::ip::udp::socket::receive_from(). + +\until } + +Finally, handle any exceptions that may have been thrown. + +\until } +\until } +See the \ref tutdaytime4src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tutdaytime3 \n +Next: \ref tutdaytime5 + +*/ + +/** +\page tutdaytime4src Source listing for Daytime.4 +\include daytime4/client.cpp +Return to \ref tutdaytime4 +*/ + +/** +\page tutdaytime5 Daytime.5 - A synchronous UDP daytime server + +This tutorial program shows how to use asio to implement a server application +with UDP. + +\dontinclude daytime5/server.cpp +\skip int main() +\until boost::asio::io_context + +Create an boost::asio::ip::udp::socket object to receive requests on UDP port 13. + +\until udp::socket + +Wait for a client to initiate contact with us. The remote_endpoint object will +be populated by boost::asio::ip::udp::socket::receive_from(). + +\until receive_from + +Determine what we are going to send back to the client. + +\until std::string message + +Send the response to the remote_endpoint. + +\until } +\until } + +Finally, handle any exceptions. + +\until } +\until } + +See the \ref tutdaytime5src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tutdaytime4 \n +Next: \ref tutdaytime6 + +*/ + +/** +\page tutdaytime5src Source listing for Daytime.5 +\include daytime5/server.cpp +Return to \ref tutdaytime5 +*/ + +/** +\page tutdaytime6 Daytime.6 - An asynchronous UDP daytime server + +\section tutdaytime6funcmain The main() function + +\dontinclude daytime6/server.cpp +\skip int main() +\until try +\until { + +Create a server object to accept incoming client requests, and run +the boost::asio::io_context object. + +\until return 0; +\until } + +\section tutdaytime6classudp_server The udp_server class + +\dontinclude daytime6/server.cpp +\skip class udp_server +\until public: + +The constructor initialises a socket to listen on UDP port 13. + +\until private: +\until { + +The function boost::asio::ip::udp::socket::async_receive_from() will cause the +application to listen in the background for a new request. When such a request +is received, the boost::asio::io_context object will invoke the +<tt>handle_receive()</tt> function with two arguments: a value of type +boost::system::error_code indicating whether the operation succeeded or failed, and a +<tt>size_t</tt> value <tt>bytes_transferred</tt> specifying the number of bytes +received. + +\until } + +The function <tt>handle_receive()</tt> will service the client request. + +\until { + +The <tt>error</tt> parameter contains the result of the asynchronous operation. +Since we only provide the 1-byte <tt>recv_buffer_</tt> to contain the client's +request, the boost::asio::io_context object would return an error if the client sent +anything larger. We can ignore such an error if it comes up. + +\until { + +Determine what we are going to send. + +\until make_daytime_string() + +We now call boost::asio::ip::udp::socket::async_send_to() to serve the data to the +client. + +\until boost::asio::placeholders::bytes_transferred + +When initiating the asynchronous operation, and if using boost::bind(), you +must specify only the arguments that match the handler's parameter list. In +this program, both of the argument placeholders (boost::asio::placeholders::error and +boost::asio::placeholders::bytes_transferred) could potentially have been removed. + +Start listening for the next client request. + +\until start_receive + +Any further actions for this client request are now the responsibility of +<tt>handle_send()</tt>. + +\until } +\until } + +The function <tt>handle_send()</tt> is invoked after the service request has +been completed. + +\until } +\until } + +See the \ref tutdaytime6src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tutdaytime5 \n +Next: \ref tutdaytime7 + +*/ + +/** +\page tutdaytime6src Source listing for Daytime.6 +\include daytime6/server.cpp +Return to \ref tutdaytime6 +*/ + +/** +\page tutdaytime7 Daytime.7 - A combined TCP/UDP asynchronous server + +This tutorial program shows how to combine the two asynchronous servers that we +have just written, into a single server application. + +\section tutdaytime7funcmain The main() function + +\dontinclude daytime7/server.cpp +\skip int main() +\until boost::asio::io_context + +We will begin by creating a server object to accept a TCP client connection. + +\until tcp_server + +We also need a server object to accept a UDP client request. + +\until udp_server + +We have created two lots of work for the boost::asio::io_context object to do. + +\until return 0; +\until } + +\section tutdaytime7classtcp The tcp_connection and tcp_server classes + +The following two classes are taken from \ref tutdaytime3 "Daytime.3". + +\dontinclude daytime7/server.cpp +\skip class tcp_connection +\until }; +\until }; + +\section tutdaytime7classudp The udp_server class + +Similarly, this next class is taken from the +\ref tutdaytime6 "previous tutorial step". + +\dontinclude daytime7/server.cpp +\skip class udp_server +\until }; + +See the \ref tutdaytime7src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tutdaytime6 + +*/ + +/** +\page tutdaytime7src Source listing for Daytime.7 +\include daytime7/server.cpp +Return to \ref tutdaytime7 +*/ diff --git a/src/boost/libs/asio/example/cpp03/tutorial/index_dox.txt b/src/boost/libs/asio/example/cpp03/tutorial/index_dox.txt new file mode 100644 index 000000000..a57c0f2d3 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/tutorial/index_dox.txt @@ -0,0 +1,48 @@ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** +\mainpage asio Tutorial + +\section tuttimer Basic Skills + +The tutorial programs in this first section introduce the fundamental concepts +required to use the asio toolkit. Before plunging into the complex world of +network programming, these tutorial programs illustrate the basic skills using +simple asynchronous timers. + +\li \ref tuttimer1 +\li \ref tuttimer2 +\li \ref tuttimer3 +\li \ref tuttimer4 +\li \ref tuttimer5 + +\section tutdaytime Introduction to Sockets + +The tutorial programs in this section show how to use asio to develop simple +client and server programs. These tutorial programs are based around the <a +href="http://www.ietf.org/rfc/rfc867.txt">daytime</a> protocol, which supports +both TCP and UDP. + +The first three tutorial programs implement the daytime protocol using TCP. + +\li \ref tutdaytime1 +\li \ref tutdaytime2 +\li \ref tutdaytime3 + +The next three tutorial programs implement the daytime protocol using UDP. + +\li \ref tutdaytime4 +\li \ref tutdaytime5 +\li \ref tutdaytime6 + +The last tutorial program in this section demonstrates how asio allows the TCP +and UDP servers to be easily combined into a single program. + +\li \ref tutdaytime7 + +*/ diff --git a/src/boost/libs/asio/example/cpp03/tutorial/timer1/timer.cpp b/src/boost/libs/asio/example/cpp03/tutorial/timer1/timer.cpp new file mode 100644 index 000000000..77906d15a --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/tutorial/timer1/timer.cpp @@ -0,0 +1,24 @@ +// +// timer.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <boost/asio.hpp> + +int main() +{ + boost::asio::io_context io; + + boost::asio::steady_timer t(io, boost::asio::chrono::seconds(5)); + t.wait(); + + std::cout << "Hello, world!" << std::endl; + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/tutorial/timer2/timer.cpp b/src/boost/libs/asio/example/cpp03/tutorial/timer2/timer.cpp new file mode 100644 index 000000000..030910b51 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/tutorial/timer2/timer.cpp @@ -0,0 +1,29 @@ +// +// timer.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <boost/asio.hpp> + +void print(const boost::system::error_code& /*e*/) +{ + std::cout << "Hello, world!" << std::endl; +} + +int main() +{ + boost::asio::io_context io; + + boost::asio::steady_timer t(io, boost::asio::chrono::seconds(5)); + t.async_wait(&print); + + io.run(); + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/tutorial/timer3/timer.cpp b/src/boost/libs/asio/example/cpp03/tutorial/timer3/timer.cpp new file mode 100644 index 000000000..44c9044de --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/tutorial/timer3/timer.cpp @@ -0,0 +1,43 @@ +// +// timer.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <boost/asio.hpp> +#include <boost/bind/bind.hpp> + +void print(const boost::system::error_code& /*e*/, + boost::asio::steady_timer* t, int* count) +{ + if (*count < 5) + { + std::cout << *count << std::endl; + ++(*count); + + t->expires_at(t->expiry() + boost::asio::chrono::seconds(1)); + t->async_wait(boost::bind(print, + boost::asio::placeholders::error, t, count)); + } +} + +int main() +{ + boost::asio::io_context io; + + int count = 0; + boost::asio::steady_timer t(io, boost::asio::chrono::seconds(1)); + t.async_wait(boost::bind(print, + boost::asio::placeholders::error, &t, &count)); + + io.run(); + + std::cout << "Final count is " << count << std::endl; + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/tutorial/timer4/timer.cpp b/src/boost/libs/asio/example/cpp03/tutorial/timer4/timer.cpp new file mode 100644 index 000000000..afcdcb396 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/tutorial/timer4/timer.cpp @@ -0,0 +1,54 @@ +// +// timer.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <boost/asio.hpp> +#include <boost/bind/bind.hpp> + +class printer +{ +public: + printer(boost::asio::io_context& io) + : timer_(io, boost::asio::chrono::seconds(1)), + count_(0) + { + timer_.async_wait(boost::bind(&printer::print, this)); + } + + ~printer() + { + std::cout << "Final count is " << count_ << std::endl; + } + + void print() + { + if (count_ < 5) + { + std::cout << count_ << std::endl; + ++count_; + + timer_.expires_at(timer_.expiry() + boost::asio::chrono::seconds(1)); + timer_.async_wait(boost::bind(&printer::print, this)); + } + } + +private: + boost::asio::steady_timer timer_; + int count_; +}; + +int main() +{ + boost::asio::io_context io; + printer p(io); + io.run(); + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/tutorial/timer5/timer.cpp b/src/boost/libs/asio/example/cpp03/tutorial/timer5/timer.cpp new file mode 100644 index 000000000..b5d48f8e2 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/tutorial/timer5/timer.cpp @@ -0,0 +1,81 @@ +// +// timer.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <boost/asio.hpp> +#include <boost/thread/thread.hpp> +#include <boost/bind/bind.hpp> + +class printer +{ +public: + printer(boost::asio::io_context& io) + : strand_(boost::asio::make_strand(io)), + timer1_(io, boost::asio::chrono::seconds(1)), + timer2_(io, boost::asio::chrono::seconds(1)), + count_(0) + { + timer1_.async_wait(boost::asio::bind_executor(strand_, + boost::bind(&printer::print1, this))); + + timer2_.async_wait(boost::asio::bind_executor(strand_, + boost::bind(&printer::print2, this))); + } + + ~printer() + { + std::cout << "Final count is " << count_ << std::endl; + } + + void print1() + { + if (count_ < 10) + { + std::cout << "Timer 1: " << count_ << std::endl; + ++count_; + + timer1_.expires_at(timer1_.expiry() + boost::asio::chrono::seconds(1)); + + timer1_.async_wait(boost::asio::bind_executor(strand_, + boost::bind(&printer::print1, this))); + } + } + + void print2() + { + if (count_ < 10) + { + std::cout << "Timer 2: " << count_ << std::endl; + ++count_; + + timer2_.expires_at(timer2_.expiry() + boost::asio::chrono::seconds(1)); + + timer2_.async_wait(boost::asio::bind_executor(strand_, + boost::bind(&printer::print2, this))); + } + } + +private: + boost::asio::strand<boost::asio::io_context::executor_type> strand_; + boost::asio::steady_timer timer1_; + boost::asio::steady_timer timer2_; + int count_; +}; + +int main() +{ + boost::asio::io_context io; + printer p(io); + boost::thread t(boost::bind(&boost::asio::io_context::run, &io)); + io.run(); + t.join(); + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp03/tutorial/timer_dox.txt b/src/boost/libs/asio/example/cpp03/tutorial/timer_dox.txt new file mode 100644 index 000000000..fdf7fb186 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/tutorial/timer_dox.txt @@ -0,0 +1,378 @@ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** +\page tuttimer1 Timer.1 - Using a timer synchronously + +This tutorial program introduces asio by showing how to perform a blocking +wait on a timer. + +\dontinclude timer1/timer.cpp +\skip #include + +We start by including the necessary header files. + +All of the asio classes can be used by simply including the <tt>"asio.hpp"</tt> +header file. + +\until asio.hpp + +All programs that use asio need to have at least one boost::asio::io_context object. +This class provides access to I/O functionality. We declare an object of this +type first thing in the main function. + +\until boost::asio::io_context + +Next we declare an object of type boost::asio::steady_timer. The core asio classes +that provide I/O functionality (or as in this case timer functionality) always +take a reference to an io_context as their first constructor argument. The +second argument to the constructor sets the timer to expire 5 seconds from now. + +\until boost::asio::steady_timer + +In this simple example we perform a blocking wait on the timer. +That is, the call to boost::asio::steady_timer::wait() will not return until the +timer has expired, 5 seconds after it was created (i.e. <b>not</b> from when the +wait starts). + +A timer is always in one of two states: "expired" or "not expired". If the +boost::asio::steady_timer::wait() function is called on an expired timer, it will +return immediately. + +\until wait + +Finally we print the obligatory <tt>"Hello, world!"</tt> +message to show when the timer has expired. + +\until } + +See the \ref tuttimer1src "full source listing" \n +Return to the \ref index "tutorial index" \n +Next: \ref tuttimer2 + +*/ + +/** +\page tuttimer1src Source listing for Timer.1 +\include timer1/timer.cpp +Return to \ref tuttimer1 +*/ + +/** +\page tuttimer2 Timer.2 - Using a timer asynchronously + +This tutorial program demonstrates how to use asio's asynchronous callback +functionality by modifying the program from tutorial Timer.1 to perform an +asynchronous wait on the timer. + +\dontinclude timer2/timer.cpp +\skip #include + +\until asio.hpp + +Using asio's asynchronous functionality means having a callback +function that will be called when an asynchronous operation completes. In this +program we define a function called <tt>print</tt> to be called when the +asynchronous wait finishes. + +\until boost::asio::steady_timer + +Next, instead of doing a blocking wait as in tutorial Timer.1, +we call the boost::asio::steady_timer::async_wait() function to perform an +asynchronous wait. When calling this function we pass the <tt>print</tt> +callback handler that was defined above. + +\skipline async_wait + +Finally, we must call the boost::asio::io_context::run() member function +on the io_context object. + +The asio library provides a guarantee that callback handlers will <b>only</b> +be called from threads that are currently calling boost::asio::io_context::run(). +Therefore unless the boost::asio::io_context::run() function is called the callback for +the asynchronous wait completion will never be invoked. + +The boost::asio::io_context::run() function will also continue to run while there is +still "work" to do. In this example, the work is the asynchronous wait on the +timer, so the call will not return until the timer has expired and the +callback has completed. + +It is important to remember to give the io_context some work to do before +calling boost::asio::io_context::run(). For example, if we had omitted the above call +to boost::asio::steady_timer::async_wait(), the io_context would not have had any +work to do, and consequently boost::asio::io_context::run() would have returned +immediately. + +\skip run +\until } + +See the \ref tuttimer2src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tuttimer1 \n +Next: \ref tuttimer3 + +*/ + +/** +\page tuttimer2src Source listing for Timer.2 +\include timer2/timer.cpp +Return to \ref tuttimer2 +*/ + +/** +\page tuttimer3 Timer.3 - Binding arguments to a handler + +In this tutorial we will modify the program from tutorial Timer.2 so that the +timer fires once a second. This will show how to pass additional parameters to +your handler function. + +\dontinclude timer3/timer.cpp +\skip #include + +\until bind.hpp + +To implement a repeating timer using asio you need to change +the timer's expiry time in your callback function, and to then start a new +asynchronous wait. Obviously this means that the callback function will need +to be able to access the timer object. To this end we add two new parameters +to the <tt>print</tt> function: + +\li A pointer to a timer object. + +\li A counter so that we can stop the program when the timer fires for the +sixth time. + +\until { + +As mentioned above, this tutorial program uses a counter to +stop running when the timer fires for the sixth time. However you will observe +that there is no explicit call to ask the io_context to stop. Recall that in +tutorial Timer.2 we learnt that the boost::asio::io_context::run() function completes +when there is no more "work" to do. By not starting a new asynchronous wait on +the timer when <tt>count</tt> reaches 5, the io_context will run out of work and +stop running. + +\until ++ + +Next we move the expiry time for the timer along by one second +from the previous expiry time. By calculating the new expiry time relative to +the old, we can ensure that the timer does not drift away from the +whole-second mark due to any delays in processing the handler. + +\until expires_at + +Then we start a new asynchronous wait on the timer. As you can +see, the boost::bind() function is used to associate the extra parameters +with your callback handler. The boost::asio::steady_timer::async_wait() function +expects a handler function (or function object) with the signature +<tt>void(const boost::system::error_code&)</tt>. Binding the additional parameters +converts your <tt>print</tt> function into a function object that matches the +signature correctly. + +See the <a href="http://www.boost.org/libs/bind/bind.html">Boost.Bind +documentation</a> for more information on how to use boost::bind(). + +In this example, the boost::asio::placeholders::error argument to boost::bind() is a +named placeholder for the error object passed to the handler. When initiating +the asynchronous operation, and if using boost::bind(), you must specify only +the arguments that match the handler's parameter list. In tutorial Timer.4 you +will see that this placeholder may be elided if the parameter is not needed by +the callback handler. + +\until boost::asio::io_context + +A new <tt>count</tt> variable is added so that we can stop the +program when the timer fires for the sixth time. + +\until boost::asio::steady_timer + +As in Step 4, when making the call to +boost::asio::steady_timer::async_wait() from <tt>main</tt> we bind the additional +parameters needed for the <tt>print</tt> function. + +\until run + +Finally, just to prove that the <tt>count</tt> variable was +being used in the <tt>print</tt> handler function, we will print out its new +value. + +\until } + +See the \ref tuttimer3src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tuttimer2 \n +Next: \ref tuttimer4 + +*/ + +/** +\page tuttimer3src Source listing for Timer.3 +\include timer3/timer.cpp +Return to \ref tuttimer3 +*/ + +/** +\page tuttimer4 Timer.4 - Using a member function as a handler + +In this tutorial we will see how to use a class member function as a callback +handler. The program should execute identically to the tutorial program from +tutorial Timer.3. + +\dontinclude timer4/timer.cpp +\skip #include + +\until bind.hpp + +Instead of defining a free function <tt>print</tt> as the +callback handler, as we did in the earlier tutorial programs, we now define a +class called <tt>printer</tt>. + +\until public + +The constructor of this class will take a reference to the +io_context object and use it when initialising the <tt>timer_</tt> member. The +counter used to shut down the program is now also a member of the class. + +\until { + +The boost::bind() function works just as well with class +member functions as with free functions. Since all non-static class member +functions have an implicit <tt>this</tt> parameter, we need to bind +<tt>this</tt> to the function. As in tutorial Timer.3, boost::bind() +converts our callback handler (now a member function) into a function object +that can be invoked as though it has the signature <tt>void(const +boost::system::error_code&)</tt>. + +You will note that the boost::asio::placeholders::error placeholder is not specified +here, as the <tt>print</tt> member function does not accept an error object as +a parameter. + +\until } + +In the class destructor we will print out the final value of +the counter. + +\until } + +The <tt>print</tt> member function is very similar to the +<tt>print</tt> function from tutorial Timer.3, except that it now operates on +the class data members instead of having the timer and counter passed in as +parameters. + +\until }; + +The <tt>main</tt> function is much simpler than before, as it +now declares a local <tt>printer</tt> object before running the io_context as +normal. + +\until } + +See the \ref tuttimer4src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tuttimer3 \n +Next: \ref tuttimer5 \n + +*/ + +/** +\page tuttimer4src Source listing for Timer.4 +\include timer4/timer.cpp +Return to \ref tuttimer4 +*/ + +/** +\page tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs + +This tutorial demonstrates the use of the boost::asio::strand class template to +synchronise callback handlers in a multithreaded program. + +The previous four tutorials avoided the issue of handler synchronisation by +calling the boost::asio::io_context::run() function from one thread only. As you +already know, the asio library provides a guarantee that callback handlers will +<b>only</b> be called from threads that are currently calling +boost::asio::io_context::run(). Consequently, calling boost::asio::io_context::run() from +only one thread ensures that callback handlers cannot run concurrently. + +The single threaded approach is usually the best place to start when +developing applications using asio. The downside is the limitations it places +on programs, particularly servers, including: + +<ul> +<li>Poor responsiveness when handlers can take a long time to complete.</li> +<li>An inability to scale on multiprocessor systems.</li> +</ul> + +If you find yourself running into these limitations, an alternative approach +is to have a pool of threads calling boost::asio::io_context::run(). However, as this +allows handlers to execute concurrently, we need a method of synchronisation +when handlers might be accessing a shared, thread-unsafe resource. + +\dontinclude timer5/timer.cpp +\skip #include + +\until bind.hpp + +We start by defining a class called <tt>printer</tt>, similar +to the class in the previous tutorial. This class will extend the previous +tutorial by running two timers in parallel. + +\until public + +In addition to initialising a pair of boost::asio::steady_timer members, the +constructor initialises the <tt>strand_</tt> member, an object of type +boost::asio::strand<boost::asio::io_context::executor_type>. + +The boost::asio::strand class template is an executor adapter that guarantees +that, for those handlers that are dispatched through it, an executing handler +will be allowed to complete before the next one is started. This is guaranteed +irrespective of the number of threads that are calling +boost::asio::io_context::run(). Of course, the handlers may still execute +concurrently with other handlers that were <b>not</b> dispatched through an +boost::asio::strand, or were dispatched through a different boost::asio::strand +object. + +\until { + +When initiating the asynchronous operations, each callback handler is "bound" +to an boost::asio::strand<boost::asio::io_context::executor_type> object. The +boost::asio::bind_executor() function returns a new handler that automatically +dispatches its contained handler through the boost::asio::strand object. By +binding the handlers to the same boost::asio::strand, we are ensuring that they +cannot execute concurrently. + +\until } +\until } + +In a multithreaded program, the handlers for asynchronous +operations should be synchronised if they access shared resources. In this +tutorial, the shared resources used by the handlers (<tt>print1</tt> and +<tt>print2</tt>) are <tt>std::cout</tt> and the <tt>count_</tt> data member. + +\until }; + +The <tt>main</tt> function now causes boost::asio::io_context::run() to +be called from two threads: the main thread and one additional thread. This is +accomplished using an boost::thread object. + +Just as it would with a call from a single thread, concurrent calls to +boost::asio::io_context::run() will continue to execute while there is "work" left to +do. The background thread will not exit until all asynchronous operations have +completed. + +\until } + +See the \ref tuttimer5src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tuttimer4 \n + +*/ + +/** +\page tuttimer5src Source listing for Timer.5 +\include timer5/timer.cpp +Return to \ref tuttimer5 +*/ diff --git a/src/boost/libs/asio/example/cpp03/windows/Jamfile.v2 b/src/boost/libs/asio/example/cpp03/windows/Jamfile.v2 new file mode 100644 index 000000000..c34228303 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/windows/Jamfile.v2 @@ -0,0 +1,30 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe transmit_file + : transmit_file.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp03/windows/transmit_file.cpp b/src/boost/libs/asio/example/cpp03/windows/transmit_file.cpp new file mode 100644 index 000000000..a544eb904 --- /dev/null +++ b/src/boost/libs/asio/example/cpp03/windows/transmit_file.cpp @@ -0,0 +1,177 @@ +// +// transmit_file.cpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <ctime> +#include <iostream> +#include <string> +#include <boost/bind/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/asio.hpp> + +#if defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) + +using boost::asio::ip::tcp; +using boost::asio::windows::overlapped_ptr; +using boost::asio::windows::random_access_handle; + +typedef boost::asio::basic_stream_socket<tcp, + boost::asio::io_context::executor_type> tcp_socket; + +typedef boost::asio::basic_socket_acceptor<tcp, + boost::asio::io_context::executor_type> tcp_acceptor; + +// A wrapper for the TransmitFile overlapped I/O operation. +template <typename Handler> +void transmit_file(tcp_socket& socket, + random_access_handle& file, Handler handler) +{ + // Construct an OVERLAPPED-derived object to contain the handler. + overlapped_ptr overlapped(socket.get_executor().context(), handler); + + // Initiate the TransmitFile operation. + BOOL ok = ::TransmitFile(socket.native_handle(), + file.native_handle(), 0, 0, overlapped.get(), 0, 0); + DWORD last_error = ::GetLastError(); + + // Check if the operation completed immediately. + if (!ok && last_error != ERROR_IO_PENDING) + { + // The operation completed immediately, so a completion notification needs + // to be posted. When complete() is called, ownership of the OVERLAPPED- + // derived object passes to the io_context. + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + overlapped.complete(ec, 0); + } + else + { + // The operation was successfully initiated, so ownership of the + // OVERLAPPED-derived object has passed to the io_context. + overlapped.release(); + } +} + +class connection + : public boost::enable_shared_from_this<connection> +{ +public: + typedef boost::shared_ptr<connection> pointer; + + static pointer create(boost::asio::io_context& io_context, + const std::string& filename) + { + return pointer(new connection(io_context, filename)); + } + + tcp_socket& socket() + { + return socket_; + } + + void start() + { + boost::system::error_code ec; + file_.assign(::CreateFile(filename_.c_str(), GENERIC_READ, 0, 0, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0), ec); + if (file_.is_open()) + { + transmit_file(socket_, file_, + boost::bind(&connection::handle_write, shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + } + +private: + connection(boost::asio::io_context& io_context, const std::string& filename) + : socket_(io_context), + filename_(filename), + file_(io_context) + { + } + + void handle_write(const boost::system::error_code& /*error*/, + size_t /*bytes_transferred*/) + { + boost::system::error_code ignored_ec; + socket_.shutdown(tcp_socket::shutdown_both, ignored_ec); + } + + tcp_socket socket_; + std::string filename_; + random_access_handle file_; +}; + +class server +{ +public: + server(boost::asio::io_context& io_context, + unsigned short port, const std::string& filename) + : acceptor_(io_context, tcp::endpoint(tcp::v4(), port)), + filename_(filename) + { + start_accept(); + } + +private: + void start_accept() + { + connection::pointer new_connection = + connection::create(acceptor_.get_executor().context(), filename_); + + acceptor_.async_accept(new_connection->socket(), + boost::bind(&server::handle_accept, this, new_connection, + boost::asio::placeholders::error)); + } + + void handle_accept(connection::pointer new_connection, + const boost::system::error_code& error) + { + if (!error) + { + new_connection->start(); + } + + start_accept(); + } + + tcp_acceptor acceptor_; + std::string filename_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: transmit_file <port> <filename>\n"; + return 1; + } + + boost::asio::io_context io_context; + + using namespace std; // For atoi. + server s(io_context, atoi(argv[1]), argv[2]); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} + +#else // defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) +# error Overlapped I/O not available on this platform +#endif // defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) diff --git a/src/boost/libs/asio/example/cpp11/allocation/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/allocation/Jamfile.v2 new file mode 100644 index 000000000..4ff960f4c --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/allocation/Jamfile.v2 @@ -0,0 +1,29 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe server + : server.cpp + /boost/system//boost_system + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp11/allocation/server.cpp b/src/boost/libs/asio/example/cpp11/allocation/server.cpp new file mode 100644 index 000000000..0edb03190 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/allocation/server.cpp @@ -0,0 +1,255 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <array> +#include <cstdlib> +#include <iostream> +#include <memory> +#include <type_traits> +#include <utility> +#include <boost/asio.hpp> + +using boost::asio::ip::tcp; + +// Class to manage the memory to be used for handler-based custom allocation. +// It contains a single block of memory which may be returned for allocation +// requests. If the memory is in use when an allocation request is made, the +// allocator delegates allocation to the global heap. +class handler_memory +{ +public: + handler_memory() + : in_use_(false) + { + } + + handler_memory(const handler_memory&) = delete; + handler_memory& operator=(const handler_memory&) = delete; + + void* allocate(std::size_t size) + { + if (!in_use_ && size < sizeof(storage_)) + { + in_use_ = true; + return &storage_; + } + else + { + return ::operator new(size); + } + } + + void deallocate(void* pointer) + { + if (pointer == &storage_) + { + in_use_ = false; + } + else + { + ::operator delete(pointer); + } + } + +private: + // Storage space used for handler-based custom memory allocation. + typename std::aligned_storage<1024>::type storage_; + + // Whether the handler-based custom allocation storage has been used. + bool in_use_; +}; + +// The allocator to be associated with the handler objects. This allocator only +// needs to satisfy the C++11 minimal allocator requirements. +template <typename T> +class handler_allocator +{ +public: + using value_type = T; + + explicit handler_allocator(handler_memory& mem) + : memory_(mem) + { + } + + template <typename U> + handler_allocator(const handler_allocator<U>& other) noexcept + : memory_(other.memory_) + { + } + + bool operator==(const handler_allocator& other) const noexcept + { + return &memory_ == &other.memory_; + } + + bool operator!=(const handler_allocator& other) const noexcept + { + return &memory_ != &other.memory_; + } + + T* allocate(std::size_t n) const + { + return static_cast<T*>(memory_.allocate(sizeof(T) * n)); + } + + void deallocate(T* p, std::size_t /*n*/) const + { + return memory_.deallocate(p); + } + +private: + template <typename> friend class handler_allocator; + + // The underlying memory. + handler_memory& memory_; +}; + +// Wrapper class template for handler objects to allow handler memory +// allocation to be customised. The allocator_type type and get_allocator() +// member function are used by the asynchronous operations to obtain the +// allocator. Calls to operator() are forwarded to the encapsulated handler. +template <typename Handler> +class custom_alloc_handler +{ +public: + using allocator_type = handler_allocator<Handler>; + + custom_alloc_handler(handler_memory& m, Handler h) + : memory_(m), + handler_(h) + { + } + + allocator_type get_allocator() const noexcept + { + return allocator_type(memory_); + } + + template <typename ...Args> + void operator()(Args&&... args) + { + handler_(std::forward<Args>(args)...); + } + +private: + handler_memory& memory_; + Handler handler_; +}; + +// Helper function to wrap a handler object to add custom allocation. +template <typename Handler> +inline custom_alloc_handler<Handler> make_custom_alloc_handler( + handler_memory& m, Handler h) +{ + return custom_alloc_handler<Handler>(m, h); +} + +class session + : public std::enable_shared_from_this<session> +{ +public: + session(tcp::socket socket) + : socket_(std::move(socket)) + { + } + + void start() + { + do_read(); + } + +private: + void do_read() + { + auto self(shared_from_this()); + socket_.async_read_some(boost::asio::buffer(data_), + make_custom_alloc_handler(handler_memory_, + [this, self](boost::system::error_code ec, std::size_t length) + { + if (!ec) + { + do_write(length); + } + })); + } + + void do_write(std::size_t length) + { + auto self(shared_from_this()); + boost::asio::async_write(socket_, boost::asio::buffer(data_, length), + make_custom_alloc_handler(handler_memory_, + [this, self](boost::system::error_code ec, std::size_t /*length*/) + { + if (!ec) + { + do_read(); + } + })); + } + + // The socket used to communicate with the client. + tcp::socket socket_; + + // Buffer used to store data received from the client. + std::array<char, 1024> data_; + + // The memory to use for handler-based custom memory allocation. + handler_memory handler_memory_; +}; + +class server +{ +public: + server(boost::asio::io_context& io_context, short port) + : acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) + { + do_accept(); + } + +private: + void do_accept() + { + acceptor_.async_accept( + [this](boost::system::error_code ec, tcp::socket socket) + { + if (!ec) + { + std::make_shared<session>(std::move(socket))->start(); + } + + do_accept(); + }); + } + + tcp::acceptor acceptor_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: server <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + server s(io_context, std::atoi(argv[1])); + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/buffers/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/buffers/Jamfile.v2 new file mode 100644 index 000000000..f04d22493 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/buffers/Jamfile.v2 @@ -0,0 +1,29 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe server + : reference_counted.cpp + /boost/system//boost_system + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp11/buffers/reference_counted.cpp b/src/boost/libs/asio/example/cpp11/buffers/reference_counted.cpp new file mode 100644 index 000000000..7ee99d349 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/buffers/reference_counted.cpp @@ -0,0 +1,122 @@ +// +// reference_counted.cpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio.hpp> +#include <iostream> +#include <memory> +#include <utility> +#include <vector> +#include <ctime> + +using boost::asio::ip::tcp; + +// A reference-counted non-modifiable buffer class. +class shared_const_buffer +{ +public: + // Construct from a std::string. + explicit shared_const_buffer(const std::string& data) + : data_(new std::vector<char>(data.begin(), data.end())), + buffer_(boost::asio::buffer(*data_)) + { + } + + // Implement the ConstBufferSequence requirements. + typedef boost::asio::const_buffer value_type; + typedef const boost::asio::const_buffer* const_iterator; + const boost::asio::const_buffer* begin() const { return &buffer_; } + const boost::asio::const_buffer* end() const { return &buffer_ + 1; } + +private: + std::shared_ptr<std::vector<char> > data_; + boost::asio::const_buffer buffer_; +}; + +class session + : public std::enable_shared_from_this<session> +{ +public: + session(tcp::socket socket) + : socket_(std::move(socket)) + { + } + + void start() + { + do_write(); + } + +private: + void do_write() + { + std::time_t now = std::time(0); + shared_const_buffer buffer(std::ctime(&now)); + + auto self(shared_from_this()); + boost::asio::async_write(socket_, buffer, + [self](boost::system::error_code /*ec*/, std::size_t /*length*/) + { + }); + } + + // The socket used to communicate with the client. + tcp::socket socket_; +}; + +class server +{ +public: + server(boost::asio::io_context& io_context, short port) + : acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) + { + do_accept(); + } + +private: + void do_accept() + { + acceptor_.async_accept( + [this](boost::system::error_code ec, tcp::socket socket) + { + if (!ec) + { + std::make_shared<session>(std::move(socket))->start(); + } + + do_accept(); + }); + } + + tcp::acceptor acceptor_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: reference_counted <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + server s(io_context, std::atoi(argv[1])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/chat/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/chat/Jamfile.v2 new file mode 100644 index 000000000..1908cf7ce --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/chat/Jamfile.v2 @@ -0,0 +1,33 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <library>/boost/thread//boost_thread + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe chat_server : chat_server.cpp ; +exe chat_client : chat_client.cpp ; diff --git a/src/boost/libs/asio/example/cpp11/chat/chat_client.cpp b/src/boost/libs/asio/example/cpp11/chat/chat_client.cpp new file mode 100644 index 000000000..c44e04fa4 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/chat/chat_client.cpp @@ -0,0 +1,167 @@ +// +// chat_client.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <deque> +#include <iostream> +#include <thread> +#include <boost/asio.hpp> +#include "chat_message.hpp" + +using boost::asio::ip::tcp; + +typedef std::deque<chat_message> chat_message_queue; + +class chat_client +{ +public: + chat_client(boost::asio::io_context& io_context, + const tcp::resolver::results_type& endpoints) + : io_context_(io_context), + socket_(io_context) + { + do_connect(endpoints); + } + + void write(const chat_message& msg) + { + boost::asio::post(io_context_, + [this, msg]() + { + bool write_in_progress = !write_msgs_.empty(); + write_msgs_.push_back(msg); + if (!write_in_progress) + { + do_write(); + } + }); + } + + void close() + { + boost::asio::post(io_context_, [this]() { socket_.close(); }); + } + +private: + void do_connect(const tcp::resolver::results_type& endpoints) + { + boost::asio::async_connect(socket_, endpoints, + [this](boost::system::error_code ec, tcp::endpoint) + { + if (!ec) + { + do_read_header(); + } + }); + } + + void do_read_header() + { + boost::asio::async_read(socket_, + boost::asio::buffer(read_msg_.data(), chat_message::header_length), + [this](boost::system::error_code ec, std::size_t /*length*/) + { + if (!ec && read_msg_.decode_header()) + { + do_read_body(); + } + else + { + socket_.close(); + } + }); + } + + void do_read_body() + { + boost::asio::async_read(socket_, + boost::asio::buffer(read_msg_.body(), read_msg_.body_length()), + [this](boost::system::error_code ec, std::size_t /*length*/) + { + if (!ec) + { + std::cout.write(read_msg_.body(), read_msg_.body_length()); + std::cout << "\n"; + do_read_header(); + } + else + { + socket_.close(); + } + }); + } + + void do_write() + { + boost::asio::async_write(socket_, + boost::asio::buffer(write_msgs_.front().data(), + write_msgs_.front().length()), + [this](boost::system::error_code ec, std::size_t /*length*/) + { + if (!ec) + { + write_msgs_.pop_front(); + if (!write_msgs_.empty()) + { + do_write(); + } + } + else + { + socket_.close(); + } + }); + } + +private: + boost::asio::io_context& io_context_; + tcp::socket socket_; + chat_message read_msg_; + chat_message_queue write_msgs_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: chat_client <host> <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + tcp::resolver resolver(io_context); + auto endpoints = resolver.resolve(argv[1], argv[2]); + chat_client c(io_context, endpoints); + + std::thread t([&io_context](){ io_context.run(); }); + + char line[chat_message::max_body_length + 1]; + while (std::cin.getline(line, chat_message::max_body_length + 1)) + { + chat_message msg; + msg.body_length(std::strlen(line)); + std::memcpy(msg.body(), line, msg.body_length()); + msg.encode_header(); + c.write(msg); + } + + c.close(); + t.join(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/chat/chat_message.hpp b/src/boost/libs/asio/example/cpp11/chat/chat_message.hpp new file mode 100644 index 000000000..9507f6ae9 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/chat/chat_message.hpp @@ -0,0 +1,91 @@ +// +// chat_message.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef CHAT_MESSAGE_HPP +#define CHAT_MESSAGE_HPP + +#include <cstdio> +#include <cstdlib> +#include <cstring> + +class chat_message +{ +public: + enum { header_length = 4 }; + enum { max_body_length = 512 }; + + chat_message() + : body_length_(0) + { + } + + const char* data() const + { + return data_; + } + + char* data() + { + return data_; + } + + std::size_t length() const + { + return header_length + body_length_; + } + + const char* body() const + { + return data_ + header_length; + } + + char* body() + { + return data_ + header_length; + } + + std::size_t body_length() const + { + return body_length_; + } + + void body_length(std::size_t new_length) + { + body_length_ = new_length; + if (body_length_ > max_body_length) + body_length_ = max_body_length; + } + + bool decode_header() + { + char header[header_length + 1] = ""; + std::strncat(header, data_, header_length); + body_length_ = std::atoi(header); + if (body_length_ > max_body_length) + { + body_length_ = 0; + return false; + } + return true; + } + + void encode_header() + { + char header[header_length + 1] = ""; + std::sprintf(header, "%4d", static_cast<int>(body_length_)); + std::memcpy(data_, header, header_length); + } + +private: + char data_[header_length + max_body_length]; + std::size_t body_length_; +}; + +#endif // CHAT_MESSAGE_HPP diff --git a/src/boost/libs/asio/example/cpp11/chat/chat_server.cpp b/src/boost/libs/asio/example/cpp11/chat/chat_server.cpp new file mode 100644 index 000000000..a96af8628 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/chat/chat_server.cpp @@ -0,0 +1,227 @@ +// +// chat_server.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <deque> +#include <iostream> +#include <list> +#include <memory> +#include <set> +#include <utility> +#include <boost/asio.hpp> +#include "chat_message.hpp" + +using boost::asio::ip::tcp; + +//---------------------------------------------------------------------- + +typedef std::deque<chat_message> chat_message_queue; + +//---------------------------------------------------------------------- + +class chat_participant +{ +public: + virtual ~chat_participant() {} + virtual void deliver(const chat_message& msg) = 0; +}; + +typedef std::shared_ptr<chat_participant> chat_participant_ptr; + +//---------------------------------------------------------------------- + +class chat_room +{ +public: + void join(chat_participant_ptr participant) + { + participants_.insert(participant); + for (auto msg: recent_msgs_) + participant->deliver(msg); + } + + void leave(chat_participant_ptr participant) + { + participants_.erase(participant); + } + + void deliver(const chat_message& msg) + { + recent_msgs_.push_back(msg); + while (recent_msgs_.size() > max_recent_msgs) + recent_msgs_.pop_front(); + + for (auto participant: participants_) + participant->deliver(msg); + } + +private: + std::set<chat_participant_ptr> participants_; + enum { max_recent_msgs = 100 }; + chat_message_queue recent_msgs_; +}; + +//---------------------------------------------------------------------- + +class chat_session + : public chat_participant, + public std::enable_shared_from_this<chat_session> +{ +public: + chat_session(tcp::socket socket, chat_room& room) + : socket_(std::move(socket)), + room_(room) + { + } + + void start() + { + room_.join(shared_from_this()); + do_read_header(); + } + + void deliver(const chat_message& msg) + { + bool write_in_progress = !write_msgs_.empty(); + write_msgs_.push_back(msg); + if (!write_in_progress) + { + do_write(); + } + } + +private: + void do_read_header() + { + auto self(shared_from_this()); + boost::asio::async_read(socket_, + boost::asio::buffer(read_msg_.data(), chat_message::header_length), + [this, self](boost::system::error_code ec, std::size_t /*length*/) + { + if (!ec && read_msg_.decode_header()) + { + do_read_body(); + } + else + { + room_.leave(shared_from_this()); + } + }); + } + + void do_read_body() + { + auto self(shared_from_this()); + boost::asio::async_read(socket_, + boost::asio::buffer(read_msg_.body(), read_msg_.body_length()), + [this, self](boost::system::error_code ec, std::size_t /*length*/) + { + if (!ec) + { + room_.deliver(read_msg_); + do_read_header(); + } + else + { + room_.leave(shared_from_this()); + } + }); + } + + void do_write() + { + auto self(shared_from_this()); + boost::asio::async_write(socket_, + boost::asio::buffer(write_msgs_.front().data(), + write_msgs_.front().length()), + [this, self](boost::system::error_code ec, std::size_t /*length*/) + { + if (!ec) + { + write_msgs_.pop_front(); + if (!write_msgs_.empty()) + { + do_write(); + } + } + else + { + room_.leave(shared_from_this()); + } + }); + } + + tcp::socket socket_; + chat_room& room_; + chat_message read_msg_; + chat_message_queue write_msgs_; +}; + +//---------------------------------------------------------------------- + +class chat_server +{ +public: + chat_server(boost::asio::io_context& io_context, + const tcp::endpoint& endpoint) + : acceptor_(io_context, endpoint) + { + do_accept(); + } + +private: + void do_accept() + { + acceptor_.async_accept( + [this](boost::system::error_code ec, tcp::socket socket) + { + if (!ec) + { + std::make_shared<chat_session>(std::move(socket), room_)->start(); + } + + do_accept(); + }); + } + + tcp::acceptor acceptor_; + chat_room room_; +}; + +//---------------------------------------------------------------------- + +int main(int argc, char* argv[]) +{ + try + { + if (argc < 2) + { + std::cerr << "Usage: chat_server <port> [<port> ...]\n"; + return 1; + } + + boost::asio::io_context io_context; + + std::list<chat_server> servers; + for (int i = 1; i < argc; ++i) + { + tcp::endpoint endpoint(tcp::v4(), std::atoi(argv[i])); + servers.emplace_back(io_context, endpoint); + } + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/echo/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/echo/Jamfile.v2 new file mode 100644 index 000000000..8af5f5beb --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/echo/Jamfile.v2 @@ -0,0 +1,37 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <library>/boost/thread//boost_thread + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe async_tcp_echo_server : async_tcp_echo_server.cpp ; +exe async_udp_echo_server : async_udp_echo_server.cpp ; +exe blocking_tcp_echo_client : blocking_tcp_echo_client.cpp ; +exe blocking_tcp_echo_server : blocking_tcp_echo_server.cpp ; +exe blocking_udp_echo_client : blocking_udp_echo_client.cpp ; +exe blocking_udp_echo_server : blocking_udp_echo_server.cpp ; diff --git a/src/boost/libs/asio/example/cpp11/echo/async_tcp_echo_server.cpp b/src/boost/libs/asio/example/cpp11/echo/async_tcp_echo_server.cpp new file mode 100644 index 000000000..f0c674e18 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/echo/async_tcp_echo_server.cpp @@ -0,0 +1,114 @@ +// +// async_tcp_echo_server.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <iostream> +#include <memory> +#include <utility> +#include <boost/asio.hpp> + +using boost::asio::ip::tcp; + +class session + : public std::enable_shared_from_this<session> +{ +public: + session(tcp::socket socket) + : socket_(std::move(socket)) + { + } + + void start() + { + do_read(); + } + +private: + void do_read() + { + auto self(shared_from_this()); + socket_.async_read_some(boost::asio::buffer(data_, max_length), + [this, self](boost::system::error_code ec, std::size_t length) + { + if (!ec) + { + do_write(length); + } + }); + } + + void do_write(std::size_t length) + { + auto self(shared_from_this()); + boost::asio::async_write(socket_, boost::asio::buffer(data_, length), + [this, self](boost::system::error_code ec, std::size_t /*length*/) + { + if (!ec) + { + do_read(); + } + }); + } + + tcp::socket socket_; + enum { max_length = 1024 }; + char data_[max_length]; +}; + +class server +{ +public: + server(boost::asio::io_context& io_context, short port) + : acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) + { + do_accept(); + } + +private: + void do_accept() + { + acceptor_.async_accept( + [this](boost::system::error_code ec, tcp::socket socket) + { + if (!ec) + { + std::make_shared<session>(std::move(socket))->start(); + } + + do_accept(); + }); + } + + tcp::acceptor acceptor_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: async_tcp_echo_server <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + server s(io_context, std::atoi(argv[1])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/echo/async_udp_echo_server.cpp b/src/boost/libs/asio/example/cpp11/echo/async_udp_echo_server.cpp new file mode 100644 index 000000000..ce3a59990 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/echo/async_udp_echo_server.cpp @@ -0,0 +1,82 @@ +// +// async_udp_echo_server.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <iostream> +#include <boost/asio.hpp> + +using boost::asio::ip::udp; + +class server +{ +public: + server(boost::asio::io_context& io_context, short port) + : socket_(io_context, udp::endpoint(udp::v4(), port)) + { + do_receive(); + } + + void do_receive() + { + socket_.async_receive_from( + boost::asio::buffer(data_, max_length), sender_endpoint_, + [this](boost::system::error_code ec, std::size_t bytes_recvd) + { + if (!ec && bytes_recvd > 0) + { + do_send(bytes_recvd); + } + else + { + do_receive(); + } + }); + } + + void do_send(std::size_t length) + { + socket_.async_send_to( + boost::asio::buffer(data_, length), sender_endpoint_, + [this](boost::system::error_code /*ec*/, std::size_t /*bytes_sent*/) + { + do_receive(); + }); + } + +private: + udp::socket socket_; + udp::endpoint sender_endpoint_; + enum { max_length = 1024 }; + char data_[max_length]; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: async_udp_echo_server <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + server s(io_context, std::atoi(argv[1])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/echo/blocking_tcp_echo_client.cpp b/src/boost/libs/asio/example/cpp11/echo/blocking_tcp_echo_client.cpp new file mode 100644 index 000000000..8e73811b7 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/echo/blocking_tcp_echo_client.cpp @@ -0,0 +1,55 @@ +// +// blocking_tcp_echo_client.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <cstring> +#include <iostream> +#include <boost/asio.hpp> + +using boost::asio::ip::tcp; + +enum { max_length = 1024 }; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: blocking_tcp_echo_client <host> <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + tcp::socket s(io_context); + tcp::resolver resolver(io_context); + boost::asio::connect(s, resolver.resolve(argv[1], argv[2])); + + std::cout << "Enter message: "; + char request[max_length]; + std::cin.getline(request, max_length); + size_t request_length = std::strlen(request); + boost::asio::write(s, boost::asio::buffer(request, request_length)); + + char reply[max_length]; + size_t reply_length = boost::asio::read(s, + boost::asio::buffer(reply, request_length)); + std::cout << "Reply is: "; + std::cout.write(reply, reply_length); + std::cout << "\n"; + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/echo/blocking_tcp_echo_server.cpp b/src/boost/libs/asio/example/cpp11/echo/blocking_tcp_echo_server.cpp new file mode 100644 index 000000000..588b4a0c7 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/echo/blocking_tcp_echo_server.cpp @@ -0,0 +1,74 @@ +// +// blocking_tcp_echo_server.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <iostream> +#include <thread> +#include <utility> +#include <boost/asio.hpp> + +using boost::asio::ip::tcp; + +const int max_length = 1024; + +void session(tcp::socket sock) +{ + try + { + for (;;) + { + char data[max_length]; + + boost::system::error_code error; + size_t length = sock.read_some(boost::asio::buffer(data), error); + if (error == boost::asio::error::eof) + break; // Connection closed cleanly by peer. + else if (error) + throw boost::system::system_error(error); // Some other error. + + boost::asio::write(sock, boost::asio::buffer(data, length)); + } + } + catch (std::exception& e) + { + std::cerr << "Exception in thread: " << e.what() << "\n"; + } +} + +void server(boost::asio::io_context& io_context, unsigned short port) +{ + tcp::acceptor a(io_context, tcp::endpoint(tcp::v4(), port)); + for (;;) + { + std::thread(session, a.accept()).detach(); + } +} + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: blocking_tcp_echo_server <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + server(io_context, std::atoi(argv[1])); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/echo/blocking_udp_echo_client.cpp b/src/boost/libs/asio/example/cpp11/echo/blocking_udp_echo_client.cpp new file mode 100644 index 000000000..8ed9e3a29 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/echo/blocking_udp_echo_client.cpp @@ -0,0 +1,58 @@ +// +// blocking_udp_echo_client.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <cstring> +#include <iostream> +#include <boost/asio.hpp> + +using boost::asio::ip::udp; + +enum { max_length = 1024 }; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: blocking_udp_echo_client <host> <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + udp::socket s(io_context, udp::endpoint(udp::v4(), 0)); + + udp::resolver resolver(io_context); + udp::resolver::results_type endpoints = + resolver.resolve(udp::v4(), argv[1], argv[2]); + + std::cout << "Enter message: "; + char request[max_length]; + std::cin.getline(request, max_length); + size_t request_length = std::strlen(request); + s.send_to(boost::asio::buffer(request, request_length), *endpoints.begin()); + + char reply[max_length]; + udp::endpoint sender_endpoint; + size_t reply_length = s.receive_from( + boost::asio::buffer(reply, max_length), sender_endpoint); + std::cout << "Reply is: "; + std::cout.write(reply, reply_length); + std::cout << "\n"; + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/echo/blocking_udp_echo_server.cpp b/src/boost/libs/asio/example/cpp11/echo/blocking_udp_echo_server.cpp new file mode 100644 index 000000000..e1f41e28f --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/echo/blocking_udp_echo_server.cpp @@ -0,0 +1,52 @@ +// +// blocking_udp_echo_server.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <iostream> +#include <boost/asio.hpp> + +using boost::asio::ip::udp; + +enum { max_length = 1024 }; + +void server(boost::asio::io_context& io_context, unsigned short port) +{ + udp::socket sock(io_context, udp::endpoint(udp::v4(), port)); + for (;;) + { + char data[max_length]; + udp::endpoint sender_endpoint; + size_t length = sock.receive_from( + boost::asio::buffer(data, max_length), sender_endpoint); + sock.send_to(boost::asio::buffer(data, length), sender_endpoint); + } +} + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: blocking_udp_echo_server <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + server(io_context, std::atoi(argv[1])); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/executors/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/executors/Jamfile.v2 new file mode 100644 index 000000000..26ef1fda1 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/executors/Jamfile.v2 @@ -0,0 +1,36 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe actor : actor.cpp ; +exe bank_account_1 : bank_account_1.cpp ; +exe bank_account_2 : bank_account_2.cpp ; +exe fork_join : fork_join.cpp ; +exe pipeline : pipeline.cpp ; +exe priority_scheduler : priority_scheduler.cpp ; diff --git a/src/boost/libs/asio/example/cpp11/executors/actor.cpp b/src/boost/libs/asio/example/cpp11/executors/actor.cpp new file mode 100644 index 000000000..2e3311d40 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/executors/actor.cpp @@ -0,0 +1,286 @@ +#include <boost/asio/defer.hpp> +#include <boost/asio/executor.hpp> +#include <boost/asio/post.hpp> +#include <boost/asio/strand.hpp> +#include <boost/asio/system_executor.hpp> +#include <condition_variable> +#include <deque> +#include <memory> +#include <mutex> +#include <typeinfo> +#include <vector> + +using boost::asio::defer; +using boost::asio::executor; +using boost::asio::post; +using boost::asio::strand; +using boost::asio::system_executor; + +//------------------------------------------------------------------------------ +// A tiny actor framework +// ~~~~~~~~~~~~~~~~~~~~~~ + +class actor; + +// Used to identify the sender and recipient of messages. +typedef actor* actor_address; + +// Base class for all registered message handlers. +class message_handler_base +{ +public: + virtual ~message_handler_base() {} + + // Used to determine which message handlers receive an incoming message. + virtual const std::type_info& message_id() const = 0; +}; + +// Base class for a handler for a specific message type. +template <class Message> +class message_handler : public message_handler_base +{ +public: + // Handle an incoming message. + virtual void handle_message(Message msg, actor_address from) = 0; +}; + +// Concrete message handler for a specific message type. +template <class Actor, class Message> +class mf_message_handler : public message_handler<Message> +{ +public: + // Construct a message handler to invoke the specified member function. + mf_message_handler(void (Actor::* mf)(Message, actor_address), Actor* a) + : function_(mf), actor_(a) + { + } + + // Used to determine which message handlers receive an incoming message. + virtual const std::type_info& message_id() const + { + return typeid(Message); + } + + // Handle an incoming message. + virtual void handle_message(Message msg, actor_address from) + { + (actor_->*function_)(std::move(msg), from); + } + + // Determine whether the message handler represents the specified function. + bool is_function(void (Actor::* mf)(Message, actor_address)) const + { + return mf == function_; + } + +private: + void (Actor::* function_)(Message, actor_address); + Actor* actor_; +}; + +// Base class for all actors. +class actor +{ +public: + virtual ~actor() + { + } + + // Obtain the actor's address for use as a message sender or recipient. + actor_address address() + { + return this; + } + + // Send a message from one actor to another. + template <class Message> + friend void send(Message msg, actor_address from, actor_address to) + { + // Execute the message handler in the context of the target's executor. + post(to->executor_, + [=] + { + to->call_handler(std::move(msg), from); + }); + } + +protected: + // Construct the actor to use the specified executor for all message handlers. + actor(executor e) + : executor_(std::move(e)) + { + } + + // Register a handler for a specific message type. Duplicates are permitted. + template <class Actor, class Message> + void register_handler(void (Actor::* mf)(Message, actor_address)) + { + handlers_.push_back( + std::make_shared<mf_message_handler<Actor, Message>>( + mf, static_cast<Actor*>(this))); + } + + // Deregister a handler. Removes only the first matching handler. + template <class Actor, class Message> + void deregister_handler(void (Actor::* mf)(Message, actor_address)) + { + const std::type_info& id = typeid(message_handler<Message>); + for (auto iter = handlers_.begin(); iter != handlers_.end(); ++iter) + { + if ((*iter)->message_id() == id) + { + auto mh = static_cast<mf_message_handler<Actor, Message>*>(iter->get()); + if (mh->is_function(mf)) + { + handlers_.erase(iter); + return; + } + } + } + } + + // Send a message from within a message handler. + template <class Message> + void tail_send(Message msg, actor_address to) + { + // Execute the message handler in the context of the target's executor. + actor* from = this; + defer(to->executor_, + [=] + { + to->call_handler(std::move(msg), from); + }); + } + +private: + // Find the matching message handlers, if any, and call them. + template <class Message> + void call_handler(Message msg, actor_address from) + { + const std::type_info& message_id = typeid(Message); + for (auto& h: handlers_) + { + if (h->message_id() == message_id) + { + auto mh = static_cast<message_handler<Message>*>(h.get()); + mh->handle_message(msg, from); + } + } + } + + // All messages associated with a single actor object should be processed + // non-concurrently. We use a strand to ensure non-concurrent execution even + // if the underlying executor may use multiple threads. + strand<executor> executor_; + + std::vector<std::shared_ptr<message_handler_base>> handlers_; +}; + +// A concrete actor that allows synchronous message retrieval. +template <class Message> +class receiver : public actor +{ +public: + receiver() + : actor(system_executor()) + { + register_handler(&receiver::message_handler); + } + + // Block until a message has been received. + Message wait() + { + std::unique_lock<std::mutex> lock(mutex_); + condition_.wait(lock, [this]{ return !message_queue_.empty(); }); + Message msg(std::move(message_queue_.front())); + message_queue_.pop_front(); + return msg; + } + +private: + // Handle a new message by adding it to the queue and waking a waiter. + void message_handler(Message msg, actor_address /* from */) + { + std::lock_guard<std::mutex> lock(mutex_); + message_queue_.push_back(std::move(msg)); + condition_.notify_one(); + } + + std::mutex mutex_; + std::condition_variable condition_; + std::deque<Message> message_queue_; +}; + +//------------------------------------------------------------------------------ + +#include <boost/asio/thread_pool.hpp> +#include <iostream> + +using boost::asio::thread_pool; + +class member : public actor +{ +public: + explicit member(executor e) + : actor(std::move(e)) + { + register_handler(&member::init_handler); + } + +private: + void init_handler(actor_address next, actor_address from) + { + next_ = next; + caller_ = from; + + register_handler(&member::token_handler); + deregister_handler(&member::init_handler); + } + + void token_handler(int token, actor_address /*from*/) + { + int msg(token); + actor_address to(caller_); + + if (token > 0) + { + msg = token - 1; + to = next_; + } + + tail_send(msg, to); + } + + actor_address next_; + actor_address caller_; +}; + +int main() +{ + const std::size_t num_threads = 16; + const int num_hops = 50000000; + const std::size_t num_actors = 503; + const int token_value = (num_hops + num_actors - 1) / num_actors; + const std::size_t actors_per_thread = num_actors / num_threads; + + struct single_thread_pool : thread_pool { single_thread_pool() : thread_pool(1) {} }; + single_thread_pool pools[num_threads]; + std::vector<std::shared_ptr<member>> members(num_actors); + receiver<int> rcvr; + + // Create the member actors. + for (std::size_t i = 0; i < num_actors; ++i) + members[i] = std::make_shared<member>(pools[(i / actors_per_thread) % num_threads].get_executor()); + + // Initialise the actors by passing each one the address of the next actor in the ring. + for (std::size_t i = num_actors, next_i = 0; i > 0; next_i = --i) + send(members[next_i]->address(), rcvr.address(), members[i - 1]->address()); + + // Send exactly one token to each actor, all with the same initial value, rounding up if required. + for (std::size_t i = 0; i < num_actors; ++i) + send(token_value, rcvr.address(), members[i]->address()); + + // Wait for all signal messages, indicating the tokens have all reached zero. + for (std::size_t i = 0; i < num_actors; ++i) + rcvr.wait(); +} diff --git a/src/boost/libs/asio/example/cpp11/executors/bank_account_1.cpp b/src/boost/libs/asio/example/cpp11/executors/bank_account_1.cpp new file mode 100644 index 000000000..35b659be8 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/executors/bank_account_1.cpp @@ -0,0 +1,54 @@ +#include <boost/asio/post.hpp> +#include <boost/asio/thread_pool.hpp> +#include <iostream> + +using boost::asio::post; +using boost::asio::thread_pool; + +// Traditional active object pattern. +// Member functions do not block. + +class bank_account +{ + int balance_ = 0; + mutable thread_pool pool_{1}; + +public: + void deposit(int amount) + { + post(pool_, [=] + { + balance_ += amount; + }); + } + + void withdraw(int amount) + { + post(pool_, [=] + { + if (balance_ >= amount) + balance_ -= amount; + }); + } + + void print_balance() const + { + post(pool_, [=] + { + std::cout << "balance = " << balance_ << "\n"; + }); + } + + ~bank_account() + { + pool_.join(); + } +}; + +int main() +{ + bank_account acct; + acct.deposit(20); + acct.withdraw(10); + acct.print_balance(); +} diff --git a/src/boost/libs/asio/example/cpp11/executors/bank_account_2.cpp b/src/boost/libs/asio/example/cpp11/executors/bank_account_2.cpp new file mode 100644 index 000000000..aebff7645 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/executors/bank_account_2.cpp @@ -0,0 +1,54 @@ +#include <boost/asio/post.hpp> +#include <boost/asio/thread_pool.hpp> +#include <boost/asio/use_future.hpp> +#include <iostream> + +using boost::asio::post; +using boost::asio::thread_pool; +using boost::asio::use_future; + +// Traditional active object pattern. +// Member functions block until operation is finished. + +class bank_account +{ + int balance_ = 0; + mutable thread_pool pool_{1}; + +public: + void deposit(int amount) + { + post(pool_, + use_future([=] + { + balance_ += amount; + })).get(); + } + + void withdraw(int amount) + { + post(pool_, + use_future([=] + { + if (balance_ >= amount) + balance_ -= amount; + })).get(); + } + + int balance() const + { + return post(pool_, + use_future([=] + { + return balance_; + })).get(); + } +}; + +int main() +{ + bank_account acct; + acct.deposit(20); + acct.withdraw(10); + std::cout << "balance = " << acct.balance() << "\n"; +} diff --git a/src/boost/libs/asio/example/cpp11/executors/fork_join.cpp b/src/boost/libs/asio/example/cpp11/executors/fork_join.cpp new file mode 100644 index 000000000..98926d53f --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/executors/fork_join.cpp @@ -0,0 +1,328 @@ +#include <boost/asio/dispatch.hpp> +#include <boost/asio/execution_context.hpp> +#include <boost/asio/thread_pool.hpp> +#include <condition_variable> +#include <memory> +#include <mutex> +#include <queue> +#include <thread> +#include <numeric> + +using boost::asio::dispatch; +using boost::asio::execution_context; +using boost::asio::thread_pool; + +// A fixed-size thread pool used to implement fork/join semantics. Functions +// are scheduled using a simple FIFO queue. Implementing work stealing, or +// using a queue based on atomic operations, are left as tasks for the reader. +class fork_join_pool : public execution_context +{ +public: + // The constructor starts a thread pool with the specified number of threads. + // Note that the thread_count is not a fixed limit on the pool's concurrency. + // Additional threads may temporarily be added to the pool if they join a + // fork_executor. + explicit fork_join_pool( + std::size_t thread_count = std::thread::hardware_concurrency() * 2) + : use_count_(1), + threads_(thread_count) + { + try + { + // Ask each thread in the pool to dequeue and execute functions until + // it is time to shut down, i.e. the use count is zero. + for (thread_count_ = 0; thread_count_ < thread_count; ++thread_count_) + { + dispatch(threads_, [&] + { + std::unique_lock<std::mutex> lock(mutex_); + while (use_count_ > 0) + if (!execute_next(lock)) + condition_.wait(lock); + }); + } + } + catch (...) + { + stop_threads(); + threads_.join(); + throw; + } + } + + // The destructor waits for the pool to finish executing functions. + ~fork_join_pool() + { + stop_threads(); + threads_.join(); + } + +private: + friend class fork_executor; + + // The base for all functions that are queued in the pool. + struct function_base + { + std::shared_ptr<std::size_t> work_count_; + void (*execute_)(std::shared_ptr<function_base>& p); + }; + + // Execute the next function from the queue, if any. Returns true if a + // function was executed, and false if the queue was empty. + bool execute_next(std::unique_lock<std::mutex>& lock) + { + if (queue_.empty()) + return false; + auto p(queue_.front()); + queue_.pop(); + lock.unlock(); + execute(lock, p); + return true; + } + + // Execute a function and decrement the outstanding work. + void execute(std::unique_lock<std::mutex>& lock, + std::shared_ptr<function_base>& p) + { + std::shared_ptr<std::size_t> work_count(std::move(p->work_count_)); + try + { + p->execute_(p); + lock.lock(); + do_work_finished(work_count); + } + catch (...) + { + lock.lock(); + do_work_finished(work_count); + throw; + } + } + + // Increment outstanding work. + void do_work_started(const std::shared_ptr<std::size_t>& work_count) noexcept + { + if (++(*work_count) == 1) + ++use_count_; + } + + // Decrement outstanding work. Notify waiting threads if we run out. + void do_work_finished(const std::shared_ptr<std::size_t>& work_count) noexcept + { + if (--(*work_count) == 0) + { + --use_count_; + condition_.notify_all(); + } + } + + // Dispatch a function, executing it immediately if the queue is already + // loaded. Otherwise adds the function to the queue and wakes a thread. + void do_dispatch(std::shared_ptr<function_base> p, + const std::shared_ptr<std::size_t>& work_count) + { + std::unique_lock<std::mutex> lock(mutex_); + if (queue_.size() > thread_count_ * 16) + { + do_work_started(work_count); + lock.unlock(); + execute(lock, p); + } + else + { + queue_.push(p); + do_work_started(work_count); + condition_.notify_one(); + } + } + + // Add a function to the queue and wake a thread. + void do_post(std::shared_ptr<function_base> p, + const std::shared_ptr<std::size_t>& work_count) + { + std::lock_guard<std::mutex> lock(mutex_); + queue_.push(p); + do_work_started(work_count); + condition_.notify_one(); + } + + // Ask all threads to shut down. + void stop_threads() + { + std::lock_guard<std::mutex> lock(mutex_); + --use_count_; + condition_.notify_all(); + } + + std::mutex mutex_; + std::condition_variable condition_; + std::queue<std::shared_ptr<function_base>> queue_; + std::size_t use_count_; + std::size_t thread_count_; + thread_pool threads_; +}; + +// A class that satisfies the Executor requirements. Every function or piece of +// work associated with a fork_executor is part of a single, joinable group. +class fork_executor +{ +public: + fork_executor(fork_join_pool& ctx) + : context_(ctx), + work_count_(std::make_shared<std::size_t>(0)) + { + } + + fork_join_pool& context() const noexcept + { + return context_; + } + + void on_work_started() const noexcept + { + std::lock_guard<std::mutex> lock(context_.mutex_); + context_.do_work_started(work_count_); + } + + void on_work_finished() const noexcept + { + std::lock_guard<std::mutex> lock(context_.mutex_); + context_.do_work_finished(work_count_); + } + + template <class Func, class Alloc> + void dispatch(Func&& f, const Alloc& a) const + { + auto p(std::allocate_shared<function<Func>>( + typename std::allocator_traits<Alloc>::template rebind_alloc<char>(a), + std::move(f), work_count_)); + context_.do_dispatch(p, work_count_); + } + + template <class Func, class Alloc> + void post(Func f, const Alloc& a) const + { + auto p(std::allocate_shared<function<Func>>( + typename std::allocator_traits<Alloc>::template rebind_alloc<char>(a), + std::move(f), work_count_)); + context_.do_post(p, work_count_); + } + + template <class Func, class Alloc> + void defer(Func&& f, const Alloc& a) const + { + post(std::forward<Func>(f), a); + } + + friend bool operator==(const fork_executor& a, + const fork_executor& b) noexcept + { + return a.work_count_ == b.work_count_; + } + + friend bool operator!=(const fork_executor& a, + const fork_executor& b) noexcept + { + return a.work_count_ != b.work_count_; + } + + // Block until all work associated with the executor is complete. While it is + // waiting, the thread may be borrowed to execute functions from the queue. + void join() const + { + std::unique_lock<std::mutex> lock(context_.mutex_); + while (*work_count_ > 0) + if (!context_.execute_next(lock)) + context_.condition_.wait(lock); + } + +private: + template <class Func> + struct function : fork_join_pool::function_base + { + explicit function(Func f, const std::shared_ptr<std::size_t>& w) + : function_(std::move(f)) + { + work_count_ = w; + execute_ = [](std::shared_ptr<fork_join_pool::function_base>& p) + { + Func tmp(std::move(static_cast<function*>(p.get())->function_)); + p.reset(); + tmp(); + }; + } + + Func function_; + }; + + fork_join_pool& context_; + std::shared_ptr<std::size_t> work_count_; +}; + +// Helper class to automatically join a fork_executor when exiting a scope. +class join_guard +{ +public: + explicit join_guard(const fork_executor& ex) : ex_(ex) {} + join_guard(const join_guard&) = delete; + join_guard(join_guard&&) = delete; + ~join_guard() { ex_.join(); } + +private: + fork_executor ex_; +}; + +//------------------------------------------------------------------------------ + +#include <algorithm> +#include <iostream> +#include <random> +#include <vector> + +fork_join_pool pool; + +template <class Iterator> +void fork_join_sort(Iterator begin, Iterator end) +{ + std::size_t n = end - begin; + if (n > 32768) + { + { + fork_executor fork(pool); + join_guard join(fork); + dispatch(fork, [=]{ fork_join_sort(begin, begin + n / 2); }); + dispatch(fork, [=]{ fork_join_sort(begin + n / 2, end); }); + } + std::inplace_merge(begin, begin + n / 2, end); + } + else + { + std::sort(begin, end); + } +} + +int main(int argc, char* argv[]) +{ + if (argc != 2) + { + std::cerr << "Usage: fork_join <size>\n"; + return 1; + } + + std::vector<double> vec(std::atoll(argv[1])); + std::iota(vec.begin(), vec.end(), 0); + + std::random_device rd; + std::mt19937 g(rd()); + std::shuffle(vec.begin(), vec.end(), g); + + std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); + + fork_join_sort(vec.begin(), vec.end()); + + std::chrono::steady_clock::duration elapsed = std::chrono::steady_clock::now() - start; + + std::cout << "sort took "; + std::cout << std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count(); + std::cout << " microseconds" << std::endl; +} diff --git a/src/boost/libs/asio/example/cpp11/executors/pipeline.cpp b/src/boost/libs/asio/example/cpp11/executors/pipeline.cpp new file mode 100644 index 000000000..9c2a778fe --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/executors/pipeline.cpp @@ -0,0 +1,299 @@ +#include <boost/asio/associated_executor.hpp> +#include <boost/asio/bind_executor.hpp> +#include <boost/asio/execution_context.hpp> +#include <boost/asio/post.hpp> +#include <boost/asio/system_executor.hpp> +#include <boost/asio/use_future.hpp> +#include <condition_variable> +#include <future> +#include <memory> +#include <mutex> +#include <queue> +#include <thread> +#include <vector> +#include <cctype> + +using boost::asio::execution_context; +using boost::asio::executor_binder; +using boost::asio::get_associated_executor; +using boost::asio::post; +using boost::asio::system_executor; +using boost::asio::use_future; +using boost::asio::use_service; + +// An executor that launches a new thread for each function submitted to it. +// This class satisfies the Executor requirements. +class thread_executor +{ +private: + // Service to track all threads started through a thread_executor. + class thread_bag : public execution_context::service + { + public: + typedef thread_bag key_type; + + explicit thread_bag(execution_context& ctx) + : execution_context::service(ctx) + { + } + + void add_thread(std::thread&& t) + { + std::unique_lock<std::mutex> lock(mutex_); + threads_.push_back(std::move(t)); + } + + private: + virtual void shutdown() + { + for (auto& t : threads_) + t.join(); + } + + std::mutex mutex_; + std::vector<std::thread> threads_; + }; + +public: + execution_context& context() const noexcept + { + return system_executor().context(); + } + + void on_work_started() const noexcept + { + // This executor doesn't count work. + } + + void on_work_finished() const noexcept + { + // This executor doesn't count work. + } + + template <class Func, class Alloc> + void dispatch(Func&& f, const Alloc& a) const + { + post(std::forward<Func>(f), a); + } + + template <class Func, class Alloc> + void post(Func f, const Alloc&) const + { + thread_bag& bag = use_service<thread_bag>(context()); + bag.add_thread(std::thread(std::move(f))); + } + + template <class Func, class Alloc> + void defer(Func&& f, const Alloc& a) const + { + post(std::forward<Func>(f), a); + } + + friend bool operator==(const thread_executor&, + const thread_executor&) noexcept + { + return true; + } + + friend bool operator!=(const thread_executor&, + const thread_executor&) noexcept + { + return false; + } +}; + +// Base class for all thread-safe queue implementations. +class queue_impl_base +{ + template <class> friend class queue_front; + template <class> friend class queue_back; + std::mutex mutex_; + std::condition_variable condition_; + bool stop_ = false; +}; + +// Underlying implementation of a thread-safe queue, shared between the +// queue_front and queue_back classes. +template <class T> +class queue_impl : public queue_impl_base +{ + template <class> friend class queue_front; + template <class> friend class queue_back; + std::queue<T> queue_; +}; + +// The front end of a queue between consecutive pipeline stages. +template <class T> +class queue_front +{ +public: + typedef T value_type; + + explicit queue_front(std::shared_ptr<queue_impl<T>> impl) + : impl_(impl) + { + } + + void push(T t) + { + std::unique_lock<std::mutex> lock(impl_->mutex_); + impl_->queue_.push(std::move(t)); + impl_->condition_.notify_one(); + } + + void stop() + { + std::unique_lock<std::mutex> lock(impl_->mutex_); + impl_->stop_ = true; + impl_->condition_.notify_one(); + } + +private: + std::shared_ptr<queue_impl<T>> impl_; +}; + +// The back end of a queue between consecutive pipeline stages. +template <class T> +class queue_back +{ +public: + typedef T value_type; + + explicit queue_back(std::shared_ptr<queue_impl<T>> impl) + : impl_(impl) + { + } + + bool pop(T& t) + { + std::unique_lock<std::mutex> lock(impl_->mutex_); + while (impl_->queue_.empty() && !impl_->stop_) + impl_->condition_.wait(lock); + if (!impl_->queue_.empty()) + { + t = impl_->queue_.front(); + impl_->queue_.pop(); + return true; + } + return false; + } + +private: + std::shared_ptr<queue_impl<T>> impl_; +}; + +// Launch the last stage in a pipeline. +template <class T, class F> +std::future<void> pipeline(queue_back<T> in, F f) +{ + // Get the function's associated executor, defaulting to thread_executor. + auto ex = get_associated_executor(f, thread_executor()); + + // Run the function, and as we're the last stage return a future so that the + // caller can wait for the pipeline to finish. + return post(ex, use_future([in, f]() mutable { f(in); })); +} + +// Launch an intermediate stage in a pipeline. +template <class T, class F, class... Tail> +std::future<void> pipeline(queue_back<T> in, F f, Tail... t) +{ + // Determine the output queue type. + typedef typename executor_binder<F, thread_executor>::second_argument_type::value_type output_value_type; + + // Create the output queue and its implementation. + auto out_impl = std::make_shared<queue_impl<output_value_type>>(); + queue_front<output_value_type> out(out_impl); + queue_back<output_value_type> next_in(out_impl); + + // Get the function's associated executor, defaulting to thread_executor. + auto ex = get_associated_executor(f, thread_executor()); + + // Run the function. + post(ex, [in, out, f]() mutable + { + f(in, out); + out.stop(); + }); + + // Launch the rest of the pipeline. + return pipeline(next_in, std::move(t)...); +} + +// Launch the first stage in a pipeline. +template <class F, class... Tail> +std::future<void> pipeline(F f, Tail... t) +{ + // Determine the output queue type. + typedef typename executor_binder<F, thread_executor>::argument_type::value_type output_value_type; + + // Create the output queue and its implementation. + auto out_impl = std::make_shared<queue_impl<output_value_type>>(); + queue_front<output_value_type> out(out_impl); + queue_back<output_value_type> next_in(out_impl); + + // Get the function's associated executor, defaulting to thread_executor. + auto ex = get_associated_executor(f, thread_executor()); + + // Run the function. + post(ex, [out, f]() mutable + { + f(out); + out.stop(); + }); + + // Launch the rest of the pipeline. + return pipeline(next_in, std::move(t)...); +} + +//------------------------------------------------------------------------------ + +#include <boost/asio/thread_pool.hpp> +#include <iostream> +#include <string> + +using boost::asio::bind_executor; +using boost::asio::thread_pool; + +void reader(queue_front<std::string> out) +{ + std::string line; + while (std::getline(std::cin, line)) + out.push(line); +} + +void filter(queue_back<std::string> in, queue_front<std::string> out) +{ + std::string line; + while (in.pop(line)) + if (line.length() > 5) + out.push(line); +} + +void upper(queue_back<std::string> in, queue_front<std::string> out) +{ + std::string line; + while (in.pop(line)) + { + std::string new_line; + for (char c : line) + new_line.push_back(std::toupper(c)); + out.push(new_line); + } +} + +void writer(queue_back<std::string> in) +{ + std::size_t count = 0; + std::string line; + while (in.pop(line)) + std::cout << count++ << ": " << line << std::endl; +} + +int main() +{ + thread_pool pool; + + auto f = pipeline(reader, filter, bind_executor(pool, upper), writer); + f.wait(); +} diff --git a/src/boost/libs/asio/example/cpp11/executors/priority_scheduler.cpp b/src/boost/libs/asio/example/cpp11/executors/priority_scheduler.cpp new file mode 100644 index 000000000..7c9bc80d7 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/executors/priority_scheduler.cpp @@ -0,0 +1,174 @@ +#include <boost/asio/dispatch.hpp> +#include <boost/asio/execution_context.hpp> +#include <condition_variable> +#include <iostream> +#include <memory> +#include <mutex> +#include <queue> + +using boost::asio::dispatch; +using boost::asio::execution_context; + +class priority_scheduler : public execution_context +{ +public: + // A class that satisfies the Executor requirements. + class executor_type + { + public: + executor_type(priority_scheduler& ctx, int pri) noexcept + : context_(ctx), priority_(pri) + { + } + + priority_scheduler& context() const noexcept + { + return context_; + } + + void on_work_started() const noexcept + { + // This executor doesn't count work. Instead, the scheduler simply runs + // until explicitly stopped. + } + + void on_work_finished() const noexcept + { + // This executor doesn't count work. Instead, the scheduler simply runs + // until explicitly stopped. + } + + template <class Func, class Alloc> + void dispatch(Func&& f, const Alloc& a) const + { + post(std::forward<Func>(f), a); + } + + template <class Func, class Alloc> + void post(Func f, const Alloc& a) const + { + auto p(std::allocate_shared<item<Func>>( + typename std::allocator_traits< + Alloc>::template rebind_alloc<char>(a), + priority_, std::move(f))); + std::lock_guard<std::mutex> lock(context_.mutex_); + context_.queue_.push(p); + context_.condition_.notify_one(); + } + + template <class Func, class Alloc> + void defer(Func&& f, const Alloc& a) const + { + post(std::forward<Func>(f), a); + } + + friend bool operator==(const executor_type& a, + const executor_type& b) noexcept + { + return &a.context_ == &b.context_; + } + + friend bool operator!=(const executor_type& a, + const executor_type& b) noexcept + { + return &a.context_ != &b.context_; + } + + private: + priority_scheduler& context_; + int priority_; + }; + + ~priority_scheduler() noexcept + { + shutdown(); + destroy(); + } + + executor_type get_executor(int pri = 0) noexcept + { + return executor_type(*const_cast<priority_scheduler*>(this), pri); + } + + void run() + { + std::unique_lock<std::mutex> lock(mutex_); + for (;;) + { + condition_.wait(lock, [&]{ return stopped_ || !queue_.empty(); }); + if (stopped_) + return; + auto p(queue_.top()); + queue_.pop(); + lock.unlock(); + p->execute_(p); + lock.lock(); + } + } + + void stop() + { + std::lock_guard<std::mutex> lock(mutex_); + stopped_ = true; + condition_.notify_all(); + } + +private: + struct item_base + { + int priority_; + void (*execute_)(std::shared_ptr<item_base>&); + }; + + template <class Func> + struct item : item_base + { + item(int pri, Func f) : function_(std::move(f)) + { + priority_ = pri; + execute_ = [](std::shared_ptr<item_base>& p) + { + Func tmp(std::move(static_cast<item*>(p.get())->function_)); + p.reset(); + tmp(); + }; + } + + Func function_; + }; + + struct item_comp + { + bool operator()( + const std::shared_ptr<item_base>& a, + const std::shared_ptr<item_base>& b) + { + return a->priority_ < b->priority_; + } + }; + + std::mutex mutex_; + std::condition_variable condition_; + std::priority_queue< + std::shared_ptr<item_base>, + std::vector<std::shared_ptr<item_base>>, + item_comp> queue_; + bool stopped_ = false; +}; + +int main() +{ + priority_scheduler sched; + auto low = sched.get_executor(0); + auto med = sched.get_executor(1); + auto high = sched.get_executor(2); + dispatch(low, []{ std::cout << "1\n"; }); + dispatch(low, []{ std::cout << "11\n"; }); + dispatch(med, []{ std::cout << "2\n"; }); + dispatch(med, []{ std::cout << "22\n"; }); + dispatch(high, []{ std::cout << "3\n"; }); + dispatch(high, []{ std::cout << "33\n"; }); + dispatch(high, []{ std::cout << "333\n"; }); + dispatch(sched.get_executor(-1), [&]{ sched.stop(); }); + sched.run(); +} diff --git a/src/boost/libs/asio/example/cpp11/fork/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/fork/Jamfile.v2 new file mode 100644 index 000000000..d6b8eb264 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/fork/Jamfile.v2 @@ -0,0 +1,45 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe daemon + : daemon.cpp + /boost/system//boost_system + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe process_per_connection + : process_per_connection.cpp + /boost/system//boost_system + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp11/fork/daemon.cpp b/src/boost/libs/asio/example/cpp11/fork/daemon.cpp new file mode 100644 index 000000000..76f9571db --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/fork/daemon.cpp @@ -0,0 +1,189 @@ +// +// daemon.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/udp.hpp> +#include <boost/asio/signal_set.hpp> +#include <array> +#include <ctime> +#include <iostream> +#include <syslog.h> +#include <unistd.h> + +using boost::asio::ip::udp; + +class udp_daytime_server +{ +public: + udp_daytime_server(boost::asio::io_context& io_context) + : socket_(io_context, {udp::v4(), 13}) + { + receive(); + } + +private: + void receive() + { + socket_.async_receive_from( + boost::asio::buffer(recv_buffer_), remote_endpoint_, + [this](boost::system::error_code ec, std::size_t /*n*/) + { + if (!ec) + { + using namespace std; // For time_t, time and ctime; + time_t now = time(0); + std::string message = ctime(&now); + + boost::system::error_code ignored_ec; + socket_.send_to(boost::asio::buffer(message), + remote_endpoint_, 0, ignored_ec); + } + + receive(); + }); + } + + udp::socket socket_; + udp::endpoint remote_endpoint_; + std::array<char, 1> recv_buffer_; +}; + +int main() +{ + try + { + boost::asio::io_context io_context; + + // Initialise the server before becoming a daemon. If the process is + // started from a shell, this means any errors will be reported back to the + // user. + udp_daytime_server server(io_context); + + // Register signal handlers so that the daemon may be shut down. You may + // also want to register for other signals, such as SIGHUP to trigger a + // re-read of a configuration file. + boost::asio::signal_set signals(io_context, SIGINT, SIGTERM); + signals.async_wait( + [&](boost::system::error_code /*ec*/, int /*signo*/) + { + io_context.stop(); + }); + + // Inform the io_context that we are about to become a daemon. The + // io_context cleans up any internal resources, such as threads, that may + // interfere with forking. + io_context.notify_fork(boost::asio::io_context::fork_prepare); + + // Fork the process and have the parent exit. If the process was started + // from a shell, this returns control to the user. Forking a new process is + // also a prerequisite for the subsequent call to setsid(). + if (pid_t pid = fork()) + { + if (pid > 0) + { + // We're in the parent process and need to exit. + // + // When the exit() function is used, the program terminates without + // invoking local variables' destructors. Only global variables are + // destroyed. As the io_context object is a local variable, this means + // we do not have to call: + // + // io_context.notify_fork(boost::asio::io_context::fork_parent); + // + // However, this line should be added before each call to exit() if + // using a global io_context object. An additional call: + // + // io_context.notify_fork(boost::asio::io_context::fork_prepare); + // + // should also precede the second fork(). + exit(0); + } + else + { + syslog(LOG_ERR | LOG_USER, "First fork failed: %m"); + return 1; + } + } + + // Make the process a new session leader. This detaches it from the + // terminal. + setsid(); + + // A process inherits its working directory from its parent. This could be + // on a mounted filesystem, which means that the running daemon would + // prevent this filesystem from being unmounted. Changing to the root + // directory avoids this problem. + chdir("/"); + + // The file mode creation mask is also inherited from the parent process. + // We don't want to restrict the permissions on files created by the + // daemon, so the mask is cleared. + umask(0); + + // A second fork ensures the process cannot acquire a controlling terminal. + if (pid_t pid = fork()) + { + if (pid > 0) + { + exit(0); + } + else + { + syslog(LOG_ERR | LOG_USER, "Second fork failed: %m"); + return 1; + } + } + + // Close the standard streams. This decouples the daemon from the terminal + // that started it. + close(0); + close(1); + close(2); + + // We don't want the daemon to have any standard input. + if (open("/dev/null", O_RDONLY) < 0) + { + syslog(LOG_ERR | LOG_USER, "Unable to open /dev/null: %m"); + return 1; + } + + // Send standard output to a log file. + const char* output = "/tmp/asio.daemon.out"; + const int flags = O_WRONLY | O_CREAT | O_APPEND; + const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + if (open(output, flags, mode) < 0) + { + syslog(LOG_ERR | LOG_USER, "Unable to open output file %s: %m", output); + return 1; + } + + // Also send standard error to the same log file. + if (dup(1) < 0) + { + syslog(LOG_ERR | LOG_USER, "Unable to dup output descriptor: %m"); + return 1; + } + + // Inform the io_context that we have finished becoming a daemon. The + // io_context uses this opportunity to create any internal file descriptors + // that need to be private to the new process. + io_context.notify_fork(boost::asio::io_context::fork_child); + + // The io_context can now be used normally. + syslog(LOG_INFO | LOG_USER, "Daemon started"); + io_context.run(); + syslog(LOG_INFO | LOG_USER, "Daemon stopped"); + } + catch (std::exception& e) + { + syslog(LOG_ERR | LOG_USER, "Exception: %s", e.what()); + std::cerr << "Exception: " << e.what() << std::endl; + } +} diff --git a/src/boost/libs/asio/example/cpp11/fork/process_per_connection.cpp b/src/boost/libs/asio/example/cpp11/fork/process_per_connection.cpp new file mode 100644 index 000000000..4fb4ae889 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/fork/process_per_connection.cpp @@ -0,0 +1,162 @@ +// +// process_per_connection.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/signal_set.hpp> +#include <boost/asio/write.hpp> +#include <cstdlib> +#include <iostream> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +using boost::asio::ip::tcp; + +class server +{ +public: + server(boost::asio::io_context& io_context, unsigned short port) + : io_context_(io_context), + signal_(io_context, SIGCHLD), + acceptor_(io_context, {tcp::v4(), port}), + socket_(io_context) + { + wait_for_signal(); + accept(); + } + +private: + void wait_for_signal() + { + signal_.async_wait( + [this](boost::system::error_code /*ec*/, int /*signo*/) + { + // Only the parent process should check for this signal. We can + // determine whether we are in the parent by checking if the acceptor + // is still open. + if (acceptor_.is_open()) + { + // Reap completed child processes so that we don't end up with + // zombies. + int status = 0; + while (waitpid(-1, &status, WNOHANG) > 0) {} + + wait_for_signal(); + } + }); + } + + void accept() + { + acceptor_.async_accept( + [this](boost::system::error_code ec, tcp::socket new_socket) + { + if (!ec) + { + // Take ownership of the newly accepted socket. + socket_ = std::move(new_socket); + + // Inform the io_context that we are about to fork. The io_context + // cleans up any internal resources, such as threads, that may + // interfere with forking. + io_context_.notify_fork(boost::asio::io_context::fork_prepare); + + if (fork() == 0) + { + // Inform the io_context that the fork is finished and that this + // is the child process. The io_context uses this opportunity to + // create any internal file descriptors that must be private to + // the new process. + io_context_.notify_fork(boost::asio::io_context::fork_child); + + // The child won't be accepting new connections, so we can close + // the acceptor. It remains open in the parent. + acceptor_.close(); + + // The child process is not interested in processing the SIGCHLD + // signal. + signal_.cancel(); + + read(); + } + else + { + + // Inform the io_context that the fork is finished (or failed) + // and that this is the parent process. The io_context uses this + // opportunity to recreate any internal resources that were + // cleaned up during preparation for the fork. + io_context_.notify_fork(boost::asio::io_context::fork_parent); + + // The parent process can now close the newly accepted socket. It + // remains open in the child. + socket_.close(); + + accept(); + } + } + else + { + std::cerr << "Accept error: " << ec.message() << std::endl; + accept(); + } + }); + } + + void read() + { + socket_.async_read_some(boost::asio::buffer(data_), + [this](boost::system::error_code ec, std::size_t length) + { + if (!ec) + write(length); + }); + } + + void write(std::size_t length) + { + boost::asio::async_write(socket_, boost::asio::buffer(data_, length), + [this](boost::system::error_code ec, std::size_t /*length*/) + { + if (!ec) + read(); + }); + } + + boost::asio::io_context& io_context_; + boost::asio::signal_set signal_; + tcp::acceptor acceptor_; + tcp::socket socket_; + std::array<char, 1024> data_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: process_per_connection <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + using namespace std; // For atoi. + server s(io_context, atoi(argv[1])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << std::endl; + } +} diff --git a/src/boost/libs/asio/example/cpp11/futures/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/futures/Jamfile.v2 new file mode 100644 index 000000000..59c8a374b --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/futures/Jamfile.v2 @@ -0,0 +1,29 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe server + : daytime_client.cpp + /boost/system//boost_system + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp11/futures/daytime_client.cpp b/src/boost/libs/asio/example/cpp11/futures/daytime_client.cpp new file mode 100644 index 000000000..7f787ed0a --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/futures/daytime_client.cpp @@ -0,0 +1,94 @@ +// +// daytime_client.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <array> +#include <future> +#include <iostream> +#include <thread> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/udp.hpp> +#include <boost/asio/use_future.hpp> + +using boost::asio::ip::udp; + +void get_daytime(boost::asio::io_context& io_context, const char* hostname) +{ + try + { + udp::resolver resolver(io_context); + + std::future<udp::resolver::results_type> endpoints = + resolver.async_resolve( + udp::v4(), hostname, "daytime", + boost::asio::use_future); + + // The async_resolve operation above returns the endpoints as a future + // value that is not retrieved ... + + udp::socket socket(io_context, udp::v4()); + + std::array<char, 1> send_buf = {{ 0 }}; + std::future<std::size_t> send_length = + socket.async_send_to(boost::asio::buffer(send_buf), + *endpoints.get().begin(), // ... until here. This call may block. + boost::asio::use_future); + + // Do other things here while the send completes. + + send_length.get(); // Blocks until the send is complete. Throws any errors. + + std::array<char, 128> recv_buf; + udp::endpoint sender_endpoint; + std::future<std::size_t> recv_length = + socket.async_receive_from( + boost::asio::buffer(recv_buf), + sender_endpoint, + boost::asio::use_future); + + // Do other things here while the receive completes. + + std::cout.write( + recv_buf.data(), + recv_length.get()); // Blocks until receive is complete. + } + catch (std::system_error& e) + { + std::cerr << e.what() << std::endl; + } +} + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: daytime_client <host>" << std::endl; + return 1; + } + + // We run the io_context off in its own thread so that it operates + // completely asynchronously with respect to the rest of the program. + boost::asio::io_context io_context; + auto work = boost::asio::make_work_guard(io_context); + std::thread thread([&io_context](){ io_context.run(); }); + + get_daytime(io_context, argv[1]); + + io_context.stop(); + thread.join(); + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/handler_tracking/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/handler_tracking/Jamfile.v2 new file mode 100644 index 000000000..20eb3aae1 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/handler_tracking/Jamfile.v2 @@ -0,0 +1,31 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe async_tcp_echo_server + : async_tcp_echo_server.cpp + /boost/system//boost_system + : <include>. + <define>BOOST_ALL_NO_LIB=1 + <define>BOOST_ASIO_CUSTOM_HANDLER_TRACKING=\\\"custom_tracking.hpp\\\" + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp11/handler_tracking/async_tcp_echo_server.cpp b/src/boost/libs/asio/example/cpp11/handler_tracking/async_tcp_echo_server.cpp new file mode 100644 index 000000000..f0c674e18 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/handler_tracking/async_tcp_echo_server.cpp @@ -0,0 +1,114 @@ +// +// async_tcp_echo_server.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <iostream> +#include <memory> +#include <utility> +#include <boost/asio.hpp> + +using boost::asio::ip::tcp; + +class session + : public std::enable_shared_from_this<session> +{ +public: + session(tcp::socket socket) + : socket_(std::move(socket)) + { + } + + void start() + { + do_read(); + } + +private: + void do_read() + { + auto self(shared_from_this()); + socket_.async_read_some(boost::asio::buffer(data_, max_length), + [this, self](boost::system::error_code ec, std::size_t length) + { + if (!ec) + { + do_write(length); + } + }); + } + + void do_write(std::size_t length) + { + auto self(shared_from_this()); + boost::asio::async_write(socket_, boost::asio::buffer(data_, length), + [this, self](boost::system::error_code ec, std::size_t /*length*/) + { + if (!ec) + { + do_read(); + } + }); + } + + tcp::socket socket_; + enum { max_length = 1024 }; + char data_[max_length]; +}; + +class server +{ +public: + server(boost::asio::io_context& io_context, short port) + : acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) + { + do_accept(); + } + +private: + void do_accept() + { + acceptor_.async_accept( + [this](boost::system::error_code ec, tcp::socket socket) + { + if (!ec) + { + std::make_shared<session>(std::move(socket))->start(); + } + + do_accept(); + }); + } + + tcp::acceptor acceptor_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: async_tcp_echo_server <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + server s(io_context, std::atoi(argv[1])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/handler_tracking/custom_tracking.hpp b/src/boost/libs/asio/example/cpp11/handler_tracking/custom_tracking.hpp new file mode 100644 index 000000000..1bb5b6ad9 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/handler_tracking/custom_tracking.hpp @@ -0,0 +1,201 @@ +// +// custom_tracking.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef CUSTOM_TRACKING_HPP +#define CUSTOM_TRACKING_HPP + +#include <cinttypes> +#include <cstdint> +#include <cstdio> + +# define BOOST_ASIO_INHERIT_TRACKED_HANDLER \ + : public ::custom_tracking::tracked_handler + +# define BOOST_ASIO_ALSO_INHERIT_TRACKED_HANDLER \ + , public ::custom_tracking::tracked_handler + +# define BOOST_ASIO_HANDLER_TRACKING_INIT \ + ::custom_tracking::init() + +# define BOOST_ASIO_HANDLER_CREATION(args) \ + ::custom_tracking::creation args + +# define BOOST_ASIO_HANDLER_COMPLETION(args) \ + ::custom_tracking::completion tracked_completion args + +# define BOOST_ASIO_HANDLER_INVOCATION_BEGIN(args) \ + tracked_completion.invocation_begin args + +# define BOOST_ASIO_HANDLER_INVOCATION_END \ + tracked_completion.invocation_end() + +# define BOOST_ASIO_HANDLER_OPERATION(args) \ + ::custom_tracking::operation args + +# define BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(args) \ + ::custom_tracking::reactor_registration args + +# define BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(args) \ + ::custom_tracking::reactor_deregistration args + +# define BOOST_ASIO_HANDLER_REACTOR_READ_EVENT 1 +# define BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT 2 +# define BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT 4 + +# define BOOST_ASIO_HANDLER_REACTOR_EVENTS(args) \ + ::custom_tracking::reactor_events args + +# define BOOST_ASIO_HANDLER_REACTOR_OPERATION(args) \ + ::custom_tracking::reactor_operation args + +struct custom_tracking +{ + // Base class for objects containing tracked handlers. + struct tracked_handler + { + std::uintmax_t handler_id_ = 0; // To uniquely identify a handler. + std::uintmax_t tree_id_ = 0; // To identify related handlers. + const char* object_type_; // The object type associated with the handler. + std::uintmax_t native_handle_; // Native handle, if any. + }; + + // Initialise the tracking system. + static void init() + { + } + + // Record the creation of a tracked handler. + static void creation(boost::asio::execution_context& /*ctx*/, + tracked_handler& h, const char* object_type, void* /*object*/, + std::uintmax_t native_handle, const char* op_name) + { + // Generate a unique id for the new handler. + static std::atomic<std::uintmax_t> next_handler_id{1}; + h.handler_id_ = next_handler_id++; + + // Copy the tree identifier forward from the current handler. + if (*current_completion()) + h.tree_id_ = (*current_completion())->handler_.tree_id_; + + // Store various attributes of the operation to use in later output. + h.object_type_ = object_type; + h.native_handle_ = native_handle; + + std::printf( + "Starting operation %s.%s for native_handle = %" PRIuMAX + ", handler = %" PRIuMAX ", tree = %" PRIuMAX "\n", + object_type, op_name, h.native_handle_, h.handler_id_, h.tree_id_); + } + + struct completion + { + explicit completion(const tracked_handler& h) + : handler_(h), + next_(*current_completion()) + { + *current_completion() = this; + } + + completion(const completion&) = delete; + completion& operator=(const completion&) = delete; + + // Destructor records only when an exception is thrown from the handler, or + // if the memory is being freed without the handler having been invoked. + ~completion() + { + *current_completion() = next_; + } + + // Records that handler is to be invoked with the specified arguments. + template <class... Args> + void invocation_begin(Args&&... /*args*/) + { + std::printf("Entering handler %" PRIuMAX " in tree %" PRIuMAX "\n", + handler_.handler_id_, handler_.tree_id_); + } + + // Record that handler invocation has ended. + void invocation_end() + { + std::printf("Leaving handler %" PRIuMAX " in tree %" PRIuMAX "\n", + handler_.handler_id_, handler_.tree_id_); + } + + tracked_handler handler_; + + // Completions may nest. Here we stash a pointer to the outer completion. + completion* next_; + }; + + static completion** current_completion() + { + static BOOST_ASIO_THREAD_KEYWORD completion* current = nullptr; + return ¤t; + } + + // Record an operation that is not directly associated with a handler. + static void operation(boost::asio::execution_context& /*ctx*/, + const char* /*object_type*/, void* /*object*/, + std::uintmax_t /*native_handle*/, const char* /*op_name*/) + { + } + + // Record that a descriptor has been registered with the reactor. + static void reactor_registration(boost::asio::execution_context& context, + uintmax_t native_handle, uintmax_t registration) + { + std::printf("Adding to reactor native_handle = %" PRIuMAX + ", registration = %" PRIuMAX "\n", native_handle, registration); + } + + // Record that a descriptor has been deregistered from the reactor. + static void reactor_deregistration(boost::asio::execution_context& context, + uintmax_t native_handle, uintmax_t registration) + { + std::printf("Removing from reactor native_handle = %" PRIuMAX + ", registration = %" PRIuMAX "\n", native_handle, registration); + } + + // Record reactor-based readiness events associated with a descriptor. + static void reactor_events(boost::asio::execution_context& context, + uintmax_t registration, unsigned events) + { + std::printf( + "Reactor readiness for registration = %" PRIuMAX ", events =%s%s%s\n", + registration, + (events & BOOST_ASIO_HANDLER_REACTOR_READ_EVENT) ? " read" : "", + (events & BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT) ? " write" : "", + (events & BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT) ? " error" : ""); + } + + // Record a reactor-based operation that is associated with a handler. + static void reactor_operation(const tracked_handler& h, + const char* op_name, const boost::system::error_code& ec) + { + std::printf( + "Performed operation %s.%s for native_handle = %" PRIuMAX + ", ec = %s:%d\n", h.object_type_, op_name, h.native_handle_, + ec.category().name(), ec.value()); + } + + // Record a reactor-based operation that is associated with a handler. + static void reactor_operation(const tracked_handler& h, + const char* op_name, const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + std::printf( + "Performed operation %s.%s for native_handle = %" PRIuMAX + ", ec = %s:%d, n = %" PRIuMAX "\n", h.object_type_, op_name, + h.native_handle_, ec.category().name(), ec.value(), + static_cast<uintmax_t>(bytes_transferred)); + } +}; + +#endif // CUSTOM_TRACKING_HPP diff --git a/src/boost/libs/asio/example/cpp11/http/server/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/http/server/Jamfile.v2 new file mode 100644 index 000000000..084b7b472 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/Jamfile.v2 @@ -0,0 +1,37 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe server + : connection.cpp + connection_manager.cpp + main.cpp + mime_types.cpp + reply.cpp + request_handler.cpp + request_parser.cpp + server.cpp + /boost/system//boost_system + /boost/thread//boost_thread + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp11/http/server/connection.cpp b/src/boost/libs/asio/example/cpp11/http/server/connection.cpp new file mode 100644 index 000000000..cdf31cc24 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/connection.cpp @@ -0,0 +1,94 @@ +// +// connection.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "connection.hpp" +#include <utility> +#include <vector> +#include "connection_manager.hpp" +#include "request_handler.hpp" + +namespace http { +namespace server { + +connection::connection(boost::asio::ip::tcp::socket socket, + connection_manager& manager, request_handler& handler) + : socket_(std::move(socket)), + connection_manager_(manager), + request_handler_(handler) +{ +} + +void connection::start() +{ + do_read(); +} + +void connection::stop() +{ + socket_.close(); +} + +void connection::do_read() +{ + auto self(shared_from_this()); + socket_.async_read_some(boost::asio::buffer(buffer_), + [this, self](boost::system::error_code ec, std::size_t bytes_transferred) + { + if (!ec) + { + request_parser::result_type result; + std::tie(result, std::ignore) = request_parser_.parse( + request_, buffer_.data(), buffer_.data() + bytes_transferred); + + if (result == request_parser::good) + { + request_handler_.handle_request(request_, reply_); + do_write(); + } + else if (result == request_parser::bad) + { + reply_ = reply::stock_reply(reply::bad_request); + do_write(); + } + else + { + do_read(); + } + } + else if (ec != boost::asio::error::operation_aborted) + { + connection_manager_.stop(shared_from_this()); + } + }); +} + +void connection::do_write() +{ + auto self(shared_from_this()); + boost::asio::async_write(socket_, reply_.to_buffers(), + [this, self](boost::system::error_code ec, std::size_t) + { + if (!ec) + { + // Initiate graceful connection closure. + boost::system::error_code ignored_ec; + socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, + ignored_ec); + } + + if (ec != boost::asio::error::operation_aborted) + { + connection_manager_.stop(shared_from_this()); + } + }); +} + +} // namespace server +} // namespace http diff --git a/src/boost/libs/asio/example/cpp11/http/server/connection.hpp b/src/boost/libs/asio/example/cpp11/http/server/connection.hpp new file mode 100644 index 000000000..83fcc0408 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/connection.hpp @@ -0,0 +1,79 @@ +// +// connection.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_CONNECTION_HPP +#define HTTP_CONNECTION_HPP + +#include <array> +#include <memory> +#include <boost/asio.hpp> +#include "reply.hpp" +#include "request.hpp" +#include "request_handler.hpp" +#include "request_parser.hpp" + +namespace http { +namespace server { + +class connection_manager; + +/// Represents a single connection from a client. +class connection + : public std::enable_shared_from_this<connection> +{ +public: + connection(const connection&) = delete; + connection& operator=(const connection&) = delete; + + /// Construct a connection with the given socket. + explicit connection(boost::asio::ip::tcp::socket socket, + connection_manager& manager, request_handler& handler); + + /// Start the first asynchronous operation for the connection. + void start(); + + /// Stop all asynchronous operations associated with the connection. + void stop(); + +private: + /// Perform an asynchronous read operation. + void do_read(); + + /// Perform an asynchronous write operation. + void do_write(); + + /// Socket for the connection. + boost::asio::ip::tcp::socket socket_; + + /// The manager for this connection. + connection_manager& connection_manager_; + + /// The handler used to process the incoming request. + request_handler& request_handler_; + + /// Buffer for incoming data. + std::array<char, 8192> buffer_; + + /// The incoming request. + request request_; + + /// The parser for the incoming request. + request_parser request_parser_; + + /// The reply to be sent back to the client. + reply reply_; +}; + +typedef std::shared_ptr<connection> connection_ptr; + +} // namespace server +} // namespace http + +#endif // HTTP_CONNECTION_HPP diff --git a/src/boost/libs/asio/example/cpp11/http/server/connection_manager.cpp b/src/boost/libs/asio/example/cpp11/http/server/connection_manager.cpp new file mode 100644 index 000000000..c07642189 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/connection_manager.cpp @@ -0,0 +1,40 @@ +// +// connection_manager.cpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "connection_manager.hpp" + +namespace http { +namespace server { + +connection_manager::connection_manager() +{ +} + +void connection_manager::start(connection_ptr c) +{ + connections_.insert(c); + c->start(); +} + +void connection_manager::stop(connection_ptr c) +{ + connections_.erase(c); + c->stop(); +} + +void connection_manager::stop_all() +{ + for (auto c: connections_) + c->stop(); + connections_.clear(); +} + +} // namespace server +} // namespace http diff --git a/src/boost/libs/asio/example/cpp11/http/server/connection_manager.hpp b/src/boost/libs/asio/example/cpp11/http/server/connection_manager.hpp new file mode 100644 index 000000000..aac32c6f0 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/connection_manager.hpp @@ -0,0 +1,48 @@ +// +// connection_manager.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_CONNECTION_MANAGER_HPP +#define HTTP_CONNECTION_MANAGER_HPP + +#include <set> +#include "connection.hpp" + +namespace http { +namespace server { + +/// Manages open connections so that they may be cleanly stopped when the server +/// needs to shut down. +class connection_manager +{ +public: + connection_manager(const connection_manager&) = delete; + connection_manager& operator=(const connection_manager&) = delete; + + /// Construct a connection manager. + connection_manager(); + + /// Add the specified connection to the manager and start it. + void start(connection_ptr c); + + /// Stop the specified connection. + void stop(connection_ptr c); + + /// Stop all connections. + void stop_all(); + +private: + /// The managed connections. + std::set<connection_ptr> connections_; +}; + +} // namespace server +} // namespace http + +#endif // HTTP_CONNECTION_MANAGER_HPP diff --git a/src/boost/libs/asio/example/cpp11/http/server/header.hpp b/src/boost/libs/asio/example/cpp11/http/server/header.hpp new file mode 100644 index 000000000..7e176c3b0 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/header.hpp @@ -0,0 +1,28 @@ +// +// header.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_HEADER_HPP +#define HTTP_HEADER_HPP + +#include <string> + +namespace http { +namespace server { + +struct header +{ + std::string name; + std::string value; +}; + +} // namespace server +} // namespace http + +#endif // HTTP_HEADER_HPP diff --git a/src/boost/libs/asio/example/cpp11/http/server/main.cpp b/src/boost/libs/asio/example/cpp11/http/server/main.cpp new file mode 100644 index 000000000..8236fa6b7 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/main.cpp @@ -0,0 +1,43 @@ +// +// main.cpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <string> +#include <boost/asio.hpp> +#include "server.hpp" + +int main(int argc, char* argv[]) +{ + try + { + // Check command line arguments. + if (argc != 4) + { + std::cerr << "Usage: http_server <address> <port> <doc_root>\n"; + std::cerr << " For IPv4, try:\n"; + std::cerr << " receiver 0.0.0.0 80 .\n"; + std::cerr << " For IPv6, try:\n"; + std::cerr << " receiver 0::0 80 .\n"; + return 1; + } + + // Initialise the server. + http::server::server s(argv[1], argv[2], argv[3]); + + // Run the server until stopped. + s.run(); + } + catch (std::exception& e) + { + std::cerr << "exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/http/server/mime_types.cpp b/src/boost/libs/asio/example/cpp11/http/server/mime_types.cpp new file mode 100644 index 000000000..806c58f9d --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/mime_types.cpp @@ -0,0 +1,45 @@ +// +// mime_types.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "mime_types.hpp" + +namespace http { +namespace server { +namespace mime_types { + +struct mapping +{ + const char* extension; + const char* mime_type; +} mappings[] = +{ + { "gif", "image/gif" }, + { "htm", "text/html" }, + { "html", "text/html" }, + { "jpg", "image/jpeg" }, + { "png", "image/png" } +}; + +std::string extension_to_type(const std::string& extension) +{ + for (mapping m: mappings) + { + if (m.extension == extension) + { + return m.mime_type; + } + } + + return "text/plain"; +} + +} // namespace mime_types +} // namespace server +} // namespace http diff --git a/src/boost/libs/asio/example/cpp11/http/server/mime_types.hpp b/src/boost/libs/asio/example/cpp11/http/server/mime_types.hpp new file mode 100644 index 000000000..e9bb88268 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/mime_types.hpp @@ -0,0 +1,27 @@ +// +// mime_types.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_MIME_TYPES_HPP +#define HTTP_MIME_TYPES_HPP + +#include <string> + +namespace http { +namespace server { +namespace mime_types { + +/// Convert a file extension into a MIME type. +std::string extension_to_type(const std::string& extension); + +} // namespace mime_types +} // namespace server +} // namespace http + +#endif // HTTP_MIME_TYPES_HPP diff --git a/src/boost/libs/asio/example/cpp11/http/server/reply.cpp b/src/boost/libs/asio/example/cpp11/http/server/reply.cpp new file mode 100644 index 000000000..1ff869f2d --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/reply.cpp @@ -0,0 +1,255 @@ +// +// reply.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "reply.hpp" +#include <string> + +namespace http { +namespace server { + +namespace status_strings { + +const std::string ok = + "HTTP/1.0 200 OK\r\n"; +const std::string created = + "HTTP/1.0 201 Created\r\n"; +const std::string accepted = + "HTTP/1.0 202 Accepted\r\n"; +const std::string no_content = + "HTTP/1.0 204 No Content\r\n"; +const std::string multiple_choices = + "HTTP/1.0 300 Multiple Choices\r\n"; +const std::string moved_permanently = + "HTTP/1.0 301 Moved Permanently\r\n"; +const std::string moved_temporarily = + "HTTP/1.0 302 Moved Temporarily\r\n"; +const std::string not_modified = + "HTTP/1.0 304 Not Modified\r\n"; +const std::string bad_request = + "HTTP/1.0 400 Bad Request\r\n"; +const std::string unauthorized = + "HTTP/1.0 401 Unauthorized\r\n"; +const std::string forbidden = + "HTTP/1.0 403 Forbidden\r\n"; +const std::string not_found = + "HTTP/1.0 404 Not Found\r\n"; +const std::string internal_server_error = + "HTTP/1.0 500 Internal Server Error\r\n"; +const std::string not_implemented = + "HTTP/1.0 501 Not Implemented\r\n"; +const std::string bad_gateway = + "HTTP/1.0 502 Bad Gateway\r\n"; +const std::string service_unavailable = + "HTTP/1.0 503 Service Unavailable\r\n"; + +boost::asio::const_buffer to_buffer(reply::status_type status) +{ + switch (status) + { + case reply::ok: + return boost::asio::buffer(ok); + case reply::created: + return boost::asio::buffer(created); + case reply::accepted: + return boost::asio::buffer(accepted); + case reply::no_content: + return boost::asio::buffer(no_content); + case reply::multiple_choices: + return boost::asio::buffer(multiple_choices); + case reply::moved_permanently: + return boost::asio::buffer(moved_permanently); + case reply::moved_temporarily: + return boost::asio::buffer(moved_temporarily); + case reply::not_modified: + return boost::asio::buffer(not_modified); + case reply::bad_request: + return boost::asio::buffer(bad_request); + case reply::unauthorized: + return boost::asio::buffer(unauthorized); + case reply::forbidden: + return boost::asio::buffer(forbidden); + case reply::not_found: + return boost::asio::buffer(not_found); + case reply::internal_server_error: + return boost::asio::buffer(internal_server_error); + case reply::not_implemented: + return boost::asio::buffer(not_implemented); + case reply::bad_gateway: + return boost::asio::buffer(bad_gateway); + case reply::service_unavailable: + return boost::asio::buffer(service_unavailable); + default: + return boost::asio::buffer(internal_server_error); + } +} + +} // namespace status_strings + +namespace misc_strings { + +const char name_value_separator[] = { ':', ' ' }; +const char crlf[] = { '\r', '\n' }; + +} // namespace misc_strings + +std::vector<boost::asio::const_buffer> reply::to_buffers() +{ + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(status_strings::to_buffer(status)); + for (std::size_t i = 0; i < headers.size(); ++i) + { + header& h = headers[i]; + buffers.push_back(boost::asio::buffer(h.name)); + buffers.push_back(boost::asio::buffer(misc_strings::name_value_separator)); + buffers.push_back(boost::asio::buffer(h.value)); + buffers.push_back(boost::asio::buffer(misc_strings::crlf)); + } + buffers.push_back(boost::asio::buffer(misc_strings::crlf)); + buffers.push_back(boost::asio::buffer(content)); + return buffers; +} + +namespace stock_replies { + +const char ok[] = ""; +const char created[] = + "<html>" + "<head><title>Created</title></head>" + "<body><h1>201 Created</h1></body>" + "</html>"; +const char accepted[] = + "<html>" + "<head><title>Accepted</title></head>" + "<body><h1>202 Accepted</h1></body>" + "</html>"; +const char no_content[] = + "<html>" + "<head><title>No Content</title></head>" + "<body><h1>204 Content</h1></body>" + "</html>"; +const char multiple_choices[] = + "<html>" + "<head><title>Multiple Choices</title></head>" + "<body><h1>300 Multiple Choices</h1></body>" + "</html>"; +const char moved_permanently[] = + "<html>" + "<head><title>Moved Permanently</title></head>" + "<body><h1>301 Moved Permanently</h1></body>" + "</html>"; +const char moved_temporarily[] = + "<html>" + "<head><title>Moved Temporarily</title></head>" + "<body><h1>302 Moved Temporarily</h1></body>" + "</html>"; +const char not_modified[] = + "<html>" + "<head><title>Not Modified</title></head>" + "<body><h1>304 Not Modified</h1></body>" + "</html>"; +const char bad_request[] = + "<html>" + "<head><title>Bad Request</title></head>" + "<body><h1>400 Bad Request</h1></body>" + "</html>"; +const char unauthorized[] = + "<html>" + "<head><title>Unauthorized</title></head>" + "<body><h1>401 Unauthorized</h1></body>" + "</html>"; +const char forbidden[] = + "<html>" + "<head><title>Forbidden</title></head>" + "<body><h1>403 Forbidden</h1></body>" + "</html>"; +const char not_found[] = + "<html>" + "<head><title>Not Found</title></head>" + "<body><h1>404 Not Found</h1></body>" + "</html>"; +const char internal_server_error[] = + "<html>" + "<head><title>Internal Server Error</title></head>" + "<body><h1>500 Internal Server Error</h1></body>" + "</html>"; +const char not_implemented[] = + "<html>" + "<head><title>Not Implemented</title></head>" + "<body><h1>501 Not Implemented</h1></body>" + "</html>"; +const char bad_gateway[] = + "<html>" + "<head><title>Bad Gateway</title></head>" + "<body><h1>502 Bad Gateway</h1></body>" + "</html>"; +const char service_unavailable[] = + "<html>" + "<head><title>Service Unavailable</title></head>" + "<body><h1>503 Service Unavailable</h1></body>" + "</html>"; + +std::string to_string(reply::status_type status) +{ + switch (status) + { + case reply::ok: + return ok; + case reply::created: + return created; + case reply::accepted: + return accepted; + case reply::no_content: + return no_content; + case reply::multiple_choices: + return multiple_choices; + case reply::moved_permanently: + return moved_permanently; + case reply::moved_temporarily: + return moved_temporarily; + case reply::not_modified: + return not_modified; + case reply::bad_request: + return bad_request; + case reply::unauthorized: + return unauthorized; + case reply::forbidden: + return forbidden; + case reply::not_found: + return not_found; + case reply::internal_server_error: + return internal_server_error; + case reply::not_implemented: + return not_implemented; + case reply::bad_gateway: + return bad_gateway; + case reply::service_unavailable: + return service_unavailable; + default: + return internal_server_error; + } +} + +} // namespace stock_replies + +reply reply::stock_reply(reply::status_type status) +{ + reply rep; + rep.status = status; + rep.content = stock_replies::to_string(status); + rep.headers.resize(2); + rep.headers[0].name = "Content-Length"; + rep.headers[0].value = std::to_string(rep.content.size()); + rep.headers[1].name = "Content-Type"; + rep.headers[1].value = "text/html"; + return rep; +} + +} // namespace server +} // namespace http diff --git a/src/boost/libs/asio/example/cpp11/http/server/reply.hpp b/src/boost/libs/asio/example/cpp11/http/server/reply.hpp new file mode 100644 index 000000000..6a3240e2d --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/reply.hpp @@ -0,0 +1,64 @@ +// +// reply.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_REPLY_HPP +#define HTTP_REPLY_HPP + +#include <string> +#include <vector> +#include <boost/asio.hpp> +#include "header.hpp" + +namespace http { +namespace server { + +/// A reply to be sent to a client. +struct reply +{ + /// The status of the reply. + enum status_type + { + ok = 200, + created = 201, + accepted = 202, + no_content = 204, + multiple_choices = 300, + moved_permanently = 301, + moved_temporarily = 302, + not_modified = 304, + bad_request = 400, + unauthorized = 401, + forbidden = 403, + not_found = 404, + internal_server_error = 500, + not_implemented = 501, + bad_gateway = 502, + service_unavailable = 503 + } status; + + /// The headers to be included in the reply. + std::vector<header> headers; + + /// The content to be sent in the reply. + std::string content; + + /// Convert the reply into a vector of buffers. The buffers do not own the + /// underlying memory blocks, therefore the reply object must remain valid and + /// not be changed until the write operation has completed. + std::vector<boost::asio::const_buffer> to_buffers(); + + /// Get a stock reply. + static reply stock_reply(status_type status); +}; + +} // namespace server +} // namespace http + +#endif // HTTP_REPLY_HPP diff --git a/src/boost/libs/asio/example/cpp11/http/server/request.hpp b/src/boost/libs/asio/example/cpp11/http/server/request.hpp new file mode 100644 index 000000000..358133512 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/request.hpp @@ -0,0 +1,34 @@ +// +// request.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_REQUEST_HPP +#define HTTP_REQUEST_HPP + +#include <string> +#include <vector> +#include "header.hpp" + +namespace http { +namespace server { + +/// A request received from a client. +struct request +{ + std::string method; + std::string uri; + int http_version_major; + int http_version_minor; + std::vector<header> headers; +}; + +} // namespace server +} // namespace http + +#endif // HTTP_REQUEST_HPP diff --git a/src/boost/libs/asio/example/cpp11/http/server/request_handler.cpp b/src/boost/libs/asio/example/cpp11/http/server/request_handler.cpp new file mode 100644 index 000000000..c0ee6139c --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/request_handler.cpp @@ -0,0 +1,121 @@ +// +// request_handler.cpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "request_handler.hpp" +#include <fstream> +#include <sstream> +#include <string> +#include "mime_types.hpp" +#include "reply.hpp" +#include "request.hpp" + +namespace http { +namespace server { + +request_handler::request_handler(const std::string& doc_root) + : doc_root_(doc_root) +{ +} + +void request_handler::handle_request(const request& req, reply& rep) +{ + // Decode url to path. + std::string request_path; + if (!url_decode(req.uri, request_path)) + { + rep = reply::stock_reply(reply::bad_request); + return; + } + + // Request path must be absolute and not contain "..". + if (request_path.empty() || request_path[0] != '/' + || request_path.find("..") != std::string::npos) + { + rep = reply::stock_reply(reply::bad_request); + return; + } + + // If path ends in slash (i.e. is a directory) then add "index.html". + if (request_path[request_path.size() - 1] == '/') + { + request_path += "index.html"; + } + + // Determine the file extension. + std::size_t last_slash_pos = request_path.find_last_of("/"); + std::size_t last_dot_pos = request_path.find_last_of("."); + std::string extension; + if (last_dot_pos != std::string::npos && last_dot_pos > last_slash_pos) + { + extension = request_path.substr(last_dot_pos + 1); + } + + // Open the file to send back. + std::string full_path = doc_root_ + request_path; + std::ifstream is(full_path.c_str(), std::ios::in | std::ios::binary); + if (!is) + { + rep = reply::stock_reply(reply::not_found); + return; + } + + // Fill out the reply to be sent to the client. + rep.status = reply::ok; + char buf[512]; + while (is.read(buf, sizeof(buf)).gcount() > 0) + rep.content.append(buf, is.gcount()); + rep.headers.resize(2); + rep.headers[0].name = "Content-Length"; + rep.headers[0].value = std::to_string(rep.content.size()); + rep.headers[1].name = "Content-Type"; + rep.headers[1].value = mime_types::extension_to_type(extension); +} + +bool request_handler::url_decode(const std::string& in, std::string& out) +{ + out.clear(); + out.reserve(in.size()); + for (std::size_t i = 0; i < in.size(); ++i) + { + if (in[i] == '%') + { + if (i + 3 <= in.size()) + { + int value = 0; + std::istringstream is(in.substr(i + 1, 2)); + if (is >> std::hex >> value) + { + out += static_cast<char>(value); + i += 2; + } + else + { + return false; + } + } + else + { + return false; + } + } + else if (in[i] == '+') + { + out += ' '; + } + else + { + out += in[i]; + } + } + return true; +} + +} // namespace server +} // namespace http diff --git a/src/boost/libs/asio/example/cpp11/http/server/request_handler.hpp b/src/boost/libs/asio/example/cpp11/http/server/request_handler.hpp new file mode 100644 index 000000000..b1670c468 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/request_handler.hpp @@ -0,0 +1,47 @@ +// +// request_handler.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_REQUEST_HANDLER_HPP +#define HTTP_REQUEST_HANDLER_HPP + +#include <string> + +namespace http { +namespace server { + +struct reply; +struct request; + +/// The common handler for all incoming requests. +class request_handler +{ +public: + request_handler(const request_handler&) = delete; + request_handler& operator=(const request_handler&) = delete; + + /// Construct with a directory containing files to be served. + explicit request_handler(const std::string& doc_root); + + /// Handle a request and produce a reply. + void handle_request(const request& req, reply& rep); + +private: + /// The directory containing the files to be served. + std::string doc_root_; + + /// Perform URL-decoding on a string. Returns false if the encoding was + /// invalid. + static bool url_decode(const std::string& in, std::string& out); +}; + +} // namespace server +} // namespace http + +#endif // HTTP_REQUEST_HANDLER_HPP diff --git a/src/boost/libs/asio/example/cpp11/http/server/request_parser.cpp b/src/boost/libs/asio/example/cpp11/http/server/request_parser.cpp new file mode 100644 index 000000000..27a253201 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/request_parser.cpp @@ -0,0 +1,315 @@ +// +// request_parser.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "request_parser.hpp" +#include "request.hpp" + +namespace http { +namespace server { + +request_parser::request_parser() + : state_(method_start) +{ +} + +void request_parser::reset() +{ + state_ = method_start; +} + +request_parser::result_type request_parser::consume(request& req, char input) +{ + switch (state_) + { + case method_start: + if (!is_char(input) || is_ctl(input) || is_tspecial(input)) + { + return bad; + } + else + { + state_ = method; + req.method.push_back(input); + return indeterminate; + } + case method: + if (input == ' ') + { + state_ = uri; + return indeterminate; + } + else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) + { + return bad; + } + else + { + req.method.push_back(input); + return indeterminate; + } + case uri: + if (input == ' ') + { + state_ = http_version_h; + return indeterminate; + } + else if (is_ctl(input)) + { + return bad; + } + else + { + req.uri.push_back(input); + return indeterminate; + } + case http_version_h: + if (input == 'H') + { + state_ = http_version_t_1; + return indeterminate; + } + else + { + return bad; + } + case http_version_t_1: + if (input == 'T') + { + state_ = http_version_t_2; + return indeterminate; + } + else + { + return bad; + } + case http_version_t_2: + if (input == 'T') + { + state_ = http_version_p; + return indeterminate; + } + else + { + return bad; + } + case http_version_p: + if (input == 'P') + { + state_ = http_version_slash; + return indeterminate; + } + else + { + return bad; + } + case http_version_slash: + if (input == '/') + { + req.http_version_major = 0; + req.http_version_minor = 0; + state_ = http_version_major_start; + return indeterminate; + } + else + { + return bad; + } + case http_version_major_start: + if (is_digit(input)) + { + req.http_version_major = req.http_version_major * 10 + input - '0'; + state_ = http_version_major; + return indeterminate; + } + else + { + return bad; + } + case http_version_major: + if (input == '.') + { + state_ = http_version_minor_start; + return indeterminate; + } + else if (is_digit(input)) + { + req.http_version_major = req.http_version_major * 10 + input - '0'; + return indeterminate; + } + else + { + return bad; + } + case http_version_minor_start: + if (is_digit(input)) + { + req.http_version_minor = req.http_version_minor * 10 + input - '0'; + state_ = http_version_minor; + return indeterminate; + } + else + { + return bad; + } + case http_version_minor: + if (input == '\r') + { + state_ = expecting_newline_1; + return indeterminate; + } + else if (is_digit(input)) + { + req.http_version_minor = req.http_version_minor * 10 + input - '0'; + return indeterminate; + } + else + { + return bad; + } + case expecting_newline_1: + if (input == '\n') + { + state_ = header_line_start; + return indeterminate; + } + else + { + return bad; + } + case header_line_start: + if (input == '\r') + { + state_ = expecting_newline_3; + return indeterminate; + } + else if (!req.headers.empty() && (input == ' ' || input == '\t')) + { + state_ = header_lws; + return indeterminate; + } + else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) + { + return bad; + } + else + { + req.headers.push_back(header()); + req.headers.back().name.push_back(input); + state_ = header_name; + return indeterminate; + } + case header_lws: + if (input == '\r') + { + state_ = expecting_newline_2; + return indeterminate; + } + else if (input == ' ' || input == '\t') + { + return indeterminate; + } + else if (is_ctl(input)) + { + return bad; + } + else + { + state_ = header_value; + req.headers.back().value.push_back(input); + return indeterminate; + } + case header_name: + if (input == ':') + { + state_ = space_before_header_value; + return indeterminate; + } + else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) + { + return bad; + } + else + { + req.headers.back().name.push_back(input); + return indeterminate; + } + case space_before_header_value: + if (input == ' ') + { + state_ = header_value; + return indeterminate; + } + else + { + return bad; + } + case header_value: + if (input == '\r') + { + state_ = expecting_newline_2; + return indeterminate; + } + else if (is_ctl(input)) + { + return bad; + } + else + { + req.headers.back().value.push_back(input); + return indeterminate; + } + case expecting_newline_2: + if (input == '\n') + { + state_ = header_line_start; + return indeterminate; + } + else + { + return bad; + } + case expecting_newline_3: + return (input == '\n') ? good : bad; + default: + return bad; + } +} + +bool request_parser::is_char(int c) +{ + return c >= 0 && c <= 127; +} + +bool request_parser::is_ctl(int c) +{ + return (c >= 0 && c <= 31) || (c == 127); +} + +bool request_parser::is_tspecial(int c) +{ + switch (c) + { + case '(': case ')': case '<': case '>': case '@': + case ',': case ';': case ':': case '\\': case '"': + case '/': case '[': case ']': case '?': case '=': + case '{': case '}': case ' ': case '\t': + return true; + default: + return false; + } +} + +bool request_parser::is_digit(int c) +{ + return c >= '0' && c <= '9'; +} + +} // namespace server +} // namespace http diff --git a/src/boost/libs/asio/example/cpp11/http/server/request_parser.hpp b/src/boost/libs/asio/example/cpp11/http/server/request_parser.hpp new file mode 100644 index 000000000..131b468de --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/request_parser.hpp @@ -0,0 +1,96 @@ +// +// request_parser.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_REQUEST_PARSER_HPP +#define HTTP_REQUEST_PARSER_HPP + +#include <tuple> + +namespace http { +namespace server { + +struct request; + +/// Parser for incoming requests. +class request_parser +{ +public: + /// Construct ready to parse the request method. + request_parser(); + + /// Reset to initial parser state. + void reset(); + + /// Result of parse. + enum result_type { good, bad, indeterminate }; + + /// Parse some data. The enum return value is good when a complete request has + /// been parsed, bad if the data is invalid, indeterminate when more data is + /// required. The InputIterator return value indicates how much of the input + /// has been consumed. + template <typename InputIterator> + std::tuple<result_type, InputIterator> parse(request& req, + InputIterator begin, InputIterator end) + { + while (begin != end) + { + result_type result = consume(req, *begin++); + if (result == good || result == bad) + return std::make_tuple(result, begin); + } + return std::make_tuple(indeterminate, begin); + } + +private: + /// Handle the next character of input. + result_type consume(request& req, char input); + + /// Check if a byte is an HTTP character. + static bool is_char(int c); + + /// Check if a byte is an HTTP control character. + static bool is_ctl(int c); + + /// Check if a byte is defined as an HTTP tspecial character. + static bool is_tspecial(int c); + + /// Check if a byte is a digit. + static bool is_digit(int c); + + /// The current state of the parser. + enum state + { + method_start, + method, + uri, + http_version_h, + http_version_t_1, + http_version_t_2, + http_version_p, + http_version_slash, + http_version_major_start, + http_version_major, + http_version_minor_start, + http_version_minor, + expecting_newline_1, + header_line_start, + header_lws, + header_name, + space_before_header_value, + header_value, + expecting_newline_2, + expecting_newline_3 + } state_; +}; + +} // namespace server +} // namespace http + +#endif // HTTP_REQUEST_PARSER_HPP diff --git a/src/boost/libs/asio/example/cpp11/http/server/server.cpp b/src/boost/libs/asio/example/cpp11/http/server/server.cpp new file mode 100644 index 000000000..3e5ca4e1f --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/server.cpp @@ -0,0 +1,94 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include "server.hpp" +#include <signal.h> +#include <utility> + +namespace http { +namespace server { + +server::server(const std::string& address, const std::string& port, + const std::string& doc_root) + : io_context_(1), + signals_(io_context_), + acceptor_(io_context_), + connection_manager_(), + request_handler_(doc_root) +{ + // Register to handle the signals that indicate when the server should exit. + // It is safe to register for the same signal multiple times in a program, + // provided all registration for the specified signal is made through Asio. + signals_.add(SIGINT); + signals_.add(SIGTERM); +#if defined(SIGQUIT) + signals_.add(SIGQUIT); +#endif // defined(SIGQUIT) + + do_await_stop(); + + // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). + boost::asio::ip::tcp::resolver resolver(io_context_); + boost::asio::ip::tcp::endpoint endpoint = + *resolver.resolve(address, port).begin(); + acceptor_.open(endpoint.protocol()); + acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + acceptor_.bind(endpoint); + acceptor_.listen(); + + do_accept(); +} + +void server::run() +{ + // The io_context::run() call will block until all asynchronous operations + // have finished. While the server is running, there is always at least one + // asynchronous operation outstanding: the asynchronous accept call waiting + // for new incoming connections. + io_context_.run(); +} + +void server::do_accept() +{ + acceptor_.async_accept( + [this](boost::system::error_code ec, boost::asio::ip::tcp::socket socket) + { + // Check whether the server was stopped by a signal before this + // completion handler had a chance to run. + if (!acceptor_.is_open()) + { + return; + } + + if (!ec) + { + connection_manager_.start(std::make_shared<connection>( + std::move(socket), connection_manager_, request_handler_)); + } + + do_accept(); + }); +} + +void server::do_await_stop() +{ + signals_.async_wait( + [this](boost::system::error_code /*ec*/, int /*signo*/) + { + // The server is stopped by cancelling all outstanding asynchronous + // operations. Once all operations have finished the io_context::run() + // call will exit. + acceptor_.close(); + connection_manager_.stop_all(); + }); +} + +} // namespace server +} // namespace http diff --git a/src/boost/libs/asio/example/cpp11/http/server/server.hpp b/src/boost/libs/asio/example/cpp11/http/server/server.hpp new file mode 100644 index 000000000..9d72a340f --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/http/server/server.hpp @@ -0,0 +1,64 @@ +// +// server.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HTTP_SERVER_HPP +#define HTTP_SERVER_HPP + +#include <boost/asio.hpp> +#include <string> +#include "connection.hpp" +#include "connection_manager.hpp" +#include "request_handler.hpp" + +namespace http { +namespace server { + +/// The top-level class of the HTTP server. +class server +{ +public: + server(const server&) = delete; + server& operator=(const server&) = delete; + + /// Construct the server to listen on the specified TCP address and port, and + /// serve up files from the given directory. + explicit server(const std::string& address, const std::string& port, + const std::string& doc_root); + + /// Run the server's io_context loop. + void run(); + +private: + /// Perform an asynchronous accept operation. + void do_accept(); + + /// Wait for a request to stop the server. + void do_await_stop(); + + /// The io_context used to perform asynchronous operations. + boost::asio::io_context io_context_; + + /// The signal_set is used to register for process termination notifications. + boost::asio::signal_set signals_; + + /// Acceptor used to listen for incoming connections. + boost::asio::ip::tcp::acceptor acceptor_; + + /// The connection manager which owns all live connections. + connection_manager connection_manager_; + + /// The handler for all incoming requests. + request_handler request_handler_; +}; + +} // namespace server +} // namespace http + +#endif // HTTP_SERVER_HPP diff --git a/src/boost/libs/asio/example/cpp11/invocation/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/invocation/Jamfile.v2 new file mode 100644 index 000000000..d348adce7 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/invocation/Jamfile.v2 @@ -0,0 +1,29 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe prioritised_handlers + : prioritised_handlers.cpp + /boost/system//boost_system + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp11/invocation/prioritised_handlers.cpp b/src/boost/libs/asio/example/cpp11/invocation/prioritised_handlers.cpp new file mode 100644 index 000000000..9bf9c26a3 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/invocation/prioritised_handlers.cpp @@ -0,0 +1,202 @@ +// +// prioritised_handlers.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio.hpp> +#include <iostream> +#include <memory> +#include <queue> + +using boost::asio::ip::tcp; + +class handler_priority_queue : public boost::asio::execution_context +{ +public: + template <typename Function> + void add(int priority, Function function) + { + std::unique_ptr<queued_handler_base> handler( + new queued_handler<Function>( + priority, std::move(function))); + + handlers_.push(std::move(handler)); + } + + void execute_all() + { + while (!handlers_.empty()) + { + handlers_.top()->execute(); + handlers_.pop(); + } + } + + class executor + { + public: + executor(handler_priority_queue& q, int p) + : context_(q), priority_(p) + { + } + + handler_priority_queue& context() const noexcept + { + return context_; + } + + template <typename Function, typename Allocator> + void dispatch(Function f, const Allocator&) const + { + context_.add(priority_, std::move(f)); + } + + template <typename Function, typename Allocator> + void post(Function f, const Allocator&) const + { + context_.add(priority_, std::move(f)); + } + + template <typename Function, typename Allocator> + void defer(Function f, const Allocator&) const + { + context_.add(priority_, std::move(f)); + } + + void on_work_started() const noexcept {} + void on_work_finished() const noexcept {} + + bool operator==(const executor& other) const noexcept + { + return &context_ == &other.context_ && priority_ == other.priority_; + } + + bool operator!=(const executor& other) const noexcept + { + return !operator==(other); + } + + private: + handler_priority_queue& context_; + int priority_; + }; + + template <typename Handler> + boost::asio::executor_binder<Handler, executor> + wrap(int priority, Handler handler) + { + return boost::asio::bind_executor( + executor(*this, priority), std::move(handler)); + } + +private: + class queued_handler_base + { + public: + queued_handler_base(int p) + : priority_(p) + { + } + + virtual ~queued_handler_base() + { + } + + virtual void execute() = 0; + + friend bool operator<(const std::unique_ptr<queued_handler_base>& a, + const std::unique_ptr<queued_handler_base>& b) noexcept + { + return a->priority_ < b->priority_; + } + + private: + int priority_; + }; + + template <typename Function> + class queued_handler : public queued_handler_base + { + public: + queued_handler(int p, Function f) + : queued_handler_base(p), function_(std::move(f)) + { + } + + void execute() override + { + function_(); + } + + private: + Function function_; + }; + + std::priority_queue<std::unique_ptr<queued_handler_base>> handlers_; +}; + +//---------------------------------------------------------------------- + +void high_priority_handler(const boost::system::error_code& /*ec*/, + tcp::socket /*socket*/) +{ + std::cout << "High priority handler\n"; +} + +void middle_priority_handler(const boost::system::error_code& /*ec*/) +{ + std::cout << "Middle priority handler\n"; +} + +struct low_priority_handler +{ + // Make the handler a move-only type. + low_priority_handler() = default; + low_priority_handler(const low_priority_handler&) = delete; + low_priority_handler(low_priority_handler&&) = default; + + void operator()() + { + std::cout << "Low priority handler\n"; + } +}; + +int main() +{ + boost::asio::io_context io_context; + + handler_priority_queue pri_queue; + + // Post a completion handler to be run immediately. + boost::asio::post(io_context, pri_queue.wrap(0, low_priority_handler())); + + // Start an asynchronous accept that will complete immediately. + tcp::endpoint endpoint(boost::asio::ip::address_v4::loopback(), 0); + tcp::acceptor acceptor(io_context, endpoint); + tcp::socket server_socket(io_context); + acceptor.async_accept(pri_queue.wrap(100, high_priority_handler)); + tcp::socket client_socket(io_context); + client_socket.connect(acceptor.local_endpoint()); + + // Set a deadline timer to expire immediately. + boost::asio::steady_timer timer(io_context); + timer.expires_at(boost::asio::steady_timer::clock_type::time_point::min()); + timer.async_wait(pri_queue.wrap(42, middle_priority_handler)); + + while (io_context.run_one()) + { + // The custom invocation hook adds the handlers to the priority queue + // rather than executing them from within the poll_one() call. + while (io_context.poll_one()) + ; + + pri_queue.execute_all(); + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/iostreams/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/iostreams/Jamfile.v2 new file mode 100644 index 000000000..a201dfd80 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/iostreams/Jamfile.v2 @@ -0,0 +1,31 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe http_client : http_client.cpp ; diff --git a/src/boost/libs/asio/example/cpp11/iostreams/http_client.cpp b/src/boost/libs/asio/example/cpp11/iostreams/http_client.cpp new file mode 100644 index 000000000..97d5f728c --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/iostreams/http_client.cpp @@ -0,0 +1,91 @@ +// +// http_client.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <istream> +#include <ostream> +#include <string> +#include <boost/asio/ip/tcp.hpp> + +using boost::asio::ip::tcp; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cout << "Usage: http_client <server> <path>\n"; + std::cout << "Example:\n"; + std::cout << " http_client www.boost.org /LICENSE_1_0.txt\n"; + return 1; + } + + boost::asio::ip::tcp::iostream s; + + // The entire sequence of I/O operations must complete within 60 seconds. + // If an expiry occurs, the socket is automatically closed and the stream + // becomes bad. + s.expires_after(std::chrono::seconds(60)); + + // Establish a connection to the server. + s.connect(argv[1], "http"); + if (!s) + { + std::cout << "Unable to connect: " << s.error().message() << "\n"; + return 1; + } + + // Send the request. We specify the "Connection: close" header so that the + // server will close the socket after transmitting the response. This will + // allow us to treat all data up until the EOF as the content. + s << "GET " << argv[2] << " HTTP/1.0\r\n"; + s << "Host: " << argv[1] << "\r\n"; + s << "Accept: */*\r\n"; + s << "Connection: close\r\n\r\n"; + + // By default, the stream is tied with itself. This means that the stream + // automatically flush the buffered output before attempting a read. It is + // not necessary not explicitly flush the stream at this point. + + // Check that response is OK. + std::string http_version; + s >> http_version; + unsigned int status_code; + s >> status_code; + std::string status_message; + std::getline(s, status_message); + if (!s || http_version.substr(0, 5) != "HTTP/") + { + std::cout << "Invalid response\n"; + return 1; + } + if (status_code != 200) + { + std::cout << "Response returned with status code " << status_code << "\n"; + return 1; + } + + // Process the response headers, which are terminated by a blank line. + std::string header; + while (std::getline(s, header) && header != "\r") + std::cout << header << "\n"; + std::cout << "\n"; + + // Write the remaining data to output. + std::cout << s.rdbuf(); + } + catch (std::exception& e) + { + std::cout << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/local/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/local/Jamfile.v2 new file mode 100644 index 000000000..e231001fa --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/local/Jamfile.v2 @@ -0,0 +1,78 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe connect_pair + : connect_pair.cpp + /boost/system//boost_system + /boost/thread//boost_thread + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe iostream_client + : iostream_client.cpp + /boost/system//boost_system + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe stream_client + : stream_client.cpp + /boost/system//boost_system + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe stream_server + : stream_server.cpp + /boost/system//boost_system + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp11/local/connect_pair.cpp b/src/boost/libs/asio/example/cpp11/local/connect_pair.cpp new file mode 100644 index 000000000..1e60848ec --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/local/connect_pair.cpp @@ -0,0 +1,130 @@ +// +// connect_pair.cpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <array> +#include <iostream> +#include <string> +#include <cctype> +#include <boost/asio.hpp> +#include <boost/thread/thread.hpp> + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +using boost::asio::local::stream_protocol; + +class uppercase_filter +{ +public: + uppercase_filter(stream_protocol::socket sock) + : socket_(std::move(sock)) + { + read(); + } + +private: + void read() + { + socket_.async_read_some(boost::asio::buffer(data_), + [this](boost::system::error_code ec, std::size_t size) + { + if (!ec) + { + // Compute result. + for (std::size_t i = 0; i < size; ++i) + data_[i] = std::toupper(data_[i]); + + // Send result. + write(size); + } + else + { + throw boost::system::system_error(ec); + } + }); + } + + void write(std::size_t size) + { + boost::asio::async_write(socket_, boost::asio::buffer(data_, size), + [this](boost::system::error_code ec, std::size_t /*size*/) + { + if (!ec) + { + // Wait for request. + read(); + } + else + { + throw boost::system::system_error(ec); + } + }); + } + + stream_protocol::socket socket_; + std::array<char, 512> data_; +}; + +int main() +{ + try + { + boost::asio::io_context io_context; + + // Create a connected pair and pass one end to a filter. + stream_protocol::socket socket(io_context); + stream_protocol::socket filter_socket(io_context); + boost::asio::local::connect_pair(socket, filter_socket); + uppercase_filter filter(std::move(filter_socket)); + + // The io_context runs in a background thread to perform filtering. + boost::thread thread( + [&io_context]() + { + try + { + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception in thread: " << e.what() << "\n"; + std::exit(1); + } + }); + + for (;;) + { + // Collect request from user. + std::cout << "Enter a string: "; + std::string request; + std::getline(std::cin, request); + + // Send request to filter. + boost::asio::write(socket, boost::asio::buffer(request)); + + // Wait for reply from filter. + std::vector<char> reply(request.size()); + boost::asio::read(socket, boost::asio::buffer(reply)); + + // Show reply to user. + std::cout << "Result: "; + std::cout.write(&reply[0], request.size()); + std::cout << std::endl; + } + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + std::exit(1); + } +} + +#else // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +# error Local sockets not available on this platform. +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) diff --git a/src/boost/libs/asio/example/cpp11/local/iostream_client.cpp b/src/boost/libs/asio/example/cpp11/local/iostream_client.cpp new file mode 100644 index 000000000..2bc79e81b --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/local/iostream_client.cpp @@ -0,0 +1,61 @@ +// +// stream_client.cpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstring> +#include <iostream> +#include <boost/asio.hpp> + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +using boost::asio::local::stream_protocol; + +constexpr std::size_t max_length = 1024; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: iostream_client <file>\n"; + return 1; + } + + stream_protocol::endpoint ep(argv[1]); + stream_protocol::iostream s(ep); + if (!s) + { + std::cerr << "Unable to connect: " << s.error().message() << std::endl; + return 1; + } + + std::cout << "Enter message: "; + char request[max_length]; + std::cin.getline(request, max_length); + size_t length = std::strlen(request); + s << request; + + char reply[max_length]; + s.read(reply, length); + std::cout << "Reply is: "; + std::cout.write(reply, length); + std::cout << "\n"; + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} + +#else // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +# error Local sockets not available on this platform. +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) diff --git a/src/boost/libs/asio/example/cpp11/local/stream_client.cpp b/src/boost/libs/asio/example/cpp11/local/stream_client.cpp new file mode 100644 index 000000000..5d03adb50 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/local/stream_client.cpp @@ -0,0 +1,60 @@ +// +// stream_client.cpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <cstring> +#include <iostream> +#include <boost/asio.hpp> + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +using boost::asio::local::stream_protocol; + +constexpr std::size_t max_length = 1024; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: stream_client <file>\n"; + return 1; + } + + boost::asio::io_context io_context; + + stream_protocol::socket s(io_context); + s.connect(stream_protocol::endpoint(argv[1])); + + std::cout << "Enter message: "; + char request[max_length]; + std::cin.getline(request, max_length); + size_t request_length = std::strlen(request); + boost::asio::write(s, boost::asio::buffer(request, request_length)); + + char reply[max_length]; + size_t reply_length = boost::asio::read(s, + boost::asio::buffer(reply, request_length)); + std::cout << "Reply is: "; + std::cout.write(reply, reply_length); + std::cout << "\n"; + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} + +#else // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +# error Local sockets not available on this platform. +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) diff --git a/src/boost/libs/asio/example/cpp11/local/stream_server.cpp b/src/boost/libs/asio/example/cpp11/local/stream_server.cpp new file mode 100644 index 000000000..6b915029e --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/local/stream_server.cpp @@ -0,0 +1,121 @@ +// +// stream_server.cpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <array> +#include <cstdio> +#include <iostream> +#include <memory> +#include <boost/asio.hpp> + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +using boost::asio::local::stream_protocol; + +class session + : public std::enable_shared_from_this<session> +{ +public: + session(stream_protocol::socket sock) + : socket_(std::move(sock)) + { + } + + void start() + { + do_read(); + } + +private: + void do_read() + { + auto self(shared_from_this()); + socket_.async_read_some(boost::asio::buffer(data_), + [this, self](boost::system::error_code ec, std::size_t length) + { + if (!ec) + do_write(length); + }); + } + + void do_write(std::size_t length) + { + auto self(shared_from_this()); + boost::asio::async_write(socket_, + boost::asio::buffer(data_, length), + [this, self](boost::system::error_code ec, std::size_t /*length*/) + { + if (!ec) + do_read(); + }); + } + + // The socket used to communicate with the client. + stream_protocol::socket socket_; + + // Buffer used to store data received from the client. + std::array<char, 1024> data_; +}; + +class server +{ +public: + server(boost::asio::io_context& io_context, const std::string& file) + : acceptor_(io_context, stream_protocol::endpoint(file)) + { + do_accept(); + } + +private: + void do_accept() + { + acceptor_.async_accept( + [this](boost::system::error_code ec, stream_protocol::socket socket) + { + if (!ec) + { + std::make_shared<session>(std::move(socket))->start(); + } + + do_accept(); + }); + } + + stream_protocol::acceptor acceptor_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: stream_server <file>\n"; + std::cerr << "*** WARNING: existing file is removed ***\n"; + return 1; + } + + boost::asio::io_context io_context; + + std::remove(argv[1]); + server s(io_context, argv[1]); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} + +#else // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +# error Local sockets not available on this platform. +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) diff --git a/src/boost/libs/asio/example/cpp11/multicast/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/multicast/Jamfile.v2 new file mode 100644 index 000000000..dbfe4f47b --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/multicast/Jamfile.v2 @@ -0,0 +1,32 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe receiver : receiver.cpp ; +exe sender : sender.cpp ; diff --git a/src/boost/libs/asio/example/cpp11/multicast/receiver.cpp b/src/boost/libs/asio/example/cpp11/multicast/receiver.cpp new file mode 100644 index 000000000..7148288b8 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/multicast/receiver.cpp @@ -0,0 +1,88 @@ +// +// receiver.cpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <array> +#include <iostream> +#include <string> +#include <boost/asio.hpp> + +constexpr short multicast_port = 30001; + +class receiver +{ +public: + receiver(boost::asio::io_context& io_context, + const boost::asio::ip::address& listen_address, + const boost::asio::ip::address& multicast_address) + : socket_(io_context) + { + // Create the socket so that multiple may be bound to the same address. + boost::asio::ip::udp::endpoint listen_endpoint( + listen_address, multicast_port); + socket_.open(listen_endpoint.protocol()); + socket_.set_option(boost::asio::ip::udp::socket::reuse_address(true)); + socket_.bind(listen_endpoint); + + // Join the multicast group. + socket_.set_option( + boost::asio::ip::multicast::join_group(multicast_address)); + + do_receive(); + } + +private: + void do_receive() + { + socket_.async_receive_from( + boost::asio::buffer(data_), sender_endpoint_, + [this](boost::system::error_code ec, std::size_t length) + { + if (!ec) + { + std::cout.write(data_.data(), length); + std::cout << std::endl; + + do_receive(); + } + }); + } + + boost::asio::ip::udp::socket socket_; + boost::asio::ip::udp::endpoint sender_endpoint_; + std::array<char, 1024> data_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: receiver <listen_address> <multicast_address>\n"; + std::cerr << " For IPv4, try:\n"; + std::cerr << " receiver 0.0.0.0 239.255.0.1\n"; + std::cerr << " For IPv6, try:\n"; + std::cerr << " receiver 0::0 ff31::8000:1234\n"; + return 1; + } + + boost::asio::io_context io_context; + receiver r(io_context, + boost::asio::ip::make_address(argv[1]), + boost::asio::ip::make_address(argv[2])); + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/multicast/sender.cpp b/src/boost/libs/asio/example/cpp11/multicast/sender.cpp new file mode 100644 index 000000000..92312a71a --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/multicast/sender.cpp @@ -0,0 +1,91 @@ +// +// sender.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <sstream> +#include <string> +#include <boost/asio.hpp> + +constexpr short multicast_port = 30001; +constexpr int max_message_count = 10; + +class sender +{ +public: + sender(boost::asio::io_context& io_context, + const boost::asio::ip::address& multicast_address) + : endpoint_(multicast_address, multicast_port), + socket_(io_context, endpoint_.protocol()), + timer_(io_context), + message_count_(0) + { + do_send(); + } + +private: + void do_send() + { + std::ostringstream os; + os << "Message " << message_count_++; + message_ = os.str(); + + socket_.async_send_to( + boost::asio::buffer(message_), endpoint_, + [this](boost::system::error_code ec, std::size_t /*length*/) + { + if (!ec && message_count_ < max_message_count) + do_timeout(); + }); + } + + void do_timeout() + { + timer_.expires_after(std::chrono::seconds(1)); + timer_.async_wait( + [this](boost::system::error_code ec) + { + if (!ec) + do_send(); + }); + } + +private: + boost::asio::ip::udp::endpoint endpoint_; + boost::asio::ip::udp::socket socket_; + boost::asio::steady_timer timer_; + int message_count_; + std::string message_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: sender <multicast_address>\n"; + std::cerr << " For IPv4, try:\n"; + std::cerr << " sender 239.255.0.1\n"; + std::cerr << " For IPv6, try:\n"; + std::cerr << " sender ff31::8000:1234\n"; + return 1; + } + + boost::asio::io_context io_context; + sender s(io_context, boost::asio::ip::make_address(argv[1])); + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/nonblocking/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/nonblocking/Jamfile.v2 new file mode 100644 index 000000000..1ef265c4f --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/nonblocking/Jamfile.v2 @@ -0,0 +1,29 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe third_party_lib + : third_party_lib.cpp + /boost/system//boost_system + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp11/nonblocking/third_party_lib.cpp b/src/boost/libs/asio/example/cpp11/nonblocking/third_party_lib.cpp new file mode 100644 index 000000000..ceea0e61e --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/nonblocking/third_party_lib.cpp @@ -0,0 +1,212 @@ +// +// third_party_lib.cpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio.hpp> +#include <array> +#include <iostream> +#include <memory> + +using boost::asio::ip::tcp; + +namespace third_party_lib { + +// Simulation of a third party library that wants to perform read and write +// operations directly on a socket. It needs to be polled to determine whether +// it requires a read or write operation, and notified when the socket is ready +// for reading or writing. +class session +{ +public: + session(tcp::socket& socket) + : socket_(socket) + { + } + + // Returns true if the third party library wants to be notified when the + // socket is ready for reading. + bool want_read() const + { + return state_ == reading; + } + + // Notify that third party library that it should perform its read operation. + void do_read(boost::system::error_code& ec) + { + if (std::size_t len = socket_.read_some(boost::asio::buffer(data_), ec)) + { + write_buffer_ = boost::asio::buffer(data_, len); + state_ = writing; + } + } + + // Returns true if the third party library wants to be notified when the + // socket is ready for writing. + bool want_write() const + { + return state_ == writing; + } + + // Notify that third party library that it should perform its write operation. + void do_write(boost::system::error_code& ec) + { + if (std::size_t len = socket_.write_some( + boost::asio::buffer(write_buffer_), ec)) + { + write_buffer_ = write_buffer_ + len; + state_ = boost::asio::buffer_size(write_buffer_) > 0 ? writing : reading; + } + } + +private: + tcp::socket& socket_; + enum { reading, writing } state_ = reading; + std::array<char, 128> data_; + boost::asio::const_buffer write_buffer_; +}; + +} // namespace third_party_lib + +// The glue between asio's sockets and the third party library. +class connection + : public std::enable_shared_from_this<connection> +{ +public: + connection(tcp::socket socket) + : socket_(std::move(socket)) + { + } + + void start() + { + // Put the socket into non-blocking mode. + socket_.non_blocking(true); + + do_operations(); + } + +private: + void do_operations() + { + auto self(shared_from_this()); + + // Start a read operation if the third party library wants one. + if (session_impl_.want_read() && !read_in_progress_) + { + read_in_progress_ = true; + socket_.async_wait(tcp::socket::wait_read, + [this, self](boost::system::error_code ec) + { + read_in_progress_ = false; + + // Notify third party library that it can perform a read. + if (!ec) + session_impl_.do_read(ec); + + // The third party library successfully performed a read on the + // socket. Start new read or write operations based on what it now + // wants. + if (!ec || ec == boost::asio::error::would_block) + do_operations(); + + // Otherwise, an error occurred. Closing the socket cancels any + // outstanding asynchronous read or write operations. The + // connection object will be destroyed automatically once those + // outstanding operations complete. + else + socket_.close(); + }); + } + + // Start a write operation if the third party library wants one. + if (session_impl_.want_write() && !write_in_progress_) + { + write_in_progress_ = true; + socket_.async_wait(tcp::socket::wait_write, + [this, self](boost::system::error_code ec) + { + write_in_progress_ = false; + + // Notify third party library that it can perform a write. + if (!ec) + session_impl_.do_write(ec); + + // The third party library successfully performed a write on the + // socket. Start new read or write operations based on what it now + // wants. + if (!ec || ec == boost::asio::error::would_block) + do_operations(); + + // Otherwise, an error occurred. Closing the socket cancels any + // outstanding asynchronous read or write operations. The + // connection object will be destroyed automatically once those + // outstanding operations complete. + else + socket_.close(); + }); + } + } + +private: + tcp::socket socket_; + third_party_lib::session session_impl_{socket_}; + bool read_in_progress_ = false; + bool write_in_progress_ = false; +}; + +class server +{ +public: + server(boost::asio::io_context& io_context, unsigned short port) + : acceptor_(io_context, {tcp::v4(), port}) + { + do_accept(); + } + +private: + void do_accept() + { + acceptor_.async_accept( + [this](boost::system::error_code ec, tcp::socket socket) + { + if (!ec) + { + std::make_shared<connection>(std::move(socket))->start(); + } + + do_accept(); + }); + } + + tcp::acceptor acceptor_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: third_party_lib <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + server s(io_context, std::atoi(argv[1])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/operations/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/operations/Jamfile.v2 new file mode 100644 index 000000000..a01b42a3a --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/operations/Jamfile.v2 @@ -0,0 +1,39 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe composed_1 : composed_1.cpp ; +exe composed_2 : composed_2.cpp ; +exe composed_3 : composed_3.cpp ; +exe composed_4 : composed_4.cpp ; +exe composed_5 : composed_5.cpp ; +exe composed_6 : composed_6.cpp ; +exe composed_7 : composed_7.cpp ; +exe composed_8 : composed_8.cpp ; diff --git a/src/boost/libs/asio/example/cpp11/operations/composed_1.cpp b/src/boost/libs/asio/example/cpp11/operations/composed_1.cpp new file mode 100644 index 000000000..31906d006 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/operations/composed_1.cpp @@ -0,0 +1,113 @@ +// +// composed_1.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/use_future.hpp> +#include <boost/asio/write.hpp> +#include <cstring> +#include <iostream> +#include <string> +#include <type_traits> +#include <utility> + +using boost::asio::ip::tcp; + +//------------------------------------------------------------------------------ + +// This is the simplest example of a composed asynchronous operation, where we +// simply repackage an existing operation. The asynchronous operation +// requirements are met by delegating responsibility to the underlying +// operation. + +template <typename CompletionToken> +auto async_write_message(tcp::socket& socket, + const char* message, CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of CompletionToken type and the completion handler's signature. When the + // completion token is a simple callback, the return type is void. However, + // when the completion token is boost::asio::yield_context (used for stackful + // coroutines) the return type would be std::size_t, and when the completion + // token is boost::asio::use_future it would be std::future<std::size_t>. + -> typename boost::asio::async_result< + typename std::decay<CompletionToken>::type, + void(boost::system::error_code, std::size_t)>::return_type +{ + // When delegating to the underlying operation we must take care to perfectly + // forward the completion token. This ensures that our operation works + // correctly with move-only function objects as callbacks, as well as other + // completion token types. + return boost::asio::async_write(socket, + boost::asio::buffer(message, std::strlen(message)), + std::forward<CompletionToken>(token)); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_message(socket, "Testing callback\r\n", + [](const boost::system::error_code& error, std::size_t n) + { + if (!error) + { + std::cout << n << " bytes transferred\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<std::size_t> f = async_write_message( + socket, "Testing future\r\n", boost::asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + std::size_t n = f.get(); + std::cout << n << " bytes transferred\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_future(); +} diff --git a/src/boost/libs/asio/example/cpp11/operations/composed_2.cpp b/src/boost/libs/asio/example/cpp11/operations/composed_2.cpp new file mode 100644 index 000000000..1d0656725 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/operations/composed_2.cpp @@ -0,0 +1,131 @@ +// +// composed_2.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/use_future.hpp> +#include <boost/asio/write.hpp> +#include <cstring> +#include <iostream> +#include <string> +#include <type_traits> +#include <utility> + +using boost::asio::ip::tcp; + +//------------------------------------------------------------------------------ + +// This next simplest example of a composed asynchronous operation involves +// repackaging multiple operations but choosing to invoke just one of them. All +// of these underlying operations have the same completion signature. The +// asynchronous operation requirements are met by delegating responsibility to +// the underlying operations. + +template <typename CompletionToken> +auto async_write_message(tcp::socket& socket, + const char* message, bool allow_partial_write, + CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of CompletionToken type and the completion handler's signature. When the + // completion token is a simple callback, the return type is void. However, + // when the completion token is boost::asio::yield_context (used for stackful + // coroutines) the return type would be std::size_t, and when the completion + // token is boost::asio::use_future it would be std::future<std::size_t>. + -> typename boost::asio::async_result< + typename std::decay<CompletionToken>::type, + void(boost::system::error_code, std::size_t)>::return_type +{ + // As the return type of the initiating function is deduced solely from the + // CompletionToken and completion signature, we know that two different + // asynchronous operations having the same completion signature will produce + // the same return type, when passed the same CompletionToken. This allows us + // to trivially delegate to alternate implementations. + if (allow_partial_write) + { + // When delegating to an underlying operation we must take care to + // perfectly forward the completion token. This ensures that our operation + // works correctly with move-only function objects as callbacks, as well as + // other completion token types. + return socket.async_write_some( + boost::asio::buffer(message, std::strlen(message)), + std::forward<CompletionToken>(token)); + } + else + { + // As above, we must perfectly forward the completion token when calling + // the alternate underlying operation. + return boost::asio::async_write(socket, + boost::asio::buffer(message, std::strlen(message)), + std::forward<CompletionToken>(token)); + } +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_message(socket, "Testing callback\r\n", false, + [](const boost::system::error_code& error, std::size_t n) + { + if (!error) + { + std::cout << n << " bytes transferred\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<std::size_t> f = async_write_message( + socket, "Testing future\r\n", false, boost::asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + std::size_t n = f.get(); + std::cout << n << " bytes transferred\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_future(); +} diff --git a/src/boost/libs/asio/example/cpp11/operations/composed_3.cpp b/src/boost/libs/asio/example/cpp11/operations/composed_3.cpp new file mode 100644 index 000000000..563db94fa --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/operations/composed_3.cpp @@ -0,0 +1,192 @@ +// +// composed_3.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/bind_executor.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/use_future.hpp> +#include <boost/asio/write.hpp> +#include <cstring> +#include <functional> +#include <iostream> +#include <string> +#include <type_traits> +#include <utility> + +using boost::asio::ip::tcp; + +// NOTE: This example requires the new boost::asio::async_initiate function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// In this composed operation we repackage an existing operation, but with a +// different completion handler signature. The asynchronous operation +// requirements are met by delegating responsibility to the underlying +// operation. + +// In addition to determining the mechanism by which an asynchronous operation +// delivers its result, a completion token also determines the time when the +// operation commences. For example, when the completion token is a simple +// callback the operation commences before the initiating function returns. +// However, if the completion token's delivery mechanism uses a future, we +// might instead want to defer initiation of the operation until the returned +// future object is waited upon. +// +// To enable this, when implementing an asynchronous operation we must package +// the initiation step as a function object. +struct async_write_message_initiation +{ + // The initiation function object's call operator is passed the concrete + // completion handler produced by the completion token. This completion + // handler matches the asynchronous operation's completion handler signature, + // which in this example is: + // + // void(boost::system::error_code error) + // + // The initiation function object also receives any additional arguments + // required to start the operation. (Note: We could have instead passed these + // arguments as members in the initiaton function object. However, we should + // prefer to propagate them as function call arguments as this allows the + // completion token to optimise how they are passed. For example, a lazy + // future which defers initiation would need to make a decay-copy of the + // arguments, but when using a simple callback the arguments can be trivially + // forwarded straight through.) + template <typename CompletionHandler> + void operator()(CompletionHandler&& completion_handler, + tcp::socket& socket, const char* message) const + { + // The async_write operation has a completion handler signature of: + // + // void(boost::system::error_code error, std::size n) + // + // This differs from our operation's signature in that it is also passed + // the number of bytes transferred as an argument of type std::size_t. We + // will adapt our completion handler to async_write's completion handler + // signature by using std::bind, which drops the additional argument. + // + // However, it is essential to the correctness of our composed operation + // that we preserve the executor of the user-supplied completion handler. + // The std::bind function will not do this for us, so we must do this by + // first obtaining the completion handler's associated executor (defaulting + // to the I/O executor - in this case the executor of the socket - if the + // completion handler does not have its own) ... + auto executor = boost::asio::get_associated_executor( + completion_handler, socket.get_executor()); + + // ... and then binding this executor to our adapted completion handler + // using the boost::asio::bind_executor function. + boost::asio::async_write(socket, + boost::asio::buffer(message, std::strlen(message)), + boost::asio::bind_executor(executor, + std::bind(std::forward<CompletionHandler>( + completion_handler), std::placeholders::_1))); + } +}; + +template <typename CompletionToken> +auto async_write_message(tcp::socket& socket, + const char* message, CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of CompletionToken type and the completion handler's signature. When the + // completion token is a simple callback, the return type is always void. + // In this example, when the completion token is boost::asio::yield_context + // (used for stackful coroutines) the return type would be also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is boost::asio::use_future it would be std::future<void>. + -> typename boost::asio::async_result< + typename std::decay<CompletionToken>::type, + void(boost::system::error_code)>::return_type +{ + // The boost::asio::async_initiate function takes: + // + // - our initiation function object, + // - the completion token, + // - the completion handler signature, and + // - any additional arguments we need to initiate the operation. + // + // It then asks the completion token to create a completion handler (i.e. a + // callback) with the specified signature, and invoke the initiation function + // object with this completion handler as well as the additional arguments. + // The return value of async_initiate is the result of our operation's + // initiating function. + // + // Note that we wrap non-const reference arguments in std::reference_wrapper + // to prevent incorrect decay-copies of these objects. + return boost::asio::async_initiate< + CompletionToken, void(boost::system::error_code)>( + async_write_message_initiation(), + token, std::ref(socket), message); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_message(socket, "Testing callback\r\n", + [](const boost::system::error_code& error) + { + if (!error) + { + std::cout << "Message sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_message( + socket, "Testing future\r\n", boost::asio::use_future); + + io_context.run(); + + // Get the result of the operation. + try + { + // Get the result of the operation. + f.get(); + std::cout << "Message sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_future(); +} diff --git a/src/boost/libs/asio/example/cpp11/operations/composed_4.cpp b/src/boost/libs/asio/example/cpp11/operations/composed_4.cpp new file mode 100644 index 000000000..cd70684ff --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/operations/composed_4.cpp @@ -0,0 +1,207 @@ +// +// composed_4.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/bind_executor.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/use_future.hpp> +#include <boost/asio/write.hpp> +#include <cstring> +#include <functional> +#include <iostream> +#include <string> +#include <type_traits> +#include <utility> + +using boost::asio::ip::tcp; + +// NOTE: This example requires the new boost::asio::async_initiate function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// In this composed operation we repackage an existing operation, but with a +// different completion handler signature. We will also intercept an empty +// message as an invalid argument, and propagate the corresponding error to the +// user. The asynchronous operation requirements are met by delegating +// responsibility to the underlying operation. + +// In addition to determining the mechanism by which an asynchronous operation +// delivers its result, a completion token also determines the time when the +// operation commences. For example, when the completion token is a simple +// callback the operation commences before the initiating function returns. +// However, if the completion token's delivery mechanism uses a future, we +// might instead want to defer initiation of the operation until the returned +// future object is waited upon. +// +// To enable this, when implementing an asynchronous operation we must package +// the initiation step as a function object. +struct async_write_message_initiation +{ + // The initiation function object's call operator is passed the concrete + // completion handler produced by the completion token. This completion + // handler matches the asynchronous operation's completion handler signature, + // which in this example is: + // + // void(boost::system::error_code error) + // + // The initiation function object also receives any additional arguments + // required to start the operation. (Note: We could have instead passed these + // arguments as members in the initiaton function object. However, we should + // prefer to propagate them as function call arguments as this allows the + // completion token to optimise how they are passed. For example, a lazy + // future which defers initiation would need to make a decay-copy of the + // arguments, but when using a simple callback the arguments can be trivially + // forwarded straight through.) + template <typename CompletionHandler> + void operator()(CompletionHandler&& completion_handler, + tcp::socket& socket, const char* message) const + { + // The post operation has a completion handler signature of: + // + // void() + // + // and the async_write operation has a completion handler signature of: + // + // void(boost::system::error_code error, std::size n) + // + // Both of these operations' completion handler signatures differ from our + // operation's completion handler signature. We will adapt our completion + // handler to these signatures by using std::bind, which drops the + // additional arguments. + // + // However, it is essential to the correctness of our composed operation + // that we preserve the executor of the user-supplied completion handler. + // The std::bind function will not do this for us, so we must do this by + // first obtaining the completion handler's associated executor (defaulting + // to the I/O executor - in this case the executor of the socket - if the + // completion handler does not have its own) ... + auto executor = boost::asio::get_associated_executor( + completion_handler, socket.get_executor()); + + // ... and then binding this executor to our adapted completion handler + // using the boost::asio::bind_executor function. + std::size_t length = std::strlen(message); + if (length == 0) + { + boost::asio::post( + boost::asio::bind_executor(executor, + std::bind(std::forward<CompletionHandler>(completion_handler), + boost::asio::error::invalid_argument))); + } + else + { + boost::asio::async_write(socket, + boost::asio::buffer(message, length), + boost::asio::bind_executor(executor, + std::bind(std::forward<CompletionHandler>(completion_handler), + std::placeholders::_1))); + } + } +}; + +template <typename CompletionToken> +auto async_write_message(tcp::socket& socket, + const char* message, CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of CompletionToken type and the completion handler's signature. When the + // completion token is a simple callback, the return type is always void. + // In this example, when the completion token is boost::asio::yield_context + // (used for stackful coroutines) the return type would be also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is boost::asio::use_future it would be std::future<void>. + -> typename boost::asio::async_result< + typename std::decay<CompletionToken>::type, + void(boost::system::error_code)>::return_type +{ + // The boost::asio::async_initiate function takes: + // + // - our initiation function object, + // - the completion token, + // - the completion handler signature, and + // - any additional arguments we need to initiate the operation. + // + // It then asks the completion token to create a completion handler (i.e. a + // callback) with the specified signature, and invoke the initiation function + // object with this completion handler as well as the additional arguments. + // The return value of async_initiate is the result of our operation's + // initiating function. + // + // Note that we wrap non-const reference arguments in std::reference_wrapper + // to prevent incorrect decay-copies of these objects. + return boost::asio::async_initiate< + CompletionToken, void(boost::system::error_code)>( + async_write_message_initiation(), + token, std::ref(socket), message); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_message(socket, "", + [](const boost::system::error_code& error) + { + if (!error) + { + std::cout << "Message sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_message( + socket, "", boost::asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + f.get(); + std::cout << "Message sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Exception: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_future(); +} diff --git a/src/boost/libs/asio/example/cpp11/operations/composed_5.cpp b/src/boost/libs/asio/example/cpp11/operations/composed_5.cpp new file mode 100644 index 000000000..2f5f823a3 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/operations/composed_5.cpp @@ -0,0 +1,243 @@ +// +// composed_5.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/use_future.hpp> +#include <boost/asio/write.hpp> +#include <functional> +#include <iostream> +#include <memory> +#include <sstream> +#include <string> +#include <type_traits> +#include <utility> + +using boost::asio::ip::tcp; + +// NOTE: This example requires the new boost::asio::async_initiate function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// This composed operation automatically serialises a message, using its I/O +// streams insertion operator, before sending it on the socket. To do this, it +// must allocate a buffer for the encoded message and ensure this buffer's +// validity until the underlying async_write operation completes. + +// In addition to determining the mechanism by which an asynchronous operation +// delivers its result, a completion token also determines the time when the +// operation commences. For example, when the completion token is a simple +// callback the operation commences before the initiating function returns. +// However, if the completion token's delivery mechanism uses a future, we +// might instead want to defer initiation of the operation until the returned +// future object is waited upon. +// +// To enable this, when implementing an asynchronous operation we must package +// the initiation step as a function object. +struct async_write_message_initiation +{ + // The initiation function object's call operator is passed the concrete + // completion handler produced by the completion token. This completion + // handler matches the asynchronous operation's completion handler signature, + // which in this example is: + // + // void(boost::system::error_code error) + // + // The initiation function object also receives any additional arguments + // required to start the operation. (Note: We could have instead passed these + // arguments as members in the initiaton function object. However, we should + // prefer to propagate them as function call arguments as this allows the + // completion token to optimise how they are passed. For example, a lazy + // future which defers initiation would need to make a decay-copy of the + // arguments, but when using a simple callback the arguments can be trivially + // forwarded straight through.) + template <typename CompletionHandler> + void operator()(CompletionHandler&& completion_handler, + tcp::socket& socket, std::unique_ptr<std::string> encoded_message) const + { + // In this example, the composed operation's intermediate completion + // handler is implemented as a hand-crafted function object, rather than + // using a lambda or std::bind. + struct intermediate_completion_handler + { + // The intermediate completion handler holds a reference to the socket so + // that it can obtain the I/O executor (see get_executor below). + tcp::socket& socket_; + + // The allocated buffer for the encoded message. The std::unique_ptr + // smart pointer is move-only, and as a consequence our intermediate + // completion handler is also move-only. + std::unique_ptr<std::string> encoded_message_; + + // The user-supplied completion handler. + typename std::decay<CompletionHandler>::type handler_; + + // The function call operator matches the completion signature of the + // async_write operation. + void operator()(const boost::system::error_code& error, std::size_t /*n*/) + { + // Deallocate the encoded message before calling the user-supplied + // completion handler. + encoded_message_.reset(); + + // Call the user-supplied handler with the result of the operation. + // The arguments must match the completion signature of our composed + // operation. + handler_(error); + } + + // It is essential to the correctness of our composed operation that we + // preserve the executor of the user-supplied completion handler. With a + // hand-crafted function object we can do this by defining a nested type + // executor_type and member function get_executor. These obtain the + // completion handler's associated executor, and default to the I/O + // executor - in this case the executor of the socket - if the completion + // handler does not have its own. + using executor_type = boost::asio::associated_executor_t< + typename std::decay<CompletionHandler>::type, + tcp::socket::executor_type>; + + executor_type get_executor() const noexcept + { + return boost::asio::get_associated_executor( + handler_, socket_.get_executor()); + } + + // Although not necessary for correctness, we may also preserve the + // allocator of the user-supplied completion handler. This is achieved by + // defining a nested type allocator_type and member function + // get_allocator. These obtain the completion handler's associated + // allocator, and default to std::allocator<void> if the completion + // handler does not have its own. + using allocator_type = boost::asio::associated_allocator_t< + typename std::decay<CompletionHandler>::type, + std::allocator<void>>; + + allocator_type get_allocator() const noexcept + { + return boost::asio::get_associated_allocator( + handler_, std::allocator<void>{}); + } + }; + + // Initiate the underlying async_write operation using our intermediate + // completion handler. + auto encoded_message_buffer = boost::asio::buffer(*encoded_message); + boost::asio::async_write(socket, encoded_message_buffer, + intermediate_completion_handler{socket, std::move(encoded_message), + std::forward<CompletionHandler>(completion_handler)}); + } +}; + +template <typename T, typename CompletionToken> +auto async_write_message(tcp::socket& socket, + const T& message, CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of CompletionToken type and the completion handler's signature. When the + // completion token is a simple callback, the return type is always void. + // In this example, when the completion token is boost::asio::yield_context + // (used for stackful coroutines) the return type would be also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is boost::asio::use_future it would be std::future<void>. + -> typename boost::asio::async_result< + typename std::decay<CompletionToken>::type, + void(boost::system::error_code)>::return_type +{ + // Encode the message and copy it into an allocated buffer. The buffer will + // be maintained for the lifetime of the asynchronous operation. + std::ostringstream os; + os << message; + std::unique_ptr<std::string> encoded_message(new std::string(os.str())); + + // The boost::asio::async_initiate function takes: + // + // - our initiation function object, + // - the completion token, + // - the completion handler signature, and + // - any additional arguments we need to initiate the operation. + // + // It then asks the completion token to create a completion handler (i.e. a + // callback) with the specified signature, and invoke the initiation function + // object with this completion handler as well as the additional arguments. + // The return value of async_initiate is the result of our operation's + // initiating function. + // + // Note that we wrap non-const reference arguments in std::reference_wrapper + // to prevent incorrect decay-copies of these objects. + return boost::asio::async_initiate< + CompletionToken, void(boost::system::error_code)>( + async_write_message_initiation(), token, + std::ref(socket), std::move(encoded_message)); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_message(socket, 123456, + [](const boost::system::error_code& error) + { + if (!error) + { + std::cout << "Message sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_message( + socket, 654.321, boost::asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + f.get(); + std::cout << "Message sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Exception: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_future(); +} diff --git a/src/boost/libs/asio/example/cpp11/operations/composed_6.cpp b/src/boost/libs/asio/example/cpp11/operations/composed_6.cpp new file mode 100644 index 000000000..d3a51fc78 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/operations/composed_6.cpp @@ -0,0 +1,302 @@ +// +// composed_6.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/executor_work_guard.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/asio/use_future.hpp> +#include <boost/asio/write.hpp> +#include <functional> +#include <iostream> +#include <memory> +#include <sstream> +#include <string> +#include <type_traits> +#include <utility> + +using boost::asio::ip::tcp; + +// NOTE: This example requires the new boost::asio::async_initiate function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// This composed operation shows composition of multiple underlying operations. +// It automatically serialises a message, using its I/O streams insertion +// operator, before sending it N times on the socket. To do this, it must +// allocate a buffer for the encoded message and ensure this buffer's validity +// until all underlying async_write operation complete. A one second delay is +// inserted prior to each write operation, using a steady_timer. + +// In addition to determining the mechanism by which an asynchronous operation +// delivers its result, a completion token also determines the time when the +// operation commences. For example, when the completion token is a simple +// callback the operation commences before the initiating function returns. +// However, if the completion token's delivery mechanism uses a future, we +// might instead want to defer initiation of the operation until the returned +// future object is waited upon. +// +// To enable this, when implementing an asynchronous operation we must package +// the initiation step as a function object. +struct async_write_message_initiation +{ + // The initiation function object's call operator is passed the concrete + // completion handler produced by the completion token. This completion + // handler matches the asynchronous operation's completion handler signature, + // which in this example is: + // + // void(boost::system::error_code error) + // + // The initiation function object also receives any additional arguments + // required to start the operation. (Note: We could have instead passed these + // arguments as members in the initiaton function object. However, we should + // prefer to propagate them as function call arguments as this allows the + // completion token to optimise how they are passed. For example, a lazy + // future which defers initiation would need to make a decay-copy of the + // arguments, but when using a simple callback the arguments can be trivially + // forwarded straight through.) + template <typename CompletionHandler> + void operator()(CompletionHandler&& completion_handler, tcp::socket& socket, + std::unique_ptr<std::string> encoded_message, std::size_t repeat_count, + std::unique_ptr<boost::asio::steady_timer> delay_timer) const + { + // In this example, the composed operation's intermediate completion + // handler is implemented as a hand-crafted function object. + struct intermediate_completion_handler + { + // The intermediate completion handler holds a reference to the socket as + // it is used for multiple async_write operations, as well as for + // obtaining the I/O executor (see get_executor below). + tcp::socket& socket_; + + // The allocated buffer for the encoded message. The std::unique_ptr + // smart pointer is move-only, and as a consequence our intermediate + // completion handler is also move-only. + std::unique_ptr<std::string> encoded_message_; + + // The repeat count remaining. + std::size_t repeat_count_; + + // A steady timer used for introducing a delay. + std::unique_ptr<boost::asio::steady_timer> delay_timer_; + + // To manage the cycle between the multiple underlying asychronous + // operations, our intermediate completion handler is implemented as a + // state machine. + enum { starting, waiting, writing } state_; + + // As our composed operation performs multiple underlying I/O operations, + // we should maintain a work object against the I/O executor. This tells + // the I/O executor that there is still more work to come in the future. + boost::asio::executor_work_guard<tcp::socket::executor_type> io_work_; + + // The user-supplied completion handler, called once only on completion + // of the entire composed operation. + typename std::decay<CompletionHandler>::type handler_; + + // By having a default value for the second argument, this function call + // operator matches the completion signature of both the async_write and + // steady_timer::async_wait operations. + void operator()(const boost::system::error_code& error, std::size_t = 0) + { + if (!error) + { + switch (state_) + { + case starting: + case writing: + if (repeat_count_ > 0) + { + --repeat_count_; + state_ = waiting; + delay_timer_->expires_after(std::chrono::seconds(1)); + delay_timer_->async_wait(std::move(*this)); + return; // Composed operation not yet complete. + } + break; // Composed operation complete, continue below. + case waiting: + state_ = writing; + boost::asio::async_write(socket_, + boost::asio::buffer(*encoded_message_), std::move(*this)); + return; // Composed operation not yet complete. + } + } + + // This point is reached only on completion of the entire composed + // operation. + + // We no longer have any future work coming for the I/O executor. + io_work_.reset(); + + // Deallocate the encoded message before calling the user-supplied + // completion handler. + encoded_message_.reset(); + + // Call the user-supplied handler with the result of the operation. + handler_(error); + } + + // It is essential to the correctness of our composed operation that we + // preserve the executor of the user-supplied completion handler. With a + // hand-crafted function object we can do this by defining a nested type + // executor_type and member function get_executor. These obtain the + // completion handler's associated executor, and default to the I/O + // executor - in this case the executor of the socket - if the completion + // handler does not have its own. + using executor_type = boost::asio::associated_executor_t< + typename std::decay<CompletionHandler>::type, + tcp::socket::executor_type>; + + executor_type get_executor() const noexcept + { + return boost::asio::get_associated_executor( + handler_, socket_.get_executor()); + } + + // Although not necessary for correctness, we may also preserve the + // allocator of the user-supplied completion handler. This is achieved by + // defining a nested type allocator_type and member function + // get_allocator. These obtain the completion handler's associated + // allocator, and default to std::allocator<void> if the completion + // handler does not have its own. + using allocator_type = boost::asio::associated_allocator_t< + typename std::decay<CompletionHandler>::type, + std::allocator<void>>; + + allocator_type get_allocator() const noexcept + { + return boost::asio::get_associated_allocator( + handler_, std::allocator<void>{}); + } + }; + + // Initiate the underlying async_write operation using our intermediate + // completion handler. + auto encoded_message_buffer = boost::asio::buffer(*encoded_message); + boost::asio::async_write(socket, encoded_message_buffer, + intermediate_completion_handler{ + socket, std::move(encoded_message), + repeat_count, std::move(delay_timer), + intermediate_completion_handler::starting, + boost::asio::make_work_guard(socket.get_executor()), + std::forward<CompletionHandler>(completion_handler)}); + } +}; + +template <typename T, typename CompletionToken> +auto async_write_messages(tcp::socket& socket, + const T& message, std::size_t repeat_count, + CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of CompletionToken type and the completion handler's signature. When the + // completion token is a simple callback, the return type is always void. + // In this example, when the completion token is boost::asio::yield_context + // (used for stackful coroutines) the return type would be also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is boost::asio::use_future it would be std::future<void>. + -> typename boost::asio::async_result< + typename std::decay<CompletionToken>::type, + void(boost::system::error_code)>::return_type +{ + // Encode the message and copy it into an allocated buffer. The buffer will + // be maintained for the lifetime of the composed asynchronous operation. + std::ostringstream os; + os << message; + std::unique_ptr<std::string> encoded_message(new std::string(os.str())); + + // Create a steady_timer to be used for the delay between messages. + std::unique_ptr<boost::asio::steady_timer> delay_timer( + new boost::asio::steady_timer(socket.get_executor())); + + // The boost::asio::async_initiate function takes: + // + // - our initiation function object, + // - the completion token, + // - the completion handler signature, and + // - any additional arguments we need to initiate the operation. + // + // It then asks the completion token to create a completion handler (i.e. a + // callback) with the specified signature, and invoke the initiation function + // object with this completion handler as well as the additional arguments. + // The return value of async_initiate is the result of our operation's + // initiating function. + // + // Note that we wrap non-const reference arguments in std::reference_wrapper + // to prevent incorrect decay-copies of these objects. + return boost::asio::async_initiate< + CompletionToken, void(boost::system::error_code)>( + async_write_message_initiation(), token, std::ref(socket), + std::move(encoded_message), repeat_count, std::move(delay_timer)); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_messages(socket, "Testing callback\r\n", 5, + [](const boost::system::error_code& error) + { + if (!error) + { + std::cout << "Messages sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_messages( + socket, "Testing future\r\n", 5, boost::asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + f.get(); + std::cout << "Messages sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_future(); +} diff --git a/src/boost/libs/asio/example/cpp11/operations/composed_7.cpp b/src/boost/libs/asio/example/cpp11/operations/composed_7.cpp new file mode 100644 index 000000000..1139c2d39 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/operations/composed_7.cpp @@ -0,0 +1,222 @@ +// +// composed_7.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/compose.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/asio/use_future.hpp> +#include <boost/asio/write.hpp> +#include <functional> +#include <iostream> +#include <memory> +#include <sstream> +#include <string> +#include <type_traits> +#include <utility> + +using boost::asio::ip::tcp; + +// NOTE: This example requires the new boost::asio::async_compose function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// This composed operation shows composition of multiple underlying operations. +// It automatically serialises a message, using its I/O streams insertion +// operator, before sending it N times on the socket. To do this, it must +// allocate a buffer for the encoded message and ensure this buffer's validity +// until all underlying async_write operation complete. A one second delay is +// inserted prior to each write operation, using a steady_timer. + +// In this example, the composed operation's logic is implemented as a state +// machine within a hand-crafted function object. +struct async_write_messages_implementation +{ + // The implementation holds a reference to the socket as it is used for + // multiple async_write operations. + tcp::socket& socket_; + + // The allocated buffer for the encoded message. The std::unique_ptr smart + // pointer is move-only, and as a consequence our implementation is also + // move-only. + std::unique_ptr<std::string> encoded_message_; + + // The repeat count remaining. + std::size_t repeat_count_; + + // A steady timer used for introducing a delay. + std::unique_ptr<boost::asio::steady_timer> delay_timer_; + + // To manage the cycle between the multiple underlying asychronous + // operations, our implementation is a state machine. + enum { starting, waiting, writing } state_; + + // The first argument to our function object's call operator is a reference + // to the enclosing intermediate completion handler. This intermediate + // completion handler is provided for us by the boost::asio::async_compose + // function, and takes care of all the details required to implement a + // conforming asynchronous operation. When calling an underlying asynchronous + // operation, we pass it this enclosing intermediate completion handler + // as the completion token. + // + // All arguments after the first must be defaulted to allow the state machine + // to be started, as well as to allow the completion handler to match the + // completion signature of both the async_write and steady_timer::async_wait + // operations. + template <typename Self> + void operator()(Self& self, + const boost::system::error_code& error = boost::system::error_code(), + std::size_t = 0) + { + if (!error) + { + switch (state_) + { + case starting: + case writing: + if (repeat_count_ > 0) + { + --repeat_count_; + state_ = waiting; + delay_timer_->expires_after(std::chrono::seconds(1)); + delay_timer_->async_wait(std::move(self)); + return; // Composed operation not yet complete. + } + break; // Composed operation complete, continue below. + case waiting: + state_ = writing; + boost::asio::async_write(socket_, + boost::asio::buffer(*encoded_message_), std::move(self)); + return; // Composed operation not yet complete. + } + } + + // This point is reached only on completion of the entire composed + // operation. + + // Deallocate the encoded message and delay timer before calling the + // user-supplied completion handler. + encoded_message_.reset(); + delay_timer_.reset(); + + // Call the user-supplied handler with the result of the operation. + self.complete(error); + } +}; + +template <typename T, typename CompletionToken> +auto async_write_messages(tcp::socket& socket, + const T& message, std::size_t repeat_count, + CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of CompletionToken type and the completion handler's signature. When the + // completion token is a simple callback, the return type is always void. + // In this example, when the completion token is boost::asio::yield_context + // (used for stackful coroutines) the return type would be also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is boost::asio::use_future it would be std::future<void>. + -> typename boost::asio::async_result< + typename std::decay<CompletionToken>::type, + void(boost::system::error_code)>::return_type +{ + // Encode the message and copy it into an allocated buffer. The buffer will + // be maintained for the lifetime of the composed asynchronous operation. + std::ostringstream os; + os << message; + std::unique_ptr<std::string> encoded_message(new std::string(os.str())); + + // Create a steady_timer to be used for the delay between messages. + std::unique_ptr<boost::asio::steady_timer> delay_timer( + new boost::asio::steady_timer(socket.get_executor())); + + // The boost::asio::async_compose function takes: + // + // - our asynchronous operation implementation, + // - the completion token, + // - the completion handler signature, and + // - any I/O objects (or executors) used by the operation + // + // It then wraps our implementation in an intermediate completion handler + // that meets the requirements of a conforming asynchronous operation. This + // includes tracking outstanding work against the I/O executors associated + // with the operation (in this example, this is the socket's executor). + return boost::asio::async_compose< + CompletionToken, void(boost::system::error_code)>( + async_write_messages_implementation{ + socket, std::move(encoded_message), + repeat_count, std::move(delay_timer), + async_write_messages_implementation::starting}, + token, socket); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_messages(socket, "Testing callback\r\n", 5, + [](const boost::system::error_code& error) + { + if (!error) + { + std::cout << "Messages sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_messages( + socket, "Testing future\r\n", 5, boost::asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + f.get(); + std::cout << "Messages sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_future(); +} diff --git a/src/boost/libs/asio/example/cpp11/operations/composed_8.cpp b/src/boost/libs/asio/example/cpp11/operations/composed_8.cpp new file mode 100644 index 000000000..4fb684656 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/operations/composed_8.cpp @@ -0,0 +1,217 @@ +// +// composed_8.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/compose.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/asio/use_future.hpp> +#include <boost/asio/write.hpp> +#include <functional> +#include <iostream> +#include <memory> +#include <sstream> +#include <string> +#include <type_traits> +#include <utility> + +using boost::asio::ip::tcp; + +// NOTE: This example requires the new boost::asio::async_compose function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// This composed operation shows composition of multiple underlying operations, +// using asio's stackless coroutines support to express the flow of control. It +// automatically serialises a message, using its I/O streams insertion +// operator, before sending it N times on the socket. To do this, it must +// allocate a buffer for the encoded message and ensure this buffer's validity +// until all underlying async_write operation complete. A one second delay is +// inserted prior to each write operation, using a steady_timer. + +#include <boost/asio/yield.hpp> + +// In this example, the composed operation's logic is implemented as a state +// machine within a hand-crafted function object. +struct async_write_messages_implementation +{ + // The implementation holds a reference to the socket as it is used for + // multiple async_write operations. + tcp::socket& socket_; + + // The allocated buffer for the encoded message. The std::unique_ptr smart + // pointer is move-only, and as a consequence our implementation is also + // move-only. + std::unique_ptr<std::string> encoded_message_; + + // The repeat count remaining. + std::size_t repeat_count_; + + // A steady timer used for introducing a delay. + std::unique_ptr<boost::asio::steady_timer> delay_timer_; + + // The coroutine state. + boost::asio::coroutine coro_; + + // The first argument to our function object's call operator is a reference + // to the enclosing intermediate completion handler. This intermediate + // completion handler is provided for us by the boost::asio::async_compose + // function, and takes care of all the details required to implement a + // conforming asynchronous operation. When calling an underlying asynchronous + // operation, we pass it this enclosing intermediate completion handler + // as the completion token. + // + // All arguments after the first must be defaulted to allow the state machine + // to be started, as well as to allow the completion handler to match the + // completion signature of both the async_write and steady_timer::async_wait + // operations. + template <typename Self> + void operator()(Self& self, + const boost::system::error_code& error = boost::system::error_code(), + std::size_t = 0) + { + reenter (coro_) + { + while (repeat_count_ > 0) + { + --repeat_count_; + + delay_timer_->expires_after(std::chrono::seconds(1)); + yield delay_timer_->async_wait(std::move(self)); + if (error) + break; + + yield boost::asio::async_write(socket_, + boost::asio::buffer(*encoded_message_), std::move(self)); + if (error) + break; + } + + // Deallocate the encoded message and delay timer before calling the + // user-supplied completion handler. + encoded_message_.reset(); + delay_timer_.reset(); + + // Call the user-supplied handler with the result of the operation. + self.complete(error); + } + } +}; + +#include <boost/asio/unyield.hpp> + +template <typename T, typename CompletionToken> +auto async_write_messages(tcp::socket& socket, + const T& message, std::size_t repeat_count, + CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of CompletionToken type and the completion handler's signature. When the + // completion token is a simple callback, the return type is always void. + // In this example, when the completion token is boost::asio::yield_context + // (used for stackful coroutines) the return type would be also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is boost::asio::use_future it would be std::future<void>. + -> typename boost::asio::async_result< + typename std::decay<CompletionToken>::type, + void(boost::system::error_code)>::return_type +{ + // Encode the message and copy it into an allocated buffer. The buffer will + // be maintained for the lifetime of the composed asynchronous operation. + std::ostringstream os; + os << message; + std::unique_ptr<std::string> encoded_message(new std::string(os.str())); + + // Create a steady_timer to be used for the delay between messages. + std::unique_ptr<boost::asio::steady_timer> delay_timer( + new boost::asio::steady_timer(socket.get_executor())); + + // The boost::asio::async_compose function takes: + // + // - our asynchronous operation implementation, + // - the completion token, + // - the completion handler signature, and + // - any I/O objects (or executors) used by the operation + // + // It then wraps our implementation in an intermediate completion handler + // that meets the requirements of a conforming asynchronous operation. This + // includes tracking outstanding work against the I/O executors associated + // with the operation (in this example, this is the socket's executor). + return boost::asio::async_compose< + CompletionToken, void(boost::system::error_code)>( + async_write_messages_implementation{socket, + std::move(encoded_message), repeat_count, + std::move(delay_timer), boost::asio::coroutine()}, + token, socket); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_messages(socket, "Testing callback\r\n", 5, + [](const boost::system::error_code& error) + { + if (!error) + { + std::cout << "Messages sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_messages( + socket, "Testing future\r\n", 5, boost::asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + f.get(); + std::cout << "Messages sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_future(); +} diff --git a/src/boost/libs/asio/example/cpp11/socks4/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/socks4/Jamfile.v2 new file mode 100644 index 000000000..aa1492bad --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/socks4/Jamfile.v2 @@ -0,0 +1,30 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe server + : sync_client.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp11/socks4/socks4.hpp b/src/boost/libs/asio/example/cpp11/socks4/socks4.hpp new file mode 100644 index 000000000..e9d37fbb0 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/socks4/socks4.hpp @@ -0,0 +1,143 @@ +// +// socks4.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef SOCKS4_HPP +#define SOCKS4_HPP + +#include <array> +#include <string> +#include <boost/asio/buffer.hpp> +#include <boost/asio/ip/tcp.hpp> + +namespace socks4 { + +const unsigned char version = 0x04; + +class request +{ +public: + enum command_type + { + connect = 0x01, + bind = 0x02 + }; + + request(command_type cmd, const boost::asio::ip::tcp::endpoint& endpoint, + const std::string& user_id) + : version_(version), + command_(cmd), + user_id_(user_id), + null_byte_(0) + { + // Only IPv4 is supported by the SOCKS 4 protocol. + if (endpoint.protocol() != boost::asio::ip::tcp::v4()) + { + throw boost::system::system_error( + boost::asio::error::address_family_not_supported); + } + + // Convert port number to network byte order. + unsigned short port = endpoint.port(); + port_high_byte_ = (port >> 8) & 0xff; + port_low_byte_ = port & 0xff; + + // Save IP address in network byte order. + address_ = endpoint.address().to_v4().to_bytes(); + } + + std::array<boost::asio::const_buffer, 7> buffers() const + { + return + { + { + boost::asio::buffer(&version_, 1), + boost::asio::buffer(&command_, 1), + boost::asio::buffer(&port_high_byte_, 1), + boost::asio::buffer(&port_low_byte_, 1), + boost::asio::buffer(address_), + boost::asio::buffer(user_id_), + boost::asio::buffer(&null_byte_, 1) + } + }; + } + +private: + unsigned char version_; + unsigned char command_; + unsigned char port_high_byte_; + unsigned char port_low_byte_; + boost::asio::ip::address_v4::bytes_type address_; + std::string user_id_; + unsigned char null_byte_; +}; + +class reply +{ +public: + enum status_type + { + request_granted = 0x5a, + request_failed = 0x5b, + request_failed_no_identd = 0x5c, + request_failed_bad_user_id = 0x5d + }; + + reply() + : null_byte_(0), + status_() + { + } + + std::array<boost::asio::mutable_buffer, 5> buffers() + { + return + { + { + boost::asio::buffer(&null_byte_, 1), + boost::asio::buffer(&status_, 1), + boost::asio::buffer(&port_high_byte_, 1), + boost::asio::buffer(&port_low_byte_, 1), + boost::asio::buffer(address_) + } + }; + } + + bool success() const + { + return null_byte_ == 0 && status_ == request_granted; + } + + unsigned char status() const + { + return status_; + } + + boost::asio::ip::tcp::endpoint endpoint() const + { + unsigned short port = port_high_byte_; + port = (port << 8) & 0xff00; + port = port | port_low_byte_; + + boost::asio::ip::address_v4 address(address_); + + return boost::asio::ip::tcp::endpoint(address, port); + } + +private: + unsigned char null_byte_; + unsigned char status_; + unsigned char port_high_byte_; + unsigned char port_low_byte_; + boost::asio::ip::address_v4::bytes_type address_; +}; + +} // namespace socks4 + +#endif // SOCKS4_HPP diff --git a/src/boost/libs/asio/example/cpp11/socks4/sync_client.cpp b/src/boost/libs/asio/example/cpp11/socks4/sync_client.cpp new file mode 100644 index 000000000..1e8e6b713 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/socks4/sync_client.cpp @@ -0,0 +1,93 @@ +// +// sync_client.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <array> +#include <iostream> +#include <iomanip> +#include <ostream> +#include <string> +#include <boost/asio.hpp> +#include "socks4.hpp" + +using boost::asio::ip::tcp; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 4) + { + std::cout << "Usage: sync_client <socks4server> <socks4port> <user>\n"; + std::cout << "Examples:\n"; + std::cout << " sync_client 127.0.0.1 1080 chris\n"; + std::cout << " sync_client localhost socks chris\n"; + return 1; + } + + boost::asio::io_context io_context; + + // Get a list of endpoints corresponding to the SOCKS 4 server name. + tcp::resolver resolver(io_context); + auto endpoints = resolver.resolve(argv[1], argv[2]); + + // Try each endpoint until we successfully establish a connection to the + // SOCKS 4 server. + tcp::socket socket(io_context); + boost::asio::connect(socket, endpoints); + + // Get an endpoint for the Boost website. This will be passed to the SOCKS + // 4 server. Explicitly specify IPv4 since SOCKS 4 does not support IPv6. + auto http_endpoint = *resolver.resolve(tcp::v4(), "www.boost.org", "http"); + + // Send the request to the SOCKS 4 server. + socks4::request socks_request( + socks4::request::connect, http_endpoint, argv[3]); + boost::asio::write(socket, socks_request.buffers()); + + // Receive a response from the SOCKS 4 server. + socks4::reply socks_reply; + boost::asio::read(socket, socks_reply.buffers()); + + // Check whether we successfully negotiated with the SOCKS 4 server. + if (!socks_reply.success()) + { + std::cout << "Connection failed.\n"; + std::cout << "status = 0x" << std::hex << socks_reply.status(); + return 1; + } + + // Form the HTTP request. We specify the "Connection: close" header so that + // the server will close the socket after transmitting the response. This + // will allow us to treat all data up until the EOF as the response. + std::string request = + "GET / HTTP/1.0\r\n" + "Host: www.boost.org\r\n" + "Accept: */*\r\n" + "Connection: close\r\n\r\n"; + + // Send the HTTP request. + boost::asio::write(socket, boost::asio::buffer(request)); + + // Read until EOF, writing data to output as we go. + std::array<char, 512> response; + boost::system::error_code error; + while (std::size_t s = socket.read_some( + boost::asio::buffer(response), error)) + std::cout.write(response.data(), s); + if (error != boost::asio::error::eof) + throw std::system_error(error); + } + catch (std::exception& e) + { + std::cout << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/spawn/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/spawn/Jamfile.v2 new file mode 100644 index 000000000..573fb124e --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/spawn/Jamfile.v2 @@ -0,0 +1,31 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe server + : echo_server.cpp + /boost/context//boost_context + /boost/coroutine//boost_coroutine + /boost/system//boost_system + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp11/spawn/echo_server.cpp b/src/boost/libs/asio/example/cpp11/spawn/echo_server.cpp new file mode 100644 index 000000000..5fb6bbbfe --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/spawn/echo_server.cpp @@ -0,0 +1,111 @@ +// +// echo_server.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/spawn.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/asio/write.hpp> +#include <iostream> +#include <memory> + +using boost::asio::ip::tcp; + +class session : public std::enable_shared_from_this<session> +{ +public: + explicit session(boost::asio::io_context& io_context, tcp::socket socket) + : socket_(std::move(socket)), + timer_(io_context), + strand_(io_context.get_executor()) + { + } + + void go() + { + auto self(shared_from_this()); + boost::asio::spawn(strand_, + [this, self](boost::asio::yield_context yield) + { + try + { + char data[128]; + for (;;) + { + timer_.expires_from_now(std::chrono::seconds(10)); + std::size_t n = socket_.async_read_some(boost::asio::buffer(data), yield); + boost::asio::async_write(socket_, boost::asio::buffer(data, n), yield); + } + } + catch (std::exception& e) + { + socket_.close(); + timer_.cancel(); + } + }); + + boost::asio::spawn(strand_, + [this, self](boost::asio::yield_context yield) + { + while (socket_.is_open()) + { + boost::system::error_code ignored_ec; + timer_.async_wait(yield[ignored_ec]); + if (timer_.expires_from_now() <= std::chrono::seconds(0)) + socket_.close(); + } + }); + } + +private: + tcp::socket socket_; + boost::asio::steady_timer timer_; + boost::asio::strand<boost::asio::io_context::executor_type> strand_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: echo_server <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + boost::asio::spawn(io_context, + [&](boost::asio::yield_context yield) + { + tcp::acceptor acceptor(io_context, + tcp::endpoint(tcp::v4(), std::atoi(argv[1]))); + + for (;;) + { + boost::system::error_code ec; + tcp::socket socket(io_context); + acceptor.async_accept(socket, yield[ec]); + if (!ec) + { + std::make_shared<session>(io_context, std::move(socket))->go(); + } + } + }); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/spawn/parallel_grep.cpp b/src/boost/libs/asio/example/cpp11/spawn/parallel_grep.cpp new file mode 100644 index 000000000..2c17131a5 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/spawn/parallel_grep.cpp @@ -0,0 +1,84 @@ +// +// parallel_grep.cpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/dispatch.hpp> +#include <boost/asio/post.hpp> +#include <boost/asio/spawn.hpp> +#include <boost/asio/strand.hpp> +#include <boost/asio/thread_pool.hpp> +#include <fstream> +#include <iostream> +#include <string> + +using boost::asio::dispatch; +using boost::asio::spawn; +using boost::asio::strand; +using boost::asio::thread_pool; +using boost::asio::yield_context; + +int main(int argc, char* argv[]) +{ + try + { + if (argc < 2) + { + std::cerr << "Usage: parallel_grep <string> <files...>\n"; + return 1; + } + + // We use a fixed size pool of threads for reading the input files. The + // number of threads is automatically determined based on the number of + // CPUs available in the system. + thread_pool pool; + + // To prevent the output from being garbled, we use a strand to synchronise + // printing. + strand<thread_pool::executor_type> output_strand(pool.get_executor()); + + // Spawn a new coroutine for each file specified on the command line. + std::string search_string = argv[1]; + for (int argn = 2; argn < argc; ++argn) + { + std::string input_file = argv[argn]; + spawn(pool, + [=](yield_context yield) + { + std::ifstream is(input_file.c_str()); + std::string line; + std::size_t line_num = 0; + while (std::getline(is, line)) + { + // If we find a match, send a message to the output. + if (line.find(search_string) != std::string::npos) + { + dispatch(output_strand, + [=] + { + std::cout << input_file << ':' << line << std::endl; + }); + } + + // Every so often we yield control to another coroutine. + if (++line_num % 10 == 0) + post(yield); + } + }); + } + + // Join the thread pool to wait for all the spawned tasks to complete. + pool.join(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/ssl/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/ssl/Jamfile.v2 new file mode 100644 index 000000000..a7805abb8 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/ssl/Jamfile.v2 @@ -0,0 +1,48 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +import os ; + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +if [ os.name ] = NT +{ + lib ssl : : <name>ssleay32 ; + lib crypto : : <name>libeay32 ; +} +else +{ + lib ssl ; + lib crypto ; +} + +project + : requirements + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + <library>ssl + <library>crypto + ; + +exe client : client.cpp ; +exe server : server.cpp ; diff --git a/src/boost/libs/asio/example/cpp11/ssl/README b/src/boost/libs/asio/example/cpp11/ssl/README new file mode 100644 index 000000000..7dea8cc9b --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/ssl/README @@ -0,0 +1,8 @@ +The passphrase for both the CA and server private keys is "test". + + +------------------------------------------------------------------------------- +Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) + +Distributed under the Boost Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/src/boost/libs/asio/example/cpp11/ssl/ca.pem b/src/boost/libs/asio/example/cpp11/ssl/ca.pem new file mode 100644 index 000000000..1ee5f2ca4 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/ssl/ca.pem @@ -0,0 +1,49 @@ +-----BEGIN CERTIFICATE----- +MIIDlzCCAn+gAwIBAgIJAMJYU3U6A0IRMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNV +BAYTAkFVMQwwCgYDVQQIEwNOU1cxDzANBgNVBAcTBlN5ZG5leTENMAsGA1UEChME +YXNpbzAeFw0xNTExMTgyMjMzNDhaFw0yMDExMTYyMjMzNDhaMDsxCzAJBgNVBAYT +AkFVMQwwCgYDVQQIEwNOU1cxDzANBgNVBAcTBlN5ZG5leTENMAsGA1UEChMEYXNp +bzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMcRJocHdVMdLUJ/pypY +QVSTC0t3IIgjwjazrK3kAaoIMvzPmDFxEXWcDx+nyz8kQ/E38Ir/ef2BCNGci5hu +wkfMSuMoW9l2N4hx3QCcF46tTDEZztFxWAH7QbE2wYMlMgKZSxWimNfq0YjxEEXb +QM0lGPLFh7Xoko29H0F3LKaaQV9u/vop3Hs0h12HeWlY4PiLp7QQTNGqbWcXycA0 +NZ/fyismireyEvPAgo6L8iXuAi7g0TVKVNlrticGGjMcMq6IMvxzEpSMkuMQ5rWj +pZjWOoBjSYBuXdblcBRvXhOr2Ws8jJLMZfehKq9q1reQfoGV6xMnbwmumSXbWRWT +0vkCAwEAAaOBnTCBmjAdBgNVHQ4EFgQUK/Zv/AVtfIeucJw8VEtux1dhI1YwawYD +VR0jBGQwYoAUK/Zv/AVtfIeucJw8VEtux1dhI1ahP6Q9MDsxCzAJBgNVBAYTAkFV +MQwwCgYDVQQIEwNOU1cxDzANBgNVBAcTBlN5ZG5leTENMAsGA1UEChMEYXNpb4IJ +AMJYU3U6A0IRMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBABLYXimq +v/HLyIJi7Xn8AJUsICj8LKF/J24nwwiF+ibf7UkoChJURs4nN78bod/lpDVPTEVl +gTBdV/vBJs416sCEFfsGjqB9OBYj4gb0VaJDsQd0+NMvXp0faKv2y9wgScxG9/cg +aM7eRmyfMn1qjb6tpNxVOPpe/nFi8Vx/1orejBRaZr4zF5TkoPepfwLWQeXDUIdE ++QHZ60jZAkR5RXTVU4u3kOKcJs839pmJYyxM4H2VxpR18vy4/YdIVWkREIUM2OgT +5iznIQIIgR56QRGP85uef+I6n0BHzrBk6du69bkQFxrFjLVGlal4bIQqSg4KGWgx +dEdymMWzmMxpO9s= +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +MIIEpgIBAAKCAQEAxxEmhwd1Ux0tQn+nKlhBVJMLS3cgiCPCNrOsreQBqggy/M+Y +MXERdZwPH6fLPyRD8Tfwiv95/YEI0ZyLmG7CR8xK4yhb2XY3iHHdAJwXjq1MMRnO +0XFYAftBsTbBgyUyAplLFaKY1+rRiPEQRdtAzSUY8sWHteiSjb0fQXcspppBX27+ ++incezSHXYd5aVjg+IuntBBM0aptZxfJwDQ1n9/KKyaKt7IS88CCjovyJe4CLuDR +NUpU2Wu2JwYaMxwyrogy/HMSlIyS4xDmtaOlmNY6gGNJgG5d1uVwFG9eE6vZazyM +ksxl96Eqr2rWt5B+gZXrEydvCa6ZJdtZFZPS+QIDAQABAoIBAQCOma+SvPoDzvvU +DiPOxqgOEMPfjHfGbm86xl0luBalGfiEd6WbjVanfGKtF4MWOUFec+chez+FJMEP +fufVC0qrKiJfNVMOpYvEd2SMgkSx1VymM8me6WXVDYsSipn2+1cm228ZEYAR9Emj +oqQ4loaGLlP/3RaJbhBF7ruMJvXaZZQ4fZy74Z4tyRaaE1B659ua7Rjne7eNhQE8 +cR7cQDkxsNNN3LTbfLRwEc/gcDXWgLe5JlR/K4ZrdKc3lyivm+Uew3ubKs+fgkyY +kHmuI3RJGIjpnsZW0/So+pHm3b/fo6lmlhTXtNNd+tkkKn2K9ttbXT3Sc13Pc+4w +c4MLyUpdAoGBAOxTtGDpeF6U4s+GPuOCzHCwKQyzfOyCL/UTZv1UJX7Kn1FYycJH +eOjtBRtS661cGkGd1MPfjdX2VV84AmBGDUmRqJ2KfTI1NjLAEJ115ANTpmSTm3lF +UYncgbzl6aflLpjE1mgY+JTJykYeN5jhhO0r2bsdY7S+zaMCSI5NLuznAoGBANej +aMtqLg2qKoq+fUkNBHHLXelR5dBXFnKgSrTj++H4yeW9pYbl8bK3gTF3I5+dSjHW +DdC4+X09iPqY7p8vm8Gq/vgO8Bu+EnKNVr80PJSj7AzFGd6mk/CVrAzoY2XJWbAp +YFwpo1WfHjS5wBfQzBlXY7kWVB7fj32kk14PYmUfAoGBAJXfd7NGHPoOfdCSGGv8 +VV7ZuQ6+/WiYH4XS6iuaI7VHFsZmAn3dCcbeGbD8Y04r7NLUH0yhB7g7YmTihk87 +3c1cPIy8eS1QJbEFsQPK8fFSKWH7YkwEM/O0DesX+5hodaaYnkiiHXNujYLuQuAH +lV87wfcyajsEDjFkj1L/i9TdAoGBAKYfRUQv8HqmdU+doHb+iEYCHb75UMpHzQtR +YTwpxoo3V5Kdnz9lNeYwaF7rIY59ZgMunEYHumw5U6V625nW228/hF0lZOR6cUu+ +hu2WGHWKMvdDgMJ+IcpeA8WN4cUwcN+9gHZ/vUzg4CxOTSYLvLBpGnIkOXnvUGPC +vaTgxTSRAoGBAOHcuZ9hcUrPuVI1HVkjQQLu5mLZ3tz6linEbe/RCdJMK8JrRX4w +ubB7gFclMYGbLlDNAJVYkydJaCy/2NAI3rfsOda+VmDqGx6z4BbSGceHhomyU1Oo +1H7YaXsuzDkzl23HRsyp0pKJpTdghZdbVsGF8vAB8ygK3ehM233neSln +-----END RSA PRIVATE KEY----- diff --git a/src/boost/libs/asio/example/cpp11/ssl/client.cpp b/src/boost/libs/asio/example/cpp11/ssl/client.cpp new file mode 100644 index 000000000..175c85156 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/ssl/client.cpp @@ -0,0 +1,165 @@ +// +// client.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <cstring> +#include <functional> +#include <iostream> +#include <boost/asio.hpp> +#include <boost/asio/ssl.hpp> + +using boost::asio::ip::tcp; +using std::placeholders::_1; +using std::placeholders::_2; + +enum { max_length = 1024 }; + +class client +{ +public: + client(boost::asio::io_context& io_context, + boost::asio::ssl::context& context, + const tcp::resolver::results_type& endpoints) + : socket_(io_context, context) + { + socket_.set_verify_mode(boost::asio::ssl::verify_peer); + socket_.set_verify_callback( + std::bind(&client::verify_certificate, this, _1, _2)); + + connect(endpoints); + } + +private: + bool verify_certificate(bool preverified, + boost::asio::ssl::verify_context& ctx) + { + // The verify callback can be used to check whether the certificate that is + // being presented is valid for the peer. For example, RFC 2818 describes + // the steps involved in doing this for HTTPS. Consult the OpenSSL + // documentation for more details. Note that the callback is called once + // for each certificate in the certificate chain, starting from the root + // certificate authority. + + // In this example we will simply print the certificate's subject name. + char subject_name[256]; + X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); + X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256); + std::cout << "Verifying " << subject_name << "\n"; + + return preverified; + } + + void connect(const tcp::resolver::results_type& endpoints) + { + boost::asio::async_connect(socket_.lowest_layer(), endpoints, + [this](const boost::system::error_code& error, + const tcp::endpoint& /*endpoint*/) + { + if (!error) + { + handshake(); + } + else + { + std::cout << "Connect failed: " << error.message() << "\n"; + } + }); + } + + void handshake() + { + socket_.async_handshake(boost::asio::ssl::stream_base::client, + [this](const boost::system::error_code& error) + { + if (!error) + { + send_request(); + } + else + { + std::cout << "Handshake failed: " << error.message() << "\n"; + } + }); + } + + void send_request() + { + std::cout << "Enter message: "; + std::cin.getline(request_, max_length); + size_t request_length = std::strlen(request_); + + boost::asio::async_write(socket_, + boost::asio::buffer(request_, request_length), + [this](const boost::system::error_code& error, std::size_t length) + { + if (!error) + { + receive_response(length); + } + else + { + std::cout << "Write failed: " << error.message() << "\n"; + } + }); + } + + void receive_response(std::size_t length) + { + boost::asio::async_read(socket_, + boost::asio::buffer(reply_, length), + [this](const boost::system::error_code& error, std::size_t length) + { + if (!error) + { + std::cout << "Reply: "; + std::cout.write(reply_, length); + std::cout << "\n"; + } + else + { + std::cout << "Read failed: " << error.message() << "\n"; + } + }); + } + + boost::asio::ssl::stream<tcp::socket> socket_; + char request_[max_length]; + char reply_[max_length]; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: client <host> <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + tcp::resolver resolver(io_context); + auto endpoints = resolver.resolve(argv[1], argv[2]); + + boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23); + ctx.load_verify_file("ca.pem"); + + client c(io_context, ctx, endpoints); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/ssl/dh2048.pem b/src/boost/libs/asio/example/cpp11/ssl/dh2048.pem new file mode 100644 index 000000000..07250cca6 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/ssl/dh2048.pem @@ -0,0 +1,8 @@ +-----BEGIN DH PARAMETERS----- +MIIBCAKCAQEAyNnxZSYc6J89mDNnqOH8bnwBiAJxcaUS3PkIEcwW8D9o2BlNq6EO +XKMIbdfwPFZi80GMpNu3YP2A2B42sAHmb7w7ZA92QDv3JjqzR0QuS/CkMv4CEjha +QBFwBDDWnnHBSj4w/t54ii0SH34mWcjBItI2eMtnM9J6fnvNiWqJxdt4iA4mZjZD +qZTjIRyjgKAevzkqAlBqQRoVUUgu+9Cf29wXjVl3bE+0VU5CdFeyT+Y9yunz88mq +rGyx1uPt+zbIfxuNLH+coY67y1ht7iZEL5WLd3wGCycRT+lYy2AL/rxGBPxStFIT +2bOkQao6sAfb4UdGEUlwHUXZrAV51oM30wIBAg== +-----END DH PARAMETERS----- diff --git a/src/boost/libs/asio/example/cpp11/ssl/server.cpp b/src/boost/libs/asio/example/cpp11/ssl/server.cpp new file mode 100644 index 000000000..32936a674 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/ssl/server.cpp @@ -0,0 +1,143 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <functional> +#include <iostream> +#include <boost/asio.hpp> +#include <boost/asio/ssl.hpp> + +using boost::asio::ip::tcp; + +class session : public std::enable_shared_from_this<session> +{ +public: + session(tcp::socket socket, boost::asio::ssl::context& context) + : socket_(std::move(socket), context) + { + } + + void start() + { + do_handshake(); + } + +private: + void do_handshake() + { + auto self(shared_from_this()); + socket_.async_handshake(boost::asio::ssl::stream_base::server, + [this, self](const boost::system::error_code& error) + { + if (!error) + { + do_read(); + } + }); + } + + void do_read() + { + auto self(shared_from_this()); + socket_.async_read_some(boost::asio::buffer(data_), + [this, self](const boost::system::error_code& ec, std::size_t length) + { + if (!ec) + { + do_write(length); + } + }); + } + + void do_write(std::size_t length) + { + auto self(shared_from_this()); + boost::asio::async_write(socket_, boost::asio::buffer(data_, length), + [this, self](const boost::system::error_code& ec, + std::size_t /*length*/) + { + if (!ec) + { + do_read(); + } + }); + } + + boost::asio::ssl::stream<tcp::socket> socket_; + char data_[1024]; +}; + +class server +{ +public: + server(boost::asio::io_context& io_context, unsigned short port) + : acceptor_(io_context, tcp::endpoint(tcp::v4(), port)), + context_(boost::asio::ssl::context::sslv23) + { + context_.set_options( + boost::asio::ssl::context::default_workarounds + | boost::asio::ssl::context::no_sslv2 + | boost::asio::ssl::context::single_dh_use); + context_.set_password_callback(std::bind(&server::get_password, this)); + context_.use_certificate_chain_file("server.pem"); + context_.use_private_key_file("server.pem", boost::asio::ssl::context::pem); + context_.use_tmp_dh_file("dh2048.pem"); + + do_accept(); + } + +private: + std::string get_password() const + { + return "test"; + } + + void do_accept() + { + acceptor_.async_accept( + [this](const boost::system::error_code& error, tcp::socket socket) + { + if (!error) + { + std::make_shared<session>(std::move(socket), context_)->start(); + } + + do_accept(); + }); + } + + tcp::acceptor acceptor_; + boost::asio::ssl::context context_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: server <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + using namespace std; // For atoi. + server s(io_context, atoi(argv[1])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/ssl/server.pem b/src/boost/libs/asio/example/cpp11/ssl/server.pem new file mode 100644 index 000000000..37ea6e267 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/ssl/server.pem @@ -0,0 +1,71 @@ +-----BEGIN CERTIFICATE----- +MIIDAzCCAesCCQD9QcRiWk0y9TANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJB +VTEMMAoGA1UECBMDTlNXMQ8wDQYDVQQHEwZTeWRuZXkxDTALBgNVBAoTBGFzaW8w +HhcNMTUxMTE4MjIzNzMxWhcNMjAxMTE2MjIzNzMxWjBMMQswCQYDVQQGEwJBVTEM +MAoGA1UECBMDTlNXMQ8wDQYDVQQHEwZTeWRuZXkxDTALBgNVBAoTBGFzaW8xDzAN +BgNVBAsTBnNlcnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALr0 ++NXSklsGJR7HYHP/H4V5+KpYrmFKva/K7iiqi+XyWEjGnj+/iImJW26phhg9GouN +JJxdrP7/0LwpMsEC/9v09dMNAEewtYhPgD4kiUH/E/79wVmayMZZZGrpF9Rw+wWv +q58y3L1wKge3qilX6slVDdNhqU3vBiMKEJfsjE4PKcEVjPCjVJG2562eHK9FxyjQ +DykyH61lQKBQOiElilPQKzAO7U36yTvs+chWuUfK47B8EC+PJ5KcLEppli4ljlwE +w01HnGxwvjDLobKm2jL6CWi3aYGWudyTsNAd7YC5C7psktBypQLBcfp7uUrrR5Bb +PEjFHJUWIlyoYvm2OjMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAtceVW6tixFsB +ZRhjL5aRCcbx2iMwEXd54lcP6BWe1qOcDPHoSYI1zvvGzohbEvBfqUv78S9MtzaT +gMe5rIU9M1ZM09PyaM6ZutGpKHE8L4qcOslTt41GQFsSqPFdcbgSV20MvBzjGayR +AI/WV0avW3oasdetJPZCR7bRbCbMbWTgclUfv5F25ENcR+BhNuilfL15owL0s4sS +Wb4jOOHhXV9iXeS2dH0snFqv4BmQ9ZoA7zbM9lG3EU5DuxHESYkCnzJyEqqY3vWv +PFRViCxLp5LQLmkTQ3dglVQA4x6ZaonaewdPtdhjkLUuIqDvQx5+kIaOELbSws+c +bREYlnGrFw== +-----END CERTIFICATE----- +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,D459676347D389E9135496D8AAFA7953 + +wbrjxr9NHur8kgxDsgXOY9qFGKpONIQLxkuahUrDD/H+s/l7ugsLWOPsOXbjNL/7 +QYUBAx85HKm9D8BQ5g78Y82qfArap3/3IIuysDfQDh4fQodhVtmGTFiCOvudlGEp +lq1niQRLThlxeRoFphH8KKiOTO9a/d8tdL7zRmiFwnVnhK4014mgVmgcSefA1AF5 +RbJAeMclUKddG6ltQK00ptg84CDXiMWQXFBGGmQ1av2lyFzC+xLP+qDqZAYTM9lZ +NFRo2oEZP1ozfOVNSbXTanJgZ0DSSmhGE1PcVrHSeE/v+k1kPh3oVKi9GV51kIDC +Zd9f/XltuDOzy1Ybn6gRy4nzNpzcwjSCIHEdSD5nxU5JfHfQ3OtnsEab7qf989iP +s2LbCSp5uGTMvfesMIkixIZAQp2FeahZTAgU2Vx+wi5Kks68rOqeywEfzACL/Um5 +7XZu8gDs4MgRRWnxK1BbJDPifICLvSJZvgB9FKX/hk4FHFF+MtcrkalehCuLooDV +3rfHNvRSbg7J97XQ3QC+k9ZDaumpy6n+LhaVv7BIJRBnBBtZ5Eg3DmPg6flqaHAU +Y/8d82wb/pCmbvR3B1/Ebgs84DPJ+uZnY9M5Iwx19oqlVSR2ts/Tx619LGAm+BiQ +7YDoC4CFmpAA8Uw0xnUbNgx94NdNmlnLeLtS50b0XlWpHKbVzmVbNYEjY6NHMlLt +aqxWHTYTa7g/c1bg2/nxF1Lbfu5VSTROGBUuer1c3yzVuyBrjcX92Jp4BJH78qOp +N6lY6MnH4HYRXHjzlt/S0ZzO0faPPe18Q8SWvnDVuE3fYzzL772B56d2t8eodc+/ +t6M3qJ60eXdsmgYOaPRLRUovN2xT2UUr0+biuguHyqfaVfcEU/adw+b9oUVE+5Nw +nZHI5qhPnhLxChyZqbBl68zMUyKlfff4OyLvRGpfcHwBw6DTGjduB+DDsqqkcIB9 +2VL6nps7ZVCwMPI18siUd6cttEOf6ZXrVqHg9wfDvJOlh2NNKNLxSAFubHc90Jlj +KejrWenXo2w6YkSUeTV4t4cWu7U8rXIkTJXDl1S6NO8DWqNDo5KjgJ2SK5NlSOJ7 +jgECn390ooneJOxxytPVQO2xppXQZZS65RHrvhB+ss5xUknly9q+ICyt6xTR9nqA +PKkeSE6qVY0J4JgFXpkgQxgwMnjSED3LKr3jlz28pr5cC6tsc5SSlekHjT2fcSrX +uccaVahaJRigf+q+4XzmJtdwbZU+YWGZRVMlQLA5yzPHQHDYkPpOeYU4WReND8S4 +TZRkPHaxOZ2lKQwJB93V8Vbt2MvwRy392452a33S4TcQLaWzoOljXjmZjrp2rvRz +prBaNe8LnO4V8Oliv+H+E0UWiWFDuI+HBy4X4O9plsbw/gk64Phl9qLiBwaX/AIR +66FXvC/czABo9oSt2jekcMtJofYr8Gr2bsJlt5ZX+GEOxz4jMv7xvz5/L3W7jVav +pHGIv4xfN9FrXzL47O7UuUF9xZg4Rp/fxwpgEDNZmX/3DnP0ewZQUcgUX0pdqNGQ +YVqJXcRF7KqG2NSQFuwPESZQnxU0WzSgRyUae7xg1WKfSuN8NVAzKhOgeqlD2IAo +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIDlzCCAn+gAwIBAgIJAMJYU3U6A0IRMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNV +BAYTAkFVMQwwCgYDVQQIEwNOU1cxDzANBgNVBAcTBlN5ZG5leTENMAsGA1UEChME +YXNpbzAeFw0xNTExMTgyMjMzNDhaFw0yMDExMTYyMjMzNDhaMDsxCzAJBgNVBAYT +AkFVMQwwCgYDVQQIEwNOU1cxDzANBgNVBAcTBlN5ZG5leTENMAsGA1UEChMEYXNp +bzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMcRJocHdVMdLUJ/pypY +QVSTC0t3IIgjwjazrK3kAaoIMvzPmDFxEXWcDx+nyz8kQ/E38Ir/ef2BCNGci5hu +wkfMSuMoW9l2N4hx3QCcF46tTDEZztFxWAH7QbE2wYMlMgKZSxWimNfq0YjxEEXb +QM0lGPLFh7Xoko29H0F3LKaaQV9u/vop3Hs0h12HeWlY4PiLp7QQTNGqbWcXycA0 +NZ/fyismireyEvPAgo6L8iXuAi7g0TVKVNlrticGGjMcMq6IMvxzEpSMkuMQ5rWj +pZjWOoBjSYBuXdblcBRvXhOr2Ws8jJLMZfehKq9q1reQfoGV6xMnbwmumSXbWRWT +0vkCAwEAAaOBnTCBmjAdBgNVHQ4EFgQUK/Zv/AVtfIeucJw8VEtux1dhI1YwawYD +VR0jBGQwYoAUK/Zv/AVtfIeucJw8VEtux1dhI1ahP6Q9MDsxCzAJBgNVBAYTAkFV +MQwwCgYDVQQIEwNOU1cxDzANBgNVBAcTBlN5ZG5leTENMAsGA1UEChMEYXNpb4IJ +AMJYU3U6A0IRMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBABLYXimq +v/HLyIJi7Xn8AJUsICj8LKF/J24nwwiF+ibf7UkoChJURs4nN78bod/lpDVPTEVl +gTBdV/vBJs416sCEFfsGjqB9OBYj4gb0VaJDsQd0+NMvXp0faKv2y9wgScxG9/cg +aM7eRmyfMn1qjb6tpNxVOPpe/nFi8Vx/1orejBRaZr4zF5TkoPepfwLWQeXDUIdE ++QHZ60jZAkR5RXTVU4u3kOKcJs839pmJYyxM4H2VxpR18vy4/YdIVWkREIUM2OgT +5iznIQIIgR56QRGP85uef+I6n0BHzrBk6du69bkQFxrFjLVGlal4bIQqSg4KGWgx +dEdymMWzmMxpO9s= +-----END CERTIFICATE----- diff --git a/src/boost/libs/asio/example/cpp11/timeouts/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/timeouts/Jamfile.v2 new file mode 100644 index 000000000..dcc83c435 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/timeouts/Jamfile.v2 @@ -0,0 +1,36 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe async_tcp_client : async_tcp_client.cpp ; +exe blocking_tcp_client : blocking_tcp_client.cpp ; +exe blocking_token_tcp_client : blocking_token_tcp_client.cpp ; +exe blocking_udp_client : blocking_udp_client.cpp ; +exe server : server.cpp ; diff --git a/src/boost/libs/asio/example/cpp11/timeouts/async_tcp_client.cpp b/src/boost/libs/asio/example/cpp11/timeouts/async_tcp_client.cpp new file mode 100644 index 000000000..9c6719060 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/timeouts/async_tcp_client.cpp @@ -0,0 +1,311 @@ +// +// async_tcp_client.cpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/buffer.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/read_until.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/asio/write.hpp> +#include <functional> +#include <iostream> +#include <string> + +using boost::asio::steady_timer; +using boost::asio::ip::tcp; +using std::placeholders::_1; +using std::placeholders::_2; + +// +// This class manages socket timeouts by applying the concept of a deadline. +// Some asynchronous operations are given deadlines by which they must complete. +// Deadlines are enforced by an "actor" that persists for the lifetime of the +// client object: +// +// +----------------+ +// | | +// | check_deadline |<---+ +// | | | +// +----------------+ | async_wait() +// | | +// +---------+ +// +// If the deadline actor determines that the deadline has expired, the socket +// is closed and any outstanding operations are consequently cancelled. +// +// Connection establishment involves trying each endpoint in turn until a +// connection is successful, or the available endpoints are exhausted. If the +// deadline actor closes the socket, the connect actor is woken up and moves to +// the next endpoint. +// +// +---------------+ +// | | +// | start_connect |<---+ +// | | | +// +---------------+ | +// | | +// async_- | +----------------+ +// connect() | | | +// +--->| handle_connect | +// | | +// +----------------+ +// : +// Once a connection is : +// made, the connect : +// actor forks in two - : +// : +// an actor for reading : and an actor for +// inbound messages: : sending heartbeats: +// : +// +------------+ : +-------------+ +// | |<- - - - -+- - - - ->| | +// | start_read | | start_write |<---+ +// | |<---+ | | | +// +------------+ | +-------------+ | async_wait() +// | | | | +// async_- | +-------------+ async_- | +--------------+ +// read_- | | | write() | | | +// until() +--->| handle_read | +--->| handle_write | +// | | | | +// +-------------+ +--------------+ +// +// The input actor reads messages from the socket, where messages are delimited +// by the newline character. The deadline for a complete message is 30 seconds. +// +// The heartbeat actor sends a heartbeat (a message that consists of a single +// newline character) every 10 seconds. In this example, no deadline is applied +// to message sending. +// +class client +{ +public: + client(boost::asio::io_context& io_context) + : socket_(io_context), + deadline_(io_context), + heartbeat_timer_(io_context) + { + } + + // Called by the user of the client class to initiate the connection process. + // The endpoints will have been obtained using a tcp::resolver. + void start(tcp::resolver::results_type endpoints) + { + // Start the connect actor. + endpoints_ = endpoints; + start_connect(endpoints_.begin()); + + // Start the deadline actor. You will note that we're not setting any + // particular deadline here. Instead, the connect and input actors will + // update the deadline prior to each asynchronous operation. + deadline_.async_wait(std::bind(&client::check_deadline, this)); + } + + // This function terminates all the actors to shut down the connection. It + // may be called by the user of the client class, or by the class itself in + // response to graceful termination or an unrecoverable error. + void stop() + { + stopped_ = true; + boost::system::error_code ignored_error; + socket_.close(ignored_error); + deadline_.cancel(); + heartbeat_timer_.cancel(); + } + +private: + void start_connect(tcp::resolver::results_type::iterator endpoint_iter) + { + if (endpoint_iter != endpoints_.end()) + { + std::cout << "Trying " << endpoint_iter->endpoint() << "...\n"; + + // Set a deadline for the connect operation. + deadline_.expires_after(std::chrono::seconds(60)); + + // Start the asynchronous connect operation. + socket_.async_connect(endpoint_iter->endpoint(), + std::bind(&client::handle_connect, + this, _1, endpoint_iter)); + } + else + { + // There are no more endpoints to try. Shut down the client. + stop(); + } + } + + void handle_connect(const boost::system::error_code& error, + tcp::resolver::results_type::iterator endpoint_iter) + { + if (stopped_) + return; + + // The async_connect() function automatically opens the socket at the start + // of the asynchronous operation. If the socket is closed at this time then + // the timeout handler must have run first. + if (!socket_.is_open()) + { + std::cout << "Connect timed out\n"; + + // Try the next available endpoint. + start_connect(++endpoint_iter); + } + + // Check if the connect operation failed before the deadline expired. + else if (error) + { + std::cout << "Connect error: " << error.message() << "\n"; + + // We need to close the socket used in the previous connection attempt + // before starting a new one. + socket_.close(); + + // Try the next available endpoint. + start_connect(++endpoint_iter); + } + + // Otherwise we have successfully established a connection. + else + { + std::cout << "Connected to " << endpoint_iter->endpoint() << "\n"; + + // Start the input actor. + start_read(); + + // Start the heartbeat actor. + start_write(); + } + } + + void start_read() + { + // Set a deadline for the read operation. + deadline_.expires_after(std::chrono::seconds(30)); + + // Start an asynchronous operation to read a newline-delimited message. + boost::asio::async_read_until(socket_, + boost::asio::dynamic_buffer(input_buffer_), '\n', + std::bind(&client::handle_read, this, _1, _2)); + } + + void handle_read(const boost::system::error_code& error, std::size_t n) + { + if (stopped_) + return; + + if (!error) + { + // Extract the newline-delimited message from the buffer. + std::string line(input_buffer_.substr(0, n - 1)); + input_buffer_.erase(0, n); + + // Empty messages are heartbeats and so ignored. + if (!line.empty()) + { + std::cout << "Received: " << line << "\n"; + } + + start_read(); + } + else + { + std::cout << "Error on receive: " << error.message() << "\n"; + + stop(); + } + } + + void start_write() + { + if (stopped_) + return; + + // Start an asynchronous operation to send a heartbeat message. + boost::asio::async_write(socket_, boost::asio::buffer("\n", 1), + std::bind(&client::handle_write, this, _1)); + } + + void handle_write(const boost::system::error_code& error) + { + if (stopped_) + return; + + if (!error) + { + // Wait 10 seconds before sending the next heartbeat. + heartbeat_timer_.expires_after(std::chrono::seconds(10)); + heartbeat_timer_.async_wait(std::bind(&client::start_write, this)); + } + else + { + std::cout << "Error on heartbeat: " << error.message() << "\n"; + + stop(); + } + } + + void check_deadline() + { + if (stopped_) + return; + + // Check whether the deadline has passed. We compare the deadline against + // the current time since a new asynchronous operation may have moved the + // deadline before this actor had a chance to run. + if (deadline_.expiry() <= steady_timer::clock_type::now()) + { + // The deadline has passed. The socket is closed so that any outstanding + // asynchronous operations are cancelled. + socket_.close(); + + // There is no longer an active deadline. The expiry is set to the + // maximum time point so that the actor takes no action until a new + // deadline is set. + deadline_.expires_at(steady_timer::time_point::max()); + } + + // Put the actor back to sleep. + deadline_.async_wait(std::bind(&client::check_deadline, this)); + } + +private: + bool stopped_ = false; + tcp::resolver::results_type endpoints_; + tcp::socket socket_; + std::string input_buffer_; + steady_timer deadline_; + steady_timer heartbeat_timer_; +}; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage: client <host> <port>\n"; + return 1; + } + + boost::asio::io_context io_context; + tcp::resolver r(io_context); + client c(io_context); + + c.start(r.resolve(argv[1], argv[2])); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/timeouts/blocking_tcp_client.cpp b/src/boost/libs/asio/example/cpp11/timeouts/blocking_tcp_client.cpp new file mode 100644 index 000000000..f64ba66a2 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/timeouts/blocking_tcp_client.cpp @@ -0,0 +1,192 @@ +// +// blocking_tcp_client.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/buffer.hpp> +#include <boost/asio/connect.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/read_until.hpp> +#include <boost/system/system_error.hpp> +#include <boost/asio/write.hpp> +#include <cstdlib> +#include <iostream> +#include <string> + +using boost::asio::ip::tcp; + +//---------------------------------------------------------------------- + +// +// This class manages socket timeouts by running the io_context using the timed +// io_context::run_for() member function. Each asynchronous operation is given +// a timeout within which it must complete. The socket operations themselves +// use lambdas as completion handlers. For a given socket operation, the client +// object runs the io_context to block thread execution until the operation +// completes or the timeout is reached. If the io_context::run_for() function +// times out, the socket is closed and the outstanding asynchronous operation +// is cancelled. +// +class client +{ +public: + void connect(const std::string& host, const std::string& service, + std::chrono::steady_clock::duration timeout) + { + // Resolve the host name and service to a list of endpoints. + auto endpoints = tcp::resolver(io_context_).resolve(host, service); + + // Start the asynchronous operation itself. The lambda that is used as a + // callback will update the error variable when the operation completes. + // The blocking_udp_client.cpp example shows how you can use std::bind + // rather than a lambda. + boost::system::error_code error; + boost::asio::async_connect(socket_, endpoints, + [&](const boost::system::error_code& result_error, + const tcp::endpoint& /*result_endpoint*/) + { + error = result_error; + }); + + // Run the operation until it completes, or until the timeout. + run(timeout); + + // Determine whether a connection was successfully established. + if (error) + throw std::system_error(error); + } + + std::string read_line(std::chrono::steady_clock::duration timeout) + { + // Start the asynchronous operation. The lambda that is used as a callback + // will update the error and n variables when the operation completes. The + // blocking_udp_client.cpp example shows how you can use std::bind rather + // than a lambda. + boost::system::error_code error; + std::size_t n = 0; + boost::asio::async_read_until(socket_, + boost::asio::dynamic_buffer(input_buffer_), '\n', + [&](const boost::system::error_code& result_error, + std::size_t result_n) + { + error = result_error; + n = result_n; + }); + + // Run the operation until it completes, or until the timeout. + run(timeout); + + // Determine whether the read completed successfully. + if (error) + throw std::system_error(error); + + std::string line(input_buffer_.substr(0, n - 1)); + input_buffer_.erase(0, n); + return line; + } + + void write_line(const std::string& line, + std::chrono::steady_clock::duration timeout) + { + std::string data = line + "\n"; + + // Start the asynchronous operation itself. The lambda that is used as a + // callback will update the error variable when the operation completes. + // The blocking_udp_client.cpp example shows how you can use std::bind + // rather than a lambda. + boost::system::error_code error; + boost::asio::async_write(socket_, boost::asio::buffer(data), + [&](const boost::system::error_code& result_error, + std::size_t /*result_n*/) + { + error = result_error; + }); + + // Run the operation until it completes, or until the timeout. + run(timeout); + + // Determine whether the read completed successfully. + if (error) + throw std::system_error(error); + } + +private: + void run(std::chrono::steady_clock::duration timeout) + { + // Restart the io_context, as it may have been left in the "stopped" state + // by a previous operation. + io_context_.restart(); + + // Block until the asynchronous operation has completed, or timed out. If + // the pending asynchronous operation is a composed operation, the deadline + // applies to the entire operation, rather than individual operations on + // the socket. + io_context_.run_for(timeout); + + // If the asynchronous operation completed successfully then the io_context + // would have been stopped due to running out of work. If it was not + // stopped, then the io_context::run_for call must have timed out. + if (!io_context_.stopped()) + { + // Close the socket to cancel the outstanding asynchronous operation. + socket_.close(); + + // Run the io_context again until the operation completes. + io_context_.run(); + } + } + + boost::asio::io_context io_context_; + tcp::socket socket_{io_context_}; + std::string input_buffer_; +}; + +//---------------------------------------------------------------------- + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 4) + { + std::cerr << "Usage: blocking_tcp_client <host> <port> <message>\n"; + return 1; + } + + client c; + c.connect(argv[1], argv[2], std::chrono::seconds(10)); + + auto time_sent = std::chrono::steady_clock::now(); + + c.write_line(argv[3], std::chrono::seconds(10)); + + for (;;) + { + std::string line = c.read_line(std::chrono::seconds(10)); + + // Keep going until we get back the line that was sent. + if (line == argv[3]) + break; + } + + auto time_received = std::chrono::steady_clock::now(); + + std::cout << "Round trip time: "; + std::cout << std::chrono::duration_cast< + std::chrono::microseconds>( + time_received - time_sent).count(); + std::cout << " microseconds\n"; + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/timeouts/blocking_token_tcp_client.cpp b/src/boost/libs/asio/example/cpp11/timeouts/blocking_token_tcp_client.cpp new file mode 100644 index 000000000..031275f73 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/timeouts/blocking_token_tcp_client.cpp @@ -0,0 +1,199 @@ +// +// blocking_token_tcp_client.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/connect.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/read_until.hpp> +#include <boost/asio/streambuf.hpp> +#include <boost/system/system_error.hpp> +#include <boost/asio/write.hpp> +#include <cstdlib> +#include <iostream> +#include <memory> +#include <string> + +using boost::asio::ip::tcp; + +// We will use our sockets only with an io_context. +using tcp_socket = boost::asio::basic_stream_socket< + tcp, boost::asio::io_context::executor_type>; + +//---------------------------------------------------------------------- + +// A custom completion token that makes asynchronous operations behave as +// though they are blocking calls with a timeout. +struct close_after +{ + close_after(std::chrono::steady_clock::duration t, tcp_socket& s) + : timeout_(t), socket_(s) + { + } + + // The maximum time to wait for an asynchronous operation to complete. + std::chrono::steady_clock::duration timeout_; + + // The socket to be closed if the operation does not complete in time. + tcp_socket& socket_; +}; + +namespace boost { +namespace asio { + +// The async_result template is specialised to allow the close_after token to +// be used with asynchronous operations that have a completion signature of +// void(error_code, T). Generalising this for all completion signature forms is +// left as an exercise for the reader. +template <typename T> +class async_result<close_after, void(boost::system::error_code, T)> +{ +public: + // An asynchronous operation's initiating function automatically creates an + // completion_handler_type object from the token. This function object is + // then called on completion of the asynchronous operation. + class completion_handler_type + { + public: + completion_handler_type(const close_after& token) + : token_(token) + { + } + + void operator()(const boost::system::error_code& error, T t) + { + *error_ = error; + *t_ = t; + } + + private: + friend class async_result; + close_after token_; + boost::system::error_code* error_; + T* t_; + }; + + // The async_result constructor associates the completion handler object with + // the result of the initiating function. + explicit async_result(completion_handler_type& h) + : timeout_(h.token_.timeout_), + socket_(h.token_.socket_) + { + h.error_ = &error_; + h.t_ = &t_; + } + + // The return_type typedef determines the result type of the asynchronous + // operation's initiating function. + typedef T return_type; + + // The get() function is used to obtain the result of the asynchronous + // operation's initiating function. For the close_after completion token, we + // use this function to run the io_context until the operation is complete. + return_type get() + { + boost::asio::io_context& io_context = socket_.get_executor().context(); + + // Restart the io_context, as it may have been left in the "stopped" state + // by a previous operation. + io_context.restart(); + + // Block until the asynchronous operation has completed, or timed out. If + // the pending asynchronous operation is a composed operation, the deadline + // applies to the entire operation, rather than individual operations on + // the socket. + io_context.run_for(timeout_); + + // If the asynchronous operation completed successfully then the io_context + // would have been stopped due to running out of work. If it was not + // stopped, then the io_context::run_for call must have timed out and the + // operation is still incomplete. + if (!io_context.stopped()) + { + // Close the socket to cancel the outstanding asynchronous operation. + socket_.close(); + + // Run the io_context again until the operation completes. + io_context.run(); + } + + // If the operation failed, throw an exception. Otherwise return the result. + return error_ ? throw std::system_error(error_) : t_; + } + +private: + std::chrono::steady_clock::duration timeout_; + tcp_socket& socket_; + boost::system::error_code error_; + T t_; +}; + +} // namespace asio +} // namespace boost + +//---------------------------------------------------------------------- + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 4) + { + std::cerr << "Usage: blocking_tcp_client <host> <port> <message>\n"; + return 1; + } + + boost::asio::io_context io_context; + + // Resolve the host name and service to a list of endpoints. + auto endpoints = tcp::resolver(io_context).resolve(argv[1], argv[2]); + + tcp_socket socket(io_context); + + // Run an asynchronous connect operation with a timeout. + boost::asio::async_connect(socket, endpoints, + close_after(std::chrono::seconds(10), socket)); + + auto time_sent = std::chrono::steady_clock::now(); + + // Run an asynchronous write operation with a timeout. + std::string msg = argv[3] + std::string("\n"); + boost::asio::async_write(socket, boost::asio::buffer(msg), + close_after(std::chrono::seconds(10), socket)); + + for (std::string input_buffer;;) + { + // Run an asynchronous read operation with a timeout. + std::size_t n = boost::asio::async_read_until(socket, + boost::asio::dynamic_buffer(input_buffer), '\n', + close_after(std::chrono::seconds(10), socket)); + + std::string line(input_buffer.substr(0, n - 1)); + input_buffer.erase(0, n); + + // Keep going until we get back the line that was sent. + if (line == argv[3]) + break; + } + + auto time_received = std::chrono::steady_clock::now(); + + std::cout << "Round trip time: "; + std::cout << std::chrono::duration_cast< + std::chrono::microseconds>( + time_received - time_sent).count(); + std::cout << " microseconds\n"; + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/timeouts/blocking_udp_client.cpp b/src/boost/libs/asio/example/cpp11/timeouts/blocking_udp_client.cpp new file mode 100644 index 000000000..c769e3e7b --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/timeouts/blocking_udp_client.cpp @@ -0,0 +1,155 @@ +// +// blocking_udp_client.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/buffer.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/udp.hpp> +#include <cstdlib> +#include <functional> +#include <iostream> + +using boost::asio::ip::udp; +using std::placeholders::_1; +using std::placeholders::_2; + +//---------------------------------------------------------------------- + +// +// This class manages socket timeouts by running the io_context using the timed +// io_context::run_for() member function. Each asynchronous operation is given +// a timeout within which it must complete. The socket operations themselves +// use std::bind to specify the completion handler: +// +// +---------------+ +// | | +// | receive | +// | | +// +---------------+ +// | +// async_- | +----------------+ +// receive() | | | +// +--->| handle_receive | +// | | +// +----------------+ +// +// For a given socket operation, the client object runs the io_context to block +// thread execution until the operation completes or the timeout is reached. If +// the io_context::run_for() function times out, the socket is closed and the +// outstanding asynchronous operation is cancelled. +// +class client +{ +public: + client(const udp::endpoint& listen_endpoint) + : socket_(io_context_, listen_endpoint) + { + } + + std::size_t receive(const boost::asio::mutable_buffer& buffer, + std::chrono::steady_clock::duration timeout, + boost::system::error_code& error) + { + // Start the asynchronous operation. The handle_receive function used as a + // callback will update the error and length variables. + std::size_t length = 0; + socket_.async_receive(boost::asio::buffer(buffer), + std::bind(&client::handle_receive, _1, _2, &error, &length)); + + // Run the operation until it completes, or until the timeout. + run(timeout); + + return length; + } + +private: + void run(std::chrono::steady_clock::duration timeout) + { + // Restart the io_context, as it may have been left in the "stopped" state + // by a previous operation. + io_context_.restart(); + + // Block until the asynchronous operation has completed, or timed out. If + // the pending asynchronous operation is a composed operation, the deadline + // applies to the entire operation, rather than individual operations on + // the socket. + io_context_.run_for(timeout); + + // If the asynchronous operation completed successfully then the io_context + // would have been stopped due to running out of work. If it was not + // stopped, then the io_context::run_for call must have timed out. + if (!io_context_.stopped()) + { + // Cancel the outstanding asynchronous operation. + socket_.cancel(); + + // Run the io_context again until the operation completes. + io_context_.run(); + } + } + + static void handle_receive( + const boost::system::error_code& error, std::size_t length, + boost::system::error_code* out_error, std::size_t* out_length) + { + *out_error = error; + *out_length = length; + } + +private: + boost::asio::io_context io_context_; + udp::socket socket_; +}; + +//---------------------------------------------------------------------- + +int main(int argc, char* argv[]) +{ + try + { + using namespace std; // For atoi. + + if (argc != 3) + { + std::cerr << "Usage: blocking_udp_client <listen_addr> <listen_port>\n"; + return 1; + } + + udp::endpoint listen_endpoint( + boost::asio::ip::make_address(argv[1]), + std::atoi(argv[2])); + + client c(listen_endpoint); + + for (;;) + { + char data[1024]; + boost::system::error_code error; + std::size_t n = c.receive(boost::asio::buffer(data), + std::chrono::seconds(10), error); + + if (error) + { + std::cout << "Receive error: " << error.message() << "\n"; + } + else + { + std::cout << "Received: "; + std::cout.write(data, n); + std::cout << "\n"; + } + } + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/timeouts/server.cpp b/src/boost/libs/asio/example/cpp11/timeouts/server.cpp new file mode 100644 index 000000000..e693791b4 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/timeouts/server.cpp @@ -0,0 +1,433 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <algorithm> +#include <cstdlib> +#include <deque> +#include <iostream> +#include <memory> +#include <set> +#include <string> +#include <boost/asio/buffer.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/ip/udp.hpp> +#include <boost/asio/read_until.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/asio/write.hpp> + +using boost::asio::steady_timer; +using boost::asio::ip::tcp; +using boost::asio::ip::udp; + +//---------------------------------------------------------------------- + +class subscriber +{ +public: + virtual ~subscriber() = default; + virtual void deliver(const std::string& msg) = 0; +}; + +typedef std::shared_ptr<subscriber> subscriber_ptr; + +//---------------------------------------------------------------------- + +class channel +{ +public: + void join(subscriber_ptr subscriber) + { + subscribers_.insert(subscriber); + } + + void leave(subscriber_ptr subscriber) + { + subscribers_.erase(subscriber); + } + + void deliver(const std::string& msg) + { + for (const auto& s : subscribers_) + { + s->deliver(msg); + } + } + +private: + std::set<subscriber_ptr> subscribers_; +}; + +//---------------------------------------------------------------------- + +// +// This class manages socket timeouts by applying the concept of a deadline. +// Some asynchronous operations are given deadlines by which they must complete. +// Deadlines are enforced by two "actors" that persist for the lifetime of the +// session object, one for input and one for output: +// +// +----------------+ +----------------+ +// | | | | +// | check_deadline |<-------+ | check_deadline |<-------+ +// | | | | | | +// +----------------+ | +----------------+ | +// | | | | +// async_wait() | +----------------+ async_wait() | +----------------+ +// on input | | lambda | on output | | lambda | +// deadline +--->| in | deadline +--->| in | +// | check_deadline | | check_deadline | +// +----------------+ +----------------+ +// +// If either deadline actor determines that the corresponding deadline has +// expired, the socket is closed and any outstanding operations are cancelled. +// +// The input actor reads messages from the socket, where messages are delimited +// by the newline character: +// +// +-------------+ +// | | +// | read_line |<----+ +// | | | +// +-------------+ | +// | | +// async_- | +-------------+ +// read_- | | lambda | +// until() +--->| in | +// | read_line | +// +-------------+ +// +// The deadline for receiving a complete message is 30 seconds. If a non-empty +// message is received, it is delivered to all subscribers. If a heartbeat (a +// message that consists of a single newline character) is received, a heartbeat +// is enqueued for the client, provided there are no other messages waiting to +// be sent. +// +// The output actor is responsible for sending messages to the client: +// +// +----------------+ +// | |<---------------------+ +// | await_output | | +// | |<-------+ | +// +----------------+ | | +// | | | | +// | async_- | +----------------+ | +// | wait() | | lambda | | +// | +->| in | | +// | | await_output | | +// | +----------------+ | +// V | +// +--------------+ +--------------+ +// | | async_write() | lambda | +// | write_line |-------------->| in | +// | | | write_line | +// +--------------+ +--------------+ +// +// The output actor first waits for an output message to be enqueued. It does +// this by using a steady_timer as an asynchronous condition variable. The +// steady_timer will be signalled whenever the output queue is non-empty. +// +// Once a message is available, it is sent to the client. The deadline for +// sending a complete message is 30 seconds. After the message is successfully +// sent, the output actor again waits for the output queue to become non-empty. +// +class tcp_session + : public subscriber, + public std::enable_shared_from_this<tcp_session> +{ +public: + tcp_session(tcp::socket socket, channel& ch) + : channel_(ch), + socket_(std::move(socket)) + { + input_deadline_.expires_at(steady_timer::time_point::max()); + output_deadline_.expires_at(steady_timer::time_point::max()); + + // The non_empty_output_queue_ steady_timer is set to the maximum time + // point whenever the output queue is empty. This ensures that the output + // actor stays asleep until a message is put into the queue. + non_empty_output_queue_.expires_at(steady_timer::time_point::max()); + } + + // Called by the server object to initiate the four actors. + void start() + { + channel_.join(shared_from_this()); + + read_line(); + check_deadline(input_deadline_); + + await_output(); + check_deadline(output_deadline_); + } + +private: + void stop() + { + channel_.leave(shared_from_this()); + + boost::system::error_code ignored_error; + socket_.close(ignored_error); + input_deadline_.cancel(); + non_empty_output_queue_.cancel(); + output_deadline_.cancel(); + } + + bool stopped() const + { + return !socket_.is_open(); + } + + void deliver(const std::string& msg) override + { + output_queue_.push_back(msg + "\n"); + + // Signal that the output queue contains messages. Modifying the expiry + // will wake the output actor, if it is waiting on the timer. + non_empty_output_queue_.expires_at(steady_timer::time_point::min()); + } + + void read_line() + { + // Set a deadline for the read operation. + input_deadline_.expires_after(std::chrono::seconds(30)); + + // Start an asynchronous operation to read a newline-delimited message. + auto self(shared_from_this()); + boost::asio::async_read_until(socket_, + boost::asio::dynamic_buffer(input_buffer_), '\n', + [this, self](const boost::system::error_code& error, std::size_t n) + { + // Check if the session was stopped while the operation was pending. + if (stopped()) + return; + + if (!error) + { + // Extract the newline-delimited message from the buffer. + std::string msg(input_buffer_.substr(0, n - 1)); + input_buffer_.erase(0, n); + + if (!msg.empty()) + { + channel_.deliver(msg); + } + else + { + + // We received a heartbeat message from the client. If there's + // nothing else being sent or ready to be sent, send a heartbeat + // right back. + if (output_queue_.empty()) + { + output_queue_.push_back("\n"); + + // Signal that the output queue contains messages. Modifying + // the expiry will wake the output actor, if it is waiting on + // the timer. + non_empty_output_queue_.expires_at( + steady_timer::time_point::min()); + } + } + + read_line(); + } + else + { + stop(); + } + }); + } + + void await_output() + { + auto self(shared_from_this()); + non_empty_output_queue_.async_wait( + [this, self](const boost::system::error_code& /*error*/) + { + // Check if the session was stopped while the operation was pending. + if (stopped()) + return; + + if (output_queue_.empty()) + { + // There are no messages that are ready to be sent. The actor goes + // to sleep by waiting on the non_empty_output_queue_ timer. When a + // new message is added, the timer will be modified and the actor + // will wake. + non_empty_output_queue_.expires_at(steady_timer::time_point::max()); + await_output(); + } + else + { + write_line(); + } + }); + } + + void write_line() + { + // Set a deadline for the write operation. + output_deadline_.expires_after(std::chrono::seconds(30)); + + // Start an asynchronous operation to send a message. + auto self(shared_from_this()); + boost::asio::async_write(socket_, + boost::asio::buffer(output_queue_.front()), + [this, self](const boost::system::error_code& error, std::size_t /*n*/) + { + // Check if the session was stopped while the operation was pending. + if (stopped()) + return; + + if (!error) + { + output_queue_.pop_front(); + + await_output(); + } + else + { + stop(); + } + }); + } + + void check_deadline(steady_timer& deadline) + { + auto self(shared_from_this()); + deadline.async_wait( + [this, self, &deadline](const boost::system::error_code& /*error*/) + { + // Check if the session was stopped while the operation was pending. + if (stopped()) + return; + + // Check whether the deadline has passed. We compare the deadline + // against the current time since a new asynchronous operation may + // have moved the deadline before this actor had a chance to run. + if (deadline.expiry() <= steady_timer::clock_type::now()) + { + // The deadline has passed. Stop the session. The other actors will + // terminate as soon as possible. + stop(); + } + else + { + // Put the actor back to sleep. + check_deadline(deadline); + } + }); + } + + channel& channel_; + tcp::socket socket_; + std::string input_buffer_; + steady_timer input_deadline_{socket_.get_executor()}; + std::deque<std::string> output_queue_; + steady_timer non_empty_output_queue_{socket_.get_executor()}; + steady_timer output_deadline_{socket_.get_executor()}; +}; + +typedef std::shared_ptr<tcp_session> tcp_session_ptr; + +//---------------------------------------------------------------------- + +class udp_broadcaster + : public subscriber +{ +public: + udp_broadcaster(boost::asio::io_context& io_context, + const udp::endpoint& broadcast_endpoint) + : socket_(io_context) + { + socket_.connect(broadcast_endpoint); + socket_.set_option(udp::socket::broadcast(true)); + } + +private: + void deliver(const std::string& msg) + { + boost::system::error_code ignored_error; + socket_.send(boost::asio::buffer(msg), 0, ignored_error); + } + + udp::socket socket_; +}; + +//---------------------------------------------------------------------- + +class server +{ +public: + server(boost::asio::io_context& io_context, + const tcp::endpoint& listen_endpoint, + const udp::endpoint& broadcast_endpoint) + : io_context_(io_context), + acceptor_(io_context, listen_endpoint) + { + channel_.join( + std::make_shared<udp_broadcaster>( + io_context_, broadcast_endpoint)); + + accept(); + } + +private: + void accept() + { + acceptor_.async_accept( + [this](const boost::system::error_code& error, tcp::socket socket) + { + if (!error) + { + std::make_shared<tcp_session>(std::move(socket), channel_)->start(); + } + + accept(); + }); + } + + boost::asio::io_context& io_context_; + tcp::acceptor acceptor_; + channel channel_; +}; + +//---------------------------------------------------------------------- + +int main(int argc, char* argv[]) +{ + try + { + using namespace std; // For atoi. + + if (argc != 4) + { + std::cerr << "Usage: server <listen_port> <bcast_address> <bcast_port>\n"; + return 1; + } + + boost::asio::io_context io_context; + + tcp::endpoint listen_endpoint(tcp::v4(), atoi(argv[1])); + + udp::endpoint broadcast_endpoint( + boost::asio::ip::make_address(argv[2]), atoi(argv[3])); + + server s(io_context, listen_endpoint, broadcast_endpoint); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp11/timers/Jamfile.v2 b/src/boost/libs/asio/example/cpp11/timers/Jamfile.v2 new file mode 100644 index 000000000..7c57391ed --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/timers/Jamfile.v2 @@ -0,0 +1,30 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +exe time_t_timer + : time_t_timer.cpp + /boost/system//boost_system + /boost/chrono//boost_chrono + : <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; diff --git a/src/boost/libs/asio/example/cpp11/timers/time_t_timer.cpp b/src/boost/libs/asio/example/cpp11/timers/time_t_timer.cpp new file mode 100644 index 000000000..9ac53d343 --- /dev/null +++ b/src/boost/libs/asio/example/cpp11/timers/time_t_timer.cpp @@ -0,0 +1,106 @@ +// +// time_t_timer.cpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio.hpp> +#include <ctime> +#include <chrono> +#include <iostream> + +// A custom implementation of the Clock concept from the standard C++ library. +struct time_t_clock +{ + // The duration type. + typedef std::chrono::steady_clock::duration duration; + + // The duration's underlying arithmetic representation. + typedef duration::rep rep; + + // The ratio representing the duration's tick period. + typedef duration::period period; + + // An absolute time point represented using the clock. + typedef std::chrono::time_point<time_t_clock> time_point; + + // The clock is not monotonically increasing. + static constexpr bool is_steady = false; + + // Get the current time. + static time_point now() noexcept + { + return time_point() + std::chrono::seconds(std::time(0)); + } +}; + +// The boost::asio::basic_waitable_timer template accepts an optional WaitTraits +// template parameter. The underlying time_t clock has one-second granularity, +// so these traits may be customised to reduce the latency between the clock +// ticking over and a wait operation's completion. When the timeout is near +// (less than one second away) we poll the clock more frequently to detect the +// time change closer to when it occurs. The user can select the appropriate +// trade off between accuracy and the increased CPU cost of polling. In extreme +// cases, a zero duration may be returned to make the timers as accurate as +// possible, albeit with 100% CPU usage. +struct time_t_wait_traits +{ + // Determine how long until the clock should be next polled to determine + // whether the duration has elapsed. + static time_t_clock::duration to_wait_duration( + const time_t_clock::duration& d) + { + if (d > std::chrono::seconds(1)) + return d - std::chrono::seconds(1); + else if (d > std::chrono::seconds(0)) + return std::chrono::milliseconds(10); + else + return std::chrono::seconds(0); + } + + // Determine how long until the clock should be next polled to determine + // whether the absoluate time has been reached. + static time_t_clock::duration to_wait_duration( + const time_t_clock::time_point& t) + { + return to_wait_duration(t - time_t_clock::now()); + } +}; + +typedef boost::asio::basic_waitable_timer< + time_t_clock, time_t_wait_traits> time_t_timer; + +int main() +{ + try + { + boost::asio::io_context io_context; + + time_t_timer timer(io_context); + + timer.expires_after(std::chrono::seconds(5)); + std::cout << "Starting synchronous wait\n"; + timer.wait(); + std::cout << "Finished synchronous wait\n"; + + timer.expires_after(std::chrono::seconds(5)); + std::cout << "Starting asynchronous wait\n"; + timer.async_wait( + [](const boost::system::error_code& /*error*/) + { + std::cout << "timeout\n"; + }); + io_context.run(); + std::cout << "Finished asynchronous wait\n"; + } + catch (std::exception& e) + { + std::cout << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp14/executors/Jamfile.v2 b/src/boost/libs/asio/example/cpp14/executors/Jamfile.v2 new file mode 100644 index 000000000..cb7b200f6 --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/executors/Jamfile.v2 @@ -0,0 +1,38 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe actor : actor.cpp ; +exe async_1 : async_1.cpp ; +exe async_2 : async_2.cpp ; +exe bank_account_1 : bank_account_1.cpp ; +exe bank_account_2 : bank_account_2.cpp ; +exe fork_join : fork_join.cpp ; +exe pipeline : pipeline.cpp ; +exe priority_scheduler : priority_scheduler.cpp ; diff --git a/src/boost/libs/asio/example/cpp14/executors/actor.cpp b/src/boost/libs/asio/example/cpp14/executors/actor.cpp new file mode 100644 index 000000000..7046e7ba9 --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/executors/actor.cpp @@ -0,0 +1,281 @@ +#include <boost/asio/ts/executor.hpp> +#include <condition_variable> +#include <deque> +#include <memory> +#include <mutex> +#include <typeinfo> +#include <vector> + +using boost::asio::defer; +using boost::asio::executor; +using boost::asio::post; +using boost::asio::strand; +using boost::asio::system_executor; + +//------------------------------------------------------------------------------ +// A tiny actor framework +// ~~~~~~~~~~~~~~~~~~~~~~ + +class actor; + +// Used to identify the sender and recipient of messages. +typedef actor* actor_address; + +// Base class for all registered message handlers. +class message_handler_base +{ +public: + virtual ~message_handler_base() {} + + // Used to determine which message handlers receive an incoming message. + virtual const std::type_info& message_id() const = 0; +}; + +// Base class for a handler for a specific message type. +template <class Message> +class message_handler : public message_handler_base +{ +public: + // Handle an incoming message. + virtual void handle_message(Message msg, actor_address from) = 0; +}; + +// Concrete message handler for a specific message type. +template <class Actor, class Message> +class mf_message_handler : public message_handler<Message> +{ +public: + // Construct a message handler to invoke the specified member function. + mf_message_handler(void (Actor::* mf)(Message, actor_address), Actor* a) + : function_(mf), actor_(a) + { + } + + // Used to determine which message handlers receive an incoming message. + virtual const std::type_info& message_id() const + { + return typeid(Message); + } + + // Handle an incoming message. + virtual void handle_message(Message msg, actor_address from) + { + (actor_->*function_)(std::move(msg), from); + } + + // Determine whether the message handler represents the specified function. + bool is_function(void (Actor::* mf)(Message, actor_address)) const + { + return mf == function_; + } + +private: + void (Actor::* function_)(Message, actor_address); + Actor* actor_; +}; + +// Base class for all actors. +class actor +{ +public: + virtual ~actor() + { + } + + // Obtain the actor's address for use as a message sender or recipient. + actor_address address() + { + return this; + } + + // Send a message from one actor to another. + template <class Message> + friend void send(Message msg, actor_address from, actor_address to) + { + // Execute the message handler in the context of the target's executor. + post(to->executor_, + [=, msg=std::move(msg)] + { + to->call_handler(std::move(msg), from); + }); + } + +protected: + // Construct the actor to use the specified executor for all message handlers. + actor(executor e) + : executor_(std::move(e)) + { + } + + // Register a handler for a specific message type. Duplicates are permitted. + template <class Actor, class Message> + void register_handler(void (Actor::* mf)(Message, actor_address)) + { + handlers_.push_back( + std::make_shared<mf_message_handler<Actor, Message>>( + mf, static_cast<Actor*>(this))); + } + + // Deregister a handler. Removes only the first matching handler. + template <class Actor, class Message> + void deregister_handler(void (Actor::* mf)(Message, actor_address)) + { + const std::type_info& id = typeid(Message); + for (auto iter = handlers_.begin(); iter != handlers_.end(); ++iter) + { + if ((*iter)->message_id() == id) + { + auto mh = static_cast<mf_message_handler<Actor, Message>*>(iter->get()); + if (mh->is_function(mf)) + { + handlers_.erase(iter); + return; + } + } + } + } + + // Send a message from within a message handler. + template <class Message> + void tail_send(Message msg, actor_address to) + { + // Execute the message handler in the context of the target's executor. + defer(to->executor_, + [=, msg=std::move(msg), from=this] + { + to->call_handler(std::move(msg), from); + }); + } + +private: + // Find the matching message handlers, if any, and call them. + template <class Message> + void call_handler(Message msg, actor_address from) + { + const std::type_info& message_id = typeid(Message); + for (auto& h: handlers_) + { + if (h->message_id() == message_id) + { + auto mh = static_cast<message_handler<Message>*>(h.get()); + mh->handle_message(msg, from); + } + } + } + + // All messages associated with a single actor object should be processed + // non-concurrently. We use a strand to ensure non-concurrent execution even + // if the underlying executor may use multiple threads. + strand<executor> executor_; + + std::vector<std::shared_ptr<message_handler_base>> handlers_; +}; + +// A concrete actor that allows synchronous message retrieval. +template <class Message> +class receiver : public actor +{ +public: + receiver() + : actor(system_executor()) + { + register_handler(&receiver::message_handler); + } + + // Block until a message has been received. + Message wait() + { + std::unique_lock<std::mutex> lock(mutex_); + condition_.wait(lock, [this]{ return !message_queue_.empty(); }); + Message msg(std::move(message_queue_.front())); + message_queue_.pop_front(); + return msg; + } + +private: + // Handle a new message by adding it to the queue and waking a waiter. + void message_handler(Message msg, actor_address /* from */) + { + std::lock_guard<std::mutex> lock(mutex_); + message_queue_.push_back(std::move(msg)); + condition_.notify_one(); + } + + std::mutex mutex_; + std::condition_variable condition_; + std::deque<Message> message_queue_; +}; + +//------------------------------------------------------------------------------ + +#include <boost/asio/thread_pool.hpp> +#include <iostream> + +using boost::asio::thread_pool; + +class member : public actor +{ +public: + explicit member(executor e) + : actor(std::move(e)) + { + register_handler(&member::init_handler); + } + +private: + void init_handler(actor_address next, actor_address from) + { + next_ = next; + caller_ = from; + + register_handler(&member::token_handler); + deregister_handler(&member::init_handler); + } + + void token_handler(int token, actor_address /*from*/) + { + int msg(token); + actor_address to(caller_); + + if (token > 0) + { + msg = token - 1; + to = next_; + } + + tail_send(msg, to); + } + + actor_address next_; + actor_address caller_; +}; + +int main() +{ + const std::size_t num_threads = 16; + const int num_hops = 50000000; + const std::size_t num_actors = 503; + const int token_value = (num_hops + num_actors - 1) / num_actors; + const std::size_t actors_per_thread = num_actors / num_threads; + + struct single_thread_pool : thread_pool { single_thread_pool() : thread_pool(1) {} }; + single_thread_pool pools[num_threads]; + std::vector<std::shared_ptr<member>> members(num_actors); + receiver<int> rcvr; + + // Create the member actors. + for (std::size_t i = 0; i < num_actors; ++i) + members[i] = std::make_shared<member>(pools[(i / actors_per_thread) % num_threads].get_executor()); + + // Initialise the actors by passing each one the address of the next actor in the ring. + for (std::size_t i = num_actors, next_i = 0; i > 0; next_i = --i) + send(members[next_i]->address(), rcvr.address(), members[i - 1]->address()); + + // Send exactly one token to each actor, all with the same initial value, rounding up if required. + for (std::size_t i = 0; i < num_actors; ++i) + send(token_value, rcvr.address(), members[i]->address()); + + // Wait for all signal messages, indicating the tokens have all reached zero. + for (std::size_t i = 0; i < num_actors; ++i) + rcvr.wait(); +} diff --git a/src/boost/libs/asio/example/cpp14/executors/async_1.cpp b/src/boost/libs/asio/example/cpp14/executors/async_1.cpp new file mode 100644 index 000000000..db72563a8 --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/executors/async_1.cpp @@ -0,0 +1,47 @@ +#include <boost/asio/ts/executor.hpp> +#include <boost/asio/thread_pool.hpp> +#include <iostream> +#include <string> + +using boost::asio::bind_executor; +using boost::asio::dispatch; +using boost::asio::make_work_guard; +using boost::asio::post; +using boost::asio::thread_pool; + +// A function to asynchronously read a single line from an input stream. +template <class Handler> +void async_getline(std::istream& is, Handler handler) +{ + // Create executor_work for the handler's associated executor. + auto work = make_work_guard(handler); + + // Post a function object to do the work asynchronously. + post([&is, work, handler=std::move(handler)]() mutable + { + std::string line; + std::getline(is, line); + + // Pass the result to the handler, via the associated executor. + dispatch(work.get_executor(), + [line=std::move(line), handler=std::move(handler)]() mutable + { + handler(std::move(line)); + }); + }); +} + +int main() +{ + thread_pool pool; + + std::cout << "Enter a line: "; + + async_getline(std::cin, + bind_executor(pool, [](std::string line) + { + std::cout << "Line: " << line << "\n"; + })); + + pool.join(); +} diff --git a/src/boost/libs/asio/example/cpp14/executors/async_2.cpp b/src/boost/libs/asio/example/cpp14/executors/async_2.cpp new file mode 100644 index 000000000..6f40a902c --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/executors/async_2.cpp @@ -0,0 +1,68 @@ +#include <boost/asio/ts/executor.hpp> +#include <boost/asio/thread_pool.hpp> +#include <iostream> +#include <string> + +using boost::asio::bind_executor; +using boost::asio::dispatch; +using boost::asio::get_associated_executor; +using boost::asio::make_work_guard; +using boost::asio::post; +using boost::asio::thread_pool; + +// A function to asynchronously read a single line from an input stream. +template <class Handler> +void async_getline(std::istream& is, Handler handler) +{ + // Create executor_work for the handler's associated executor. + auto work = make_work_guard(handler); + + // Post a function object to do the work asynchronously. + post([&is, work, handler=std::move(handler)]() mutable + { + std::string line; + std::getline(is, line); + + // Pass the result to the handler, via the associated executor. + dispatch(work.get_executor(), + [line=std::move(line), handler=std::move(handler)]() mutable + { + handler(std::move(line)); + }); + }); +} + +// A function to asynchronously read multiple lines from an input stream. +template <class Handler> +void async_getlines(std::istream& is, std::string init, Handler handler) +{ + // Get the final handler's associated executor. + auto ex = get_associated_executor(handler); + + // Use the associated executor for each operation in the composition. + async_getline(is, + bind_executor(ex, + [&is, lines=std::move(init), handler=std::move(handler)] + (std::string line) mutable + { + if (line.empty()) + handler(lines); + else + async_getlines(is, lines + line + "\n", std::move(handler)); + })); +} + +int main() +{ + thread_pool pool; + + std::cout << "Enter text, terminating with a blank line:\n"; + + async_getlines(std::cin, "", + bind_executor(pool, [](std::string lines) + { + std::cout << "Lines:\n" << lines << "\n"; + })); + + pool.join(); +} diff --git a/src/boost/libs/asio/example/cpp14/executors/bank_account_1.cpp b/src/boost/libs/asio/example/cpp14/executors/bank_account_1.cpp new file mode 100644 index 000000000..6464b48d3 --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/executors/bank_account_1.cpp @@ -0,0 +1,54 @@ +#include <boost/asio/ts/executor.hpp> +#include <boost/asio/thread_pool.hpp> +#include <iostream> + +using boost::asio::post; +using boost::asio::thread_pool; + +// Traditional active object pattern. +// Member functions do not block. + +class bank_account +{ + int balance_ = 0; + mutable thread_pool pool_{1}; + +public: + void deposit(int amount) + { + post(pool_, [=] + { + balance_ += amount; + }); + } + + void withdraw(int amount) + { + post(pool_, [=] + { + if (balance_ >= amount) + balance_ -= amount; + }); + } + + void print_balance() const + { + post(pool_, [=] + { + std::cout << "balance = " << balance_ << "\n"; + }); + } + + ~bank_account() + { + pool_.join(); + } +}; + +int main() +{ + bank_account acct; + acct.deposit(20); + acct.withdraw(10); + acct.print_balance(); +} diff --git a/src/boost/libs/asio/example/cpp14/executors/bank_account_2.cpp b/src/boost/libs/asio/example/cpp14/executors/bank_account_2.cpp new file mode 100644 index 000000000..8de9a3cc2 --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/executors/bank_account_2.cpp @@ -0,0 +1,53 @@ +#include <boost/asio/ts/executor.hpp> +#include <boost/asio/thread_pool.hpp> +#include <iostream> + +using boost::asio::post; +using boost::asio::thread_pool; +using boost::asio::use_future; + +// Traditional active object pattern. +// Member functions block until operation is finished. + +class bank_account +{ + int balance_ = 0; + mutable thread_pool pool_{1}; + +public: + void deposit(int amount) + { + post(pool_, + use_future([=] + { + balance_ += amount; + })).get(); + } + + void withdraw(int amount) + { + post(pool_, + use_future([=] + { + if (balance_ >= amount) + balance_ -= amount; + })).get(); + } + + int balance() const + { + return post(pool_, + use_future([=] + { + return balance_; + })).get(); + } +}; + +int main() +{ + bank_account acct; + acct.deposit(20); + acct.withdraw(10); + std::cout << "balance = " << acct.balance() << "\n"; +} diff --git a/src/boost/libs/asio/example/cpp14/executors/fork_join.cpp b/src/boost/libs/asio/example/cpp14/executors/fork_join.cpp new file mode 100644 index 000000000..2d9b4f7bd --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/executors/fork_join.cpp @@ -0,0 +1,327 @@ +#include <boost/asio/ts/executor.hpp> +#include <boost/asio/thread_pool.hpp> +#include <condition_variable> +#include <memory> +#include <mutex> +#include <queue> +#include <thread> +#include <numeric> + +using boost::asio::dispatch; +using boost::asio::execution_context; +using boost::asio::thread_pool; + +// A fixed-size thread pool used to implement fork/join semantics. Functions +// are scheduled using a simple FIFO queue. Implementing work stealing, or +// using a queue based on atomic operations, are left as tasks for the reader. +class fork_join_pool : public execution_context +{ +public: + // The constructor starts a thread pool with the specified number of threads. + // Note that the thread_count is not a fixed limit on the pool's concurrency. + // Additional threads may temporarily be added to the pool if they join a + // fork_executor. + explicit fork_join_pool( + std::size_t thread_count = std::thread::hardware_concurrency() * 2) + : use_count_(1), + threads_(thread_count) + { + try + { + // Ask each thread in the pool to dequeue and execute functions until + // it is time to shut down, i.e. the use count is zero. + for (thread_count_ = 0; thread_count_ < thread_count; ++thread_count_) + { + dispatch(threads_, [&] + { + std::unique_lock<std::mutex> lock(mutex_); + while (use_count_ > 0) + if (!execute_next(lock)) + condition_.wait(lock); + }); + } + } + catch (...) + { + stop_threads(); + threads_.join(); + throw; + } + } + + // The destructor waits for the pool to finish executing functions. + ~fork_join_pool() + { + stop_threads(); + threads_.join(); + } + +private: + friend class fork_executor; + + // The base for all functions that are queued in the pool. + struct function_base + { + std::shared_ptr<std::size_t> work_count_; + void (*execute_)(std::shared_ptr<function_base>& p); + }; + + // Execute the next function from the queue, if any. Returns true if a + // function was executed, and false if the queue was empty. + bool execute_next(std::unique_lock<std::mutex>& lock) + { + if (queue_.empty()) + return false; + auto p(queue_.front()); + queue_.pop(); + lock.unlock(); + execute(lock, p); + return true; + } + + // Execute a function and decrement the outstanding work. + void execute(std::unique_lock<std::mutex>& lock, + std::shared_ptr<function_base>& p) + { + std::shared_ptr<std::size_t> work_count(std::move(p->work_count_)); + try + { + p->execute_(p); + lock.lock(); + do_work_finished(work_count); + } + catch (...) + { + lock.lock(); + do_work_finished(work_count); + throw; + } + } + + // Increment outstanding work. + void do_work_started(const std::shared_ptr<std::size_t>& work_count) noexcept + { + if (++(*work_count) == 1) + ++use_count_; + } + + // Decrement outstanding work. Notify waiting threads if we run out. + void do_work_finished(const std::shared_ptr<std::size_t>& work_count) noexcept + { + if (--(*work_count) == 0) + { + --use_count_; + condition_.notify_all(); + } + } + + // Dispatch a function, executing it immediately if the queue is already + // loaded. Otherwise adds the function to the queue and wakes a thread. + void do_dispatch(std::shared_ptr<function_base> p, + const std::shared_ptr<std::size_t>& work_count) + { + std::unique_lock<std::mutex> lock(mutex_); + if (queue_.size() > thread_count_ * 16) + { + do_work_started(work_count); + lock.unlock(); + execute(lock, p); + } + else + { + queue_.push(p); + do_work_started(work_count); + condition_.notify_one(); + } + } + + // Add a function to the queue and wake a thread. + void do_post(std::shared_ptr<function_base> p, + const std::shared_ptr<std::size_t>& work_count) + { + std::lock_guard<std::mutex> lock(mutex_); + queue_.push(p); + do_work_started(work_count); + condition_.notify_one(); + } + + // Ask all threads to shut down. + void stop_threads() + { + std::lock_guard<std::mutex> lock(mutex_); + --use_count_; + condition_.notify_all(); + } + + std::mutex mutex_; + std::condition_variable condition_; + std::queue<std::shared_ptr<function_base>> queue_; + std::size_t use_count_; + std::size_t thread_count_; + thread_pool threads_; +}; + +// A class that satisfies the Executor requirements. Every function or piece of +// work associated with a fork_executor is part of a single, joinable group. +class fork_executor +{ +public: + fork_executor(fork_join_pool& ctx) + : context_(ctx), + work_count_(std::make_shared<std::size_t>(0)) + { + } + + fork_join_pool& context() const noexcept + { + return context_; + } + + void on_work_started() const noexcept + { + std::lock_guard<std::mutex> lock(context_.mutex_); + context_.do_work_started(work_count_); + } + + void on_work_finished() const noexcept + { + std::lock_guard<std::mutex> lock(context_.mutex_); + context_.do_work_finished(work_count_); + } + + template <class Func, class Alloc> + void dispatch(Func&& f, const Alloc& a) const + { + auto p(std::allocate_shared<function<Func>>( + typename std::allocator_traits<Alloc>::template rebind_alloc<char>(a), + std::move(f), work_count_)); + context_.do_dispatch(p, work_count_); + } + + template <class Func, class Alloc> + void post(Func f, const Alloc& a) const + { + auto p(std::allocate_shared<function<Func>>( + typename std::allocator_traits<Alloc>::template rebind_alloc<char>(a), + std::move(f), work_count_)); + context_.do_post(p, work_count_); + } + + template <class Func, class Alloc> + void defer(Func&& f, const Alloc& a) const + { + post(std::forward<Func>(f), a); + } + + friend bool operator==(const fork_executor& a, + const fork_executor& b) noexcept + { + return a.work_count_ == b.work_count_; + } + + friend bool operator!=(const fork_executor& a, + const fork_executor& b) noexcept + { + return a.work_count_ != b.work_count_; + } + + // Block until all work associated with the executor is complete. While it is + // waiting, the thread may be borrowed to execute functions from the queue. + void join() const + { + std::unique_lock<std::mutex> lock(context_.mutex_); + while (*work_count_ > 0) + if (!context_.execute_next(lock)) + context_.condition_.wait(lock); + } + +private: + template <class Func> + struct function : fork_join_pool::function_base + { + explicit function(Func f, const std::shared_ptr<std::size_t>& w) + : function_(std::move(f)) + { + work_count_ = w; + execute_ = [](std::shared_ptr<fork_join_pool::function_base>& p) + { + Func tmp(std::move(static_cast<function*>(p.get())->function_)); + p.reset(); + tmp(); + }; + } + + Func function_; + }; + + fork_join_pool& context_; + std::shared_ptr<std::size_t> work_count_; +}; + +// Helper class to automatically join a fork_executor when exiting a scope. +class join_guard +{ +public: + explicit join_guard(const fork_executor& ex) : ex_(ex) {} + join_guard(const join_guard&) = delete; + join_guard(join_guard&&) = delete; + ~join_guard() { ex_.join(); } + +private: + fork_executor ex_; +}; + +//------------------------------------------------------------------------------ + +#include <algorithm> +#include <iostream> +#include <random> +#include <vector> + +fork_join_pool pool; + +template <class Iterator> +void fork_join_sort(Iterator begin, Iterator end) +{ + std::size_t n = end - begin; + if (n > 32768) + { + { + fork_executor fork(pool); + join_guard join(fork); + dispatch(fork, [=]{ fork_join_sort(begin, begin + n / 2); }); + dispatch(fork, [=]{ fork_join_sort(begin + n / 2, end); }); + } + std::inplace_merge(begin, begin + n / 2, end); + } + else + { + std::sort(begin, end); + } +} + +int main(int argc, char* argv[]) +{ + if (argc != 2) + { + std::cerr << "Usage: fork_join <size>\n"; + return 1; + } + + std::vector<double> vec(std::atoll(argv[1])); + std::iota(vec.begin(), vec.end(), 0); + + std::random_device rd; + std::mt19937 g(rd()); + std::shuffle(vec.begin(), vec.end(), g); + + std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); + + fork_join_sort(vec.begin(), vec.end()); + + std::chrono::steady_clock::duration elapsed = std::chrono::steady_clock::now() - start; + + std::cout << "sort took "; + std::cout << std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count(); + std::cout << " microseconds" << std::endl; +} diff --git a/src/boost/libs/asio/example/cpp14/executors/pipeline.cpp b/src/boost/libs/asio/example/cpp14/executors/pipeline.cpp new file mode 100644 index 000000000..bd837083b --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/executors/pipeline.cpp @@ -0,0 +1,294 @@ +#include <boost/asio/ts/executor.hpp> +#include <condition_variable> +#include <future> +#include <memory> +#include <mutex> +#include <queue> +#include <thread> +#include <vector> +#include <cctype> + +using boost::asio::execution_context; +using boost::asio::executor_binder; +using boost::asio::get_associated_executor; +using boost::asio::post; +using boost::asio::system_executor; +using boost::asio::use_future; +using boost::asio::use_service; + +// An executor that launches a new thread for each function submitted to it. +// This class satisfies the Executor requirements. +class thread_executor +{ +private: + // Service to track all threads started through a thread_executor. + class thread_bag : public execution_context::service + { + public: + typedef thread_bag key_type; + + explicit thread_bag(execution_context& ctx) + : execution_context::service(ctx) + { + } + + void add_thread(std::thread&& t) + { + std::unique_lock<std::mutex> lock(mutex_); + threads_.push_back(std::move(t)); + } + + private: + virtual void shutdown() + { + for (auto& t : threads_) + t.join(); + } + + std::mutex mutex_; + std::vector<std::thread> threads_; + }; + +public: + execution_context& context() const noexcept + { + return system_executor().context(); + } + + void on_work_started() const noexcept + { + // This executor doesn't count work. + } + + void on_work_finished() const noexcept + { + // This executor doesn't count work. + } + + template <class Func, class Alloc> + void dispatch(Func&& f, const Alloc& a) const + { + post(std::forward<Func>(f), a); + } + + template <class Func, class Alloc> + void post(Func f, const Alloc&) const + { + thread_bag& bag = use_service<thread_bag>(context()); + bag.add_thread(std::thread(std::move(f))); + } + + template <class Func, class Alloc> + void defer(Func&& f, const Alloc& a) const + { + post(std::forward<Func>(f), a); + } + + friend bool operator==(const thread_executor&, + const thread_executor&) noexcept + { + return true; + } + + friend bool operator!=(const thread_executor&, + const thread_executor&) noexcept + { + return false; + } +}; + +// Base class for all thread-safe queue implementations. +class queue_impl_base +{ + template <class> friend class queue_front; + template <class> friend class queue_back; + std::mutex mutex_; + std::condition_variable condition_; + bool stop_ = false; +}; + +// Underlying implementation of a thread-safe queue, shared between the +// queue_front and queue_back classes. +template <class T> +class queue_impl : public queue_impl_base +{ + template <class> friend class queue_front; + template <class> friend class queue_back; + std::queue<T> queue_; +}; + +// The front end of a queue between consecutive pipeline stages. +template <class T> +class queue_front +{ +public: + typedef T value_type; + + explicit queue_front(std::shared_ptr<queue_impl<T>> impl) + : impl_(impl) + { + } + + void push(T t) + { + std::unique_lock<std::mutex> lock(impl_->mutex_); + impl_->queue_.push(std::move(t)); + impl_->condition_.notify_one(); + } + + void stop() + { + std::unique_lock<std::mutex> lock(impl_->mutex_); + impl_->stop_ = true; + impl_->condition_.notify_one(); + } + +private: + std::shared_ptr<queue_impl<T>> impl_; +}; + +// The back end of a queue between consecutive pipeline stages. +template <class T> +class queue_back +{ +public: + typedef T value_type; + + explicit queue_back(std::shared_ptr<queue_impl<T>> impl) + : impl_(impl) + { + } + + bool pop(T& t) + { + std::unique_lock<std::mutex> lock(impl_->mutex_); + while (impl_->queue_.empty() && !impl_->stop_) + impl_->condition_.wait(lock); + if (!impl_->queue_.empty()) + { + t = impl_->queue_.front(); + impl_->queue_.pop(); + return true; + } + return false; + } + +private: + std::shared_ptr<queue_impl<T>> impl_; +}; + +// Launch the last stage in a pipeline. +template <class T, class F> +std::future<void> pipeline(queue_back<T> in, F f) +{ + // Get the function's associated executor, defaulting to thread_executor. + auto ex = get_associated_executor(f, thread_executor()); + + // Run the function, and as we're the last stage return a future so that the + // caller can wait for the pipeline to finish. + return post(ex, use_future([in, f = std::move(f)]() mutable { f(in); })); +} + +// Launch an intermediate stage in a pipeline. +template <class T, class F, class... Tail> +std::future<void> pipeline(queue_back<T> in, F f, Tail... t) +{ + // Determine the output queue type. + typedef typename executor_binder<F, thread_executor>::second_argument_type::value_type output_value_type; + + // Create the output queue and its implementation. + auto out_impl = std::make_shared<queue_impl<output_value_type>>(); + queue_front<output_value_type> out(out_impl); + queue_back<output_value_type> next_in(out_impl); + + // Get the function's associated executor, defaulting to thread_executor. + auto ex = get_associated_executor(f, thread_executor()); + + // Run the function. + post(ex, [in, out, f = std::move(f)]() mutable + { + f(in, out); + out.stop(); + }); + + // Launch the rest of the pipeline. + return pipeline(next_in, std::move(t)...); +} + +// Launch the first stage in a pipeline. +template <class F, class... Tail> +std::future<void> pipeline(F f, Tail... t) +{ + // Determine the output queue type. + typedef typename executor_binder<F, thread_executor>::argument_type::value_type output_value_type; + + // Create the output queue and its implementation. + auto out_impl = std::make_shared<queue_impl<output_value_type>>(); + queue_front<output_value_type> out(out_impl); + queue_back<output_value_type> next_in(out_impl); + + // Get the function's associated executor, defaulting to thread_executor. + auto ex = get_associated_executor(f, thread_executor()); + + // Run the function. + post(ex, [out, f = std::move(f)]() mutable + { + f(out); + out.stop(); + }); + + // Launch the rest of the pipeline. + return pipeline(next_in, std::move(t)...); +} + +//------------------------------------------------------------------------------ + +#include <boost/asio/thread_pool.hpp> +#include <iostream> +#include <string> + +using boost::asio::bind_executor; +using boost::asio::thread_pool; + +void reader(queue_front<std::string> out) +{ + std::string line; + while (std::getline(std::cin, line)) + out.push(line); +} + +void filter(queue_back<std::string> in, queue_front<std::string> out) +{ + std::string line; + while (in.pop(line)) + if (line.length() > 5) + out.push(line); +} + +void upper(queue_back<std::string> in, queue_front<std::string> out) +{ + std::string line; + while (in.pop(line)) + { + std::string new_line; + for (char c : line) + new_line.push_back(std::toupper(c)); + out.push(new_line); + } +} + +void writer(queue_back<std::string> in) +{ + std::size_t count = 0; + std::string line; + while (in.pop(line)) + std::cout << count++ << ": " << line << std::endl; +} + +int main() +{ + thread_pool pool; + + auto f = pipeline(reader, filter, bind_executor(pool, upper), writer); + f.wait(); +} diff --git a/src/boost/libs/asio/example/cpp14/executors/priority_scheduler.cpp b/src/boost/libs/asio/example/cpp14/executors/priority_scheduler.cpp new file mode 100644 index 000000000..f11853192 --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/executors/priority_scheduler.cpp @@ -0,0 +1,173 @@ +#include <boost/asio/ts/executor.hpp> +#include <condition_variable> +#include <iostream> +#include <memory> +#include <mutex> +#include <queue> + +using boost::asio::dispatch; +using boost::asio::execution_context; + +class priority_scheduler : public execution_context +{ +public: + // A class that satisfies the Executor requirements. + class executor_type + { + public: + executor_type(priority_scheduler& ctx, int pri) noexcept + : context_(ctx), priority_(pri) + { + } + + priority_scheduler& context() const noexcept + { + return context_; + } + + void on_work_started() const noexcept + { + // This executor doesn't count work. Instead, the scheduler simply runs + // until explicitly stopped. + } + + void on_work_finished() const noexcept + { + // This executor doesn't count work. Instead, the scheduler simply runs + // until explicitly stopped. + } + + template <class Func, class Alloc> + void dispatch(Func&& f, const Alloc& a) const + { + post(std::forward<Func>(f), a); + } + + template <class Func, class Alloc> + void post(Func f, const Alloc& a) const + { + auto p(std::allocate_shared<item<Func>>( + typename std::allocator_traits< + Alloc>::template rebind_alloc<char>(a), + priority_, std::move(f))); + std::lock_guard<std::mutex> lock(context_.mutex_); + context_.queue_.push(p); + context_.condition_.notify_one(); + } + + template <class Func, class Alloc> + void defer(Func&& f, const Alloc& a) const + { + post(std::forward<Func>(f), a); + } + + friend bool operator==(const executor_type& a, + const executor_type& b) noexcept + { + return &a.context_ == &b.context_; + } + + friend bool operator!=(const executor_type& a, + const executor_type& b) noexcept + { + return &a.context_ != &b.context_; + } + + private: + priority_scheduler& context_; + int priority_; + }; + + ~priority_scheduler() noexcept + { + shutdown(); + destroy(); + } + + executor_type get_executor(int pri = 0) noexcept + { + return executor_type(*const_cast<priority_scheduler*>(this), pri); + } + + void run() + { + std::unique_lock<std::mutex> lock(mutex_); + for (;;) + { + condition_.wait(lock, [&]{ return stopped_ || !queue_.empty(); }); + if (stopped_) + return; + auto p(queue_.top()); + queue_.pop(); + lock.unlock(); + p->execute_(p); + lock.lock(); + } + } + + void stop() + { + std::lock_guard<std::mutex> lock(mutex_); + stopped_ = true; + condition_.notify_all(); + } + +private: + struct item_base + { + int priority_; + void (*execute_)(std::shared_ptr<item_base>&); + }; + + template <class Func> + struct item : item_base + { + item(int pri, Func f) : function_(std::move(f)) + { + priority_ = pri; + execute_ = [](std::shared_ptr<item_base>& p) + { + Func tmp(std::move(static_cast<item*>(p.get())->function_)); + p.reset(); + tmp(); + }; + } + + Func function_; + }; + + struct item_comp + { + bool operator()( + const std::shared_ptr<item_base>& a, + const std::shared_ptr<item_base>& b) + { + return a->priority_ < b->priority_; + } + }; + + std::mutex mutex_; + std::condition_variable condition_; + std::priority_queue< + std::shared_ptr<item_base>, + std::vector<std::shared_ptr<item_base>>, + item_comp> queue_; + bool stopped_ = false; +}; + +int main() +{ + priority_scheduler sched; + auto low = sched.get_executor(0); + auto med = sched.get_executor(1); + auto high = sched.get_executor(2); + dispatch(low, []{ std::cout << "1\n"; }); + dispatch(low, []{ std::cout << "11\n"; }); + dispatch(med, []{ std::cout << "2\n"; }); + dispatch(med, []{ std::cout << "22\n"; }); + dispatch(high, []{ std::cout << "3\n"; }); + dispatch(high, []{ std::cout << "33\n"; }); + dispatch(high, []{ std::cout << "333\n"; }); + dispatch(sched.get_executor(-1), [&]{ sched.stop(); }); + sched.run(); +} diff --git a/src/boost/libs/asio/example/cpp14/operations/Jamfile.v2 b/src/boost/libs/asio/example/cpp14/operations/Jamfile.v2 new file mode 100644 index 000000000..a01b42a3a --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/operations/Jamfile.v2 @@ -0,0 +1,39 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe composed_1 : composed_1.cpp ; +exe composed_2 : composed_2.cpp ; +exe composed_3 : composed_3.cpp ; +exe composed_4 : composed_4.cpp ; +exe composed_5 : composed_5.cpp ; +exe composed_6 : composed_6.cpp ; +exe composed_7 : composed_7.cpp ; +exe composed_8 : composed_8.cpp ; diff --git a/src/boost/libs/asio/example/cpp14/operations/composed_1.cpp b/src/boost/libs/asio/example/cpp14/operations/composed_1.cpp new file mode 100644 index 000000000..4439fef6e --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/operations/composed_1.cpp @@ -0,0 +1,113 @@ +// +// composed_1.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/use_future.hpp> +#include <boost/asio/write.hpp> +#include <cstring> +#include <iostream> +#include <string> +#include <type_traits> +#include <utility> + +using boost::asio::ip::tcp; + +//------------------------------------------------------------------------------ + +// This is the simplest example of a composed asynchronous operation, where we +// simply repackage an existing operation. The asynchronous operation +// requirements are met by delegating responsibility to the underlying +// operation. + +template <typename CompletionToken> +auto async_write_message(tcp::socket& socket, + const char* message, CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of CompletionToken type and the completion handler's signature. When the + // completion token is a simple callback, the return type is void. However, + // when the completion token is boost::asio::yield_context (used for stackful + // coroutines) the return type would be std::size_t, and when the completion + // token is boost::asio::use_future it would be std::future<std::size_t>. + // + // In C++14 we can omit the return type as it is automatically deduced from + // the return type of our underlying asynchronous operation +{ + // When delegating to the underlying operation we must take care to perfectly + // forward the completion token. This ensures that our operation works + // correctly with move-only function objects as callbacks, as well as other + // completion token types. + return boost::asio::async_write(socket, + boost::asio::buffer(message, std::strlen(message)), + std::forward<CompletionToken>(token)); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_message(socket, "Testing callback\r\n", + [](const boost::system::error_code& error, std::size_t n) + { + if (!error) + { + std::cout << n << " bytes transferred\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<std::size_t> f = async_write_message( + socket, "Testing future\r\n", boost::asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + std::size_t n = f.get(); + std::cout << n << " bytes transferred\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_future(); +} diff --git a/src/boost/libs/asio/example/cpp14/operations/composed_2.cpp b/src/boost/libs/asio/example/cpp14/operations/composed_2.cpp new file mode 100644 index 000000000..4c16776a5 --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/operations/composed_2.cpp @@ -0,0 +1,131 @@ +// +// composed_2.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/use_future.hpp> +#include <boost/asio/write.hpp> +#include <cstring> +#include <iostream> +#include <string> +#include <type_traits> +#include <utility> + +using boost::asio::ip::tcp; + +//------------------------------------------------------------------------------ + +// This next simplest example of a composed asynchronous operation involves +// repackaging multiple operations but choosing to invoke just one of them. All +// of these underlying operations have the same completion signature. The +// asynchronous operation requirements are met by delegating responsibility to +// the underlying operations. + +template <typename CompletionToken> +auto async_write_message(tcp::socket& socket, + const char* message, bool allow_partial_write, + CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of CompletionToken type and the completion handler's signature. When the + // completion token is a simple callback, the return type is void. However, + // when the completion token is boost::asio::yield_context (used for stackful + // coroutines) the return type would be std::size_t, and when the completion + // token is boost::asio::use_future it would be std::future<std::size_t>. + // + // In C++14 we can omit the return type as it is automatically deduced from + // the return type of our underlying asynchronous operation +{ + // As the return type of the initiating function is deduced solely from the + // CompletionToken and completion signature, we know that two different + // asynchronous operations having the same completion signature will produce + // the same return type, when passed the same CompletionToken. This allows us + // to trivially delegate to alternate implementations. + if (allow_partial_write) + { + // When delegating to an underlying operation we must take care to + // perfectly forward the completion token. This ensures that our operation + // works correctly with move-only function objects as callbacks, as well as + // other completion token types. + return socket.async_write_some( + boost::asio::buffer(message, std::strlen(message)), + std::forward<CompletionToken>(token)); + } + else + { + // As above, we must perfectly forward the completion token when calling + // the alternate underlying operation. + return boost::asio::async_write(socket, + boost::asio::buffer(message, std::strlen(message)), + std::forward<CompletionToken>(token)); + } +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_message(socket, "Testing callback\r\n", false, + [](const boost::system::error_code& error, std::size_t n) + { + if (!error) + { + std::cout << n << " bytes transferred\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<std::size_t> f = async_write_message( + socket, "Testing future\r\n", false, boost::asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + std::size_t n = f.get(); + std::cout << n << " bytes transferred\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_future(); +} diff --git a/src/boost/libs/asio/example/cpp14/operations/composed_3.cpp b/src/boost/libs/asio/example/cpp14/operations/composed_3.cpp new file mode 100644 index 000000000..00ab11206 --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/operations/composed_3.cpp @@ -0,0 +1,186 @@ +// +// composed_3.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/bind_executor.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/use_future.hpp> +#include <boost/asio/write.hpp> +#include <cstring> +#include <functional> +#include <iostream> +#include <string> +#include <type_traits> +#include <utility> + +using boost::asio::ip::tcp; + +// NOTE: This example requires the new boost::asio::async_initiate function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// In this composed operation we repackage an existing operation, but with a +// different completion handler signature. The asynchronous operation +// requirements are met by delegating responsibility to the underlying +// operation. + +template <typename CompletionToken> +auto async_write_message(tcp::socket& socket, + const char* message, CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of CompletionToken type and the completion handler's signature. When the + // completion token is a simple callback, the return type is always void. + // In this example, when the completion token is boost::asio::yield_context + // (used for stackful coroutines) the return type would be also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is boost::asio::use_future it would be std::future<void>. + // + // In C++14 we can omit the return type as it is automatically deduced from + // the return type of boost::asio::async_initiate. +{ + // In addition to determining the mechanism by which an asynchronous + // operation delivers its result, a completion token also determines the time + // when the operation commences. For example, when the completion token is a + // simple callback the operation commences before the initiating function + // returns. However, if the completion token's delivery mechanism uses a + // future, we might instead want to defer initiation of the operation until + // the returned future object is waited upon. + // + // To enable this, when implementing an asynchronous operation we must + // package the initiation step as a function object. The initiation function + // object's call operator is passed the concrete completion handler produced + // by the completion token. This completion handler matches the asynchronous + // operation's completion handler signature, which in this example is: + // + // void(boost::system::error_code error) + // + // The initiation function object also receives any additional arguments + // required to start the operation. (Note: We could have instead passed these + // arguments in the lambda capture set. However, we should prefer to + // propagate them as function call arguments as this allows the completion + // token to optimise how they are passed. For example, a lazy future which + // defers initiation would need to make a decay-copy of the arguments, but + // when using a simple callback the arguments can be trivially forwarded + // straight through.) + auto initiation = [](auto&& completion_handler, + tcp::socket& socket, const char* message) + { + // The async_write operation has a completion handler signature of: + // + // void(boost::system::error_code error, std::size n) + // + // This differs from our operation's signature in that it is also passed + // the number of bytes transferred as an argument of type std::size_t. We + // will adapt our completion handler to async_write's completion handler + // signature by using std::bind, which drops the additional argument. + // + // However, it is essential to the correctness of our composed operation + // that we preserve the executor of the user-supplied completion handler. + // The std::bind function will not do this for us, so we must do this by + // first obtaining the completion handler's associated executor (defaulting + // to the I/O executor - in this case the executor of the socket - if the + // completion handler does not have its own) ... + auto executor = boost::asio::get_associated_executor( + completion_handler, socket.get_executor()); + + // ... and then binding this executor to our adapted completion handler + // using the boost::asio::bind_executor function. + boost::asio::async_write(socket, + boost::asio::buffer(message, std::strlen(message)), + boost::asio::bind_executor(executor, + std::bind(std::forward<decltype(completion_handler)>( + completion_handler), std::placeholders::_1))); + }; + + // The boost::asio::async_initiate function takes: + // + // - our initiation function object, + // - the completion token, + // - the completion handler signature, and + // - any additional arguments we need to initiate the operation. + // + // It then asks the completion token to create a completion handler (i.e. a + // callback) with the specified signature, and invoke the initiation function + // object with this completion handler as well as the additional arguments. + // The return value of async_initiate is the result of our operation's + // initiating function. + // + // Note that we wrap non-const reference arguments in std::reference_wrapper + // to prevent incorrect decay-copies of these objects. + return boost::asio::async_initiate< + CompletionToken, void(boost::system::error_code)>( + initiation, token, std::ref(socket), message); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_message(socket, "Testing callback\r\n", + [](const boost::system::error_code& error) + { + if (!error) + { + std::cout << "Message sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_message( + socket, "Testing future\r\n", boost::asio::use_future); + + io_context.run(); + + // Get the result of the operation. + try + { + // Get the result of the operation. + f.get(); + std::cout << "Message sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_future(); +} diff --git a/src/boost/libs/asio/example/cpp14/operations/composed_4.cpp b/src/boost/libs/asio/example/cpp14/operations/composed_4.cpp new file mode 100644 index 000000000..65e0bf21b --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/operations/composed_4.cpp @@ -0,0 +1,201 @@ +// +// composed_4.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/bind_executor.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/use_future.hpp> +#include <boost/asio/write.hpp> +#include <cstring> +#include <functional> +#include <iostream> +#include <string> +#include <type_traits> +#include <utility> + +using boost::asio::ip::tcp; + +// NOTE: This example requires the new boost::asio::async_initiate function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// In this composed operation we repackage an existing operation, but with a +// different completion handler signature. We will also intercept an empty +// message as an invalid argument, and propagate the corresponding error to the +// user. The asynchronous operation requirements are met by delegating +// responsibility to the underlying operation. + +template <typename CompletionToken> +auto async_write_message(tcp::socket& socket, + const char* message, CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of CompletionToken type and the completion handler's signature. When the + // completion token is a simple callback, the return type is always void. + // In this example, when the completion token is boost::asio::yield_context + // (used for stackful coroutines) the return type would be also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is boost::asio::use_future it would be std::future<void>. + // + // In C++14 we can omit the return type as it is automatically deduced from + // the return type of boost::asio::async_initiate. +{ + // In addition to determining the mechanism by which an asynchronous + // operation delivers its result, a completion token also determines the time + // when the operation commences. For example, when the completion token is a + // simple callback the operation commences before the initiating function + // returns. However, if the completion token's delivery mechanism uses a + // future, we might instead want to defer initiation of the operation until + // the returned future object is waited upon. + // + // To enable this, when implementing an asynchronous operation we must + // package the initiation step as a function object. The initiation function + // object's call operator is passed the concrete completion handler produced + // by the completion token. This completion handler matches the asynchronous + // operation's completion handler signature, which in this example is: + // + // void(boost::system::error_code error) + // + // The initiation function object also receives any additional arguments + // required to start the operation. (Note: We could have instead passed these + // arguments in the lambda capture set. However, we should prefer to + // propagate them as function call arguments as this allows the completion + // token to optimise how they are passed. For example, a lazy future which + // defers initiation would need to make a decay-copy of the arguments, but + // when using a simple callback the arguments can be trivially forwarded + // straight through.) + auto initiation = [](auto&& completion_handler, + tcp::socket& socket, const char* message) + { + // The post operation has a completion handler signature of: + // + // void() + // + // and the async_write operation has a completion handler signature of: + // + // void(boost::system::error_code error, std::size n) + // + // Both of these operations' completion handler signatures differ from our + // operation's completion handler signature. We will adapt our completion + // handler to these signatures by using std::bind, which drops the + // additional arguments. + // + // However, it is essential to the correctness of our composed operation + // that we preserve the executor of the user-supplied completion handler. + // The std::bind function will not do this for us, so we must do this by + // first obtaining the completion handler's associated executor (defaulting + // to the I/O executor - in this case the executor of the socket - if the + // completion handler does not have its own) ... + auto executor = boost::asio::get_associated_executor( + completion_handler, socket.get_executor()); + + // ... and then binding this executor to our adapted completion handler + // using the boost::asio::bind_executor function. + std::size_t length = std::strlen(message); + if (length == 0) + { + boost::asio::post( + boost::asio::bind_executor(executor, + std::bind(std::forward<decltype(completion_handler)>( + completion_handler), boost::asio::error::invalid_argument))); + } + else + { + boost::asio::async_write(socket, + boost::asio::buffer(message, length), + boost::asio::bind_executor(executor, + std::bind(std::forward<decltype(completion_handler)>( + completion_handler), std::placeholders::_1))); + } + }; + + // The boost::asio::async_initiate function takes: + // + // - our initiation function object, + // - the completion token, + // - the completion handler signature, and + // - any additional arguments we need to initiate the operation. + // + // It then asks the completion token to create a completion handler (i.e. a + // callback) with the specified signature, and invoke the initiation function + // object with this completion handler as well as the additional arguments. + // The return value of async_initiate is the result of our operation's + // initiating function. + // + // Note that we wrap non-const reference arguments in std::reference_wrapper + // to prevent incorrect decay-copies of these objects. + return boost::asio::async_initiate< + CompletionToken, void(boost::system::error_code)>( + initiation, token, std::ref(socket), message); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_message(socket, "", + [](const boost::system::error_code& error) + { + if (!error) + { + std::cout << "Message sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_message( + socket, "", boost::asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + f.get(); + std::cout << "Message sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Exception: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_future(); +} diff --git a/src/boost/libs/asio/example/cpp14/operations/composed_5.cpp b/src/boost/libs/asio/example/cpp14/operations/composed_5.cpp new file mode 100644 index 000000000..f7bcb169a --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/operations/composed_5.cpp @@ -0,0 +1,238 @@ +// +// composed_5.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/use_future.hpp> +#include <boost/asio/write.hpp> +#include <functional> +#include <iostream> +#include <memory> +#include <sstream> +#include <string> +#include <type_traits> +#include <utility> + +using boost::asio::ip::tcp; + +// NOTE: This example requires the new boost::asio::async_initiate function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// This composed operation automatically serialises a message, using its I/O +// streams insertion operator, before sending it on the socket. To do this, it +// must allocate a buffer for the encoded message and ensure this buffer's +// validity until the underlying async_write operation completes. + +template <typename T, typename CompletionToken> +auto async_write_message(tcp::socket& socket, + const T& message, CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of CompletionToken type and the completion handler's signature. When the + // completion token is a simple callback, the return type is always void. + // In this example, when the completion token is boost::asio::yield_context + // (used for stackful coroutines) the return type would be also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is boost::asio::use_future it would be std::future<void>. + // + // In C++14 we can omit the return type as it is automatically deduced from + // the return type of boost::asio::async_initiate. +{ + // In addition to determining the mechanism by which an asynchronous + // operation delivers its result, a completion token also determines the time + // when the operation commences. For example, when the completion token is a + // simple callback the operation commences before the initiating function + // returns. However, if the completion token's delivery mechanism uses a + // future, we might instead want to defer initiation of the operation until + // the returned future object is waited upon. + // + // To enable this, when implementing an asynchronous operation we must + // package the initiation step as a function object. The initiation function + // object's call operator is passed the concrete completion handler produced + // by the completion token. This completion handler matches the asynchronous + // operation's completion handler signature, which in this example is: + // + // void(boost::system::error_code error) + // + // The initiation function object also receives any additional arguments + // required to start the operation. (Note: We could have instead passed these + // arguments in the lambda capture set. However, we should prefer to + // propagate them as function call arguments as this allows the completion + // token to optimise how they are passed. For example, a lazy future which + // defers initiation would need to make a decay-copy of the arguments, but + // when using a simple callback the arguments can be trivially forwarded + // straight through.) + auto initiation = [](auto&& completion_handler, + tcp::socket& socket, std::unique_ptr<std::string> encoded_message) + { + // In this example, the composed operation's intermediate completion + // handler is implemented as a hand-crafted function object, rather than + // using a lambda or std::bind. + struct intermediate_completion_handler + { + // The intermediate completion handler holds a reference to the socket so + // that it can obtain the I/O executor (see get_executor below). + tcp::socket& socket_; + + // The allocated buffer for the encoded message. The std::unique_ptr + // smart pointer is move-only, and as a consequence our intermediate + // completion handler is also move-only. + std::unique_ptr<std::string> encoded_message_; + + // The user-supplied completion handler. + typename std::decay<decltype(completion_handler)>::type handler_; + + // The function call operator matches the completion signature of the + // async_write operation. + void operator()(const boost::system::error_code& error, std::size_t /*n*/) + { + // Deallocate the encoded message before calling the user-supplied + // completion handler. + encoded_message_.reset(); + + // Call the user-supplied handler with the result of the operation. + // The arguments must match the completion signature of our composed + // operation. + handler_(error); + } + + // It is essential to the correctness of our composed operation that we + // preserve the executor of the user-supplied completion handler. With a + // hand-crafted function object we can do this by defining a nested type + // executor_type and member function get_executor. These obtain the + // completion handler's associated executor, and default to the I/O + // executor - in this case the executor of the socket - if the completion + // handler does not have its own. + using executor_type = boost::asio::associated_executor_t< + typename std::decay<decltype(completion_handler)>::type, + tcp::socket::executor_type>; + + executor_type get_executor() const noexcept + { + return boost::asio::get_associated_executor( + handler_, socket_.get_executor()); + } + + // Although not necessary for correctness, we may also preserve the + // allocator of the user-supplied completion handler. This is achieved by + // defining a nested type allocator_type and member function + // get_allocator. These obtain the completion handler's associated + // allocator, and default to std::allocator<void> if the completion + // handler does not have its own. + using allocator_type = boost::asio::associated_allocator_t< + typename std::decay<decltype(completion_handler)>::type, + std::allocator<void>>; + + allocator_type get_allocator() const noexcept + { + return boost::asio::get_associated_allocator( + handler_, std::allocator<void>{}); + } + }; + + // Initiate the underlying async_write operation using our intermediate + // completion handler. + auto encoded_message_buffer = boost::asio::buffer(*encoded_message); + boost::asio::async_write(socket, encoded_message_buffer, + intermediate_completion_handler{socket, std::move(encoded_message), + std::forward<decltype(completion_handler)>(completion_handler)}); + }; + + // Encode the message and copy it into an allocated buffer. The buffer will + // be maintained for the lifetime of the asynchronous operation. + std::ostringstream os; + os << message; + std::unique_ptr<std::string> encoded_message(new std::string(os.str())); + + // The boost::asio::async_initiate function takes: + // + // - our initiation function object, + // - the completion token, + // - the completion handler signature, and + // - any additional arguments we need to initiate the operation. + // + // It then asks the completion token to create a completion handler (i.e. a + // callback) with the specified signature, and invoke the initiation function + // object with this completion handler as well as the additional arguments. + // The return value of async_initiate is the result of our operation's + // initiating function. + // + // Note that we wrap non-const reference arguments in std::reference_wrapper + // to prevent incorrect decay-copies of these objects. + return boost::asio::async_initiate< + CompletionToken, void(boost::system::error_code)>( + initiation, token, std::ref(socket), + std::move(encoded_message)); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_message(socket, 123456, + [](const boost::system::error_code& error) + { + if (!error) + { + std::cout << "Message sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_message( + socket, 654.321, boost::asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + f.get(); + std::cout << "Message sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Exception: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_future(); +} diff --git a/src/boost/libs/asio/example/cpp14/operations/composed_6.cpp b/src/boost/libs/asio/example/cpp14/operations/composed_6.cpp new file mode 100644 index 000000000..8b6d01190 --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/operations/composed_6.cpp @@ -0,0 +1,298 @@ +// +// composed_6.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/executor_work_guard.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/asio/use_future.hpp> +#include <boost/asio/write.hpp> +#include <functional> +#include <iostream> +#include <memory> +#include <sstream> +#include <string> +#include <type_traits> +#include <utility> + +using boost::asio::ip::tcp; + +// NOTE: This example requires the new boost::asio::async_initiate function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// This composed operation shows composition of multiple underlying operations. +// It automatically serialises a message, using its I/O streams insertion +// operator, before sending it N times on the socket. To do this, it must +// allocate a buffer for the encoded message and ensure this buffer's validity +// until all underlying async_write operation complete. A one second delay is +// inserted prior to each write operation, using a steady_timer. + +template <typename T, typename CompletionToken> +auto async_write_messages(tcp::socket& socket, + const T& message, std::size_t repeat_count, + CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of CompletionToken type and the completion handler's signature. When the + // completion token is a simple callback, the return type is always void. + // In this example, when the completion token is boost::asio::yield_context + // (used for stackful coroutines) the return type would be also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is boost::asio::use_future it would be std::future<void>. + // + // In C++14 we can omit the return type as it is automatically deduced from + // the return type of boost::asio::async_initiate. +{ + // In addition to determining the mechanism by which an asynchronous + // operation delivers its result, a completion token also determines the time + // when the operation commences. For example, when the completion token is a + // simple callback the operation commences before the initiating function + // returns. However, if the completion token's delivery mechanism uses a + // future, we might instead want to defer initiation of the operation until + // the returned future object is waited upon. + // + // To enable this, when implementing an asynchronous operation we must + // package the initiation step as a function object. The initiation function + // object's call operator is passed the concrete completion handler produced + // by the completion token. This completion handler matches the asynchronous + // operation's completion handler signature, which in this example is: + // + // void(boost::system::error_code error) + // + // The initiation function object also receives any additional arguments + // required to start the operation. (Note: We could have instead passed these + // arguments in the lambda capture set. However, we should prefer to + // propagate them as function call arguments as this allows the completion + // token to optimise how they are passed. For example, a lazy future which + // defers initiation would need to make a decay-copy of the arguments, but + // when using a simple callback the arguments can be trivially forwarded + // straight through.) + auto initiation = [](auto&& completion_handler, tcp::socket& socket, + std::unique_ptr<std::string> encoded_message, std::size_t repeat_count, + std::unique_ptr<boost::asio::steady_timer> delay_timer) + { + // In this example, the composed operation's intermediate completion + // handler is implemented as a hand-crafted function object. + struct intermediate_completion_handler + { + // The intermediate completion handler holds a reference to the socket as + // it is used for multiple async_write operations, as well as for + // obtaining the I/O executor (see get_executor below). + tcp::socket& socket_; + + // The allocated buffer for the encoded message. The std::unique_ptr + // smart pointer is move-only, and as a consequence our intermediate + // completion handler is also move-only. + std::unique_ptr<std::string> encoded_message_; + + // The repeat count remaining. + std::size_t repeat_count_; + + // A steady timer used for introducing a delay. + std::unique_ptr<boost::asio::steady_timer> delay_timer_; + + // To manage the cycle between the multiple underlying asychronous + // operations, our intermediate completion handler is implemented as a + // state machine. + enum { starting, waiting, writing } state_; + + // As our composed operation performs multiple underlying I/O operations, + // we should maintain a work object against the I/O executor. This tells + // the I/O executor that there is still more work to come in the future. + boost::asio::executor_work_guard<tcp::socket::executor_type> io_work_; + + // The user-supplied completion handler, called once only on completion + // of the entire composed operation. + typename std::decay<decltype(completion_handler)>::type handler_; + + // By having a default value for the second argument, this function call + // operator matches the completion signature of both the async_write and + // steady_timer::async_wait operations. + void operator()(const boost::system::error_code& error, std::size_t = 0) + { + if (!error) + { + switch (state_) + { + case starting: + case writing: + if (repeat_count_ > 0) + { + --repeat_count_; + state_ = waiting; + delay_timer_->expires_after(std::chrono::seconds(1)); + delay_timer_->async_wait(std::move(*this)); + return; // Composed operation not yet complete. + } + break; // Composed operation complete, continue below. + case waiting: + state_ = writing; + boost::asio::async_write(socket_, + boost::asio::buffer(*encoded_message_), std::move(*this)); + return; // Composed operation not yet complete. + } + } + + // This point is reached only on completion of the entire composed + // operation. + + // We no longer have any future work coming for the I/O executor. + io_work_.reset(); + + // Deallocate the encoded message before calling the user-supplied + // completion handler. + encoded_message_.reset(); + + // Call the user-supplied handler with the result of the operation. + handler_(error); + } + + // It is essential to the correctness of our composed operation that we + // preserve the executor of the user-supplied completion handler. With a + // hand-crafted function object we can do this by defining a nested type + // executor_type and member function get_executor. These obtain the + // completion handler's associated executor, and default to the I/O + // executor - in this case the executor of the socket - if the completion + // handler does not have its own. + using executor_type = boost::asio::associated_executor_t< + typename std::decay<decltype(completion_handler)>::type, + tcp::socket::executor_type>; + + executor_type get_executor() const noexcept + { + return boost::asio::get_associated_executor( + handler_, socket_.get_executor()); + } + + // Although not necessary for correctness, we may also preserve the + // allocator of the user-supplied completion handler. This is achieved by + // defining a nested type allocator_type and member function + // get_allocator. These obtain the completion handler's associated + // allocator, and default to std::allocator<void> if the completion + // handler does not have its own. + using allocator_type = boost::asio::associated_allocator_t< + typename std::decay<decltype(completion_handler)>::type, + std::allocator<void>>; + + allocator_type get_allocator() const noexcept + { + return boost::asio::get_associated_allocator( + handler_, std::allocator<void>{}); + } + }; + + // Initiate the underlying async_write operation using our intermediate + // completion handler. + auto encoded_message_buffer = boost::asio::buffer(*encoded_message); + boost::asio::async_write(socket, encoded_message_buffer, + intermediate_completion_handler{ + socket, std::move(encoded_message), + repeat_count, std::move(delay_timer), + intermediate_completion_handler::starting, + boost::asio::make_work_guard(socket.get_executor()), + std::forward<decltype(completion_handler)>(completion_handler)}); + }; + + // Encode the message and copy it into an allocated buffer. The buffer will + // be maintained for the lifetime of the composed asynchronous operation. + std::ostringstream os; + os << message; + std::unique_ptr<std::string> encoded_message(new std::string(os.str())); + + // Create a steady_timer to be used for the delay between messages. + std::unique_ptr<boost::asio::steady_timer> delay_timer( + new boost::asio::steady_timer(socket.get_executor())); + + // The boost::asio::async_initiate function takes: + // + // - our initiation function object, + // - the completion token, + // - the completion handler signature, and + // - any additional arguments we need to initiate the operation. + // + // It then asks the completion token to create a completion handler (i.e. a + // callback) with the specified signature, and invoke the initiation function + // object with this completion handler as well as the additional arguments. + // The return value of async_initiate is the result of our operation's + // initiating function. + // + // Note that we wrap non-const reference arguments in std::reference_wrapper + // to prevent incorrect decay-copies of these objects. + return boost::asio::async_initiate< + CompletionToken, void(boost::system::error_code)>( + initiation, token, std::ref(socket), + std::move(encoded_message), repeat_count, + std::move(delay_timer)); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_messages(socket, "Testing callback\r\n", 5, + [](const boost::system::error_code& error) + { + if (!error) + { + std::cout << "Messages sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_messages( + socket, "Testing future\r\n", 5, boost::asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + f.get(); + std::cout << "Messages sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_future(); +} diff --git a/src/boost/libs/asio/example/cpp14/operations/composed_7.cpp b/src/boost/libs/asio/example/cpp14/operations/composed_7.cpp new file mode 100644 index 000000000..352693085 --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/operations/composed_7.cpp @@ -0,0 +1,219 @@ +// +// composed_7.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/compose.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/asio/use_future.hpp> +#include <boost/asio/write.hpp> +#include <functional> +#include <iostream> +#include <memory> +#include <sstream> +#include <string> +#include <type_traits> +#include <utility> + +using boost::asio::ip::tcp; + +// NOTE: This example requires the new boost::asio::async_compose function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// This composed operation shows composition of multiple underlying operations. +// It automatically serialises a message, using its I/O streams insertion +// operator, before sending it N times on the socket. To do this, it must +// allocate a buffer for the encoded message and ensure this buffer's validity +// until all underlying async_write operation complete. A one second delay is +// inserted prior to each write operation, using a steady_timer. + +template <typename T, typename CompletionToken> +auto async_write_messages(tcp::socket& socket, + const T& message, std::size_t repeat_count, + CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of CompletionToken type and the completion handler's signature. When the + // completion token is a simple callback, the return type is always void. + // In this example, when the completion token is boost::asio::yield_context + // (used for stackful coroutines) the return type would be also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is boost::asio::use_future it would be std::future<void>. + // + // In C++14 we can omit the return type as it is automatically deduced from + // the return type of boost::asio::async_initiate. +{ + // Encode the message and copy it into an allocated buffer. The buffer will + // be maintained for the lifetime of the composed asynchronous operation. + std::ostringstream os; + os << message; + std::unique_ptr<std::string> encoded_message(new std::string(os.str())); + + // Create a steady_timer to be used for the delay between messages. + std::unique_ptr<boost::asio::steady_timer> delay_timer( + new boost::asio::steady_timer(socket.get_executor())); + + // To manage the cycle between the multiple underlying asychronous + // operations, our implementation is a state machine. + enum { starting, waiting, writing }; + + // The boost::asio::async_compose function takes: + // + // - our asynchronous operation implementation, + // - the completion token, + // - the completion handler signature, and + // - any I/O objects (or executors) used by the operation + // + // It then wraps our implementation, which is implemented here as a state + // machine in a lambda, in an intermediate completion handler that meets the + // requirements of a conforming asynchronous operation. This includes + // tracking outstanding work against the I/O executors associated with the + // operation (in this example, this is the socket's executor). + // + // The first argument to our lambda is a reference to the enclosing + // intermediate completion handler. This intermediate completion handler is + // provided for us by the boost::asio::async_compose function, and takes care + // of all the details required to implement a conforming asynchronous + // operation. When calling an underlying asynchronous operation, we pass it + // this enclosing intermediate completion handler as the completion token. + // + // All arguments to our lambda after the first must be defaulted to allow the + // state machine to be started, as well as to allow the completion handler to + // match the completion signature of both the async_write and + // steady_timer::async_wait operations. + return boost::asio::async_compose< + CompletionToken, void(boost::system::error_code)>( + [ + // The implementation holds a reference to the socket as it is used for + // multiple async_write operations. + &socket, + + // The allocated buffer for the encoded message. The std::unique_ptr + // smart pointer is move-only, and as a consequence our lambda + // implementation is also move-only. + encoded_message = std::move(encoded_message), + + // The repeat count remaining. + repeat_count, + + // A steady timer used for introducing a delay. + delay_timer = std::move(delay_timer), + + // To manage the cycle between the multiple underlying asychronous + // operations, our implementation is a state machine. + state = starting + ] + ( + auto& self, + const boost::system::error_code& error = {}, + std::size_t = 0 + ) mutable + { + if (!error) + { + switch (state) + { + case starting: + case writing: + if (repeat_count > 0) + { + --repeat_count; + state = waiting; + delay_timer->expires_after(std::chrono::seconds(1)); + delay_timer->async_wait(std::move(self)); + return; // Composed operation not yet complete. + } + break; // Composed operation complete, continue below. + case waiting: + state = writing; + boost::asio::async_write(socket, + boost::asio::buffer(*encoded_message), std::move(self)); + return; // Composed operation not yet complete. + } + } + + // This point is reached only on completion of the entire composed + // operation. + + // Deallocate the encoded message and delay timer before calling the + // user-supplied completion handler. + encoded_message.reset(); + delay_timer.reset(); + + // Call the user-supplied handler with the result of the operation. + self.complete(error); + }, + token, socket); +} + +//------------------------------------------------------------------------------ + +void test_callback() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_messages(socket, "Testing callback\r\n", 5, + [](const boost::system::error_code& error) + { + if (!error) + { + std::cout << "Messages sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_messages( + socket, "Testing future\r\n", 5, boost::asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + f.get(); + std::cout << "Messages sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_future(); +} diff --git a/src/boost/libs/asio/example/cpp14/operations/composed_8.cpp b/src/boost/libs/asio/example/cpp14/operations/composed_8.cpp new file mode 100644 index 000000000..9fe948cd6 --- /dev/null +++ b/src/boost/libs/asio/example/cpp14/operations/composed_8.cpp @@ -0,0 +1,212 @@ +// +// composed_8.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/compose.hpp> +#include <boost/asio/coroutine.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/asio/use_future.hpp> +#include <boost/asio/write.hpp> +#include <functional> +#include <iostream> +#include <memory> +#include <sstream> +#include <string> +#include <type_traits> +#include <utility> + +using boost::asio::ip::tcp; + +// NOTE: This example requires the new boost::asio::async_compose function. For +// an example that works with the Networking TS style of completion tokens, +// please see an older version of asio. + +//------------------------------------------------------------------------------ + +// This composed operation shows composition of multiple underlying operations, +// using asio's stackless coroutines support to express the flow of control. It +// automatically serialises a message, using its I/O streams insertion +// operator, before sending it N times on the socket. To do this, it must +// allocate a buffer for the encoded message and ensure this buffer's validity +// until all underlying async_write operation complete. A one second delay is +// inserted prior to each write operation, using a steady_timer. + +#include <boost/asio/yield.hpp> + +template <typename T, typename CompletionToken> +auto async_write_messages(tcp::socket& socket, + const T& message, std::size_t repeat_count, + CompletionToken&& token) + // The return type of the initiating function is deduced from the combination + // of CompletionToken type and the completion handler's signature. When the + // completion token is a simple callback, the return type is always void. + // In this example, when the completion token is boost::asio::yield_context + // (used for stackful coroutines) the return type would be also be void, as + // there is no non-error argument to the completion handler. When the + // completion token is boost::asio::use_future it would be std::future<void>. + // + // In C++14 we can omit the return type as it is automatically deduced from + // the return type of boost::asio::async_initiate. +{ + // Encode the message and copy it into an allocated buffer. The buffer will + // be maintained for the lifetime of the composed asynchronous operation. + std::ostringstream os; + os << message; + std::unique_ptr<std::string> encoded_message(new std::string(os.str())); + + // Create a steady_timer to be used for the delay between messages. + std::unique_ptr<boost::asio::steady_timer> delay_timer( + new boost::asio::steady_timer(socket.get_executor())); + + // The boost::asio::async_compose function takes: + // + // - our asynchronous operation implementation, + // - the completion token, + // - the completion handler signature, and + // - any I/O objects (or executors) used by the operation + // + // It then wraps our implementation, which is implemented here as a stackless + // coroutine in a lambda, in an intermediate completion handler that meets the + // requirements of a conforming asynchronous operation. This includes + // tracking outstanding work against the I/O executors associated with the + // operation (in this example, this is the socket's executor). + // + // The first argument to our lambda is a reference to the enclosing + // intermediate completion handler. This intermediate completion handler is + // provided for us by the boost::asio::async_compose function, and takes care + // of all the details required to implement a conforming asynchronous + // operation. When calling an underlying asynchronous operation, we pass it + // this enclosing intermediate completion handler as the completion token. + // + // All arguments to our lambda after the first must be defaulted to allow the + // state machine to be started, as well as to allow the completion handler to + // match the completion signature of both the async_write and + // steady_timer::async_wait operations. + return boost::asio::async_compose< + CompletionToken, void(boost::system::error_code)>( + [ + // The implementation holds a reference to the socket as it is used for + // multiple async_write operations. + &socket, + + // The allocated buffer for the encoded message. The std::unique_ptr + // smart pointer is move-only, and as a consequence our lambda + // implementation is also move-only. + encoded_message = std::move(encoded_message), + + // The repeat count remaining. + repeat_count, + + // A steady timer used for introducing a delay. + delay_timer = std::move(delay_timer), + + // The coroutine state. + coro = boost::asio::coroutine() + ] + ( + auto& self, + const boost::system::error_code& error = {}, + std::size_t = 0 + ) mutable + { + reenter (coro) + { + while (repeat_count > 0) + { + --repeat_count; + + delay_timer->expires_after(std::chrono::seconds(1)); + yield delay_timer->async_wait(std::move(self)); + if (error) + break; + + yield boost::asio::async_write(socket, + boost::asio::buffer(*encoded_message), std::move(self)); + if (error) + break; + } + + // Deallocate the encoded message and delay timer before calling the + // user-supplied completion handler. + encoded_message.reset(); + delay_timer.reset(); + + // Call the user-supplied handler with the result of the operation. + self.complete(error); + } + }, + token, socket); +} + +#include <boost/asio/unyield.hpp> + +//------------------------------------------------------------------------------ + +void test_callback() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using a lambda as a callback. + async_write_messages(socket, "Testing callback\r\n", 5, + [](const boost::system::error_code& error) + { + if (!error) + { + std::cout << "Messages sent\n"; + } + else + { + std::cout << "Error: " << error.message() << "\n"; + } + }); + + io_context.run(); +} + +//------------------------------------------------------------------------------ + +void test_future() +{ + boost::asio::io_context io_context; + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + tcp::socket socket = acceptor.accept(); + + // Test our asynchronous operation using the use_future completion token. + // This token causes the operation's initiating function to return a future, + // which may be used to synchronously wait for the result of the operation. + std::future<void> f = async_write_messages( + socket, "Testing future\r\n", 5, boost::asio::use_future); + + io_context.run(); + + try + { + // Get the result of the operation. + f.get(); + std::cout << "Messages sent\n"; + } + catch (const std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + } +} + +//------------------------------------------------------------------------------ + +int main() +{ + test_callback(); + test_future(); +} diff --git a/src/boost/libs/asio/example/cpp17/coroutines_ts/chat_server.cpp b/src/boost/libs/asio/example/cpp17/coroutines_ts/chat_server.cpp new file mode 100644 index 000000000..e233e9d6d --- /dev/null +++ b/src/boost/libs/asio/example/cpp17/coroutines_ts/chat_server.cpp @@ -0,0 +1,225 @@ +// +// chat_server.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <cstdlib> +#include <deque> +#include <iostream> +#include <list> +#include <memory> +#include <set> +#include <string> +#include <utility> +#include <boost/asio/awaitable.hpp> +#include <boost/asio/detached.hpp> +#include <boost/asio/co_spawn.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/read_until.hpp> +#include <boost/asio/redirect_error.hpp> +#include <boost/asio/signal_set.hpp> +#include <boost/asio/steady_timer.hpp> +#include <boost/asio/use_awaitable.hpp> +#include <boost/asio/write.hpp> + +using boost::asio::ip::tcp; +using boost::asio::awaitable; +using boost::asio::co_spawn; +using boost::asio::detached; +using boost::asio::redirect_error; +using boost::asio::use_awaitable; + +//---------------------------------------------------------------------- + +class chat_participant +{ +public: + virtual ~chat_participant() {} + virtual void deliver(const std::string& msg) = 0; +}; + +typedef std::shared_ptr<chat_participant> chat_participant_ptr; + +//---------------------------------------------------------------------- + +class chat_room +{ +public: + void join(chat_participant_ptr participant) + { + participants_.insert(participant); + for (auto msg: recent_msgs_) + participant->deliver(msg); + } + + void leave(chat_participant_ptr participant) + { + participants_.erase(participant); + } + + void deliver(const std::string& msg) + { + recent_msgs_.push_back(msg); + while (recent_msgs_.size() > max_recent_msgs) + recent_msgs_.pop_front(); + + for (auto participant: participants_) + participant->deliver(msg); + } + +private: + std::set<chat_participant_ptr> participants_; + enum { max_recent_msgs = 100 }; + std::deque<std::string> recent_msgs_; +}; + +//---------------------------------------------------------------------- + +class chat_session + : public chat_participant, + public std::enable_shared_from_this<chat_session> +{ +public: + chat_session(tcp::socket socket, chat_room& room) + : socket_(std::move(socket)), + timer_(socket_.get_executor()), + room_(room) + { + timer_.expires_at(std::chrono::steady_clock::time_point::max()); + } + + void start() + { + room_.join(shared_from_this()); + + co_spawn(socket_.get_executor(), + [self = shared_from_this()]{ return self->reader(); }, + detached); + + co_spawn(socket_.get_executor(), + [self = shared_from_this()]{ return self->writer(); }, + detached); + } + + void deliver(const std::string& msg) + { + write_msgs_.push_back(msg); + timer_.cancel_one(); + } + +private: + awaitable<void> reader() + { + try + { + for (std::string read_msg;;) + { + std::size_t n = co_await boost::asio::async_read_until(socket_, + boost::asio::dynamic_buffer(read_msg, 1024), "\n", use_awaitable); + + room_.deliver(read_msg.substr(0, n)); + read_msg.erase(0, n); + } + } + catch (std::exception&) + { + stop(); + } + } + + awaitable<void> writer() + { + try + { + while (socket_.is_open()) + { + if (write_msgs_.empty()) + { + boost::system::error_code ec; + co_await timer_.async_wait(redirect_error(use_awaitable, ec)); + } + else + { + co_await boost::asio::async_write(socket_, + boost::asio::buffer(write_msgs_.front()), use_awaitable); + write_msgs_.pop_front(); + } + } + } + catch (std::exception&) + { + stop(); + } + } + + void stop() + { + room_.leave(shared_from_this()); + socket_.close(); + timer_.cancel(); + } + + tcp::socket socket_; + boost::asio::steady_timer timer_; + chat_room& room_; + std::deque<std::string> write_msgs_; +}; + +//---------------------------------------------------------------------- + +awaitable<void> listener(tcp::acceptor acceptor) +{ + chat_room room; + + for (;;) + { + std::make_shared<chat_session>( + co_await acceptor.async_accept(use_awaitable), + room + )->start(); + } +} + +//---------------------------------------------------------------------- + +int main(int argc, char* argv[]) +{ + try + { + if (argc < 2) + { + std::cerr << "Usage: chat_server <port> [<port> ...]\n"; + return 1; + } + + boost::asio::io_context io_context(1); + + for (int i = 1; i < argc; ++i) + { + unsigned short port = std::atoi(argv[i]); + co_spawn(io_context, + [&io_context, port] + { + return listener(tcp::acceptor(io_context, {tcp::v4(), port})); + }, + detached); + } + + boost::asio::signal_set signals(io_context, SIGINT, SIGTERM); + signals.async_wait([&](auto, auto){ io_context.stop(); }); + + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << "Exception: " << e.what() << "\n"; + } + + return 0; +} diff --git a/src/boost/libs/asio/example/cpp17/coroutines_ts/echo_server.cpp b/src/boost/libs/asio/example/cpp17/coroutines_ts/echo_server.cpp new file mode 100644 index 000000000..7ca12c69a --- /dev/null +++ b/src/boost/libs/asio/example/cpp17/coroutines_ts/echo_server.cpp @@ -0,0 +1,76 @@ +// +// echo_server.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/co_spawn.hpp> +#include <boost/asio/detached.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/signal_set.hpp> +#include <boost/asio/write.hpp> +#include <cstdio> + +using boost::asio::ip::tcp; +using boost::asio::awaitable; +using boost::asio::co_spawn; +using boost::asio::detached; +using boost::asio::use_awaitable; +namespace this_coro = boost::asio::this_coro; + +awaitable<void> echo(tcp::socket socket) +{ + try + { + char data[1024]; + for (;;) + { + std::size_t n = co_await socket.async_read_some(boost::asio::buffer(data), use_awaitable); + co_await async_write(socket, boost::asio::buffer(data, n), use_awaitable); + } + } + catch (std::exception& e) + { + std::printf("echo Exception: %s\n", e.what()); + } +} + +awaitable<void> listener() +{ + auto executor = co_await this_coro::executor; + tcp::acceptor acceptor(executor, {tcp::v4(), 55555}); + for (;;) + { + tcp::socket socket = co_await acceptor.async_accept(use_awaitable); + co_spawn(executor, + [socket = std::move(socket)]() mutable + { + return echo(std::move(socket)); + }, + detached); + } +} + +int main() +{ + try + { + boost::asio::io_context io_context(1); + + boost::asio::signal_set signals(io_context, SIGINT, SIGTERM); + signals.async_wait([&](auto, auto){ io_context.stop(); }); + + co_spawn(io_context, listener, detached); + + io_context.run(); + } + catch (std::exception& e) + { + std::printf("Exception: %s\n", e.what()); + } +} diff --git a/src/boost/libs/asio/example/cpp17/coroutines_ts/echo_server_with_default.cpp b/src/boost/libs/asio/example/cpp17/coroutines_ts/echo_server_with_default.cpp new file mode 100644 index 000000000..a34f8bf57 --- /dev/null +++ b/src/boost/libs/asio/example/cpp17/coroutines_ts/echo_server_with_default.cpp @@ -0,0 +1,78 @@ +// +// echo_server_with_default.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/co_spawn.hpp> +#include <boost/asio/detached.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/signal_set.hpp> +#include <boost/asio/write.hpp> +#include <cstdio> + +using boost::asio::ip::tcp; +using boost::asio::awaitable; +using boost::asio::co_spawn; +using boost::asio::detached; +using boost::asio::use_awaitable_t; +using tcp_acceptor = use_awaitable_t<>::as_default_on_t<tcp::acceptor>; +using tcp_socket = use_awaitable_t<>::as_default_on_t<tcp::socket>; +namespace this_coro = boost::asio::this_coro; + +awaitable<void> echo(tcp_socket socket) +{ + try + { + char data[1024]; + for (;;) + { + std::size_t n = co_await socket.async_read_some(boost::asio::buffer(data)); + co_await async_write(socket, boost::asio::buffer(data, n)); + } + } + catch (std::exception& e) + { + std::printf("echo Exception: %s\n", e.what()); + } +} + +awaitable<void> listener() +{ + auto executor = co_await this_coro::executor; + tcp_acceptor acceptor(executor, {tcp::v4(), 55555}); + for (;;) + { + auto socket = co_await acceptor.async_accept(); + co_spawn(executor, + [socket = std::move(socket)]() mutable + { + return echo(std::move(socket)); + }, + detached); + } +} + +int main() +{ + try + { + boost::asio::io_context io_context(1); + + boost::asio::signal_set signals(io_context, SIGINT, SIGTERM); + signals.async_wait([&](auto, auto){ io_context.stop(); }); + + co_spawn(io_context, listener, detached); + + io_context.run(); + } + catch (std::exception& e) + { + std::printf("Exception: %s\n", e.what()); + } +} diff --git a/src/boost/libs/asio/example/cpp17/coroutines_ts/range_based_for.cpp b/src/boost/libs/asio/example/cpp17/coroutines_ts/range_based_for.cpp new file mode 100644 index 000000000..477349aee --- /dev/null +++ b/src/boost/libs/asio/example/cpp17/coroutines_ts/range_based_for.cpp @@ -0,0 +1,107 @@ +// +// range_based_for.cpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/co_spawn.hpp> +#include <boost/asio/detached.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/signal_set.hpp> +#include <boost/asio/write.hpp> +#include <cstdio> + +using boost::asio::ip::tcp; +using boost::asio::awaitable; +using boost::asio::co_spawn; +using boost::asio::detached; +using boost::asio::use_awaitable; + +class connection_iter +{ + friend class connections; + tcp::acceptor* acceptor_ = nullptr; + tcp::socket socket_; + + connection_iter(tcp::acceptor& a, tcp::socket s) + : acceptor_(&a), socket_(std::move(s)) {} + +public: + tcp::socket operator*() + { + return std::move(socket_); + } + + awaitable<void> operator++() + { + socket_ = co_await acceptor_->async_accept(use_awaitable); + } + + bool operator==(const connection_iter&) const noexcept + { + return false; + } + + bool operator!=(const connection_iter&) const noexcept + { + return true; + } +}; + +class connections +{ + tcp::acceptor& acceptor_; + +public: + explicit connections(tcp::acceptor& a) : acceptor_(a) {} + + awaitable<connection_iter> begin() + { + tcp::socket s = co_await acceptor_.async_accept(use_awaitable); + co_return connection_iter(acceptor_, std::move(s)); + } + + connection_iter end() + { + return connection_iter(acceptor_, + tcp::socket(acceptor_.get_executor())); + } +}; + +awaitable<void> listener(tcp::acceptor acceptor) +{ + for co_await (tcp::socket s : connections(acceptor)) + { + co_await boost::asio::async_write(s, boost::asio::buffer("hello\r\n", 7), use_awaitable); + } +} + +int main() +{ + try + { + boost::asio::io_context io_context(1); + + boost::asio::signal_set signals(io_context, SIGINT, SIGTERM); + signals.async_wait([&](auto, auto){ io_context.stop(); }); + + tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); + co_spawn(io_context, + [acceptor = std::move(acceptor)]() mutable + { + return listener(std::move(acceptor)); + }, + detached); + + io_context.run(); + } + catch (std::exception& e) + { + std::printf("Exception: %s\n", e.what()); + } +} diff --git a/src/boost/libs/asio/example/cpp17/coroutines_ts/refactored_echo_server.cpp b/src/boost/libs/asio/example/cpp17/coroutines_ts/refactored_echo_server.cpp new file mode 100644 index 000000000..062efc16c --- /dev/null +++ b/src/boost/libs/asio/example/cpp17/coroutines_ts/refactored_echo_server.cpp @@ -0,0 +1,85 @@ +// +// refactored_echo_server.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/co_spawn.hpp> +#include <boost/asio/detached.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/signal_set.hpp> +#include <boost/asio/write.hpp> +#include <cstdio> + +using boost::asio::ip::tcp; +using boost::asio::awaitable; +using boost::asio::co_spawn; +using boost::asio::detached; +using boost::asio::use_awaitable; +namespace this_coro = boost::asio::this_coro; + +awaitable<void> echo_once(tcp::socket& socket) +{ + char data[128]; + std::size_t n = co_await socket.async_read_some(boost::asio::buffer(data), use_awaitable); + co_await async_write(socket, boost::asio::buffer(data, n), use_awaitable); +} + +awaitable<void> echo(tcp::socket socket) +{ + try + { + for (;;) + { + // The asynchronous operations to echo a single chunk of data have been + // refactored into a separate function. When this function is called, the + // operations are still performed in the context of the current + // coroutine, and the behaviour is functionally equivalent. + co_await echo_once(socket); + } + } + catch (std::exception& e) + { + std::printf("echo Exception: %s\n", e.what()); + } +} + +awaitable<void> listener() +{ + auto executor = co_await this_coro::executor; + tcp::acceptor acceptor(executor, {tcp::v4(), 55555}); + for (;;) + { + tcp::socket socket = co_await acceptor.async_accept(use_awaitable); + co_spawn(executor, + [socket = std::move(socket)]() mutable + { + return echo(std::move(socket)); + }, + detached); + } +} + +int main() +{ + try + { + boost::asio::io_context io_context(1); + + boost::asio::signal_set signals(io_context, SIGINT, SIGTERM); + signals.async_wait([&](auto, auto){ io_context.stop(); }); + + co_spawn(io_context, listener, detached); + + io_context.run(); + } + catch (std::exception& e) + { + std::printf("Exception: %s\n", e.what()); + } +} diff --git a/src/boost/libs/asio/index.html b/src/boost/libs/asio/index.html new file mode 100644 index 000000000..a63ccdabe --- /dev/null +++ b/src/boost/libs/asio/index.html @@ -0,0 +1,21 @@ +<html> + <head> + <title>Boost.Asio</title> + <meta http-equiv="refresh" content="0; URL=../../doc/html/boost_asio.html"/> + </head> + <body> + <p> + Automatic redirection failed, please go to + <a href="../../doc/html/boost_asio.html">../../doc/html/boost_asio.html</a> + </p> + <hr/> + <p> + Copyright (c) 2008 Christopher M. Kohlhoff + </p> + <p> + Distributed under the Boost Software License, Version 1.0. (See accompanying + file <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at + <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>) + </p> + </body> +</html> diff --git a/src/boost/libs/asio/meta/libraries.json b/src/boost/libs/asio/meta/libraries.json new file mode 100644 index 000000000..685753d08 --- /dev/null +++ b/src/boost/libs/asio/meta/libraries.json @@ -0,0 +1,15 @@ +{ + "key": "asio", + "name": "Asio", + "authors": [ + "Chris Kohlhoff" + ], + "description": "Portable networking and other low-level I/O, including sockets, timers, hostname resolution, socket iostreams, serial ports, file descriptors and Windows HANDLEs.", + "category": [ + "Concurrent", + "IO" + ], + "maintainers": [ + "Chris Kohlhoff <chris -at- kohlhoff.com>" + ] +} diff --git a/src/boost/libs/asio/test/Jamfile.v2 b/src/boost/libs/asio/test/Jamfile.v2 new file mode 100644 index 000000000..a9835751c --- /dev/null +++ b/src/boost/libs/asio/test/Jamfile.v2 @@ -0,0 +1,235 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +import feature ; + +lib socket ; # SOLARIS, QNXNTO +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +local USE_SELECT = + <define>BOOST_ASIO_DISABLE_DEV_POLL + <define>BOOST_ASIO_DISABLE_EPOLL + <define>BOOST_ASIO_DISABLE_KQUEUE + <define>BOOST_ASIO_DISABLE_IOCP + ; + +project + : requirements + <library>/boost/date_time//boost_date_time + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <library>/boost/regex//boost_regex + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>linux:<define>_XOPEN_SOURCE=600 + <target-os>linux:<define>_GNU_SOURCE=1 + <target-os>solaris:<define>_XOPEN_SOURCE=500 + <target-os>solaris:<define>__EXTENSIONS__ + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>cw:<library>ws2_32 + <target-os>windows,<toolset>cw:<library>mswsock + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>qnxnto:<library>socket + <target-os>haiku:<library>network + ; + +test-suite "asio" : + [ link awaitable.cpp ] + [ link awaitable.cpp : $(USE_SELECT) : awaitable_select ] + [ link basic_datagram_socket.cpp ] + [ link basic_datagram_socket.cpp : $(USE_SELECT) : basic_datagram_socket_select ] + [ link basic_deadline_timer.cpp ] + [ link basic_deadline_timer.cpp : $(USE_SELECT) : basic_deadline_timer_select ] + [ link basic_raw_socket.cpp ] + [ link basic_raw_socket.cpp : $(USE_SELECT) : basic_raw_socket_select ] + [ link basic_seq_packet_socket.cpp ] + [ link basic_seq_packet_socket.cpp : $(USE_SELECT) : basic_seq_packet_socket_select ] + [ link basic_signal_set.cpp ] + [ link basic_signal_set.cpp : $(USE_SELECT) : basic_signal_set_select ] + [ link basic_socket_acceptor.cpp ] + [ link basic_socket_acceptor.cpp : $(USE_SELECT) : basic_socket_acceptor_select ] + [ link basic_stream_socket.cpp ] + [ link basic_stream_socket.cpp : $(USE_SELECT) : basic_stream_socket_select ] + [ link basic_streambuf.cpp ] + [ link basic_streambuf.cpp : $(USE_SELECT) : basic_streambuf_select ] + [ link basic_waitable_timer.cpp ] + [ link basic_waitable_timer.cpp : $(USE_SELECT) : basic_waitable_timer_select ] + [ run buffer.cpp ] + [ run buffer.cpp : : : $(USE_SELECT) : buffer_select ] + [ run buffered_read_stream.cpp ] + [ run buffered_read_stream.cpp : : : $(USE_SELECT) : buffered_read_stream_select ] + [ run buffered_stream.cpp ] + [ run buffered_stream.cpp : : : $(USE_SELECT) : buffered_stream_select ] + [ run buffered_write_stream.cpp ] + [ run buffered_write_stream.cpp : : : $(USE_SELECT) : buffered_write_stream_select ] + [ run buffers_iterator.cpp ] + [ run buffers_iterator.cpp : : : $(USE_SELECT) : buffers_iterator_select ] + [ link co_spawn.cpp ] + [ link co_spawn.cpp : $(USE_SELECT) : co_spawn_select ] + [ link completion_condition.cpp ] + [ link completion_condition.cpp : $(USE_SELECT) : completion_condition_select ] + [ run compose.cpp ] + [ run compose.cpp : : : $(USE_SELECT) : compose_select ] + [ link connect.cpp ] + [ link connect.cpp : $(USE_SELECT) : connect_select ] + [ link coroutine.cpp ] + [ link coroutine.cpp : $(USE_SELECT) : coroutine_select ] + [ run deadline_timer.cpp ] + [ run deadline_timer.cpp : : : $(USE_SELECT) : deadline_timer_select ] + [ link detached.cpp ] + [ link detached.cpp : $(USE_SELECT) : detached_select ] + [ run error.cpp ] + [ run error.cpp : : : $(USE_SELECT) : error_select ] + [ link generic/basic_endpoint.cpp : : generic_basic_endpoint ] + [ link generic/basic_endpoint.cpp : $(USE_SELECT) : generic_basic_endpoint_select ] + [ link generic/datagram_protocol.cpp : : generic_datagram_protocol ] + [ link generic/datagram_protocol.cpp : $(USE_SELECT) : generic_datagram_protocol_select ] + [ link generic/raw_protocol.cpp : : generic_raw_protocol ] + [ link generic/raw_protocol.cpp : $(USE_SELECT) : generic_raw_protocol_select ] + [ link generic/seq_packet_protocol.cpp : : generic_seq_packet_protocol ] + [ link generic/seq_packet_protocol.cpp : $(USE_SELECT) : generic_seq_packet_protocol_select ] + [ link generic/stream_protocol.cpp : : generic_stream_protocol ] + [ link generic/stream_protocol.cpp : $(USE_SELECT) : generic_stream_protocol_select ] + [ link high_resolution_timer.cpp ] + [ link high_resolution_timer.cpp : $(USE_SELECT) : high_resolution_timer_select ] + [ run io_context.cpp ] + [ run io_context.cpp : : : $(USE_SELECT) : io_context_select ] + [ run io_context_strand.cpp ] + [ run io_context_strand.cpp : : : $(USE_SELECT) : io_context_strand_select ] + [ link ip/address.cpp : : ip_address ] + [ link ip/address.cpp : $(USE_SELECT) : ip_address_select ] + [ link ip/address_v4.cpp : : ip_address_v4 ] + [ link ip/address_v4.cpp : $(USE_SELECT) : ip_address_v4_select ] + [ link ip/address_v6.cpp : : ip_address_v6 ] + [ link ip/address_v6.cpp : $(USE_SELECT) : ip_address_v6_select ] + [ link ip/basic_endpoint.cpp : : ip_basic_endpoint ] + [ link ip/basic_endpoint.cpp : $(USE_SELECT) : ip_basic_endpoint_select ] + [ link ip/basic_resolver.cpp : : ip_basic_resolver ] + [ link ip/basic_resolver.cpp : $(USE_SELECT) : ip_basic_resolver_select ] + [ link ip/basic_resolver_entry.cpp : : ip_basic_resolver_entry ] + [ link ip/basic_resolver_entry.cpp : $(USE_SELECT) : ip_basic_resolver_entry_select ] + [ link ip/basic_resolver_iterator.cpp : : ip_basic_resolver_iterator ] + [ link ip/basic_resolver_iterator.cpp : $(USE_SELECT) : ip_basic_resolver_iterator_select ] + [ link ip/basic_resolver_query.cpp : : ip_basic_resolver_query ] + [ link ip/basic_resolver_query.cpp : $(USE_SELECT) : ip_basic_resolver_query_select ] + [ run ip/host_name.cpp : : : : ip_host_name ] + [ run ip/host_name.cpp : : : $(USE_SELECT) : ip_host_name_select ] + [ run ip/icmp.cpp : : : : ip_icmp ] + [ run ip/icmp.cpp : : : $(USE_SELECT) : ip_icmp_select ] + [ run ip/multicast.cpp : : : : ip_multicast ] + [ run ip/multicast.cpp : : : $(USE_SELECT) : ip_multicast_select ] + [ link ip/resolver_query_base.cpp : : ip_resolver_query_base ] + [ link ip/resolver_query_base.cpp : $(USE_SELECT) : ip_resolver_query_base_select ] + [ run ip/tcp.cpp : : : : ip_tcp ] + [ run ip/tcp.cpp : : : $(USE_SELECT) : ip_tcp_select ] + [ run ip/udp.cpp : : : : ip_udp ] + [ run ip/udp.cpp : : : $(USE_SELECT) : ip_udp_select ] + [ run ip/unicast.cpp : : : : ip_unicast ] + [ run ip/unicast.cpp : : : $(USE_SELECT) : ip_unicast_select ] + [ run ip/v6_only.cpp : : : : ip_v6_only ] + [ run ip/v6_only.cpp : : : $(USE_SELECT) : ip_v6_only_select ] + [ run is_read_buffered.cpp ] + [ run is_read_buffered.cpp : : : $(USE_SELECT) : is_read_buffered_select ] + [ run is_write_buffered.cpp ] + [ run is_write_buffered.cpp : : : $(USE_SELECT) : is_write_buffered_select ] + [ link local/basic_endpoint.cpp : : local_basic_endpoint ] + [ link local/basic_endpoint.cpp : $(USE_SELECT) : local_basic_endpoint_select ] + [ link local/connect_pair.cpp : : local_connect_pair ] + [ link local/connect_pair.cpp : $(USE_SELECT) : local_connect_pair_select ] + [ link local/datagram_protocol.cpp : : local_datagram_protocol ] + [ link local/datagram_protocol.cpp : $(USE_SELECT) : local_datagram_protocol_select ] + [ link local/stream_protocol.cpp : : local_stream_protocol ] + [ link local/stream_protocol.cpp : $(USE_SELECT) : local_stream_protocol_select ] + [ link placeholders.cpp ] + [ link placeholders.cpp : $(USE_SELECT) : placeholders_select ] + [ link posix/basic_descriptor.cpp : : posix_basic_descriptor ] + [ link posix/basic_descriptor.cpp : $(USE_SELECT) : posix_basic_descriptor_select ] + [ link posix/basic_stream_descriptor.cpp : : posix_basic_stream_descriptor ] + [ link posix/basic_stream_descriptor.cpp : $(USE_SELECT) : posix_basic_stream_descriptor_select ] + [ link posix/descriptor_base.cpp : : posix_descriptor_base ] + [ link posix/descriptor_base.cpp : $(USE_SELECT) : posix_descriptor_base_select ] + [ link posix/stream_descriptor.cpp : : posix_stream_descriptor ] + [ link posix/stream_descriptor.cpp : $(USE_SELECT) : posix_stream_descriptor_select ] + [ run read.cpp ] + [ run read.cpp : : : $(USE_SELECT) : read_select ] + [ run read_at.cpp ] + [ run read_at.cpp : : : $(USE_SELECT) : read_at_select ] + [ run read_until.cpp ] + [ run read_until.cpp : : : $(USE_SELECT) : read_until_select ] + [ link redirect_error.cpp ] + [ link redirect_error.cpp : $(USE_SELECT) : redirect_error_select ] + [ run signal_set.cpp ] + [ run signal_set.cpp : : : $(USE_SELECT) : signal_set_select ] + [ run socket_base.cpp ] + [ run socket_base.cpp : : : $(USE_SELECT) : socket_base_select ] + [ link steady_timer.cpp ] + [ link steady_timer.cpp : $(USE_SELECT) : steady_timer_select ] + [ run strand.cpp ] + [ run strand.cpp : : : $(USE_SELECT) : strand_select ] + [ run streambuf.cpp ] + [ run streambuf.cpp : : : $(USE_SELECT) : streambuf_select ] + [ link system_timer.cpp ] + [ link system_timer.cpp : $(USE_SELECT) : system_timer_select ] + [ link system_context.cpp ] + [ link system_context.cpp : $(USE_SELECT) : system_context_select ] + [ link system_executor.cpp ] + [ link system_executor.cpp : $(USE_SELECT) : system_executor_select ] + [ link this_coro.cpp ] + [ link this_coro.cpp : $(USE_SELECT) : this_coro_select ] + [ link time_traits.cpp ] + [ link time_traits.cpp : $(USE_SELECT) : time_traits_select ] + [ link ts/buffer.cpp : : ts_buffer ] + [ link ts/buffer.cpp : $(USE_SELECT) : ts_buffer_select ] + [ link ts/executor.cpp : : ts_executor ] + [ link ts/executor.cpp : $(USE_SELECT) : ts_executor_select ] + [ link ts/internet.cpp : : ts_internet ] + [ link ts/internet.cpp : $(USE_SELECT) : ts_internet_select ] + [ link ts/io_context.cpp : : ts_io_context ] + [ link ts/io_context.cpp : $(USE_SELECT) : ts_io_context_select ] + [ link ts/net.cpp : : ts_net ] + [ link ts/net.cpp : $(USE_SELECT) : ts_net_select ] + [ link ts/netfwd.cpp : : ts_netfwd ] + [ link ts/netfwd.cpp : $(USE_SELECT) : ts_netfwd_select ] + [ link ts/socket.cpp : : ts_socket ] + [ link ts/socket.cpp : $(USE_SELECT) : ts_socket_select ] + [ link ts/timer.cpp : : ts_timer ] + [ link ts/timer.cpp : $(USE_SELECT) : ts_timer_select ] + [ link use_awaitable.cpp ] + [ link use_awaitable.cpp : $(USE_SELECT) : use_awaitable_select ] + [ link wait_traits.cpp ] + [ link wait_traits.cpp : $(USE_SELECT) : wait_traits_select ] + [ link windows/basic_object_handle.cpp : : windows_basic_object_handle ] + [ link windows/basic_object_handle.cpp : $(USE_SELECT) : windows_basic_object_handle_select ] + [ link windows/basic_overlapped_handle.cpp : : windows_basic_overlapped_handle ] + [ link windows/basic_overlapped_handle.cpp : $(USE_SELECT) : windows_basic_overlapped_handle_select ] + [ link windows/basic_random_access_handle.cpp : : windows_basic_random_access_handle ] + [ link windows/basic_random_access_handle.cpp : $(USE_SELECT) : windows_basic_random_access_handle_select ] + [ link windows/basic_stream_handle.cpp : : windows_basic_stream_handle ] + [ link windows/basic_stream_handle.cpp : $(USE_SELECT) : windows_basic_stream_handle_select ] + [ link windows/object_handle.cpp : : windows_object_handle ] + [ link windows/object_handle.cpp : $(USE_SELECT) : windows_object_handle_select ] + [ link windows/overlapped_ptr.cpp : : windows_overlapped_ptr ] + [ link windows/overlapped_ptr.cpp : $(USE_SELECT) : windows_overlapped_ptr_select ] + [ link windows/random_access_handle.cpp : : windows_random_access_handle ] + [ link windows/random_access_handle.cpp : $(USE_SELECT) : windows_random_access_handle_select ] + [ link windows/stream_handle.cpp : : windows_stream_handle ] + [ link windows/stream_handle.cpp : $(USE_SELECT) : windows_stream_handle_select ] + [ run write.cpp ] + [ run write.cpp : : : $(USE_SELECT) : write_select ] + [ run write_at.cpp ] + [ run write_at.cpp : : : $(USE_SELECT) : write_at_select ] + ; diff --git a/src/boost/libs/asio/test/archetypes/async_ops.hpp b/src/boost/libs/asio/test/archetypes/async_ops.hpp new file mode 100644 index 000000000..99a33b28d --- /dev/null +++ b/src/boost/libs/asio/test/archetypes/async_ops.hpp @@ -0,0 +1,415 @@ +// +// async_ops.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ARCHETYPES_ASYNC_OPS_HPP +#define ARCHETYPES_ASYNC_OPS_HPP + +#include <boost/asio/associated_allocator.hpp> +#include <boost/asio/associated_executor.hpp> +#include <boost/asio/async_result.hpp> +#include <boost/asio/error.hpp> + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +namespace archetypes { + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) +async_op_0(BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef typename boost::asio::async_completion<CompletionToken, + void()>::completion_handler_type handler_type; + + boost::asio::async_completion<CompletionToken, + void()> completion(token); + + typename boost::asio::associated_allocator<handler_type>::type a + = boost::asio::get_associated_allocator(completion.completion_handler); + + typename boost::asio::associated_executor<handler_type>::type ex + = boost::asio::get_associated_executor(completion.completion_handler); + + ex.post(BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), a); + + return completion.result.get(); +} + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(boost::system::error_code)) +async_op_ec_0(bool ok, BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef typename boost::asio::async_completion<CompletionToken, + void(boost::system::error_code)>::completion_handler_type handler_type; + + boost::asio::async_completion<CompletionToken, + void(boost::system::error_code)> completion(token); + + typename boost::asio::associated_allocator<handler_type>::type a + = boost::asio::get_associated_allocator(completion.completion_handler); + + typename boost::asio::associated_executor<handler_type>::type ex + = boost::asio::get_associated_executor(completion.completion_handler); + + if (ok) + { + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + boost::system::error_code()), a); + } + else + { + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + boost::system::error_code(boost::asio::error::operation_aborted)), a); + } + + return completion.result.get(); +} + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(std::exception_ptr)) +async_op_ex_0(bool ok, BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef typename boost::asio::async_completion<CompletionToken, + void(std::exception_ptr)>::completion_handler_type handler_type; + + boost::asio::async_completion<CompletionToken, + void(std::exception_ptr)> completion(token); + + typename boost::asio::associated_allocator<handler_type>::type a + = boost::asio::get_associated_allocator(completion.completion_handler); + + typename boost::asio::associated_executor<handler_type>::type ex + = boost::asio::get_associated_executor(completion.completion_handler); + + if (ok) + { + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + std::exception_ptr()), a); + } + else + { + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + std::make_exception_ptr(std::runtime_error("blah"))), a); + } + + return completion.result.get(); +} + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(int)) +async_op_1(BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef typename boost::asio::async_completion<CompletionToken, + void(int)>::completion_handler_type handler_type; + + boost::asio::async_completion<CompletionToken, + void(int)> completion(token); + + typename boost::asio::associated_allocator<handler_type>::type a + = boost::asio::get_associated_allocator(completion.completion_handler); + + typename boost::asio::associated_executor<handler_type>::type ex + = boost::asio::get_associated_executor(completion.completion_handler); + + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + 42), a); + + return completion.result.get(); +} + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, + void(boost::system::error_code, int)) +async_op_ec_1(bool ok, BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef typename boost::asio::async_completion<CompletionToken, + void(boost::system::error_code, int)>::completion_handler_type + handler_type; + + boost::asio::async_completion<CompletionToken, + void(boost::system::error_code, int)> completion(token); + + typename boost::asio::associated_allocator<handler_type>::type a + = boost::asio::get_associated_allocator(completion.completion_handler); + + typename boost::asio::associated_executor<handler_type>::type ex + = boost::asio::get_associated_executor(completion.completion_handler); + + if (ok) + { + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + boost::system::error_code(), 42), a); + } + else + { + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + boost::system::error_code(boost::asio::error::operation_aborted), + 0), a); + } + + return completion.result.get(); +} + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(std::exception_ptr, int)) +async_op_ex_1(bool ok, BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef typename boost::asio::async_completion<CompletionToken, + void(std::exception_ptr, int)>::completion_handler_type + handler_type; + + boost::asio::async_completion<CompletionToken, + void(std::exception_ptr, int)> completion(token); + + typename boost::asio::associated_allocator<handler_type>::type a + = boost::asio::get_associated_allocator(completion.completion_handler); + + typename boost::asio::associated_executor<handler_type>::type ex + = boost::asio::get_associated_executor(completion.completion_handler); + + if (ok) + { + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + std::exception_ptr(), 42), a); + } + else + { + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + std::make_exception_ptr(std::runtime_error("blah")), 0), a); + } + + return completion.result.get(); +} + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(int, double)) +async_op_2(BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef typename boost::asio::async_completion<CompletionToken, + void(int, double)>::completion_handler_type handler_type; + + boost::asio::async_completion<CompletionToken, + void(int, double)> completion(token); + + typename boost::asio::associated_allocator<handler_type>::type a + = boost::asio::get_associated_allocator(completion.completion_handler); + + typename boost::asio::associated_executor<handler_type>::type ex + = boost::asio::get_associated_executor(completion.completion_handler); + + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + 42, 2.0), a); + + return completion.result.get(); +} + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, + void(boost::system::error_code, int, double)) +async_op_ec_2(bool ok, BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef typename boost::asio::async_completion<CompletionToken, + void(boost::system::error_code, int, double)>::completion_handler_type + handler_type; + + boost::asio::async_completion<CompletionToken, + void(boost::system::error_code, int, double)> completion(token); + + typename boost::asio::associated_allocator<handler_type>::type a + = boost::asio::get_associated_allocator(completion.completion_handler); + + typename boost::asio::associated_executor<handler_type>::type ex + = boost::asio::get_associated_executor(completion.completion_handler); + + if (ok) + { + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + boost::system::error_code(), 42, 2.0), a); + } + else + { + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + boost::system::error_code(boost::asio::error::operation_aborted), + 0, 0.0), a); + } + + return completion.result.get(); +} + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, + void(std::exception_ptr, int, double)) +async_op_ex_2(bool ok, BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef typename boost::asio::async_completion<CompletionToken, + void(std::exception_ptr, int, double)>::completion_handler_type + handler_type; + + boost::asio::async_completion<CompletionToken, + void(std::exception_ptr, int, double)> completion(token); + + typename boost::asio::associated_allocator<handler_type>::type a + = boost::asio::get_associated_allocator(completion.completion_handler); + + typename boost::asio::associated_executor<handler_type>::type ex + = boost::asio::get_associated_executor(completion.completion_handler); + + if (ok) + { + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + std::exception_ptr(), 42, 2.0), a); + } + else + { + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + std::make_exception_ptr(std::runtime_error("blah")), 0, 0.0), a); + } + + return completion.result.get(); +} + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(int, double, char)) +async_op_3(BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef typename boost::asio::async_completion<CompletionToken, + void(int, double, char)>::completion_handler_type handler_type; + + boost::asio::async_completion<CompletionToken, + void(int, double, char)> completion(token); + + typename boost::asio::associated_allocator<handler_type>::type a + = boost::asio::get_associated_allocator(completion.completion_handler); + + typename boost::asio::associated_executor<handler_type>::type ex + = boost::asio::get_associated_executor(completion.completion_handler); + + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + 42, 2.0, 'a'), a); + + return completion.result.get(); +} + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, + void(boost::system::error_code, int, double, char)) +async_op_ec_3(bool ok, BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef typename boost::asio::async_completion<CompletionToken, + void(boost::system::error_code, int, double, char)>::completion_handler_type + handler_type; + + boost::asio::async_completion<CompletionToken, + void(boost::system::error_code, int, double, char)> completion(token); + + typename boost::asio::associated_allocator<handler_type>::type a + = boost::asio::get_associated_allocator(completion.completion_handler); + + typename boost::asio::associated_executor<handler_type>::type ex + = boost::asio::get_associated_executor(completion.completion_handler); + + if (ok) + { + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + boost::system::error_code(), 42, 2.0, 'a'), a); + } + else + { + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + boost::system::error_code(boost::asio::error::operation_aborted), + 0, 0.0, 'z'), a); + } + + return completion.result.get(); +} + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, + void(std::exception_ptr, int, double, char)) +async_op_ex_3(bool ok, BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + typedef typename boost::asio::async_completion<CompletionToken, + void(std::exception_ptr, int, double, char)>::completion_handler_type + handler_type; + + boost::asio::async_completion<CompletionToken, + void(std::exception_ptr, int, double, char)> completion(token); + + typename boost::asio::associated_allocator<handler_type>::type a + = boost::asio::get_associated_allocator(completion.completion_handler); + + typename boost::asio::associated_executor<handler_type>::type ex + = boost::asio::get_associated_executor(completion.completion_handler); + + if (ok) + { + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + std::exception_ptr(), 42, 2.0, 'a'), a); + } + else + { + ex.post( + bindns::bind( + BOOST_ASIO_MOVE_CAST(handler_type)(completion.completion_handler), + std::make_exception_ptr(std::runtime_error("blah")), + 0, 0.0, 'z'), a); + } + + return completion.result.get(); +} + +} // namespace archetypes + +#endif // ARCHETYPES_ASYNC_OPS_HPP diff --git a/src/boost/libs/asio/test/archetypes/async_result.hpp b/src/boost/libs/asio/test/archetypes/async_result.hpp new file mode 100644 index 000000000..50193eca3 --- /dev/null +++ b/src/boost/libs/asio/test/archetypes/async_result.hpp @@ -0,0 +1,96 @@ +// +// async_result.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ARCHETYPES_ASYNC_RESULT_HPP +#define ARCHETYPES_ASYNC_RESULT_HPP + +#include <boost/asio/async_result.hpp> + +namespace archetypes { + +struct lazy_handler +{ +}; + +template <typename Signature> +struct concrete_handler; + +template <typename R, typename Arg1> +struct concrete_handler<R(Arg1)> +{ + concrete_handler(lazy_handler) + { + } + + void operator()(typename boost::asio::decay<Arg1>::type) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + concrete_handler(concrete_handler&&) {} +private: + concrete_handler(const concrete_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +template <typename R, typename Arg1, typename Arg2> +struct concrete_handler<R(Arg1, Arg2)> +{ + concrete_handler(lazy_handler) + { + } + + void operator()(typename boost::asio::decay<Arg1>::type, typename boost::asio::decay<Arg2>::type) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + concrete_handler(concrete_handler&&) {} +private: + concrete_handler(const concrete_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +} // namespace archetypes + +namespace boost { +namespace asio { + +template <typename Signature> +class async_result<archetypes::lazy_handler, Signature> +{ +public: + // The concrete completion handler type. + typedef archetypes::concrete_handler<Signature> completion_handler_type; + + // The return type of the initiating function. + typedef int return_type; + + // Construct an async_result from a given handler. + explicit async_result(completion_handler_type&) + { + } + + // Obtain the value to be returned from the initiating function. + return_type get() + { + return 42; + } + +private: + // Disallow copying and assignment. + async_result(const async_result&) BOOST_ASIO_DELETED; + async_result& operator=(const async_result&) BOOST_ASIO_DELETED; +}; + +} // namespace asio +} // namespace boost + +#endif // ARCHETYPES_ASYNC_RESULT_HPP diff --git a/src/boost/libs/asio/test/archetypes/gettable_socket_option.hpp b/src/boost/libs/asio/test/archetypes/gettable_socket_option.hpp new file mode 100644 index 000000000..29a75753b --- /dev/null +++ b/src/boost/libs/asio/test/archetypes/gettable_socket_option.hpp @@ -0,0 +1,54 @@ +// +// gettable_socket_option.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ARCHETYPES_GETTABLE_SOCKET_OPTION_HPP +#define ARCHETYPES_GETTABLE_SOCKET_OPTION_HPP + +#include <cstddef> + +namespace archetypes { + +template <typename PointerType> +class gettable_socket_option +{ +public: + template <typename Protocol> + int level(const Protocol&) const + { + return 0; + } + + template <typename Protocol> + int name(const Protocol&) const + { + return 0; + } + + template <typename Protocol> + PointerType* data(const Protocol&) + { + return 0; + } + + template <typename Protocol> + std::size_t size(const Protocol&) const + { + return 0; + } + + template <typename Protocol> + void resize(const Protocol&, std::size_t) + { + } +}; + +} // namespace archetypes + +#endif // ARCHETYPES_GETTABLE_SOCKET_OPTION_HPP diff --git a/src/boost/libs/asio/test/archetypes/io_control_command.hpp b/src/boost/libs/asio/test/archetypes/io_control_command.hpp new file mode 100644 index 000000000..d0c329360 --- /dev/null +++ b/src/boost/libs/asio/test/archetypes/io_control_command.hpp @@ -0,0 +1,32 @@ +// +// io_control_command.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ARCHETYPES_IO_CONTROL_COMMAND_HPP +#define ARCHETYPES_IO_CONTROL_COMMAND_HPP + +namespace archetypes { + +class io_control_command +{ +public: + int name() const + { + return 0; + } + + void* data() + { + return 0; + } +}; + +} // namespace archetypes + +#endif // ARCHETYPES_IO_CONTROL_COMMAND_HPP diff --git a/src/boost/libs/asio/test/archetypes/settable_socket_option.hpp b/src/boost/libs/asio/test/archetypes/settable_socket_option.hpp new file mode 100644 index 000000000..01eeb0d94 --- /dev/null +++ b/src/boost/libs/asio/test/archetypes/settable_socket_option.hpp @@ -0,0 +1,49 @@ +// +// settable_socket_option.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ARCHETYPES_SETTABLE_SOCKET_OPTION_HPP +#define ARCHETYPES_SETTABLE_SOCKET_OPTION_HPP + +#include <cstddef> + +namespace archetypes { + +template <typename PointerType> +class settable_socket_option +{ +public: + template <typename Protocol> + int level(const Protocol&) const + { + return 0; + } + + template <typename Protocol> + int name(const Protocol&) const + { + return 0; + } + + template <typename Protocol> + const PointerType* data(const Protocol&) const + { + return 0; + } + + template <typename Protocol> + std::size_t size(const Protocol&) const + { + return 0; + } +}; + +} // namespace archetypes + +#endif // ARCHETYPES_SETTABLE_SOCKET_OPTION_HPP diff --git a/src/boost/libs/asio/test/associated_allocator.cpp b/src/boost/libs/asio/test/associated_allocator.cpp new file mode 100644 index 000000000..5a4471e13 --- /dev/null +++ b/src/boost/libs/asio/test/associated_allocator.cpp @@ -0,0 +1,25 @@ +// +// associated_allocator.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/associated_allocator.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "associated_allocator", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/associated_executor.cpp b/src/boost/libs/asio/test/associated_executor.cpp new file mode 100644 index 000000000..b26a450ed --- /dev/null +++ b/src/boost/libs/asio/test/associated_executor.cpp @@ -0,0 +1,25 @@ +// +// associated_executor.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/associated_executor.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "associated_executor", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/async_result.cpp b/src/boost/libs/asio/test/async_result.cpp new file mode 100644 index 000000000..8df819d53 --- /dev/null +++ b/src/boost/libs/asio/test/async_result.cpp @@ -0,0 +1,25 @@ +// +// async_result.cpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/async_result.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "async_result", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/awaitable.cpp b/src/boost/libs/asio/test/awaitable.cpp new file mode 100644 index 000000000..6730bce8a --- /dev/null +++ b/src/boost/libs/asio/test/awaitable.cpp @@ -0,0 +1,25 @@ +// +// awaitable.cpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/awaitable.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "awaitable", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/basic_datagram_socket.cpp b/src/boost/libs/asio/test/basic_datagram_socket.cpp new file mode 100644 index 000000000..f21788543 --- /dev/null +++ b/src/boost/libs/asio/test/basic_datagram_socket.cpp @@ -0,0 +1,25 @@ +// +// basic_datagram_socket.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/basic_datagram_socket.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "basic_datagram_socket", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/basic_deadline_timer.cpp b/src/boost/libs/asio/test/basic_deadline_timer.cpp new file mode 100644 index 000000000..ac5e43e97 --- /dev/null +++ b/src/boost/libs/asio/test/basic_deadline_timer.cpp @@ -0,0 +1,25 @@ +// +// basic_deadline_timer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/basic_deadline_timer.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "basic_deadline_timer", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/basic_raw_socket.cpp b/src/boost/libs/asio/test/basic_raw_socket.cpp new file mode 100644 index 000000000..e93d27c3d --- /dev/null +++ b/src/boost/libs/asio/test/basic_raw_socket.cpp @@ -0,0 +1,25 @@ +// +// basic_raw_socket.cpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/basic_raw_socket.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "basic_raw_socket", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/basic_seq_packet_socket.cpp b/src/boost/libs/asio/test/basic_seq_packet_socket.cpp new file mode 100644 index 000000000..27268b360 --- /dev/null +++ b/src/boost/libs/asio/test/basic_seq_packet_socket.cpp @@ -0,0 +1,25 @@ +// +// basic_seq_packet_socket.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/basic_seq_packet_socket.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "basic_seq_packet_socket", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/basic_serial_port.cpp b/src/boost/libs/asio/test/basic_serial_port.cpp new file mode 100644 index 000000000..f5055317a --- /dev/null +++ b/src/boost/libs/asio/test/basic_serial_port.cpp @@ -0,0 +1,26 @@ +// +// basic_serial_port.cpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/basic_serial_port.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "basic_serial_port", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/basic_signal_set.cpp b/src/boost/libs/asio/test/basic_signal_set.cpp new file mode 100644 index 000000000..d699b07f9 --- /dev/null +++ b/src/boost/libs/asio/test/basic_signal_set.cpp @@ -0,0 +1,25 @@ +// +// basic_signal_set.cpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/basic_signal_set.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "basic_signal_set", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/basic_socket.cpp b/src/boost/libs/asio/test/basic_socket.cpp new file mode 100644 index 000000000..9b4d13746 --- /dev/null +++ b/src/boost/libs/asio/test/basic_socket.cpp @@ -0,0 +1,25 @@ +// +// basic_socket.cpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/basic_socket.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "basic_socket", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/basic_socket_acceptor.cpp b/src/boost/libs/asio/test/basic_socket_acceptor.cpp new file mode 100644 index 000000000..aa6e4c113 --- /dev/null +++ b/src/boost/libs/asio/test/basic_socket_acceptor.cpp @@ -0,0 +1,25 @@ +// +// basic_socket_acceptor.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/basic_socket_acceptor.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "basic_socket_acceptor", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/basic_stream_socket.cpp b/src/boost/libs/asio/test/basic_stream_socket.cpp new file mode 100644 index 000000000..01195d315 --- /dev/null +++ b/src/boost/libs/asio/test/basic_stream_socket.cpp @@ -0,0 +1,25 @@ +// +// basic_stream_socket.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/basic_stream_socket.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "basic_stream_socket", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/basic_streambuf.cpp b/src/boost/libs/asio/test/basic_streambuf.cpp new file mode 100644 index 000000000..e9d6139cd --- /dev/null +++ b/src/boost/libs/asio/test/basic_streambuf.cpp @@ -0,0 +1,25 @@ +// +// basic_streambuf.cpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/basic_streambuf.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "basic_streambuf", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/basic_waitable_timer.cpp b/src/boost/libs/asio/test/basic_waitable_timer.cpp new file mode 100644 index 000000000..2321747c9 --- /dev/null +++ b/src/boost/libs/asio/test/basic_waitable_timer.cpp @@ -0,0 +1,25 @@ +// +// basic_waitable_timer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/basic_waitable_timer.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "basic_waitable_timer", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/bind_executor.cpp b/src/boost/libs/asio/test/bind_executor.cpp new file mode 100644 index 000000000..cc95310b5 --- /dev/null +++ b/src/boost/libs/asio/test/bind_executor.cpp @@ -0,0 +1,25 @@ +// +// bind_executor.cpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/bind_executor.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "bind_executor", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/buffer.cpp b/src/boost/libs/asio/test/buffer.cpp new file mode 100644 index 000000000..806856026 --- /dev/null +++ b/src/boost/libs/asio/test/buffer.cpp @@ -0,0 +1,830 @@ +// +// buffer.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/buffer.hpp> + +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) +# include <boost/array.hpp> +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) +# include <array> +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + +//------------------------------------------------------------------------------ + +// buffer_compile test +// ~~~~~~~~~~~~~~~~~~~ +// The following test checks that all overloads of the buffer function compile +// and link correctly. Runtime failures are ignored. + +namespace buffer_compile { + +using namespace boost::asio; + +void test() +{ + try + { + char raw_data[1024]; + const char const_raw_data[1024] = ""; + void* void_ptr_data = raw_data; + const void* const_void_ptr_data = const_raw_data; +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) + boost::array<char, 1024> array_data; + const boost::array<char, 1024>& const_array_data_1 = array_data; + boost::array<const char, 1024> const_array_data_2 = { { 0 } }; +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + std::array<char, 1024> std_array_data; + const std::array<char, 1024>& const_std_array_data_1 = std_array_data; + std::array<const char, 1024> const_std_array_data_2 = { { 0 } }; +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + std::vector<char> vector_data(1024); + const std::vector<char>& const_vector_data = vector_data; + std::string string_data(1024, ' '); + const std::string const_string_data(1024, ' '); + std::vector<mutable_buffer> mutable_buffer_sequence; + std::vector<const_buffer> const_buffer_sequence; +#if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + std::string_view string_view_data(string_data); +#elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + std::experimental::string_view string_view_data(string_data); +#endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + + // mutable_buffer constructors. + + mutable_buffer mb1; + mutable_buffer mb2(void_ptr_data, 1024); + mutable_buffer mb3(mb1); + (void)mb3; + + // mutable_buffer functions. + + void* ptr1 = mb1.data(); + (void)ptr1; + + std::size_t n1 = mb1.size(); + (void)n1; + + // mutable_buffer operators. + + mb1 += 128; + mb1 = mb2 + 128; + mb1 = 128 + mb2; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + + // mutable_buffers_1 constructors. + + mutable_buffers_1 mbc1(mb1); + mutable_buffers_1 mbc2(mbc1); + + // mutable_buffers_1 functions. + + mutable_buffers_1::const_iterator iter1 = mbc1.begin(); + (void)iter1; + mutable_buffers_1::const_iterator iter2 = mbc1.end(); + (void)iter2; + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + // const_buffer constructors. + + const_buffer cb1; + const_buffer cb2(const_void_ptr_data, 1024); + const_buffer cb3(cb1); + (void)cb3; + const_buffer cb4(mb1); + (void)cb4; + + // const_buffer functions. + + const void* ptr2 = cb1.data(); + (void)ptr2; + + std::size_t n2 = cb1.size(); + (void)n2; + + // const_buffer operators. + + cb1 += 128; + cb1 = cb2 + 128; + cb1 = 128 + cb2; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + + // const_buffers_1 constructors. + + const_buffers_1 cbc1(cb1); + const_buffers_1 cbc2(cbc1); + + // const_buffers_1 functions. + + const_buffers_1::const_iterator iter3 = cbc1.begin(); + (void)iter3; + const_buffers_1::const_iterator iter4 = cbc1.end(); + (void)iter4; + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + // buffer_size function overloads. + + std::size_t size1 = buffer_size(mb1); + (void)size1; + std::size_t size2 = buffer_size(cb1); + (void)size2; +#if !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size3 = buffer_size(mbc1); + (void)size3; + std::size_t size4 = buffer_size(cbc1); + (void)size4; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size5 = buffer_size(mutable_buffer_sequence); + (void)size5; + std::size_t size6 = buffer_size(const_buffer_sequence); + (void)size6; + + // buffer_cast function overloads. + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + void* ptr3 = buffer_cast<void*>(mb1); + (void)ptr3; + const void* ptr4 = buffer_cast<const void*>(cb1); + (void)ptr4; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + // buffer function overloads. + + mb1 = buffer(mb2); + mb1 = buffer(mb2, 128); + cb1 = buffer(cb2); + cb1 = buffer(cb2, 128); + mb1 = buffer(void_ptr_data, 1024); + cb1 = buffer(const_void_ptr_data, 1024); + mb1 = buffer(raw_data); + mb1 = buffer(raw_data, 1024); + cb1 = buffer(const_raw_data); + cb1 = buffer(const_raw_data, 1024); +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) + mb1 = buffer(array_data); + mb1 = buffer(array_data, 1024); + cb1 = buffer(const_array_data_1); + cb1 = buffer(const_array_data_1, 1024); + cb1 = buffer(const_array_data_2); + cb1 = buffer(const_array_data_2, 1024); +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + mb1 = buffer(std_array_data); + mb1 = buffer(std_array_data, 1024); + cb1 = buffer(const_std_array_data_1); + cb1 = buffer(const_std_array_data_1, 1024); + cb1 = buffer(const_std_array_data_2); + cb1 = buffer(const_std_array_data_2, 1024); +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + mb1 = buffer(vector_data); + mb1 = buffer(vector_data, 1024); + cb1 = buffer(const_vector_data); + cb1 = buffer(const_vector_data, 1024); + mb1 = buffer(string_data); + mb1 = buffer(string_data, 1024); + cb1 = buffer(const_string_data); + cb1 = buffer(const_string_data, 1024); +#if defined(BOOST_ASIO_HAS_STRING_VIEW) + cb1 = buffer(string_view_data); + cb1 = buffer(string_view_data, 1024); +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + + // buffer_copy function overloads. + + std::size_t size7 = buffer_copy(mb1, cb2); + (void)size7; +#if !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size8 = buffer_copy(mb1, cbc2); + (void)size8; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size9 = buffer_copy(mb1, mb2); + (void)size9; +#if !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size10 = buffer_copy(mb1, mbc2); + (void)size10; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size11 = buffer_copy(mb1, const_buffer_sequence); + (void)size11; +#if !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size12 = buffer_copy(mbc1, cb2); + (void)size12; + std::size_t size13 = buffer_copy(mbc1, cbc2); + (void)size13; + std::size_t size14 = buffer_copy(mbc1, mb2); + (void)size14; + std::size_t size15 = buffer_copy(mbc1, mbc2); + (void)size15; + std::size_t size16 = buffer_copy(mbc1, const_buffer_sequence); + (void)size16; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size17 = buffer_copy(mutable_buffer_sequence, cb2); + (void)size17; +#if !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size18 = buffer_copy(mutable_buffer_sequence, cbc2); + (void)size18; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size19 = buffer_copy(mutable_buffer_sequence, mb2); + (void)size19; +#if !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size20 = buffer_copy(mutable_buffer_sequence, mbc2); + (void)size20; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size21 = buffer_copy( + mutable_buffer_sequence, const_buffer_sequence); + (void)size21; + std::size_t size22 = buffer_copy(mb1, cb2, 128); + (void)size22; +#if !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size23 = buffer_copy(mb1, cbc2, 128); + (void)size23; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size24 = buffer_copy(mb1, mb2, 128); + (void)size24; +#if !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size25 = buffer_copy(mb1, mbc2, 128); + (void)size25; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size26 = buffer_copy(mb1, const_buffer_sequence, 128); + (void)size26; +#if !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size27 = buffer_copy(mbc1, cb2, 128); + (void)size27; + std::size_t size28 = buffer_copy(mbc1, cbc2, 128); + (void)size28; + std::size_t size29 = buffer_copy(mbc1, mb2, 128); + (void)size29; + std::size_t size30 = buffer_copy(mbc1, mbc2, 128); + (void)size30; + std::size_t size31 = buffer_copy(mbc1, const_buffer_sequence, 128); + (void)size31; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size32 = buffer_copy(mutable_buffer_sequence, cb2, 128); + (void)size32; +#if !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size33 = buffer_copy(mutable_buffer_sequence, cbc2, 128); + (void)size33; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size34 = buffer_copy(mutable_buffer_sequence, mb2, 128); + (void)size34; +#if !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size35 = buffer_copy(mutable_buffer_sequence, mbc2, 128); + (void)size35; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + std::size_t size36 = buffer_copy( + mutable_buffer_sequence, const_buffer_sequence, 128); + (void)size36; + + // dynamic_buffer function overloads. + + dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> db1 = dynamic_buffer(string_data); + (void)db1; + dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> db2 = dynamic_buffer(string_data, 1024); + (void)db2; + dynamic_vector_buffer<char, std::allocator<char> > + db3 = dynamic_buffer(vector_data); + (void)db3; + dynamic_vector_buffer<char, std::allocator<char> > + db4 = dynamic_buffer(vector_data, 1024); + (void)db4; + + // dynamic_buffer member functions. + + std::size_t size37 = db1.size(); + (void)size37; + std::size_t size38 = db3.size(); + (void)size38; + + std::size_t size39 = db1.max_size(); + (void)size39; + std::size_t size40 = db3.max_size(); + (void)size40; + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type>::const_buffers_type + cb5 = db1.data(); + (void)cb5; + dynamic_vector_buffer<char, std::allocator<char> >::const_buffers_type + cb6 = db3.data(); + (void)cb6; + + dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type>::mutable_buffers_type mb5 + = db1.prepare(1024); + (void)mb5; + dynamic_vector_buffer<char, std::allocator<char> >::mutable_buffers_type + mb6 = db3.prepare(1024); + (void)mb6; + + db1.commit(1024); + db3.commit(1024); +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + + dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type>::mutable_buffers_type + mb7 = db1.data(0, 1); + (void)mb7; + dynamic_vector_buffer<char, std::allocator<char> >::mutable_buffers_type + mb8 = db3.data(0, 1); + (void)mb8; + + dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type>::const_buffers_type + cb7 = static_cast<const dynamic_string_buffer<char, + std::string::traits_type, + std::string::allocator_type>&>(db1).data(0, 1); + (void)cb7; + dynamic_vector_buffer<char, std::allocator<char> >::const_buffers_type + cb8 = static_cast<const dynamic_vector_buffer<char, + std::allocator<char> >&>(db3).data(0, 1); + (void)cb8; + + db1.grow(1024); + db3.grow(1024); + + db1.shrink(1024); + db3.shrink(1024); + + db1.consume(0); + db3.consume(0); + } + catch (std::exception&) + { + } +} + +} // namespace buffer_compile + +//------------------------------------------------------------------------------ + +namespace buffer_copy_runtime { + +using namespace boost::asio; +using namespace std; + +void test() +{ + char dest_data[256]; + char source_data[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + memset(dest_data, 0, sizeof(dest_data)); + mutable_buffer mb1 = boost::asio::buffer(dest_data); + mutable_buffer mb2 = boost::asio::buffer(source_data); + std::size_t n = buffer_copy(mb1, mb2); + BOOST_ASIO_CHECK(n == sizeof(source_data)); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mb1 = boost::asio::buffer(dest_data); + const_buffer cb1 = boost::asio::buffer(source_data); + n = buffer_copy(mb1, cb1); + BOOST_ASIO_CHECK(n == sizeof(source_data)); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + memset(dest_data, 0, sizeof(dest_data)); + mb1 = boost::asio::buffer(dest_data); + mutable_buffers_1 mbc1 = boost::asio::buffer(source_data); + n = buffer_copy(mb1, mbc1); + BOOST_ASIO_CHECK(n == sizeof(source_data)); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mb1 = boost::asio::buffer(dest_data); + const_buffers_1 cbc1 = const_buffers_1(boost::asio::buffer(source_data)); + n = buffer_copy(mb1, cbc1); + BOOST_ASIO_CHECK(n == sizeof(source_data)); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mbc1 = boost::asio::buffer(dest_data); + mb1 = boost::asio::buffer(source_data); + n = buffer_copy(mbc1, mb1); + BOOST_ASIO_CHECK(n == sizeof(source_data)); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mbc1 = boost::asio::buffer(dest_data); + cb1 = boost::asio::buffer(source_data); + n = buffer_copy(mbc1, cb1); + BOOST_ASIO_CHECK(n == sizeof(source_data)); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mbc1 = boost::asio::buffer(dest_data); + mutable_buffers_1 mbc2 = boost::asio::buffer(source_data); + n = buffer_copy(mbc1, mbc2); + BOOST_ASIO_CHECK(n == sizeof(source_data)); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mbc1 = boost::asio::buffer(dest_data); + cbc1 = const_buffers_1(boost::asio::buffer(source_data)); + n = buffer_copy(mbc1, cbc1); + BOOST_ASIO_CHECK(n == sizeof(source_data)); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + memset(dest_data, 0, sizeof(dest_data)); + mb1 = boost::asio::buffer(dest_data); + std::vector<mutable_buffer> mv1; + mv1.push_back(boost::asio::buffer(source_data, 5)); + mv1.push_back(boost::asio::buffer(source_data) + 5); + n = buffer_copy(mb1, mv1); + BOOST_ASIO_CHECK(n == sizeof(source_data)); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mb1 = boost::asio::buffer(dest_data); + std::vector<const_buffer> cv1; + cv1.push_back(boost::asio::buffer(source_data, 6)); + cv1.push_back(boost::asio::buffer(source_data) + 6); + n = buffer_copy(mb1, cv1); + BOOST_ASIO_CHECK(n == sizeof(source_data)); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mv1.clear(); + mv1.push_back(boost::asio::buffer(dest_data, 7)); + mv1.push_back(boost::asio::buffer(dest_data) + 7); + cb1 = boost::asio::buffer(source_data); + n = buffer_copy(mv1, cb1); + BOOST_ASIO_CHECK(n == sizeof(source_data)); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mv1.clear(); + mv1.push_back(boost::asio::buffer(dest_data, 7)); + mv1.push_back(boost::asio::buffer(dest_data) + 7); + cv1.clear(); + cv1.push_back(boost::asio::buffer(source_data, 8)); + cv1.push_back(boost::asio::buffer(source_data) + 8); + n = buffer_copy(mv1, cv1); + BOOST_ASIO_CHECK(n == sizeof(source_data)); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mb1 = boost::asio::buffer(dest_data); + mb2 = boost::asio::buffer(source_data); + n = buffer_copy(mb1, mb2, 10); + BOOST_ASIO_CHECK(n == 10); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mb1 = boost::asio::buffer(dest_data); + cb1 = boost::asio::buffer(source_data); + n = buffer_copy(mb1, cb1, 10); + BOOST_ASIO_CHECK(n == 10); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + memset(dest_data, 0, sizeof(dest_data)); + mb1 = boost::asio::buffer(dest_data); + mbc1 = boost::asio::buffer(source_data); + n = buffer_copy(mb1, mbc1, 10); + BOOST_ASIO_CHECK(n == 10); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mb1 = boost::asio::buffer(dest_data); + cbc1 = const_buffers_1(boost::asio::buffer(source_data)); + n = buffer_copy(mb1, cbc1, 10); + BOOST_ASIO_CHECK(n == 10); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mbc1 = boost::asio::buffer(dest_data); + mb1 = boost::asio::buffer(source_data); + n = buffer_copy(mbc1, mb1, 10); + BOOST_ASIO_CHECK(n == 10); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mbc1 = boost::asio::buffer(dest_data); + cb1 = boost::asio::buffer(source_data); + n = buffer_copy(mbc1, cb1, 10); + BOOST_ASIO_CHECK(n == 10); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mbc1 = boost::asio::buffer(dest_data); + mbc2 = boost::asio::buffer(source_data); + n = buffer_copy(mbc1, mbc2, 10); + BOOST_ASIO_CHECK(n == 10); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mbc1 = boost::asio::buffer(dest_data); + cbc1 = const_buffers_1(boost::asio::buffer(source_data)); + n = buffer_copy(mbc1, cbc1, 10); + BOOST_ASIO_CHECK(n == 10); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + memset(dest_data, 0, sizeof(dest_data)); + mb1 = boost::asio::buffer(dest_data); + mv1.clear(); + mv1.push_back(boost::asio::buffer(source_data, 5)); + mv1.push_back(boost::asio::buffer(source_data) + 5); + n = buffer_copy(mb1, mv1, 10); + BOOST_ASIO_CHECK(n == 10); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mb1 = boost::asio::buffer(dest_data); + cv1.clear(); + cv1.push_back(boost::asio::buffer(source_data, 6)); + cv1.push_back(boost::asio::buffer(source_data) + 6); + n = buffer_copy(mb1, cv1, 10); + BOOST_ASIO_CHECK(n == 10); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mv1.clear(); + mv1.push_back(boost::asio::buffer(dest_data, 7)); + mv1.push_back(boost::asio::buffer(dest_data) + 7); + cb1 = boost::asio::buffer(source_data); + n = buffer_copy(mv1, cb1, 10); + BOOST_ASIO_CHECK(n == 10); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); + + memset(dest_data, 0, sizeof(dest_data)); + mv1.clear(); + mv1.push_back(boost::asio::buffer(dest_data, 7)); + mv1.push_back(boost::asio::buffer(dest_data) + 7); + cv1.clear(); + cv1.push_back(boost::asio::buffer(source_data, 8)); + cv1.push_back(boost::asio::buffer(source_data) + 8); + n = buffer_copy(mv1, cv1, 10); + BOOST_ASIO_CHECK(n == 10); + BOOST_ASIO_CHECK(memcmp(dest_data, source_data, n) == 0); +} + +} // namespace buffer_copy_runtime + +//------------------------------------------------------------------------------ + +namespace buffer_sequence { + +using namespace boost::asio; +using namespace std; + +struct valid_const_a +{ + typedef const_buffer* const_iterator; + typedef const_buffer value_type; + const_buffer* begin() const { return 0; } + const_buffer* end() const { return 0; } +}; + +#if defined(BOOST_ASIO_HAS_DECLTYPE) +struct valid_const_b +{ + const_buffer* begin() const { return 0; } + const_buffer* end() const { return 0; } +}; +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + +struct valid_mutable_a +{ + typedef mutable_buffer* const_iterator; + typedef mutable_buffer value_type; + mutable_buffer* begin() const { return 0; } + mutable_buffer* end() const { return 0; } +}; + +#if defined(BOOST_ASIO_HAS_DECLTYPE) +struct valid_mutable_b +{ + mutable_buffer* begin() const { return 0; } + mutable_buffer* end() const { return 0; } +}; +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + +struct invalid_const_a +{ + typedef int value_type; + int* begin() const { return 0; } + const_buffer* end() const { return 0; } +}; + +struct invalid_const_b +{ + typedef const_buffer value_type; + const_buffer* begin() const { return 0; } +}; + +struct invalid_const_c +{ + typedef const_buffer value_type; + const_buffer* end() const { return 0; } +}; + +#if defined(BOOST_ASIO_HAS_DECLTYPE) +struct invalid_const_d +{ + int* begin() const { return 0; } + const_buffer* end() const { return 0; } +}; + +struct invalid_const_e +{ + const_buffer* begin() const { return 0; } +}; + +struct invalid_const_f +{ + const_buffer* end() const { return 0; } +}; +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + +struct invalid_mutable_a +{ + typedef int value_type; + int* begin() const { return 0; } + mutable_buffer* end() const { return 0; } +}; + +struct invalid_mutable_b +{ + typedef mutable_buffer value_type; + mutable_buffer* begin() const { return 0; } +}; + +struct invalid_mutable_c +{ + typedef mutable_buffer value_type; + mutable_buffer* end() const { return 0; } +}; + +#if defined(BOOST_ASIO_HAS_DECLTYPE) +struct invalid_mutable_d +{ + int* begin() const { return 0; } + mutable_buffer* end() const { return 0; } +}; + +struct invalid_mutable_e +{ + mutable_buffer* begin() const { return 0; } +}; + +struct invalid_mutable_f +{ + mutable_buffer* end() const { return 0; } +}; +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + +void test() +{ + BOOST_ASIO_CHECK(is_const_buffer_sequence<const_buffer>::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<const_buffer>::value); + + const_buffer b1; + BOOST_ASIO_CHECK(buffer_sequence_begin(b1) == &b1); + BOOST_ASIO_CHECK(buffer_sequence_end(b1) == &b1 + 1); + + BOOST_ASIO_CHECK(is_const_buffer_sequence<mutable_buffer>::value); + BOOST_ASIO_CHECK(is_mutable_buffer_sequence<mutable_buffer>::value); + + mutable_buffer b2; + BOOST_ASIO_CHECK(buffer_sequence_begin(b2) == &b2); + BOOST_ASIO_CHECK(buffer_sequence_end(b2) == &b2 + 1); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + BOOST_ASIO_CHECK(is_const_buffer_sequence<const_buffers_1>::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<const_buffers_1>::value); + + const_buffers_1 b3(0, 0); + BOOST_ASIO_CHECK(buffer_sequence_begin(b3) == &b3); + BOOST_ASIO_CHECK(buffer_sequence_end(b3) == &b3 + 1); + + BOOST_ASIO_CHECK(is_const_buffer_sequence<mutable_buffers_1>::value); + BOOST_ASIO_CHECK(is_mutable_buffer_sequence<mutable_buffers_1>::value); + + mutable_buffers_1 b4(0, 0); + BOOST_ASIO_CHECK(buffer_sequence_begin(b4) == &b4); + BOOST_ASIO_CHECK(buffer_sequence_end(b4) == &b4 + 1); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + BOOST_ASIO_CHECK(is_const_buffer_sequence<vector<const_buffer> >::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<vector<const_buffer> >::value); + + vector<const_buffer> b5; + BOOST_ASIO_CHECK(buffer_sequence_begin(b5) == b5.begin()); + BOOST_ASIO_CHECK(buffer_sequence_end(b5) == b5.end()); + + BOOST_ASIO_CHECK(is_const_buffer_sequence<vector<mutable_buffer> >::value); + BOOST_ASIO_CHECK(is_mutable_buffer_sequence<vector<mutable_buffer> >::value); + + vector<mutable_buffer> b6; + BOOST_ASIO_CHECK(buffer_sequence_begin(b6) == b6.begin()); + BOOST_ASIO_CHECK(buffer_sequence_end(b6) == b6.end()); + + BOOST_ASIO_CHECK(is_const_buffer_sequence<valid_const_a>::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<valid_const_a>::value); + + valid_const_a b7; + BOOST_ASIO_CHECK(buffer_sequence_begin(b7) == b7.begin()); + BOOST_ASIO_CHECK(buffer_sequence_end(b7) == b7.end()); + +#if defined(BOOST_ASIO_HAS_DECLTYPE) + BOOST_ASIO_CHECK(is_const_buffer_sequence<valid_const_b>::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<valid_const_b>::value); + + valid_const_b b8; + BOOST_ASIO_CHECK(buffer_sequence_begin(b8) == b8.begin()); + BOOST_ASIO_CHECK(buffer_sequence_end(b8) == b8.end()); +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + + BOOST_ASIO_CHECK(is_const_buffer_sequence<valid_mutable_a>::value); + BOOST_ASIO_CHECK(is_mutable_buffer_sequence<valid_mutable_a>::value); + + valid_mutable_a b9; + BOOST_ASIO_CHECK(buffer_sequence_begin(b9) == b9.begin()); + BOOST_ASIO_CHECK(buffer_sequence_end(b9) == b9.end()); + +#if defined(BOOST_ASIO_HAS_DECLTYPE) + BOOST_ASIO_CHECK(is_const_buffer_sequence<valid_mutable_b>::value); + BOOST_ASIO_CHECK(is_mutable_buffer_sequence<valid_mutable_b>::value); + + valid_mutable_b b10; + BOOST_ASIO_CHECK(buffer_sequence_begin(b10) == b10.begin()); + BOOST_ASIO_CHECK(buffer_sequence_end(b10) == b10.end()); +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + + BOOST_ASIO_CHECK(!is_const_buffer_sequence<invalid_const_a>::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_const_a>::value); + + BOOST_ASIO_CHECK(!is_const_buffer_sequence<invalid_const_b>::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_const_b>::value); + + BOOST_ASIO_CHECK(!is_const_buffer_sequence<invalid_const_c>::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_const_c>::value); + +#if defined(BOOST_ASIO_HAS_DECLTYPE) + BOOST_ASIO_CHECK(!is_const_buffer_sequence<invalid_const_d>::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_const_d>::value); + + BOOST_ASIO_CHECK(!is_const_buffer_sequence<invalid_const_e>::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_const_e>::value); + + BOOST_ASIO_CHECK(!is_const_buffer_sequence<invalid_const_f>::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_const_f>::value); +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_mutable_a>::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_mutable_a>::value); + + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_mutable_b>::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_mutable_b>::value); + + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_mutable_c>::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_mutable_c>::value); + +#if defined(BOOST_ASIO_HAS_DECLTYPE) + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_mutable_d>::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_mutable_d>::value); + + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_mutable_e>::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_mutable_e>::value); + + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_mutable_f>::value); + BOOST_ASIO_CHECK(!is_mutable_buffer_sequence<invalid_mutable_f>::value); +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) +} + +} // namespace buffer_sequence + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "buffer", + BOOST_ASIO_COMPILE_TEST_CASE(buffer_compile::test) + BOOST_ASIO_TEST_CASE(buffer_copy_runtime::test) + BOOST_ASIO_TEST_CASE(buffer_sequence::test) +) diff --git a/src/boost/libs/asio/test/buffered_read_stream.cpp b/src/boost/libs/asio/test/buffered_read_stream.cpp new file mode 100644 index 000000000..0228e8caf --- /dev/null +++ b/src/boost/libs/asio/test/buffered_read_stream.cpp @@ -0,0 +1,338 @@ +// +// buffered_read_stream.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/buffered_read_stream.hpp> + +#include <cstring> +#include "archetypes/async_result.hpp" +#include <boost/asio/buffer.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/system/system_error.hpp> +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) +# include <boost/array.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_ARRAY) +# include <array> +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +typedef boost::asio::buffered_read_stream< + boost::asio::ip::tcp::socket> stream_type; + +void write_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void fill_handler(const boost::system::error_code&, std::size_t) +{ +} + +void read_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void test_compile() +{ +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) + using boost::array; +#else // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + using std::array; +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + + using namespace boost::asio; + + try + { + io_context ioc; + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + array<boost::asio::mutable_buffer, 2> mutable_buffers = {{ + boost::asio::buffer(mutable_char_buffer, 10), + boost::asio::buffer(mutable_char_buffer + 10, 10) }}; + array<boost::asio::const_buffer, 2> const_buffers = {{ + boost::asio::buffer(const_char_buffer, 10), + boost::asio::buffer(const_char_buffer + 10, 10) }}; + archetypes::lazy_handler lazy; + boost::system::error_code ec; + + stream_type stream1(ioc); + stream_type stream2(ioc, 1024); + + stream_type::executor_type ex = stream1.get_executor(); + (void)ex; + + stream_type::lowest_layer_type& lowest_layer = stream1.lowest_layer(); + (void)lowest_layer; + + stream1.write_some(buffer(mutable_char_buffer)); + stream1.write_some(buffer(const_char_buffer)); + stream1.write_some(mutable_buffers); + stream1.write_some(const_buffers); + stream1.write_some(null_buffers()); + stream1.write_some(buffer(mutable_char_buffer), ec); + stream1.write_some(buffer(const_char_buffer), ec); + stream1.write_some(mutable_buffers, ec); + stream1.write_some(const_buffers, ec); + stream1.write_some(null_buffers(), ec); + + stream1.async_write_some(buffer(mutable_char_buffer), &write_some_handler); + stream1.async_write_some(buffer(const_char_buffer), &write_some_handler); + stream1.async_write_some(mutable_buffers, &write_some_handler); + stream1.async_write_some(const_buffers, &write_some_handler); + stream1.async_write_some(null_buffers(), &write_some_handler); + int i1 = stream1.async_write_some(buffer(mutable_char_buffer), lazy); + (void)i1; + int i2 = stream1.async_write_some(buffer(const_char_buffer), lazy); + (void)i2; + int i3 = stream1.async_write_some(mutable_buffers, lazy); + (void)i3; + int i4 = stream1.async_write_some(const_buffers, lazy); + (void)i4; + int i5 = stream1.async_write_some(null_buffers(), lazy); + (void)i5; + + stream1.fill(); + stream1.fill(ec); + + stream1.async_fill(&fill_handler); + int i6 = stream1.async_fill(lazy); + (void)i6; + + stream1.read_some(buffer(mutable_char_buffer)); + stream1.read_some(mutable_buffers); + stream1.read_some(null_buffers()); + stream1.read_some(buffer(mutable_char_buffer), ec); + stream1.read_some(mutable_buffers, ec); + stream1.read_some(null_buffers(), ec); + + stream1.async_read_some(buffer(mutable_char_buffer), &read_some_handler); + stream1.async_read_some(mutable_buffers, &read_some_handler); + stream1.async_read_some(null_buffers(), &read_some_handler); + int i7 = stream1.async_read_some(buffer(mutable_char_buffer), lazy); + (void)i7; + int i8 = stream1.async_read_some(mutable_buffers, lazy); + (void)i8; + int i9 = stream1.async_read_some(null_buffers(), lazy); + (void)i9; + } + catch (std::exception&) + { + } +} + +void test_sync_operations() +{ + using namespace std; // For memcmp. + + boost::asio::io_context io_context; + + boost::asio::ip::tcp::acceptor acceptor(io_context, + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 0)); + boost::asio::ip::tcp::endpoint server_endpoint = acceptor.local_endpoint(); + server_endpoint.address(boost::asio::ip::address_v4::loopback()); + + stream_type client_socket(io_context); + client_socket.lowest_layer().connect(server_endpoint); + + stream_type server_socket(io_context); + acceptor.accept(server_socket.lowest_layer()); + + const char write_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + const boost::asio::const_buffer write_buf = boost::asio::buffer(write_data); + + std::size_t bytes_written = 0; + while (bytes_written < sizeof(write_data)) + { + bytes_written += client_socket.write_some( + boost::asio::buffer(write_buf + bytes_written)); + } + + char read_data[sizeof(write_data)]; + const boost::asio::mutable_buffer read_buf = boost::asio::buffer(read_data); + + std::size_t bytes_read = 0; + while (bytes_read < sizeof(read_data)) + { + bytes_read += server_socket.read_some( + boost::asio::buffer(read_buf + bytes_read)); + } + + BOOST_ASIO_CHECK(bytes_written == sizeof(write_data)); + BOOST_ASIO_CHECK(bytes_read == sizeof(read_data)); + BOOST_ASIO_CHECK(memcmp(write_data, read_data, sizeof(write_data)) == 0); + + bytes_written = 0; + while (bytes_written < sizeof(write_data)) + { + bytes_written += server_socket.write_some( + boost::asio::buffer(write_buf + bytes_written)); + } + + bytes_read = 0; + while (bytes_read < sizeof(read_data)) + { + bytes_read += client_socket.read_some( + boost::asio::buffer(read_buf + bytes_read)); + } + + BOOST_ASIO_CHECK(bytes_written == sizeof(write_data)); + BOOST_ASIO_CHECK(bytes_read == sizeof(read_data)); + BOOST_ASIO_CHECK(memcmp(write_data, read_data, sizeof(write_data)) == 0); + + server_socket.close(); + boost::system::error_code error; + bytes_read = client_socket.read_some( + boost::asio::buffer(read_buf), error); + + BOOST_ASIO_CHECK(bytes_read == 0); + BOOST_ASIO_CHECK(error == boost::asio::error::eof); + + client_socket.close(error); +} + +void handle_accept(const boost::system::error_code& e) +{ + BOOST_ASIO_CHECK(!e); +} + +void handle_write(const boost::system::error_code& e, + std::size_t bytes_transferred, + std::size_t* total_bytes_written) +{ + BOOST_ASIO_CHECK(!e); + if (e) + throw boost::system::system_error(e); // Terminate test. + *total_bytes_written += bytes_transferred; +} + +void handle_read(const boost::system::error_code& e, + std::size_t bytes_transferred, + std::size_t* total_bytes_read) +{ + BOOST_ASIO_CHECK(!e); + if (e) + throw boost::system::system_error(e); // Terminate test. + *total_bytes_read += bytes_transferred; +} + +void handle_read_eof(const boost::system::error_code& e, + std::size_t bytes_transferred) +{ + BOOST_ASIO_CHECK(e == boost::asio::error::eof); + BOOST_ASIO_CHECK(bytes_transferred == 0); +} + +void test_async_operations() +{ + using namespace std; // For memcmp. + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context io_context; + + boost::asio::ip::tcp::acceptor acceptor(io_context, + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 0)); + boost::asio::ip::tcp::endpoint server_endpoint = acceptor.local_endpoint(); + server_endpoint.address(boost::asio::ip::address_v4::loopback()); + + stream_type client_socket(io_context); + client_socket.lowest_layer().connect(server_endpoint); + + stream_type server_socket(io_context); + acceptor.async_accept(server_socket.lowest_layer(), &handle_accept); + io_context.run(); + io_context.restart(); + + const char write_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + const boost::asio::const_buffer write_buf = boost::asio::buffer(write_data); + + std::size_t bytes_written = 0; + while (bytes_written < sizeof(write_data)) + { + client_socket.async_write_some( + boost::asio::buffer(write_buf + bytes_written), + bindns::bind(handle_write, _1, _2, &bytes_written)); + io_context.run(); + io_context.restart(); + } + + char read_data[sizeof(write_data)]; + const boost::asio::mutable_buffer read_buf = boost::asio::buffer(read_data); + + std::size_t bytes_read = 0; + while (bytes_read < sizeof(read_data)) + { + server_socket.async_read_some( + boost::asio::buffer(read_buf + bytes_read), + bindns::bind(handle_read, _1, _2, &bytes_read)); + io_context.run(); + io_context.restart(); + } + + BOOST_ASIO_CHECK(bytes_written == sizeof(write_data)); + BOOST_ASIO_CHECK(bytes_read == sizeof(read_data)); + BOOST_ASIO_CHECK(memcmp(write_data, read_data, sizeof(write_data)) == 0); + + bytes_written = 0; + while (bytes_written < sizeof(write_data)) + { + server_socket.async_write_some( + boost::asio::buffer(write_buf + bytes_written), + bindns::bind(handle_write, _1, _2, &bytes_written)); + io_context.run(); + io_context.restart(); + } + + bytes_read = 0; + while (bytes_read < sizeof(read_data)) + { + client_socket.async_read_some( + boost::asio::buffer(read_buf + bytes_read), + bindns::bind(handle_read, _1, _2, &bytes_read)); + io_context.run(); + io_context.restart(); + } + + BOOST_ASIO_CHECK(bytes_written == sizeof(write_data)); + BOOST_ASIO_CHECK(bytes_read == sizeof(read_data)); + BOOST_ASIO_CHECK(memcmp(write_data, read_data, sizeof(write_data)) == 0); + + server_socket.close(); + client_socket.async_read_some(boost::asio::buffer(read_buf), handle_read_eof); +} + +BOOST_ASIO_TEST_SUITE +( + "buffered_read_stream", + BOOST_ASIO_TEST_CASE(test_compile) + BOOST_ASIO_TEST_CASE(test_sync_operations) + BOOST_ASIO_TEST_CASE(test_async_operations) +) diff --git a/src/boost/libs/asio/test/buffered_stream.cpp b/src/boost/libs/asio/test/buffered_stream.cpp new file mode 100644 index 000000000..155c0bc5b --- /dev/null +++ b/src/boost/libs/asio/test/buffered_stream.cpp @@ -0,0 +1,364 @@ +// +// buffered_stream.cpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/buffered_stream.hpp> + +#include <cstring> +#include "archetypes/async_result.hpp" +#include <boost/asio/buffer.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/system/system_error.hpp> +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) +# include <boost/array.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_ARRAY) +# include <array> +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +typedef boost::asio::buffered_stream< + boost::asio::ip::tcp::socket> stream_type; + +void write_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void flush_handler(const boost::system::error_code&, std::size_t) +{ +} + +void fill_handler(const boost::system::error_code&, std::size_t) +{ +} + +void read_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void test_compile() +{ +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) + using boost::array; +#else // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + using std::array; +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + + using namespace boost::asio; + + try + { + io_context ioc; + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + array<boost::asio::mutable_buffer, 2> mutable_buffers = {{ + boost::asio::buffer(mutable_char_buffer, 10), + boost::asio::buffer(mutable_char_buffer + 10, 10) }}; + array<boost::asio::const_buffer, 2> const_buffers = {{ + boost::asio::buffer(const_char_buffer, 10), + boost::asio::buffer(const_char_buffer + 10, 10) }}; + archetypes::lazy_handler lazy; + boost::system::error_code ec; + + stream_type stream1(ioc); + stream_type stream2(ioc, 1024, 1024); + + stream_type::executor_type ex = stream1.get_executor(); + (void)ex; + + stream_type::lowest_layer_type& lowest_layer = stream1.lowest_layer(); + (void)lowest_layer; + + stream1.write_some(buffer(mutable_char_buffer)); + stream1.write_some(buffer(const_char_buffer)); + stream1.write_some(mutable_buffers); + stream1.write_some(const_buffers); + stream1.write_some(null_buffers()); + stream1.write_some(buffer(mutable_char_buffer), ec); + stream1.write_some(buffer(const_char_buffer), ec); + stream1.write_some(mutable_buffers, ec); + stream1.write_some(const_buffers, ec); + stream1.write_some(null_buffers(), ec); + + stream1.async_write_some(buffer(mutable_char_buffer), &write_some_handler); + stream1.async_write_some(buffer(const_char_buffer), &write_some_handler); + stream1.async_write_some(mutable_buffers, &write_some_handler); + stream1.async_write_some(const_buffers, &write_some_handler); + stream1.async_write_some(null_buffers(), &write_some_handler); + int i1 = stream1.async_write_some(buffer(mutable_char_buffer), lazy); + (void)i1; + int i2 = stream1.async_write_some(buffer(const_char_buffer), lazy); + (void)i2; + int i3 = stream1.async_write_some(mutable_buffers, lazy); + (void)i3; + int i4 = stream1.async_write_some(const_buffers, lazy); + (void)i4; + int i5 = stream1.async_write_some(null_buffers(), lazy); + (void)i5; + + stream1.flush(); + stream1.flush(ec); + + stream1.async_flush(&flush_handler); + int i6 = stream1.async_flush(lazy); + (void)i6; + + stream1.fill(); + stream1.fill(ec); + + stream1.async_fill(&fill_handler); + int i7 = stream1.async_fill(lazy); + (void)i7; + + stream1.read_some(buffer(mutable_char_buffer)); + stream1.read_some(mutable_buffers); + stream1.read_some(null_buffers()); + stream1.read_some(buffer(mutable_char_buffer), ec); + stream1.read_some(mutable_buffers, ec); + stream1.read_some(null_buffers(), ec); + + stream1.async_read_some(buffer(mutable_char_buffer), &read_some_handler); + stream1.async_read_some(mutable_buffers, &read_some_handler); + stream1.async_read_some(null_buffers(), &read_some_handler); + int i8 = stream1.async_read_some(buffer(mutable_char_buffer), lazy); + (void)i8; + int i9 = stream1.async_read_some(mutable_buffers, lazy); + (void)i9; + int i10 = stream1.async_read_some(null_buffers(), lazy); + (void)i10; + } + catch (std::exception&) + { + } +} + +void test_sync_operations() +{ + using namespace std; // For memcmp. + + boost::asio::io_context io_context; + + boost::asio::ip::tcp::acceptor acceptor(io_context, + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 0)); + boost::asio::ip::tcp::endpoint server_endpoint = acceptor.local_endpoint(); + server_endpoint.address(boost::asio::ip::address_v4::loopback()); + + stream_type client_socket(io_context); + client_socket.lowest_layer().connect(server_endpoint); + + stream_type server_socket(io_context); + acceptor.accept(server_socket.lowest_layer()); + + const char write_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + const boost::asio::const_buffer write_buf = boost::asio::buffer(write_data); + + std::size_t bytes_written = 0; + while (bytes_written < sizeof(write_data)) + { + bytes_written += client_socket.write_some( + boost::asio::buffer(write_buf + bytes_written)); + client_socket.flush(); + } + + char read_data[sizeof(write_data)]; + const boost::asio::mutable_buffer read_buf = boost::asio::buffer(read_data); + + std::size_t bytes_read = 0; + while (bytes_read < sizeof(read_data)) + { + bytes_read += server_socket.read_some( + boost::asio::buffer(read_buf + bytes_read)); + } + + BOOST_ASIO_CHECK(bytes_written == sizeof(write_data)); + BOOST_ASIO_CHECK(bytes_read == sizeof(read_data)); + BOOST_ASIO_CHECK(memcmp(write_data, read_data, sizeof(write_data)) == 0); + + bytes_written = 0; + while (bytes_written < sizeof(write_data)) + { + bytes_written += server_socket.write_some( + boost::asio::buffer(write_buf + bytes_written)); + server_socket.flush(); + } + + bytes_read = 0; + while (bytes_read < sizeof(read_data)) + { + bytes_read += client_socket.read_some( + boost::asio::buffer(read_buf + bytes_read)); + } + + BOOST_ASIO_CHECK(bytes_written == sizeof(write_data)); + BOOST_ASIO_CHECK(bytes_read == sizeof(read_data)); + BOOST_ASIO_CHECK(memcmp(write_data, read_data, sizeof(write_data)) == 0); + + server_socket.close(); + boost::system::error_code error; + bytes_read = client_socket.read_some( + boost::asio::buffer(read_buf), error); + + BOOST_ASIO_CHECK(bytes_read == 0); + BOOST_ASIO_CHECK(error == boost::asio::error::eof); + + client_socket.close(error); +} + +void handle_accept(const boost::system::error_code& e) +{ + BOOST_ASIO_CHECK(!e); +} + +void handle_write(const boost::system::error_code& e, + std::size_t bytes_transferred, + std::size_t* total_bytes_written) +{ + BOOST_ASIO_CHECK(!e); + if (e) + throw boost::system::system_error(e); // Terminate test. + *total_bytes_written += bytes_transferred; +} + +void handle_flush(const boost::system::error_code& e) +{ + BOOST_ASIO_CHECK(!e); +} + +void handle_read(const boost::system::error_code& e, + std::size_t bytes_transferred, + std::size_t* total_bytes_read) +{ + BOOST_ASIO_CHECK(!e); + if (e) + throw boost::system::system_error(e); // Terminate test. + *total_bytes_read += bytes_transferred; +} + +void handle_read_eof(const boost::system::error_code& e, + std::size_t bytes_transferred) +{ + BOOST_ASIO_CHECK(e == boost::asio::error::eof); + BOOST_ASIO_CHECK(bytes_transferred == 0); +} + +void test_async_operations() +{ + using namespace std; // For memcmp. + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context io_context; + + boost::asio::ip::tcp::acceptor acceptor(io_context, + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 0)); + boost::asio::ip::tcp::endpoint server_endpoint = acceptor.local_endpoint(); + server_endpoint.address(boost::asio::ip::address_v4::loopback()); + + stream_type client_socket(io_context); + client_socket.lowest_layer().connect(server_endpoint); + + stream_type server_socket(io_context); + acceptor.async_accept(server_socket.lowest_layer(), &handle_accept); + io_context.run(); + io_context.restart(); + + const char write_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + const boost::asio::const_buffer write_buf = boost::asio::buffer(write_data); + + std::size_t bytes_written = 0; + while (bytes_written < sizeof(write_data)) + { + client_socket.async_write_some( + boost::asio::buffer(write_buf + bytes_written), + bindns::bind(handle_write, _1, _2, &bytes_written)); + io_context.run(); + io_context.restart(); + client_socket.async_flush( + bindns::bind(handle_flush, _1)); + io_context.run(); + io_context.restart(); + } + + char read_data[sizeof(write_data)]; + const boost::asio::mutable_buffer read_buf = boost::asio::buffer(read_data); + + std::size_t bytes_read = 0; + while (bytes_read < sizeof(read_data)) + { + server_socket.async_read_some( + boost::asio::buffer(read_buf + bytes_read), + bindns::bind(handle_read, _1, _2, &bytes_read)); + io_context.run(); + io_context.restart(); + } + + BOOST_ASIO_CHECK(bytes_written == sizeof(write_data)); + BOOST_ASIO_CHECK(bytes_read == sizeof(read_data)); + BOOST_ASIO_CHECK(memcmp(write_data, read_data, sizeof(write_data)) == 0); + + bytes_written = 0; + while (bytes_written < sizeof(write_data)) + { + server_socket.async_write_some( + boost::asio::buffer(write_buf + bytes_written), + bindns::bind(handle_write, _1, _2, &bytes_written)); + io_context.run(); + io_context.restart(); + server_socket.async_flush( + bindns::bind(handle_flush, _1)); + io_context.run(); + io_context.restart(); + } + + bytes_read = 0; + while (bytes_read < sizeof(read_data)) + { + client_socket.async_read_some( + boost::asio::buffer(read_buf + bytes_read), + bindns::bind(handle_read, _1, _2, &bytes_read)); + io_context.run(); + io_context.restart(); + } + + BOOST_ASIO_CHECK(bytes_written == sizeof(write_data)); + BOOST_ASIO_CHECK(bytes_read == sizeof(read_data)); + BOOST_ASIO_CHECK(memcmp(write_data, read_data, sizeof(write_data)) == 0); + + server_socket.close(); + client_socket.async_read_some(boost::asio::buffer(read_buf), handle_read_eof); +} + +BOOST_ASIO_TEST_SUITE +( + "buffered_stream", + BOOST_ASIO_TEST_CASE(test_compile) + BOOST_ASIO_TEST_CASE(test_sync_operations) + BOOST_ASIO_TEST_CASE(test_async_operations) +) diff --git a/src/boost/libs/asio/test/buffered_write_stream.cpp b/src/boost/libs/asio/test/buffered_write_stream.cpp new file mode 100644 index 000000000..98e50e43a --- /dev/null +++ b/src/boost/libs/asio/test/buffered_write_stream.cpp @@ -0,0 +1,353 @@ +// +// buffered_write_stream.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/buffered_write_stream.hpp> + +#include <cstring> +#include "archetypes/async_result.hpp" +#include <boost/asio/buffer.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/system/system_error.hpp> +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) +# include <boost/array.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_ARRAY) +# include <array> +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +typedef boost::asio::buffered_write_stream< + boost::asio::ip::tcp::socket> stream_type; + +void write_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void flush_handler(const boost::system::error_code&, std::size_t) +{ +} + +void read_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void test_compile() +{ +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) + using boost::array; +#else // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + using std::array; +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + + using namespace boost::asio; + + try + { + io_context ioc; + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + array<boost::asio::mutable_buffer, 2> mutable_buffers = {{ + boost::asio::buffer(mutable_char_buffer, 10), + boost::asio::buffer(mutable_char_buffer + 10, 10) }}; + array<boost::asio::const_buffer, 2> const_buffers = {{ + boost::asio::buffer(const_char_buffer, 10), + boost::asio::buffer(const_char_buffer + 10, 10) }}; + archetypes::lazy_handler lazy; + boost::system::error_code ec; + + stream_type stream1(ioc); + stream_type stream2(ioc, 1024); + + stream_type::executor_type ex = stream1.get_executor(); + (void)ex; + + stream_type::lowest_layer_type& lowest_layer = stream1.lowest_layer(); + (void)lowest_layer; + + stream1.write_some(buffer(mutable_char_buffer)); + stream1.write_some(buffer(const_char_buffer)); + stream1.write_some(mutable_buffers); + stream1.write_some(const_buffers); + stream1.write_some(null_buffers()); + stream1.write_some(buffer(mutable_char_buffer), ec); + stream1.write_some(buffer(const_char_buffer), ec); + stream1.write_some(mutable_buffers, ec); + stream1.write_some(const_buffers, ec); + stream1.write_some(null_buffers(), ec); + + stream1.async_write_some(buffer(mutable_char_buffer), &write_some_handler); + stream1.async_write_some(buffer(const_char_buffer), &write_some_handler); + stream1.async_write_some(mutable_buffers, &write_some_handler); + stream1.async_write_some(const_buffers, &write_some_handler); + stream1.async_write_some(null_buffers(), &write_some_handler); + int i1 = stream1.async_write_some(buffer(mutable_char_buffer), lazy); + (void)i1; + int i2 = stream1.async_write_some(buffer(const_char_buffer), lazy); + (void)i2; + int i3 = stream1.async_write_some(mutable_buffers, lazy); + (void)i3; + int i4 = stream1.async_write_some(const_buffers, lazy); + (void)i4; + int i5 = stream1.async_write_some(null_buffers(), lazy); + (void)i5; + + stream1.flush(); + stream1.flush(ec); + + stream1.async_flush(&flush_handler); + int i6 = stream1.async_flush(lazy); + (void)i6; + + stream1.read_some(buffer(mutable_char_buffer)); + stream1.read_some(mutable_buffers); + stream1.read_some(null_buffers()); + stream1.read_some(buffer(mutable_char_buffer), ec); + stream1.read_some(mutable_buffers, ec); + stream1.read_some(null_buffers(), ec); + + stream1.async_read_some(buffer(mutable_char_buffer), &read_some_handler); + stream1.async_read_some(mutable_buffers, &read_some_handler); + stream1.async_read_some(null_buffers(), &read_some_handler); + int i7 = stream1.async_read_some(buffer(mutable_char_buffer), lazy); + (void)i7; + int i8 = stream1.async_read_some(mutable_buffers, lazy); + (void)i8; + int i9 = stream1.async_read_some(null_buffers(), lazy); + (void)i9; + } + catch (std::exception&) + { + } +} + +void test_sync_operations() +{ + using namespace std; // For memcmp. + + boost::asio::io_context io_context; + + boost::asio::ip::tcp::acceptor acceptor(io_context, + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 0)); + boost::asio::ip::tcp::endpoint server_endpoint = acceptor.local_endpoint(); + server_endpoint.address(boost::asio::ip::address_v4::loopback()); + + stream_type client_socket(io_context); + client_socket.lowest_layer().connect(server_endpoint); + + stream_type server_socket(io_context); + acceptor.accept(server_socket.lowest_layer()); + + const char write_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + const boost::asio::const_buffer write_buf = boost::asio::buffer(write_data); + + std::size_t bytes_written = 0; + while (bytes_written < sizeof(write_data)) + { + bytes_written += client_socket.write_some( + boost::asio::buffer(write_buf + bytes_written)); + client_socket.flush(); + } + + char read_data[sizeof(write_data)]; + const boost::asio::mutable_buffer read_buf = boost::asio::buffer(read_data); + + std::size_t bytes_read = 0; + while (bytes_read < sizeof(read_data)) + { + bytes_read += server_socket.read_some( + boost::asio::buffer(read_buf + bytes_read)); + } + + BOOST_ASIO_CHECK(bytes_written == sizeof(write_data)); + BOOST_ASIO_CHECK(bytes_read == sizeof(read_data)); + BOOST_ASIO_CHECK(memcmp(write_data, read_data, sizeof(write_data)) == 0); + + bytes_written = 0; + while (bytes_written < sizeof(write_data)) + { + bytes_written += server_socket.write_some( + boost::asio::buffer(write_buf + bytes_written)); + server_socket.flush(); + } + + bytes_read = 0; + while (bytes_read < sizeof(read_data)) + { + bytes_read += client_socket.read_some( + boost::asio::buffer(read_buf + bytes_read)); + } + + BOOST_ASIO_CHECK(bytes_written == sizeof(write_data)); + BOOST_ASIO_CHECK(bytes_read == sizeof(read_data)); + BOOST_ASIO_CHECK(memcmp(write_data, read_data, sizeof(write_data)) == 0); + + server_socket.close(); + boost::system::error_code error; + bytes_read = client_socket.read_some( + boost::asio::buffer(read_buf), error); + + BOOST_ASIO_CHECK(bytes_read == 0); + BOOST_ASIO_CHECK(error == boost::asio::error::eof); + + client_socket.close(error); +} + +void handle_accept(const boost::system::error_code& e) +{ + BOOST_ASIO_CHECK(!e); +} + +void handle_write(const boost::system::error_code& e, + std::size_t bytes_transferred, + std::size_t* total_bytes_written) +{ + BOOST_ASIO_CHECK(!e); + if (e) + throw boost::system::system_error(e); // Terminate test. + *total_bytes_written += bytes_transferred; +} + +void handle_flush(const boost::system::error_code& e) +{ + BOOST_ASIO_CHECK(!e); +} + +void handle_read(const boost::system::error_code& e, + std::size_t bytes_transferred, + std::size_t* total_bytes_read) +{ + BOOST_ASIO_CHECK(!e); + if (e) + throw boost::system::system_error(e); // Terminate test. + *total_bytes_read += bytes_transferred; +} + +void handle_read_eof(const boost::system::error_code& e, + std::size_t bytes_transferred) +{ + BOOST_ASIO_CHECK(e == boost::asio::error::eof); + BOOST_ASIO_CHECK(bytes_transferred == 0); +} + +void test_async_operations() +{ + using namespace std; // For memcmp. + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context io_context; + + boost::asio::ip::tcp::acceptor acceptor(io_context, + boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 0)); + boost::asio::ip::tcp::endpoint server_endpoint = acceptor.local_endpoint(); + server_endpoint.address(boost::asio::ip::address_v4::loopback()); + + stream_type client_socket(io_context); + client_socket.lowest_layer().connect(server_endpoint); + + stream_type server_socket(io_context); + acceptor.async_accept(server_socket.lowest_layer(), &handle_accept); + io_context.run(); + io_context.restart(); + + const char write_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + const boost::asio::const_buffer write_buf = boost::asio::buffer(write_data); + + std::size_t bytes_written = 0; + while (bytes_written < sizeof(write_data)) + { + client_socket.async_write_some( + boost::asio::buffer(write_buf + bytes_written), + bindns::bind(handle_write, _1, _2, &bytes_written)); + io_context.run(); + io_context.restart(); + client_socket.async_flush( + bindns::bind(handle_flush, _1)); + io_context.run(); + io_context.restart(); + } + + char read_data[sizeof(write_data)]; + const boost::asio::mutable_buffer read_buf = boost::asio::buffer(read_data); + + std::size_t bytes_read = 0; + while (bytes_read < sizeof(read_data)) + { + server_socket.async_read_some( + boost::asio::buffer(read_buf + bytes_read), + bindns::bind(handle_read, _1, _2, &bytes_read)); + io_context.run(); + io_context.restart(); + } + + BOOST_ASIO_CHECK(bytes_written == sizeof(write_data)); + BOOST_ASIO_CHECK(bytes_read == sizeof(read_data)); + BOOST_ASIO_CHECK(memcmp(write_data, read_data, sizeof(write_data)) == 0); + + bytes_written = 0; + while (bytes_written < sizeof(write_data)) + { + server_socket.async_write_some( + boost::asio::buffer(write_buf + bytes_written), + bindns::bind(handle_write, _1, _2, &bytes_written)); + io_context.run(); + io_context.restart(); + server_socket.async_flush( + bindns::bind(handle_flush, _1)); + io_context.run(); + io_context.restart(); + } + + bytes_read = 0; + while (bytes_read < sizeof(read_data)) + { + client_socket.async_read_some( + boost::asio::buffer(read_buf + bytes_read), + bindns::bind(handle_read, _1, _2, &bytes_read)); + io_context.run(); + io_context.restart(); + } + + BOOST_ASIO_CHECK(bytes_written == sizeof(write_data)); + BOOST_ASIO_CHECK(bytes_read == sizeof(read_data)); + BOOST_ASIO_CHECK(memcmp(write_data, read_data, sizeof(write_data)) == 0); + + server_socket.close(); + client_socket.async_read_some(boost::asio::buffer(read_buf), handle_read_eof); +} + +BOOST_ASIO_TEST_SUITE +( + "buffered_write_stream", + BOOST_ASIO_TEST_CASE(test_compile) + BOOST_ASIO_TEST_CASE(test_sync_operations) + BOOST_ASIO_TEST_CASE(test_async_operations) +) diff --git a/src/boost/libs/asio/test/buffers_iterator.cpp b/src/boost/libs/asio/test/buffers_iterator.cpp new file mode 100644 index 000000000..caedeae71 --- /dev/null +++ b/src/boost/libs/asio/test/buffers_iterator.cpp @@ -0,0 +1,292 @@ +// +// buffers_iterator.cpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/buffers_iterator.hpp> + +#include <boost/asio/buffer.hpp> +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) +# include <boost/array.hpp> +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) +# include <array> +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + +//------------------------------------------------------------------------------ + +// buffers_iterator_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all operations on the buffers_iterator compile +// and link correctly. Runtime failures are ignored. + +namespace buffers_iterator_compile { + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) +using boost::array; +#elif defined(BOOST_ASIO_HAS_STD_ARRAY) +using std::array; +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) +using std::vector; +using namespace boost::asio; + +void test() +{ + try + { + char data1[16], data2[16]; + const char cdata1[16] = "", cdata2[16] = ""; + mutable_buffer mb1 = buffer(data1); + array<mutable_buffer, 2> mb2 = {{ buffer(data1), buffer(data2) }}; + std::vector<mutable_buffer> mb3; + mb3.push_back(buffer(data1)); + const_buffer cb1 = buffer(cdata1); + array<const_buffer, 2> cb2 = {{ buffer(cdata1), buffer(cdata2) }}; + vector<const_buffer> cb3; + cb3.push_back(buffer(cdata1)); + + + // buffers_iterator constructors. + + buffers_iterator<mutable_buffer, char> bi1; + buffers_iterator<mutable_buffer, const char> bi2; + buffers_iterator<array<mutable_buffer, 2>, char> bi3; + buffers_iterator<array<mutable_buffer, 2>, const char> bi4; + buffers_iterator<vector<mutable_buffer>, char> bi5; + buffers_iterator<vector<mutable_buffer>, const char> bi6; + buffers_iterator<const_buffer, char> bi7; + buffers_iterator<const_buffer, const char> bi8; + buffers_iterator<array<const_buffer, 2>, char> bi9; + buffers_iterator<array<const_buffer, 2>, const char> bi10; + buffers_iterator<vector<const_buffer>, char> bi11; + buffers_iterator<vector<const_buffer>, const char> bi12; + + buffers_iterator<mutable_buffer, char> bi13( + buffers_iterator<mutable_buffer, char>::begin(mb1)); + buffers_iterator<mutable_buffer, const char> bi14( + buffers_iterator<mutable_buffer, const char>::begin(mb1)); + buffers_iterator<array<mutable_buffer, 2>, char> bi15( + buffers_iterator<array<mutable_buffer, 2>, char>::begin(mb2)); + buffers_iterator<array<mutable_buffer, 2>, const char> bi16( + buffers_iterator<array<mutable_buffer, 2>, const char>::begin(mb2)); + buffers_iterator<vector<mutable_buffer>, char> bi17( + buffers_iterator<vector<mutable_buffer>, char>::begin(mb3)); + buffers_iterator<vector<mutable_buffer>, const char> bi18( + buffers_iterator<vector<mutable_buffer>, const char>::begin(mb3)); + buffers_iterator<const_buffer, char> bi19( + buffers_iterator<const_buffer, char>::begin(cb1)); + buffers_iterator<const_buffer, const char> bi20( + buffers_iterator<const_buffer, const char>::begin(cb1)); + buffers_iterator<array<const_buffer, 2>, char> bi21( + buffers_iterator<array<const_buffer, 2>, char>::begin(cb2)); + buffers_iterator<array<const_buffer, 2>, const char> bi22( + buffers_iterator<array<const_buffer, 2>, const char>::begin(cb2)); + buffers_iterator<vector<const_buffer>, char> bi23( + buffers_iterator<vector<const_buffer>, char>::begin(cb3)); + buffers_iterator<vector<const_buffer>, const char> bi24( + buffers_iterator<vector<const_buffer>, const char>::begin(cb3)); + + // buffers_iterator member functions. + + bi1 = buffers_iterator<mutable_buffer, char>::begin(mb1); + bi2 = buffers_iterator<mutable_buffer, const char>::begin(mb1); + bi3 = buffers_iterator<array<mutable_buffer, 2>, char>::begin(mb2); + bi4 = buffers_iterator<array<mutable_buffer, 2>, const char>::begin(mb2); + bi5 = buffers_iterator<vector<mutable_buffer>, char>::begin(mb3); + bi6 = buffers_iterator<vector<mutable_buffer>, const char>::begin(mb3); + bi7 = buffers_iterator<const_buffer, char>::begin(cb1); + bi8 = buffers_iterator<const_buffer, const char>::begin(cb1); + bi9 = buffers_iterator<array<const_buffer, 2>, char>::begin(cb2); + bi10 = buffers_iterator<array<const_buffer, 2>, const char>::begin(cb2); + bi11 = buffers_iterator<vector<const_buffer>, char>::begin(cb3); + bi12 = buffers_iterator<vector<const_buffer>, const char>::begin(cb3); + + bi1 = buffers_iterator<mutable_buffer, char>::end(mb1); + bi2 = buffers_iterator<mutable_buffer, const char>::end(mb1); + bi3 = buffers_iterator<array<mutable_buffer, 2>, char>::end(mb2); + bi4 = buffers_iterator<array<mutable_buffer, 2>, const char>::end(mb2); + bi5 = buffers_iterator<vector<mutable_buffer>, char>::end(mb3); + bi6 = buffers_iterator<vector<mutable_buffer>, const char>::end(mb3); + bi7 = buffers_iterator<const_buffer, char>::end(cb1); + bi8 = buffers_iterator<const_buffer, const char>::end(cb1); + bi9 = buffers_iterator<array<const_buffer, 2>, char>::end(cb2); + bi10 = buffers_iterator<array<const_buffer, 2>, const char>::end(cb2); + bi11 = buffers_iterator<vector<const_buffer>, char>::end(cb3); + bi12 = buffers_iterator<vector<const_buffer>, const char>::end(cb3); + + // buffers_iterator related functions. + + bi1 = buffers_begin(mb1); + bi3 = buffers_begin(mb2); + bi5 = buffers_begin(mb3); + bi7 = buffers_begin(cb1); + bi9 = buffers_begin(cb2); + bi11 = buffers_begin(cb3); + + bi1 = buffers_end(mb1); + bi3 = buffers_end(mb2); + bi5 = buffers_end(mb3); + bi7 = buffers_end(cb1); + bi9 = buffers_end(cb2); + bi11 = buffers_end(cb3); + + // RandomAccessIterator operations. + + --bi1; + --bi2; + --bi3; + --bi4; + --bi5; + --bi6; + --bi7; + --bi8; + --bi9; + --bi10; + --bi11; + --bi12; + + ++bi1; + ++bi2; + ++bi3; + ++bi4; + ++bi5; + ++bi6; + ++bi7; + ++bi8; + ++bi9; + ++bi10; + ++bi11; + ++bi12; + + bi1--; + bi2--; + bi3--; + bi4--; + bi5--; + bi6--; + bi7--; + bi8--; + bi9--; + bi10--; + bi11--; + bi12--; + + bi1++; + bi2++; + bi3++; + bi4++; + bi5++; + bi6++; + bi7++; + bi8++; + bi9++; + bi10++; + bi11++; + bi12++; + + bi1 -= 1; + bi2 -= 1; + bi3 -= 1; + bi4 -= 1; + bi5 -= 1; + bi6 -= 1; + bi7 -= 1; + bi8 -= 1; + bi9 -= 1; + bi10 -= 1; + bi11 -= 1; + bi12 -= 1; + + bi1 += 1; + bi2 += 1; + bi3 += 1; + bi4 += 1; + bi5 += 1; + bi6 += 1; + bi7 += 1; + bi8 += 1; + bi9 += 1; + bi10 += 1; + bi11 += 1; + bi12 += 1; + + bi1 = bi1 - 1; + bi2 = bi2 - 1; + bi3 = bi3 - 1; + bi4 = bi4 - 1; + bi5 = bi5 - 1; + bi6 = bi6 - 1; + bi7 = bi7 - 1; + bi8 = bi8 - 1; + bi9 = bi9 - 1; + bi10 = bi10 - 1; + bi11 = bi11 - 1; + bi12 = bi12 - 1; + + bi1 = bi1 + 1; + bi2 = bi2 + 1; + bi3 = bi3 + 1; + bi4 = bi4 + 1; + bi5 = bi5 + 1; + bi6 = bi6 + 1; + bi7 = bi7 + 1; + bi8 = bi8 + 1; + bi9 = bi9 + 1; + bi10 = bi10 + 1; + bi11 = bi11 + 1; + bi12 = bi12 + 1; + + bi1 = (-1) + bi1; + bi2 = (-1) + bi2; + bi3 = (-1) + bi3; + bi4 = (-1) + bi4; + bi5 = (-1) + bi5; + bi6 = (-1) + bi6; + bi7 = (-1) + bi7; + bi8 = (-1) + bi8; + bi9 = (-1) + bi9; + bi10 = (-1) + bi10; + bi11 = (-1) + bi11; + bi12 = (-1) + bi12; + + (void)static_cast<std::ptrdiff_t>(bi13 - bi1); + (void)static_cast<std::ptrdiff_t>(bi14 - bi2); + (void)static_cast<std::ptrdiff_t>(bi15 - bi3); + (void)static_cast<std::ptrdiff_t>(bi16 - bi4); + (void)static_cast<std::ptrdiff_t>(bi17 - bi5); + (void)static_cast<std::ptrdiff_t>(bi18 - bi6); + (void)static_cast<std::ptrdiff_t>(bi19 - bi7); + (void)static_cast<std::ptrdiff_t>(bi20 - bi8); + (void)static_cast<std::ptrdiff_t>(bi21 - bi9); + (void)static_cast<std::ptrdiff_t>(bi22 - bi10); + (void)static_cast<std::ptrdiff_t>(bi23 - bi11); + (void)static_cast<std::ptrdiff_t>(bi24 - bi12); + } + catch (std::exception&) + { + } +} + +} // namespace buffers_iterator_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "buffers_iterator", + BOOST_ASIO_TEST_CASE(buffers_iterator_compile::test) +) diff --git a/src/boost/libs/asio/test/co_spawn.cpp b/src/boost/libs/asio/test/co_spawn.cpp new file mode 100644 index 000000000..da88ceb55 --- /dev/null +++ b/src/boost/libs/asio/test/co_spawn.cpp @@ -0,0 +1,25 @@ +// +// co_spawn.cpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/co_spawn.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "co_spawn", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/completion_condition.cpp b/src/boost/libs/asio/test/completion_condition.cpp new file mode 100644 index 000000000..4f5971bca --- /dev/null +++ b/src/boost/libs/asio/test/completion_condition.cpp @@ -0,0 +1,25 @@ +// +// completion_condition.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/completion_condition.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "completion_condition", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/compose.cpp b/src/boost/libs/asio/test/compose.cpp new file mode 100644 index 000000000..3255ef824 --- /dev/null +++ b/src/boost/libs/asio/test/compose.cpp @@ -0,0 +1,185 @@ +// +// compose.cpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/compose.hpp> + +#include "unit_test.hpp" + +#include <boost/asio/io_context.hpp> +#include <boost/asio/post.hpp> + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +//------------------------------------------------------------------------------ + +class impl_0_completion_args +{ +public: + explicit impl_0_completion_args(boost::asio::io_context& ioc) + : ioc_(ioc), + state_(starting) + { + } + + template <typename Self> + void operator()(Self& self) + { + switch (state_) + { + case starting: + state_ = posting; + boost::asio::post(ioc_, BOOST_ASIO_MOVE_CAST(Self)(self)); + break; + case posting: + self.complete(); + break; + default: + break; + } + } + +private: + boost::asio::io_context& ioc_; + enum { starting, posting } state_; +}; + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) +async_0_completion_args(boost::asio::io_context& ioc, + BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + return boost::asio::async_compose<CompletionToken, void()>( + impl_0_completion_args(ioc), token); +} + +void compose_0_args_handler(int* count) +{ + ++(*count); +} + +void compose_0_completion_args_test() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + + boost::asio::io_context ioc; + int count = 0; + + async_0_completion_args(ioc, bindns::bind(&compose_0_args_handler, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); +} + +//------------------------------------------------------------------------------ + +class impl_1_completion_arg +{ +public: + explicit impl_1_completion_arg(boost::asio::io_context& ioc) + : ioc_(ioc), + state_(starting) + { + } + + template <typename Self> + void operator()(Self& self) + { + switch (state_) + { + case starting: + state_ = posting; + boost::asio::post(ioc_, BOOST_ASIO_MOVE_CAST(Self)(self)); + break; + case posting: + self.complete(42); + break; + default: + break; + } + } + +private: + boost::asio::io_context& ioc_; + enum { starting, posting } state_; +}; + +template <typename CompletionToken> +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(int)) +async_1_completion_arg(boost::asio::io_context& ioc, + BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + return boost::asio::async_compose<CompletionToken, void(int)>( + impl_1_completion_arg(ioc), token); +} + +void compose_1_args_handler(int* count, int* result_out, int result) +{ + ++(*count); + *result_out = result; +} + +void compose_1_completion_arg_test() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + + boost::asio::io_context ioc; + int count = 0; + int result = 0; + + async_1_completion_arg(ioc, + bindns::bind(&compose_1_args_handler, &count, &result, _1)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + BOOST_ASIO_CHECK(result == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + BOOST_ASIO_CHECK(result == 42); +} + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "compose", + BOOST_ASIO_TEST_CASE(compose_0_completion_args_test) + BOOST_ASIO_TEST_CASE(compose_1_completion_arg_test) +) diff --git a/src/boost/libs/asio/test/connect.cpp b/src/boost/libs/asio/test/connect.cpp new file mode 100644 index 000000000..32f9cbd15 --- /dev/null +++ b/src/boost/libs/asio/test/connect.cpp @@ -0,0 +1,1190 @@ +// +// connect.cpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/connect.hpp> + +#include <vector> +#include <boost/asio/detail/thread.hpp> +#include <boost/asio/ip/tcp.hpp> + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) +using bindns::placeholders::_1; +using bindns::placeholders::_2; + +class connection_sink +{ +public: + connection_sink() + : acceptor_(io_context_, + boost::asio::ip::tcp::endpoint( + boost::asio::ip::address_v4::loopback(), 0)), + target_endpoint_(acceptor_.local_endpoint()), + socket_(io_context_), + thread_(bindns::bind(&connection_sink::run, this)) + { + } + + ~connection_sink() + { + io_context_.stop(); + thread_.join(); + } + + boost::asio::ip::tcp::endpoint target_endpoint() + { + return target_endpoint_; + } + +private: + void run() + { + io_context_.run(); + } + + void handle_accept() + { + socket_.close(); + acceptor_.async_accept(socket_, + bindns::bind(&connection_sink::handle_accept, this)); + } + + boost::asio::io_context io_context_; + boost::asio::ip::tcp::acceptor acceptor_; + boost::asio::ip::tcp::endpoint target_endpoint_; + boost::asio::ip::tcp::socket socket_; + boost::asio::detail::thread thread_; +}; + +bool true_cond_1(const boost::system::error_code& /*ec*/, + const boost::asio::ip::tcp::endpoint& /*endpoint*/) +{ + return true; +} + +struct true_cond_2 +{ + template <typename Endpoint> + bool operator()(const boost::system::error_code& /*ec*/, + const Endpoint& /*endpoint*/) + { + return true; + } +}; + +std::vector<boost::asio::ip::tcp::endpoint>::const_iterator legacy_true_cond_1( + const boost::system::error_code& /*ec*/, + std::vector<boost::asio::ip::tcp::endpoint>::const_iterator next) +{ + return next; +} + +struct legacy_true_cond_2 +{ + template <typename Iterator> + Iterator operator()(const boost::system::error_code& /*ec*/, Iterator next) + { + return next; + } +}; + +bool false_cond(const boost::system::error_code& /*ec*/, + const boost::asio::ip::tcp::endpoint& /*endpoint*/) +{ + return false; +} + +void range_handler(const boost::system::error_code& ec, + const boost::asio::ip::tcp::endpoint& endpoint, + boost::system::error_code* out_ec, + boost::asio::ip::tcp::endpoint* out_endpoint) +{ + *out_ec = ec; + *out_endpoint = endpoint; +} + +void iter_handler(const boost::system::error_code& ec, + std::vector<boost::asio::ip::tcp::endpoint>::const_iterator iter, + boost::system::error_code* out_ec, + std::vector<boost::asio::ip::tcp::endpoint>::const_iterator* out_iter) +{ + *out_ec = ec; + *out_iter = iter; +} + +void test_connect_range() +{ + connection_sink sink; + boost::asio::io_context io_context; + boost::asio::ip::tcp::socket socket(io_context); + std::vector<boost::asio::ip::tcp::endpoint> endpoints; + boost::asio::ip::tcp::endpoint result; + + try + { + result = boost::asio::connect(socket, endpoints); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } + + endpoints.push_back(sink.target_endpoint()); + + result = boost::asio::connect(socket, endpoints); + BOOST_ASIO_CHECK(result == endpoints[0]); + + endpoints.push_back(sink.target_endpoint()); + + result = boost::asio::connect(socket, endpoints); + BOOST_ASIO_CHECK(result == endpoints[0]); + + endpoints.insert(endpoints.begin(), boost::asio::ip::tcp::endpoint()); + + result = boost::asio::connect(socket, endpoints); + BOOST_ASIO_CHECK(result == endpoints[1]); +} + +void test_connect_range_ec() +{ + connection_sink sink; + boost::asio::io_context io_context; + boost::asio::ip::tcp::socket socket(io_context); + std::vector<boost::asio::ip::tcp::endpoint> endpoints; + boost::asio::ip::tcp::endpoint result; + boost::system::error_code ec; + + result = boost::asio::connect(socket, endpoints, ec); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + endpoints.push_back(sink.target_endpoint()); + + result = boost::asio::connect(socket, endpoints, ec); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + endpoints.push_back(sink.target_endpoint()); + + result = boost::asio::connect(socket, endpoints, ec); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + endpoints.insert(endpoints.begin(), boost::asio::ip::tcp::endpoint()); + + result = boost::asio::connect(socket, endpoints, ec); + BOOST_ASIO_CHECK(result == endpoints[1]); + BOOST_ASIO_CHECK(!ec); +} + +void test_connect_range_cond() +{ + connection_sink sink; + boost::asio::io_context io_context; + boost::asio::ip::tcp::socket socket(io_context); + std::vector<boost::asio::ip::tcp::endpoint> endpoints; + boost::asio::ip::tcp::endpoint result; + + try + { + result = boost::asio::connect(socket, endpoints, true_cond_1); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } + + try + { + result = boost::asio::connect(socket, endpoints, true_cond_2()); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } + + try + { + result = boost::asio::connect(socket, endpoints, legacy_true_cond_1); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } + + try + { + result = boost::asio::connect(socket, endpoints, legacy_true_cond_2()); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } + + try + { + result = boost::asio::connect(socket, endpoints, false_cond); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } + + endpoints.push_back(sink.target_endpoint()); + + result = boost::asio::connect(socket, endpoints, true_cond_1); + BOOST_ASIO_CHECK(result == endpoints[0]); + + result = boost::asio::connect(socket, endpoints, true_cond_2()); + BOOST_ASIO_CHECK(result == endpoints[0]); + + result = boost::asio::connect(socket, endpoints, legacy_true_cond_1); + BOOST_ASIO_CHECK(result == endpoints[0]); + + result = boost::asio::connect(socket, endpoints, legacy_true_cond_2()); + BOOST_ASIO_CHECK(result == endpoints[0]); + + try + { + result = boost::asio::connect(socket, endpoints, false_cond); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } + + endpoints.push_back(sink.target_endpoint()); + + result = boost::asio::connect(socket, endpoints, true_cond_1); + BOOST_ASIO_CHECK(result == endpoints[0]); + + result = boost::asio::connect(socket, endpoints, true_cond_2()); + BOOST_ASIO_CHECK(result == endpoints[0]); + + result = boost::asio::connect(socket, endpoints, legacy_true_cond_1); + BOOST_ASIO_CHECK(result == endpoints[0]); + + result = boost::asio::connect(socket, endpoints, legacy_true_cond_2()); + BOOST_ASIO_CHECK(result == endpoints[0]); + + try + { + result = boost::asio::connect(socket, endpoints, false_cond); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } + + endpoints.insert(endpoints.begin(), boost::asio::ip::tcp::endpoint()); + + result = boost::asio::connect(socket, endpoints, true_cond_1); + BOOST_ASIO_CHECK(result == endpoints[1]); + + result = boost::asio::connect(socket, endpoints, true_cond_2()); + BOOST_ASIO_CHECK(result == endpoints[1]); + + result = boost::asio::connect(socket, endpoints, legacy_true_cond_1); + BOOST_ASIO_CHECK(result == endpoints[1]); + + result = boost::asio::connect(socket, endpoints, legacy_true_cond_2()); + BOOST_ASIO_CHECK(result == endpoints[1]); + + try + { + result = boost::asio::connect(socket, endpoints, false_cond); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } +} + +void test_connect_range_cond_ec() +{ + connection_sink sink; + boost::asio::io_context io_context; + boost::asio::ip::tcp::socket socket(io_context); + std::vector<boost::asio::ip::tcp::endpoint> endpoints; + boost::asio::ip::tcp::endpoint result; + boost::system::error_code ec; + + result = boost::asio::connect(socket, endpoints, true_cond_1, ec); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + result = boost::asio::connect(socket, endpoints, true_cond_2(), ec); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + result = boost::asio::connect(socket, endpoints, legacy_true_cond_1, ec); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + result = boost::asio::connect(socket, endpoints, legacy_true_cond_2(), ec); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + result = boost::asio::connect(socket, endpoints, false_cond, ec); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + endpoints.push_back(sink.target_endpoint()); + + result = boost::asio::connect(socket, endpoints, true_cond_1, ec); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, endpoints, true_cond_2(), ec); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, endpoints, legacy_true_cond_1, ec); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, endpoints, legacy_true_cond_2(), ec); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, endpoints, false_cond, ec); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + endpoints.push_back(sink.target_endpoint()); + + result = boost::asio::connect(socket, endpoints, true_cond_1, ec); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, endpoints, true_cond_2(), ec); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, endpoints, legacy_true_cond_1, ec); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, endpoints, legacy_true_cond_2(), ec); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, endpoints, false_cond, ec); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + endpoints.insert(endpoints.begin(), boost::asio::ip::tcp::endpoint()); + + result = boost::asio::connect(socket, endpoints, true_cond_1, ec); + BOOST_ASIO_CHECK(result == endpoints[1]); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, endpoints, true_cond_2(), ec); + BOOST_ASIO_CHECK(result == endpoints[1]); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, endpoints, legacy_true_cond_1, ec); + BOOST_ASIO_CHECK(result == endpoints[1]); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, endpoints, legacy_true_cond_2(), ec); + BOOST_ASIO_CHECK(result == endpoints[1]); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, endpoints, false_cond, ec); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); +} + +void test_connect_iter() +{ + connection_sink sink; + boost::asio::io_context io_context; + boost::asio::ip::tcp::socket socket(io_context); + std::vector<boost::asio::ip::tcp::endpoint> endpoints; + const std::vector<boost::asio::ip::tcp::endpoint>& cendpoints = endpoints; + std::vector<boost::asio::ip::tcp::endpoint>::const_iterator result; + + try + { + result = boost::asio::connect(socket, cendpoints.begin(), cendpoints.end()); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } + + endpoints.push_back(sink.target_endpoint()); + + result = boost::asio::connect(socket, cendpoints.begin(), cendpoints.end()); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + + endpoints.push_back(sink.target_endpoint()); + + result = boost::asio::connect(socket, cendpoints.begin(), cendpoints.end()); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + + endpoints.insert(endpoints.begin(), boost::asio::ip::tcp::endpoint()); + + result = boost::asio::connect(socket, cendpoints.begin(), cendpoints.end()); + BOOST_ASIO_CHECK(result == cendpoints.begin() + 1); +} + +void test_connect_iter_ec() +{ + connection_sink sink; + boost::asio::io_context io_context; + boost::asio::ip::tcp::socket socket(io_context); + std::vector<boost::asio::ip::tcp::endpoint> endpoints; + const std::vector<boost::asio::ip::tcp::endpoint>& cendpoints = endpoints; + std::vector<boost::asio::ip::tcp::endpoint>::const_iterator result; + boost::system::error_code ec; + + result = boost::asio::connect(socket, + cendpoints.begin(), cendpoints.end(), ec); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + endpoints.push_back(sink.target_endpoint()); + + result = boost::asio::connect(socket, + cendpoints.begin(), cendpoints.end(), ec); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + endpoints.push_back(sink.target_endpoint()); + + result = boost::asio::connect(socket, + cendpoints.begin(), cendpoints.end(), ec); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + endpoints.insert(endpoints.begin(), boost::asio::ip::tcp::endpoint()); + + result = boost::asio::connect(socket, + cendpoints.begin(), cendpoints.end(), ec); + BOOST_ASIO_CHECK(result == cendpoints.begin() + 1); + BOOST_ASIO_CHECK(!ec); +} + +void test_connect_iter_cond() +{ + connection_sink sink; + boost::asio::io_context io_context; + boost::asio::ip::tcp::socket socket(io_context); + std::vector<boost::asio::ip::tcp::endpoint> endpoints; + const std::vector<boost::asio::ip::tcp::endpoint>& cendpoints = endpoints; + std::vector<boost::asio::ip::tcp::endpoint>::const_iterator result; + + try + { + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), true_cond_1); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } + + try + { + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), true_cond_2()); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } + + try + { + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), legacy_true_cond_1); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } + + try + { + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), legacy_true_cond_2()); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } + + try + { + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), false_cond); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } + + endpoints.push_back(sink.target_endpoint()); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), true_cond_1); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), true_cond_2()); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), legacy_true_cond_1); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), legacy_true_cond_2()); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + + try + { + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), false_cond); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } + + endpoints.push_back(sink.target_endpoint()); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), true_cond_1); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), true_cond_2()); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), legacy_true_cond_1); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), legacy_true_cond_2()); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + + try + { + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), false_cond); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } + + endpoints.insert(endpoints.begin(), boost::asio::ip::tcp::endpoint()); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), true_cond_1); + BOOST_ASIO_CHECK(result == cendpoints.begin() + 1); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), true_cond_2()); + BOOST_ASIO_CHECK(result == cendpoints.begin() + 1); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), legacy_true_cond_1); + BOOST_ASIO_CHECK(result == cendpoints.begin() + 1); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), legacy_true_cond_2()); + BOOST_ASIO_CHECK(result == cendpoints.begin() + 1); + + try + { + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), false_cond); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::not_found); + } +} + +void test_connect_iter_cond_ec() +{ + connection_sink sink; + boost::asio::io_context io_context; + boost::asio::ip::tcp::socket socket(io_context); + std::vector<boost::asio::ip::tcp::endpoint> endpoints; + const std::vector<boost::asio::ip::tcp::endpoint>& cendpoints = endpoints; + std::vector<boost::asio::ip::tcp::endpoint>::const_iterator result; + boost::system::error_code ec; + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), true_cond_1, ec); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), true_cond_2(), ec); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), legacy_true_cond_1, ec); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), legacy_true_cond_2(), ec); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), false_cond, ec); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + endpoints.push_back(sink.target_endpoint()); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), true_cond_1, ec); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), true_cond_2(), ec); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), legacy_true_cond_1, ec); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), legacy_true_cond_2(), ec); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), false_cond, ec); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + endpoints.push_back(sink.target_endpoint()); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), true_cond_1, ec); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), true_cond_2(), ec); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), legacy_true_cond_1, ec); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), legacy_true_cond_2(), ec); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), false_cond, ec); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + endpoints.insert(endpoints.begin(), boost::asio::ip::tcp::endpoint()); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), true_cond_1, ec); + BOOST_ASIO_CHECK(result == cendpoints.begin() + 1); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), true_cond_2(), ec); + BOOST_ASIO_CHECK(result == cendpoints.begin() + 1); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), legacy_true_cond_1, ec); + BOOST_ASIO_CHECK(result == cendpoints.begin() + 1); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), legacy_true_cond_2(), ec); + BOOST_ASIO_CHECK(result == cendpoints.begin() + 1); + BOOST_ASIO_CHECK(!ec); + + result = boost::asio::connect(socket, cendpoints.begin(), + cendpoints.end(), false_cond, ec); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); +} + +void test_async_connect_range() +{ + connection_sink sink; + boost::asio::io_context io_context; + boost::asio::ip::tcp::socket socket(io_context); + std::vector<boost::asio::ip::tcp::endpoint> endpoints; + boost::asio::ip::tcp::endpoint result; + boost::system::error_code ec; + + boost::asio::async_connect(socket, endpoints, + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + endpoints.push_back(sink.target_endpoint()); + + boost::asio::async_connect(socket, endpoints, + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + endpoints.push_back(sink.target_endpoint()); + + boost::asio::async_connect(socket, endpoints, + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + endpoints.insert(endpoints.begin(), boost::asio::ip::tcp::endpoint()); + + boost::asio::async_connect(socket, endpoints, + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == endpoints[1]); + BOOST_ASIO_CHECK(!ec); +} + +void test_async_connect_range_cond() +{ + connection_sink sink; + boost::asio::io_context io_context; + boost::asio::ip::tcp::socket socket(io_context); + std::vector<boost::asio::ip::tcp::endpoint> endpoints; + boost::asio::ip::tcp::endpoint result; + boost::system::error_code ec; + + boost::asio::async_connect(socket, endpoints, true_cond_1, + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + boost::asio::async_connect(socket, endpoints, true_cond_2(), + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + boost::asio::async_connect(socket, endpoints, legacy_true_cond_1, + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + boost::asio::async_connect(socket, endpoints, legacy_true_cond_2(), + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + boost::asio::async_connect(socket, endpoints, false_cond, + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + endpoints.push_back(sink.target_endpoint()); + + boost::asio::async_connect(socket, endpoints, true_cond_1, + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, endpoints, true_cond_2(), + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, endpoints, legacy_true_cond_1, + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, endpoints, legacy_true_cond_2(), + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, endpoints, false_cond, + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + endpoints.push_back(sink.target_endpoint()); + + boost::asio::async_connect(socket, endpoints, true_cond_1, + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, endpoints, true_cond_2(), + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, endpoints, legacy_true_cond_1, + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, endpoints, legacy_true_cond_2(), + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == endpoints[0]); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, endpoints, false_cond, + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + endpoints.insert(endpoints.begin(), boost::asio::ip::tcp::endpoint()); + + boost::asio::async_connect(socket, endpoints, true_cond_1, + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == endpoints[1]); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, endpoints, true_cond_2(), + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == endpoints[1]); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, endpoints, legacy_true_cond_1, + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == endpoints[1]); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, endpoints, legacy_true_cond_2(), + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == endpoints[1]); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, endpoints, false_cond, + bindns::bind(range_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == boost::asio::ip::tcp::endpoint()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); +} + +void test_async_connect_iter() +{ + connection_sink sink; + boost::asio::io_context io_context; + boost::asio::ip::tcp::socket socket(io_context); + std::vector<boost::asio::ip::tcp::endpoint> endpoints; + const std::vector<boost::asio::ip::tcp::endpoint>& cendpoints = endpoints; + std::vector<boost::asio::ip::tcp::endpoint>::const_iterator result; + boost::system::error_code ec; + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + endpoints.push_back(sink.target_endpoint()); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + endpoints.push_back(sink.target_endpoint()); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + endpoints.insert(endpoints.begin(), boost::asio::ip::tcp::endpoint()); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.begin() + 1); + BOOST_ASIO_CHECK(!ec); +} + +void test_async_connect_iter_cond() +{ + connection_sink sink; + boost::asio::io_context io_context; + boost::asio::ip::tcp::socket socket(io_context); + std::vector<boost::asio::ip::tcp::endpoint> endpoints; + const std::vector<boost::asio::ip::tcp::endpoint>& cendpoints = endpoints; + std::vector<boost::asio::ip::tcp::endpoint>::const_iterator result; + boost::system::error_code ec; + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + true_cond_1, bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + true_cond_2(), bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + legacy_true_cond_1, bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + legacy_true_cond_2(), bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + false_cond, bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + endpoints.push_back(sink.target_endpoint()); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + true_cond_1, bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + true_cond_2(), bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + legacy_true_cond_1, bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + legacy_true_cond_2(), bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + false_cond, bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + endpoints.push_back(sink.target_endpoint()); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + true_cond_1, bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + true_cond_2(), bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + legacy_true_cond_1, bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + legacy_true_cond_2(), bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.begin()); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + false_cond, bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + + endpoints.insert(endpoints.begin(), boost::asio::ip::tcp::endpoint()); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + true_cond_1, bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.begin() + 1); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + true_cond_2(), bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.begin() + 1); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + legacy_true_cond_1, bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.begin() + 1); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + legacy_true_cond_2(), bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.begin() + 1); + BOOST_ASIO_CHECK(!ec); + + boost::asio::async_connect(socket, cendpoints.begin(), cendpoints.end(), + false_cond, bindns::bind(iter_handler, _1, _2, &ec, &result)); + io_context.restart(); + io_context.run(); + BOOST_ASIO_CHECK(result == cendpoints.end()); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); +} + +BOOST_ASIO_TEST_SUITE +( + "connect", + BOOST_ASIO_TEST_CASE(test_connect_range) + BOOST_ASIO_TEST_CASE(test_connect_range_ec) + BOOST_ASIO_TEST_CASE(test_connect_range_cond) + BOOST_ASIO_TEST_CASE(test_connect_range_cond_ec) + BOOST_ASIO_TEST_CASE(test_connect_iter) + BOOST_ASIO_TEST_CASE(test_connect_iter_ec) + BOOST_ASIO_TEST_CASE(test_connect_iter_cond) + BOOST_ASIO_TEST_CASE(test_connect_iter_cond_ec) + BOOST_ASIO_TEST_CASE(test_async_connect_range) + BOOST_ASIO_TEST_CASE(test_async_connect_range_cond) + BOOST_ASIO_TEST_CASE(test_async_connect_iter) + BOOST_ASIO_TEST_CASE(test_async_connect_iter_cond) +) diff --git a/src/boost/libs/asio/test/coroutine.cpp b/src/boost/libs/asio/test/coroutine.cpp new file mode 100644 index 000000000..703feb67d --- /dev/null +++ b/src/boost/libs/asio/test/coroutine.cpp @@ -0,0 +1,112 @@ +// +// coroutine.cpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/coroutine.hpp> + +#include "unit_test.hpp" + +// Must come after all other headers. +#include <boost/asio/yield.hpp> + +//------------------------------------------------------------------------------ + +// Coroutine completes via yield break. + +void yield_break_coro(boost::asio::coroutine& coro) +{ + reenter (coro) + { + yield return; + yield break; + } +} + +void yield_break_test() +{ + boost::asio::coroutine coro; + BOOST_ASIO_CHECK(!coro.is_complete()); + yield_break_coro(coro); + BOOST_ASIO_CHECK(!coro.is_complete()); + yield_break_coro(coro); + BOOST_ASIO_CHECK(coro.is_complete()); +} + +//------------------------------------------------------------------------------ + +// Coroutine completes via return. + +void return_coro(boost::asio::coroutine& coro) +{ + reenter (coro) + { + return; + } +} + +void return_test() +{ + boost::asio::coroutine coro; + return_coro(coro); + BOOST_ASIO_CHECK(coro.is_complete()); +} + +//------------------------------------------------------------------------------ + +// Coroutine completes via exception. + +void exception_coro(boost::asio::coroutine& coro) +{ + reenter (coro) + { + throw 1; + } +} + +void exception_test() +{ + boost::asio::coroutine coro; + try { exception_coro(coro); } catch (int) {} + BOOST_ASIO_CHECK(coro.is_complete()); +} + +//------------------------------------------------------------------------------ + +// Coroutine completes by falling off the end. + +void fall_off_end_coro(boost::asio::coroutine& coro) +{ + reenter (coro) + { + } +} + +void fall_off_end_test() +{ + boost::asio::coroutine coro; + fall_off_end_coro(coro); + BOOST_ASIO_CHECK(coro.is_complete()); +} + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "coroutine", + BOOST_ASIO_TEST_CASE(yield_break_test) + BOOST_ASIO_TEST_CASE(return_test) + BOOST_ASIO_TEST_CASE(exception_test) + BOOST_ASIO_TEST_CASE(fall_off_end_test) +) diff --git a/src/boost/libs/asio/test/deadline_timer.cpp b/src/boost/libs/asio/test/deadline_timer.cpp new file mode 100644 index 000000000..0ff0d9bd8 --- /dev/null +++ b/src/boost/libs/asio/test/deadline_timer.cpp @@ -0,0 +1,392 @@ +// +// deadline_timer.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/deadline_timer.hpp> + +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +#include <boost/bind/bind.hpp> +#include "archetypes/async_result.hpp" +#include <boost/asio/executor_work_guard.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/placeholders.hpp> +#include <boost/asio/detail/thread.hpp> + +using namespace boost::posix_time; + +void increment(int* count) +{ + ++(*count); +} + +void decrement_to_zero(boost::asio::deadline_timer* t, int* count) +{ + if (*count > 0) + { + --(*count); + + int before_value = *count; + + t->expires_at(t->expires_at() + seconds(1)); + t->async_wait(boost::bind(decrement_to_zero, t, count)); + + // Completion cannot nest, so count value should remain unchanged. + BOOST_ASIO_CHECK(*count == before_value); + } +} + +void increment_if_not_cancelled(int* count, + const boost::system::error_code& ec) +{ + if (!ec) + ++(*count); +} + +void cancel_timer(boost::asio::deadline_timer* t) +{ + std::size_t num_cancelled = t->cancel(); + BOOST_ASIO_CHECK(num_cancelled == 1); +} + +void cancel_one_timer(boost::asio::deadline_timer* t) +{ + std::size_t num_cancelled = t->cancel_one(); + BOOST_ASIO_CHECK(num_cancelled == 1); +} + +ptime now() +{ +#if defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) + return microsec_clock::universal_time(); +#else // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) + return second_clock::universal_time(); +#endif // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) +} + +void deadline_timer_test() +{ + boost::asio::io_context ioc; + int count = 0; + + ptime start = now(); + + boost::asio::deadline_timer t1(ioc, seconds(1)); + t1.wait(); + + // The timer must block until after its expiry time. + ptime end = now(); + ptime expected_end = start + seconds(1); + BOOST_ASIO_CHECK(expected_end < end || expected_end == end); + + start = now(); + + boost::asio::deadline_timer t2(ioc, seconds(1) + microseconds(500000)); + t2.wait(); + + // The timer must block until after its expiry time. + end = now(); + expected_end = start + seconds(1) + microseconds(500000); + BOOST_ASIO_CHECK(expected_end < end || expected_end == end); + + t2.expires_at(t2.expires_at() + seconds(1)); + t2.wait(); + + // The timer must block until after its expiry time. + end = now(); + expected_end += seconds(1); + BOOST_ASIO_CHECK(expected_end < end || expected_end == end); + + start = now(); + + t2.expires_from_now(seconds(1) + microseconds(200000)); + t2.wait(); + + // The timer must block until after its expiry time. + end = now(); + expected_end = start + seconds(1) + microseconds(200000); + BOOST_ASIO_CHECK(expected_end < end || expected_end == end); + + start = now(); + + boost::asio::deadline_timer t3(ioc, seconds(5)); + t3.async_wait(boost::bind(increment, &count)); + + // No completions can be delivered until run() is called. + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all operations have finished, and + // this should not be until after the timer's expiry time. + BOOST_ASIO_CHECK(count == 1); + end = now(); + expected_end = start + seconds(1); + BOOST_ASIO_CHECK(expected_end < end || expected_end == end); + + count = 3; + start = now(); + + boost::asio::deadline_timer t4(ioc, seconds(1)); + t4.async_wait(boost::bind(decrement_to_zero, &t4, &count)); + + // No completions can be delivered until run() is called. + BOOST_ASIO_CHECK(count == 3); + + ioc.restart(); + ioc.run(); + + // The run() call will not return until all operations have finished, and + // this should not be until after the timer's final expiry time. + BOOST_ASIO_CHECK(count == 0); + end = now(); + expected_end = start + seconds(3); + BOOST_ASIO_CHECK(expected_end < end || expected_end == end); + + count = 0; + start = now(); + + boost::asio::deadline_timer t5(ioc, seconds(10)); + t5.async_wait(boost::bind(increment_if_not_cancelled, &count, + boost::asio::placeholders::error)); + boost::asio::deadline_timer t6(ioc, seconds(1)); + t6.async_wait(boost::bind(cancel_timer, &t5)); + + // No completions can be delivered until run() is called. + BOOST_ASIO_CHECK(count == 0); + + ioc.restart(); + ioc.run(); + + // The timer should have been cancelled, so count should not have changed. + // The total run time should not have been much more than 1 second (and + // certainly far less than 10 seconds). + BOOST_ASIO_CHECK(count == 0); + end = now(); + expected_end = start + seconds(2); + BOOST_ASIO_CHECK(end < expected_end); + + // Wait on the timer again without cancelling it. This time the asynchronous + // wait should run to completion and increment the counter. + t5.async_wait(boost::bind(increment_if_not_cancelled, &count, + boost::asio::placeholders::error)); + + ioc.restart(); + ioc.run(); + + // The timer should not have been cancelled, so count should have changed. + // The total time since the timer was created should be more than 10 seconds. + BOOST_ASIO_CHECK(count == 1); + end = now(); + expected_end = start + seconds(10); + BOOST_ASIO_CHECK(expected_end < end || expected_end == end); + + count = 0; + start = now(); + + // Start two waits on a timer, one of which will be cancelled. The one + // which is not cancelled should still run to completion and increment the + // counter. + boost::asio::deadline_timer t7(ioc, seconds(3)); + t7.async_wait(boost::bind(increment_if_not_cancelled, &count, + boost::asio::placeholders::error)); + t7.async_wait(boost::bind(increment_if_not_cancelled, &count, + boost::asio::placeholders::error)); + boost::asio::deadline_timer t8(ioc, seconds(1)); + t8.async_wait(boost::bind(cancel_one_timer, &t7)); + + ioc.restart(); + ioc.run(); + + // One of the waits should not have been cancelled, so count should have + // changed. The total time since the timer was created should be more than 3 + // seconds. + BOOST_ASIO_CHECK(count == 1); + end = now(); + expected_end = start + seconds(3); + BOOST_ASIO_CHECK(expected_end < end || expected_end == end); +} + +void timer_handler(const boost::system::error_code&) +{ +} + +void deadline_timer_cancel_test() +{ + static boost::asio::io_context io_context; + struct timer + { + boost::asio::deadline_timer t; + timer() : t(io_context) { t.expires_at(boost::posix_time::pos_infin); } + } timers[50]; + + timers[2].t.async_wait(&timer_handler); + timers[41].t.async_wait(&timer_handler); + for (int i = 10; i < 20; ++i) + timers[i].t.async_wait(&timer_handler); + + BOOST_ASIO_CHECK(timers[2].t.cancel() == 1); + BOOST_ASIO_CHECK(timers[41].t.cancel() == 1); + for (int i = 10; i < 20; ++i) + BOOST_ASIO_CHECK(timers[i].t.cancel() == 1); +} + +struct custom_allocation_timer_handler +{ + custom_allocation_timer_handler(int* count) : count_(count) {} + void operator()(const boost::system::error_code&) {} + int* count_; +}; + +void* asio_handler_allocate(std::size_t size, + custom_allocation_timer_handler* handler) +{ + ++(*handler->count_); + return ::operator new(size); +} + +void asio_handler_deallocate(void* pointer, std::size_t, + custom_allocation_timer_handler* handler) +{ + --(*handler->count_); + ::operator delete(pointer); +} + +void deadline_timer_custom_allocation_test() +{ + static boost::asio::io_context io_context; + struct timer + { + boost::asio::deadline_timer t; + timer() : t(io_context) {} + } timers[100]; + + int allocation_count = 0; + + for (int i = 0; i < 50; ++i) + { + timers[i].t.expires_at(boost::posix_time::pos_infin); + timers[i].t.async_wait(custom_allocation_timer_handler(&allocation_count)); + } + + for (int i = 50; i < 100; ++i) + { + timers[i].t.expires_at(boost::posix_time::neg_infin); + timers[i].t.async_wait(custom_allocation_timer_handler(&allocation_count)); + } + + for (int i = 0; i < 50; ++i) + timers[i].t.cancel(); + + io_context.run(); + + BOOST_ASIO_CHECK(allocation_count == 0); +} + +void io_context_run(boost::asio::io_context* ioc) +{ + ioc->run(); +} + +void deadline_timer_thread_test() +{ + boost::asio::io_context ioc; + boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work + = boost::asio::make_work_guard(ioc); + boost::asio::deadline_timer t1(ioc); + boost::asio::deadline_timer t2(ioc); + int count = 0; + + boost::asio::detail::thread th(boost::bind(io_context_run, &ioc)); + + t2.expires_from_now(boost::posix_time::seconds(2)); + t2.wait(); + + t1.expires_from_now(boost::posix_time::seconds(2)); + t1.async_wait(boost::bind(increment, &count)); + + t2.expires_from_now(boost::posix_time::seconds(4)); + t2.wait(); + + ioc.stop(); + th.join(); + + BOOST_ASIO_CHECK(count == 1); +} + +void deadline_timer_async_result_test() +{ + boost::asio::io_context ioc; + boost::asio::deadline_timer t1(ioc); + + t1.expires_from_now(boost::posix_time::seconds(1)); + int i = t1.async_wait(archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + + ioc.run(); +} + +#if defined(BOOST_ASIO_HAS_MOVE) +boost::asio::deadline_timer make_timer(boost::asio::io_context& ioc, int* count) +{ + boost::asio::deadline_timer t(ioc); + t.expires_from_now(boost::posix_time::seconds(1)); + t.async_wait(boost::bind(increment, count)); + return t; +} +#endif // defined(BOOST_ASIO_HAS_MOVE) + +void deadline_timer_move_test() +{ +#if defined(BOOST_ASIO_HAS_MOVE) + boost::asio::io_context io_context1; + boost::asio::io_context io_context2; + int count = 0; + + boost::asio::deadline_timer t1 = make_timer(io_context1, &count); + boost::asio::deadline_timer t2 = make_timer(io_context2, &count); + boost::asio::deadline_timer t3 = std::move(t1); + + t2 = std::move(t1); + + io_context2.run(); + + BOOST_ASIO_CHECK(count == 1); + + io_context1.run(); + + BOOST_ASIO_CHECK(count == 2); +#endif // defined(BOOST_ASIO_HAS_MOVE) +} + +BOOST_ASIO_TEST_SUITE +( + "deadline_timer", + BOOST_ASIO_TEST_CASE(deadline_timer_test) + BOOST_ASIO_TEST_CASE(deadline_timer_cancel_test) + BOOST_ASIO_TEST_CASE(deadline_timer_custom_allocation_test) + BOOST_ASIO_TEST_CASE(deadline_timer_thread_test) + BOOST_ASIO_TEST_CASE(deadline_timer_async_result_test) + BOOST_ASIO_TEST_CASE(deadline_timer_move_test) +) +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +BOOST_ASIO_TEST_SUITE +( + "deadline_timer", + BOOST_ASIO_TEST_CASE(null_test) +) +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) diff --git a/src/boost/libs/asio/test/defer.cpp b/src/boost/libs/asio/test/defer.cpp new file mode 100644 index 000000000..49e85fe24 --- /dev/null +++ b/src/boost/libs/asio/test/defer.cpp @@ -0,0 +1,25 @@ +// +// defer.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/defer.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "defer", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/detached.cpp b/src/boost/libs/asio/test/detached.cpp new file mode 100644 index 000000000..2c62e6d66 --- /dev/null +++ b/src/boost/libs/asio/test/detached.cpp @@ -0,0 +1,25 @@ +// +// detached.cpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/detached.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "detached", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/dispatch.cpp b/src/boost/libs/asio/test/dispatch.cpp new file mode 100644 index 000000000..f97531469 --- /dev/null +++ b/src/boost/libs/asio/test/dispatch.cpp @@ -0,0 +1,25 @@ +// +// dispatch.cpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/dispatch.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "dispatch", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/error.cpp b/src/boost/libs/asio/test/error.cpp new file mode 100644 index 000000000..5be958401 --- /dev/null +++ b/src/boost/libs/asio/test/error.cpp @@ -0,0 +1,89 @@ +// +// error.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/error.hpp> + +#include <sstream> +#include "unit_test.hpp" + +void test_error_code(const boost::system::error_code& code) +{ + boost::system::error_code error(code); + BOOST_ASIO_CHECK(code == error); + + BOOST_ASIO_CHECK(!code || error); + BOOST_ASIO_CHECK(!code || !!error); + + boost::system::error_code error2(error); + BOOST_ASIO_CHECK(error == error2); + BOOST_ASIO_CHECK(!(error != error2)); + + boost::system::error_code error3; + error3 = error; + BOOST_ASIO_CHECK(error == error3); + BOOST_ASIO_CHECK(!(error != error3)); + + std::ostringstream os; + os << error; + BOOST_ASIO_CHECK(!os.str().empty()); +} + +void error_test() +{ + test_error_code(boost::asio::error::access_denied); + test_error_code(boost::asio::error::address_family_not_supported); + test_error_code(boost::asio::error::address_in_use); + test_error_code(boost::asio::error::already_connected); + test_error_code(boost::asio::error::already_started); + test_error_code(boost::asio::error::connection_aborted); + test_error_code(boost::asio::error::connection_refused); + test_error_code(boost::asio::error::connection_reset); + test_error_code(boost::asio::error::bad_descriptor); + test_error_code(boost::asio::error::eof); + test_error_code(boost::asio::error::fault); + test_error_code(boost::asio::error::host_not_found); + test_error_code(boost::asio::error::host_not_found_try_again); + test_error_code(boost::asio::error::host_unreachable); + test_error_code(boost::asio::error::in_progress); + test_error_code(boost::asio::error::interrupted); + test_error_code(boost::asio::error::invalid_argument); + test_error_code(boost::asio::error::message_size); + test_error_code(boost::asio::error::network_down); + test_error_code(boost::asio::error::network_reset); + test_error_code(boost::asio::error::network_unreachable); + test_error_code(boost::asio::error::no_descriptors); + test_error_code(boost::asio::error::no_buffer_space); + test_error_code(boost::asio::error::no_data); + test_error_code(boost::asio::error::no_memory); + test_error_code(boost::asio::error::no_permission); + test_error_code(boost::asio::error::no_protocol_option); + test_error_code(boost::asio::error::no_recovery); + test_error_code(boost::asio::error::not_connected); + test_error_code(boost::asio::error::not_socket); + test_error_code(boost::asio::error::operation_aborted); + test_error_code(boost::asio::error::operation_not_supported); + test_error_code(boost::asio::error::service_not_found); + test_error_code(boost::asio::error::shut_down); + test_error_code(boost::asio::error::timed_out); + test_error_code(boost::asio::error::try_again); + test_error_code(boost::asio::error::would_block); +} + +BOOST_ASIO_TEST_SUITE +( + "error", + BOOST_ASIO_TEST_CASE(error_test) +) diff --git a/src/boost/libs/asio/test/execution_context.cpp b/src/boost/libs/asio/test/execution_context.cpp new file mode 100644 index 000000000..feea39c87 --- /dev/null +++ b/src/boost/libs/asio/test/execution_context.cpp @@ -0,0 +1,25 @@ +// +// execution_context.cpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/execution_context.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "execution_context", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/executor.cpp b/src/boost/libs/asio/test/executor.cpp new file mode 100644 index 000000000..4b6bd7aa4 --- /dev/null +++ b/src/boost/libs/asio/test/executor.cpp @@ -0,0 +1,25 @@ +// +// executor.cpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/executor.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "executor", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/executor_work_guard.cpp b/src/boost/libs/asio/test/executor_work_guard.cpp new file mode 100644 index 000000000..b27df7bd4 --- /dev/null +++ b/src/boost/libs/asio/test/executor_work_guard.cpp @@ -0,0 +1,25 @@ +// +// executor_work_guard.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/executor_work_guard.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "executor_work_guard", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/generic/basic_endpoint.cpp b/src/boost/libs/asio/test/generic/basic_endpoint.cpp new file mode 100644 index 000000000..c9522a7d0 --- /dev/null +++ b/src/boost/libs/asio/test/generic/basic_endpoint.cpp @@ -0,0 +1,25 @@ +// +// generic/basic_endpoint.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/generic/basic_endpoint.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "generic/basic_endpoint", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/generic/datagram_protocol.cpp b/src/boost/libs/asio/test/generic/datagram_protocol.cpp new file mode 100644 index 000000000..76184edf2 --- /dev/null +++ b/src/boost/libs/asio/test/generic/datagram_protocol.cpp @@ -0,0 +1,263 @@ +// +// generic/datagram_protocol.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/generic/datagram_protocol.hpp> + +#include <cstring> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/udp.hpp> +#include "../unit_test.hpp" + +#if defined(__cplusplus_cli) || defined(__cplusplus_winrt) +# define generic cpp_generic +#endif + +//------------------------------------------------------------------------------ + +// generic_datagram_protocol_socket_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// generic::datagram_socket::socket compile and link correctly. Runtime +// failures are ignored. + +namespace generic_datagram_protocol_socket_compile { + +void connect_handler(const boost::system::error_code&) +{ +} + +void send_handler(const boost::system::error_code&, std::size_t) +{ +} + +void receive_handler(const boost::system::error_code&, std::size_t) +{ +} + +void test() +{ + using namespace boost::asio; + namespace generic = boost::asio::generic; + typedef generic::datagram_protocol dp; + + const int af_inet = BOOST_ASIO_OS_DEF(AF_INET); + const int ipproto_udp = BOOST_ASIO_OS_DEF(IPPROTO_UDP); + const int sock_dgram = BOOST_ASIO_OS_DEF(SOCK_DGRAM); + + try + { + io_context ioc; + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + socket_base::message_flags in_flags = 0; + socket_base::send_buffer_size socket_option; + socket_base::bytes_readable io_control_command; + boost::system::error_code ec; + + // basic_datagram_socket constructors. + + dp::socket socket1(ioc); + dp::socket socket2(ioc, dp(af_inet, ipproto_udp)); + dp::socket socket3(ioc, dp::endpoint()); +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + dp::socket::native_handle_type native_socket1 + = ::socket(af_inet, sock_dgram, 0); + dp::socket socket4(ioc, dp(af_inet, ipproto_udp), native_socket1); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#if defined(BOOST_ASIO_HAS_MOVE) + dp::socket socket5(std::move(socket4)); + boost::asio::ip::udp::socket udp_socket(ioc); + dp::socket socket6(std::move(udp_socket)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_datagram_socket operators. + +#if defined(BOOST_ASIO_HAS_MOVE) + socket1 = dp::socket(ioc); + socket1 = std::move(socket2); + socket1 = boost::asio::ip::udp::socket(ioc); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_io_object functions. + + dp::socket::executor_type ex = socket1.get_executor(); + (void)ex; + + // basic_socket functions. + + dp::socket::lowest_layer_type& lowest_layer = socket1.lowest_layer(); + (void)lowest_layer; + + socket1.open(dp(af_inet, ipproto_udp)); + socket1.open(dp(af_inet, ipproto_udp), ec); + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + dp::socket::native_handle_type native_socket2 + = ::socket(af_inet, sock_dgram, 0); + socket1.assign(dp(af_inet, ipproto_udp), native_socket2); + dp::socket::native_handle_type native_socket3 + = ::socket(af_inet, sock_dgram, 0); + socket1.assign(dp(af_inet, ipproto_udp), native_socket3, ec); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + + bool is_open = socket1.is_open(); + (void)is_open; + + socket1.close(); + socket1.close(ec); + + dp::socket::native_handle_type native_socket4 = socket1.native_handle(); + (void)native_socket4; + + socket1.cancel(); + socket1.cancel(ec); + + bool at_mark1 = socket1.at_mark(); + (void)at_mark1; + bool at_mark2 = socket1.at_mark(ec); + (void)at_mark2; + + std::size_t available1 = socket1.available(); + (void)available1; + std::size_t available2 = socket1.available(ec); + (void)available2; + + socket1.bind(dp::endpoint()); + socket1.bind(dp::endpoint(), ec); + + socket1.connect(dp::endpoint()); + socket1.connect(dp::endpoint(), ec); + + socket1.async_connect(dp::endpoint(), connect_handler); + + socket1.set_option(socket_option); + socket1.set_option(socket_option, ec); + + socket1.get_option(socket_option); + socket1.get_option(socket_option, ec); + + socket1.io_control(io_control_command); + socket1.io_control(io_control_command, ec); + + dp::endpoint endpoint1 = socket1.local_endpoint(); + (void)endpoint1; + dp::endpoint endpoint2 = socket1.local_endpoint(ec); + (void)endpoint2; + + dp::endpoint endpoint3 = socket1.remote_endpoint(); + (void)endpoint3; + dp::endpoint endpoint4 = socket1.remote_endpoint(ec); + (void)endpoint4; + + socket1.shutdown(socket_base::shutdown_both); + socket1.shutdown(socket_base::shutdown_both, ec); + + // basic_datagram_socket functions. + + socket1.send(buffer(mutable_char_buffer)); + socket1.send(buffer(const_char_buffer)); + socket1.send(null_buffers()); + socket1.send(buffer(mutable_char_buffer), in_flags); + socket1.send(buffer(const_char_buffer), in_flags); + socket1.send(null_buffers(), in_flags); + socket1.send(buffer(mutable_char_buffer), in_flags, ec); + socket1.send(buffer(const_char_buffer), in_flags, ec); + socket1.send(null_buffers(), in_flags, ec); + + socket1.async_send(buffer(mutable_char_buffer), send_handler); + socket1.async_send(buffer(const_char_buffer), send_handler); + socket1.async_send(null_buffers(), send_handler); + socket1.async_send(buffer(mutable_char_buffer), in_flags, send_handler); + socket1.async_send(buffer(const_char_buffer), in_flags, send_handler); + socket1.async_send(null_buffers(), in_flags, send_handler); + + socket1.send_to(buffer(mutable_char_buffer), + dp::endpoint()); + socket1.send_to(buffer(const_char_buffer), + dp::endpoint()); + socket1.send_to(null_buffers(), + dp::endpoint()); + socket1.send_to(buffer(mutable_char_buffer), + dp::endpoint(), in_flags); + socket1.send_to(buffer(const_char_buffer), + dp::endpoint(), in_flags); + socket1.send_to(null_buffers(), + dp::endpoint(), in_flags); + socket1.send_to(buffer(mutable_char_buffer), + dp::endpoint(), in_flags, ec); + socket1.send_to(buffer(const_char_buffer), + dp::endpoint(), in_flags, ec); + socket1.send_to(null_buffers(), + dp::endpoint(), in_flags, ec); + + socket1.async_send_to(buffer(mutable_char_buffer), + dp::endpoint(), send_handler); + socket1.async_send_to(buffer(const_char_buffer), + dp::endpoint(), send_handler); + socket1.async_send_to(null_buffers(), + dp::endpoint(), send_handler); + socket1.async_send_to(buffer(mutable_char_buffer), + dp::endpoint(), in_flags, send_handler); + socket1.async_send_to(buffer(const_char_buffer), + dp::endpoint(), in_flags, send_handler); + socket1.async_send_to(null_buffers(), + dp::endpoint(), in_flags, send_handler); + + socket1.receive(buffer(mutable_char_buffer)); + socket1.receive(null_buffers()); + socket1.receive(buffer(mutable_char_buffer), in_flags); + socket1.receive(null_buffers(), in_flags); + socket1.receive(buffer(mutable_char_buffer), in_flags, ec); + socket1.receive(null_buffers(), in_flags, ec); + + socket1.async_receive(buffer(mutable_char_buffer), receive_handler); + socket1.async_receive(null_buffers(), receive_handler); + socket1.async_receive(buffer(mutable_char_buffer), in_flags, + receive_handler); + socket1.async_receive(null_buffers(), in_flags, receive_handler); + + dp::endpoint endpoint; + socket1.receive_from(buffer(mutable_char_buffer), endpoint); + socket1.receive_from(null_buffers(), endpoint); + socket1.receive_from(buffer(mutable_char_buffer), endpoint, in_flags); + socket1.receive_from(null_buffers(), endpoint, in_flags); + socket1.receive_from(buffer(mutable_char_buffer), endpoint, in_flags, ec); + socket1.receive_from(null_buffers(), endpoint, in_flags, ec); + + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, receive_handler); + socket1.async_receive_from(null_buffers(), + endpoint, receive_handler); + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, in_flags, receive_handler); + socket1.async_receive_from(null_buffers(), + endpoint, in_flags, receive_handler); + } + catch (std::exception&) + { + } +} + +} // namespace generic_datagram_protocol_socket_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "generic/datagram_protocol", + BOOST_ASIO_TEST_CASE(generic_datagram_protocol_socket_compile::test) +) diff --git a/src/boost/libs/asio/test/generic/raw_protocol.cpp b/src/boost/libs/asio/test/generic/raw_protocol.cpp new file mode 100644 index 000000000..35bb98636 --- /dev/null +++ b/src/boost/libs/asio/test/generic/raw_protocol.cpp @@ -0,0 +1,263 @@ +// +// generic/raw_protocol.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/generic/raw_protocol.hpp> + +#include <cstring> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/icmp.hpp> +#include "../unit_test.hpp" + +#if defined(__cplusplus_cli) || defined(__cplusplus_winrt) +# define generic cpp_generic +#endif + +//------------------------------------------------------------------------------ + +// generic_raw_protocol_socket_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// generic::raw_socket::socket compile and link correctly. Runtime failures +// are ignored. + +namespace generic_raw_protocol_socket_compile { + +void connect_handler(const boost::system::error_code&) +{ +} + +void send_handler(const boost::system::error_code&, std::size_t) +{ +} + +void receive_handler(const boost::system::error_code&, std::size_t) +{ +} + +void test() +{ + using namespace boost::asio; + namespace generic = boost::asio::generic; + typedef generic::raw_protocol rp; + + const int af_inet = BOOST_ASIO_OS_DEF(AF_INET); + const int ipproto_icmp = BOOST_ASIO_OS_DEF(IPPROTO_ICMP); + const int sock_raw = BOOST_ASIO_OS_DEF(SOCK_RAW); + + try + { + io_context ioc; + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + socket_base::message_flags in_flags = 0; + socket_base::send_buffer_size socket_option; + socket_base::bytes_readable io_control_command; + boost::system::error_code ec; + + // basic_raw_socket constructors. + + rp::socket socket1(ioc); + rp::socket socket2(ioc, rp(af_inet, ipproto_icmp)); + rp::socket socket3(ioc, rp::endpoint()); +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + rp::socket::native_handle_type native_socket1 + = ::socket(af_inet, sock_raw, 0); + rp::socket socket4(ioc, rp(af_inet, ipproto_icmp), native_socket1); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#if defined(BOOST_ASIO_HAS_MOVE) + rp::socket socket5(std::move(socket4)); + boost::asio::ip::icmp::socket icmp_socket(ioc); + rp::socket socket6(std::move(icmp_socket)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_datagram_socket operators. + +#if defined(BOOST_ASIO_HAS_MOVE) + socket1 = rp::socket(ioc); + socket1 = std::move(socket2); + socket1 = boost::asio::ip::icmp::socket(ioc); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_io_object functions. + + rp::socket::executor_type ex = socket1.get_executor(); + (void)ex; + + // basic_socket functions. + + rp::socket::lowest_layer_type& lowest_layer = socket1.lowest_layer(); + (void)lowest_layer; + + socket1.open(rp(af_inet, ipproto_icmp)); + socket1.open(rp(af_inet, ipproto_icmp), ec); + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + rp::socket::native_handle_type native_socket2 + = ::socket(af_inet, sock_raw, 0); + socket1.assign(rp(af_inet, ipproto_icmp), native_socket2); + rp::socket::native_handle_type native_socket3 + = ::socket(af_inet, sock_raw, 0); + socket1.assign(rp(af_inet, ipproto_icmp), native_socket3, ec); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + + bool is_open = socket1.is_open(); + (void)is_open; + + socket1.close(); + socket1.close(ec); + + rp::socket::native_handle_type native_socket4 = socket1.native_handle(); + (void)native_socket4; + + socket1.cancel(); + socket1.cancel(ec); + + bool at_mark1 = socket1.at_mark(); + (void)at_mark1; + bool at_mark2 = socket1.at_mark(ec); + (void)at_mark2; + + std::size_t available1 = socket1.available(); + (void)available1; + std::size_t available2 = socket1.available(ec); + (void)available2; + + socket1.bind(rp::endpoint()); + socket1.bind(rp::endpoint(), ec); + + socket1.connect(rp::endpoint()); + socket1.connect(rp::endpoint(), ec); + + socket1.async_connect(rp::endpoint(), connect_handler); + + socket1.set_option(socket_option); + socket1.set_option(socket_option, ec); + + socket1.get_option(socket_option); + socket1.get_option(socket_option, ec); + + socket1.io_control(io_control_command); + socket1.io_control(io_control_command, ec); + + rp::endpoint endpoint1 = socket1.local_endpoint(); + (void)endpoint1; + rp::endpoint endpoint2 = socket1.local_endpoint(ec); + (void)endpoint2; + + rp::endpoint endpoint3 = socket1.remote_endpoint(); + (void)endpoint3; + rp::endpoint endpoint4 = socket1.remote_endpoint(ec); + (void)endpoint4; + + socket1.shutdown(socket_base::shutdown_both); + socket1.shutdown(socket_base::shutdown_both, ec); + + // basic_raw_socket functions. + + socket1.send(buffer(mutable_char_buffer)); + socket1.send(buffer(const_char_buffer)); + socket1.send(null_buffers()); + socket1.send(buffer(mutable_char_buffer), in_flags); + socket1.send(buffer(const_char_buffer), in_flags); + socket1.send(null_buffers(), in_flags); + socket1.send(buffer(mutable_char_buffer), in_flags, ec); + socket1.send(buffer(const_char_buffer), in_flags, ec); + socket1.send(null_buffers(), in_flags, ec); + + socket1.async_send(buffer(mutable_char_buffer), send_handler); + socket1.async_send(buffer(const_char_buffer), send_handler); + socket1.async_send(null_buffers(), send_handler); + socket1.async_send(buffer(mutable_char_buffer), in_flags, send_handler); + socket1.async_send(buffer(const_char_buffer), in_flags, send_handler); + socket1.async_send(null_buffers(), in_flags, send_handler); + + socket1.send_to(buffer(mutable_char_buffer), + rp::endpoint()); + socket1.send_to(buffer(const_char_buffer), + rp::endpoint()); + socket1.send_to(null_buffers(), + rp::endpoint()); + socket1.send_to(buffer(mutable_char_buffer), + rp::endpoint(), in_flags); + socket1.send_to(buffer(const_char_buffer), + rp::endpoint(), in_flags); + socket1.send_to(null_buffers(), + rp::endpoint(), in_flags); + socket1.send_to(buffer(mutable_char_buffer), + rp::endpoint(), in_flags, ec); + socket1.send_to(buffer(const_char_buffer), + rp::endpoint(), in_flags, ec); + socket1.send_to(null_buffers(), + rp::endpoint(), in_flags, ec); + + socket1.async_send_to(buffer(mutable_char_buffer), + rp::endpoint(), send_handler); + socket1.async_send_to(buffer(const_char_buffer), + rp::endpoint(), send_handler); + socket1.async_send_to(null_buffers(), + rp::endpoint(), send_handler); + socket1.async_send_to(buffer(mutable_char_buffer), + rp::endpoint(), in_flags, send_handler); + socket1.async_send_to(buffer(const_char_buffer), + rp::endpoint(), in_flags, send_handler); + socket1.async_send_to(null_buffers(), + rp::endpoint(), in_flags, send_handler); + + socket1.receive(buffer(mutable_char_buffer)); + socket1.receive(null_buffers()); + socket1.receive(buffer(mutable_char_buffer), in_flags); + socket1.receive(null_buffers(), in_flags); + socket1.receive(buffer(mutable_char_buffer), in_flags, ec); + socket1.receive(null_buffers(), in_flags, ec); + + socket1.async_receive(buffer(mutable_char_buffer), receive_handler); + socket1.async_receive(null_buffers(), receive_handler); + socket1.async_receive(buffer(mutable_char_buffer), in_flags, + receive_handler); + socket1.async_receive(null_buffers(), in_flags, receive_handler); + + rp::endpoint endpoint; + socket1.receive_from(buffer(mutable_char_buffer), endpoint); + socket1.receive_from(null_buffers(), endpoint); + socket1.receive_from(buffer(mutable_char_buffer), endpoint, in_flags); + socket1.receive_from(null_buffers(), endpoint, in_flags); + socket1.receive_from(buffer(mutable_char_buffer), endpoint, in_flags, ec); + socket1.receive_from(null_buffers(), endpoint, in_flags, ec); + + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, receive_handler); + socket1.async_receive_from(null_buffers(), + endpoint, receive_handler); + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, in_flags, receive_handler); + socket1.async_receive_from(null_buffers(), + endpoint, in_flags, receive_handler); + } + catch (std::exception&) + { + } +} + +} // namespace generic_raw_protocol_socket_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "generic/raw_protocol", + BOOST_ASIO_TEST_CASE(generic_raw_protocol_socket_compile::test) +) diff --git a/src/boost/libs/asio/test/generic/seq_packet_protocol.cpp b/src/boost/libs/asio/test/generic/seq_packet_protocol.cpp new file mode 100644 index 000000000..bf6135654 --- /dev/null +++ b/src/boost/libs/asio/test/generic/seq_packet_protocol.cpp @@ -0,0 +1,205 @@ +// +// generic/seq_packet_protocol.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/generic/seq_packet_protocol.hpp> + +#include <cstring> +#include <boost/asio/io_context.hpp> +#include "../unit_test.hpp" + +#if defined(__cplusplus_cli) || defined(__cplusplus_winrt) +# define generic cpp_generic +#endif + +//------------------------------------------------------------------------------ + +// generic_seq_packet_protocol_socket_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// generic::seq_packet_socket::socket compile and link correctly. Runtime +// failures are ignored. + +namespace generic_seq_packet_protocol_socket_compile { + +void connect_handler(const boost::system::error_code&) +{ +} + +void send_handler(const boost::system::error_code&, std::size_t) +{ +} + +void receive_handler(const boost::system::error_code&, std::size_t) +{ +} + +void test() +{ + using namespace boost::asio; + namespace generic = boost::asio::generic; + typedef generic::seq_packet_protocol spp; + + const int af_inet = BOOST_ASIO_OS_DEF(AF_INET); + const int sock_seqpacket = BOOST_ASIO_OS_DEF(SOCK_SEQPACKET); + + try + { + io_context ioc; + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + const socket_base::message_flags in_flags = 0; + socket_base::message_flags out_flags = 0; + socket_base::send_buffer_size socket_option; + socket_base::bytes_readable io_control_command; + boost::system::error_code ec; + + // basic_seq_packet_socket constructors. + + spp::socket socket1(ioc); + spp::socket socket2(ioc, spp(af_inet, 0)); + spp::socket socket3(ioc, spp::endpoint()); +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + spp::socket::native_handle_type native_socket1 + = ::socket(af_inet, sock_seqpacket, 0); + spp::socket socket4(ioc, spp(af_inet, 0), native_socket1); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#if defined(BOOST_ASIO_HAS_MOVE) + spp::socket socket5(std::move(socket4)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_seq_packet_socket operators. + +#if defined(BOOST_ASIO_HAS_MOVE) + socket1 = spp::socket(ioc); + socket1 = std::move(socket2); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_io_object functions. + + spp::socket::executor_type ex = socket1.get_executor(); + (void)ex; + + // basic_socket functions. + + spp::socket::lowest_layer_type& lowest_layer = socket1.lowest_layer(); + (void)lowest_layer; + + socket1.open(spp(af_inet, 0)); + socket1.open(spp(af_inet, 0), ec); + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + spp::socket::native_handle_type native_socket2 + = ::socket(af_inet, sock_seqpacket, 0); + socket1.assign(spp(af_inet, 0), native_socket2); + spp::socket::native_handle_type native_socket3 + = ::socket(af_inet, sock_seqpacket, 0); + socket1.assign(spp(af_inet, 0), native_socket3, ec); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + + bool is_open = socket1.is_open(); + (void)is_open; + + socket1.close(); + socket1.close(ec); + + spp::socket::native_handle_type native_socket4 = socket1.native_handle(); + (void)native_socket4; + + socket1.cancel(); + socket1.cancel(ec); + + bool at_mark1 = socket1.at_mark(); + (void)at_mark1; + bool at_mark2 = socket1.at_mark(ec); + (void)at_mark2; + + std::size_t available1 = socket1.available(); + (void)available1; + std::size_t available2 = socket1.available(ec); + (void)available2; + + socket1.bind(spp::endpoint()); + socket1.bind(spp::endpoint(), ec); + + socket1.connect(spp::endpoint()); + socket1.connect(spp::endpoint(), ec); + + socket1.async_connect(spp::endpoint(), connect_handler); + + socket1.set_option(socket_option); + socket1.set_option(socket_option, ec); + + socket1.get_option(socket_option); + socket1.get_option(socket_option, ec); + + socket1.io_control(io_control_command); + socket1.io_control(io_control_command, ec); + + spp::endpoint endpoint1 = socket1.local_endpoint(); + (void)endpoint1; + spp::endpoint endpoint2 = socket1.local_endpoint(ec); + (void)endpoint2; + + spp::endpoint endpoint3 = socket1.remote_endpoint(); + (void)endpoint3; + spp::endpoint endpoint4 = socket1.remote_endpoint(ec); + (void)endpoint4; + + socket1.shutdown(socket_base::shutdown_both); + socket1.shutdown(socket_base::shutdown_both, ec); + + // basic_seq_packet_socket functions. + + socket1.send(buffer(mutable_char_buffer), in_flags); + socket1.send(buffer(const_char_buffer), in_flags); + socket1.send(null_buffers(), in_flags); + socket1.send(buffer(mutable_char_buffer), in_flags, ec); + socket1.send(buffer(const_char_buffer), in_flags, ec); + socket1.send(null_buffers(), in_flags, ec); + + socket1.async_send(buffer(mutable_char_buffer), in_flags, send_handler); + socket1.async_send(buffer(const_char_buffer), in_flags, send_handler); + socket1.async_send(null_buffers(), in_flags, send_handler); + + socket1.receive(buffer(mutable_char_buffer), out_flags); + socket1.receive(null_buffers(), out_flags); + socket1.receive(buffer(mutable_char_buffer), in_flags, out_flags); + socket1.receive(null_buffers(), in_flags, out_flags); + socket1.receive(buffer(mutable_char_buffer), in_flags, out_flags, ec); + socket1.receive(null_buffers(), in_flags, out_flags, ec); + + socket1.async_receive(buffer(mutable_char_buffer), out_flags, + receive_handler); + socket1.async_receive(null_buffers(), out_flags, receive_handler); + socket1.async_receive(buffer(mutable_char_buffer), in_flags, + out_flags, receive_handler); + socket1.async_receive(null_buffers(), in_flags, out_flags, receive_handler); + } + catch (std::exception&) + { + } +} + +} // namespace generic_seq_packet_protocol_socket_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "generic/seq_packet_protocol", + BOOST_ASIO_TEST_CASE(generic_seq_packet_protocol_socket_compile::test) +) diff --git a/src/boost/libs/asio/test/generic/stream_protocol.cpp b/src/boost/libs/asio/test/generic/stream_protocol.cpp new file mode 100644 index 000000000..23176677b --- /dev/null +++ b/src/boost/libs/asio/test/generic/stream_protocol.cpp @@ -0,0 +1,248 @@ +// +// generic/stream_protocol.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/generic/stream_protocol.hpp> + +#include <cstring> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include "../unit_test.hpp" + +#if defined(__cplusplus_cli) || defined(__cplusplus_winrt) +# define generic cpp_generic +#endif + +//------------------------------------------------------------------------------ + +// generic_stream_protocol_socket_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// generic::stream_protocol::socket compile and link correctly. Runtime +// failures are ignored. + +namespace generic_stream_protocol_socket_compile { + +void connect_handler(const boost::system::error_code&) +{ +} + +void send_handler(const boost::system::error_code&, std::size_t) +{ +} + +void receive_handler(const boost::system::error_code&, std::size_t) +{ +} + +void write_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void read_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void test() +{ + using namespace boost::asio; + namespace generic = boost::asio::generic; + typedef generic::stream_protocol sp; + + const int af_inet = BOOST_ASIO_OS_DEF(AF_INET); + const int ipproto_tcp = BOOST_ASIO_OS_DEF(IPPROTO_TCP); + const int sock_stream = BOOST_ASIO_OS_DEF(SOCK_STREAM); + + try + { + io_context ioc; + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + socket_base::message_flags in_flags = 0; + socket_base::keep_alive socket_option; + socket_base::bytes_readable io_control_command; + boost::system::error_code ec; + + // basic_stream_socket constructors. + + sp::socket socket1(ioc); + sp::socket socket2(ioc, sp(af_inet, ipproto_tcp)); + sp::socket socket3(ioc, sp::endpoint()); +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + Windows::Networking::Sockets::StreamSocket^ native_socket1 = nullptr; +#else // defined(BOOST_ASIO_WINDOWS_RUNTIME) + sp::socket::native_handle_type native_socket1 + = ::socket(af_inet, sock_stream, 0); +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + sp::socket socket4(ioc, sp(af_inet, ipproto_tcp), native_socket1); + +#if defined(BOOST_ASIO_HAS_MOVE) + sp::socket socket5(std::move(socket4)); + boost::asio::ip::tcp::socket tcp_socket(ioc); + sp::socket socket6(std::move(tcp_socket)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_stream_socket operators. + +#if defined(BOOST_ASIO_HAS_MOVE) + socket1 = sp::socket(ioc); + socket1 = std::move(socket2); + socket1 = boost::asio::ip::tcp::socket(ioc); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_io_object functions. + + sp::socket::executor_type ex = socket1.get_executor(); + (void)ex; + + // basic_socket functions. + + sp::socket::lowest_layer_type& lowest_layer = socket1.lowest_layer(); + (void)lowest_layer; + + socket1.open(sp(af_inet, ipproto_tcp)); + socket1.open(sp(af_inet, ipproto_tcp), ec); + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + Windows::Networking::Sockets::StreamSocket^ native_socket2 = nullptr; +#else // defined(BOOST_ASIO_WINDOWS_RUNTIME) + sp::socket::native_handle_type native_socket2 + = ::socket(af_inet, sock_stream, 0); +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + socket1.assign(sp(af_inet, ipproto_tcp), native_socket2); +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + Windows::Networking::Sockets::StreamSocket^ native_socket3 = nullptr; +#else // defined(BOOST_ASIO_WINDOWS_RUNTIME) + sp::socket::native_handle_type native_socket3 + = ::socket(af_inet, sock_stream, 0); +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + socket1.assign(sp(af_inet, ipproto_tcp), native_socket3, ec); + + bool is_open = socket1.is_open(); + (void)is_open; + + socket1.close(); + socket1.close(ec); + + sp::socket::native_handle_type native_socket4 = socket1.native_handle(); + (void)native_socket4; + + socket1.cancel(); + socket1.cancel(ec); + + bool at_mark1 = socket1.at_mark(); + (void)at_mark1; + bool at_mark2 = socket1.at_mark(ec); + (void)at_mark2; + + std::size_t available1 = socket1.available(); + (void)available1; + std::size_t available2 = socket1.available(ec); + (void)available2; + + socket1.bind(sp::endpoint()); + socket1.bind(sp::endpoint(), ec); + + socket1.connect(sp::endpoint()); + socket1.connect(sp::endpoint(), ec); + + socket1.async_connect(sp::endpoint(), connect_handler); + + socket1.set_option(socket_option); + socket1.set_option(socket_option, ec); + + socket1.get_option(socket_option); + socket1.get_option(socket_option, ec); + + socket1.io_control(io_control_command); + socket1.io_control(io_control_command, ec); + + sp::endpoint endpoint1 = socket1.local_endpoint(); + (void)endpoint1; + sp::endpoint endpoint2 = socket1.local_endpoint(ec); + (void)endpoint2; + + sp::endpoint endpoint3 = socket1.remote_endpoint(); + (void)endpoint3; + sp::endpoint endpoint4 = socket1.remote_endpoint(ec); + (void)endpoint4; + + socket1.shutdown(socket_base::shutdown_both); + socket1.shutdown(socket_base::shutdown_both, ec); + + // basic_stream_socket functions. + + socket1.send(buffer(mutable_char_buffer)); + socket1.send(buffer(const_char_buffer)); + socket1.send(null_buffers()); + socket1.send(buffer(mutable_char_buffer), in_flags); + socket1.send(buffer(const_char_buffer), in_flags); + socket1.send(null_buffers(), in_flags); + socket1.send(buffer(mutable_char_buffer), in_flags, ec); + socket1.send(buffer(const_char_buffer), in_flags, ec); + socket1.send(null_buffers(), in_flags, ec); + + socket1.async_send(buffer(mutable_char_buffer), send_handler); + socket1.async_send(buffer(const_char_buffer), send_handler); + socket1.async_send(null_buffers(), send_handler); + socket1.async_send(buffer(mutable_char_buffer), in_flags, send_handler); + socket1.async_send(buffer(const_char_buffer), in_flags, send_handler); + socket1.async_send(null_buffers(), in_flags, send_handler); + + socket1.receive(buffer(mutable_char_buffer)); + socket1.receive(null_buffers()); + socket1.receive(buffer(mutable_char_buffer), in_flags); + socket1.receive(null_buffers(), in_flags); + socket1.receive(buffer(mutable_char_buffer), in_flags, ec); + socket1.receive(null_buffers(), in_flags, ec); + + socket1.async_receive(buffer(mutable_char_buffer), receive_handler); + socket1.async_receive(null_buffers(), receive_handler); + socket1.async_receive(buffer(mutable_char_buffer), in_flags, + receive_handler); + socket1.async_receive(null_buffers(), in_flags, receive_handler); + + socket1.write_some(buffer(mutable_char_buffer)); + socket1.write_some(buffer(const_char_buffer)); + socket1.write_some(null_buffers()); + socket1.write_some(buffer(mutable_char_buffer), ec); + socket1.write_some(buffer(const_char_buffer), ec); + socket1.write_some(null_buffers(), ec); + + socket1.async_write_some(buffer(mutable_char_buffer), write_some_handler); + socket1.async_write_some(buffer(const_char_buffer), write_some_handler); + socket1.async_write_some(null_buffers(), write_some_handler); + + socket1.read_some(buffer(mutable_char_buffer)); + socket1.read_some(buffer(mutable_char_buffer), ec); + socket1.read_some(null_buffers(), ec); + + socket1.async_read_some(buffer(mutable_char_buffer), read_some_handler); + socket1.async_read_some(null_buffers(), read_some_handler); + } + catch (std::exception&) + { + } +} + +} // namespace generic_stream_protocol_socket_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "generic/stream_protocol", + BOOST_ASIO_TEST_CASE(generic_stream_protocol_socket_compile::test) +) diff --git a/src/boost/libs/asio/test/high_resolution_timer.cpp b/src/boost/libs/asio/test/high_resolution_timer.cpp new file mode 100644 index 000000000..a667f872c --- /dev/null +++ b/src/boost/libs/asio/test/high_resolution_timer.cpp @@ -0,0 +1,30 @@ +// +// high_resolution_timer.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Prevent link dependency on the Boost.System library. +#if !defined(BOOST_SYSTEM_NO_DEPRECATED) +#define BOOST_SYSTEM_NO_DEPRECATED +#endif // !defined(BOOST_SYSTEM_NO_DEPRECATED) + +// Test that header file is self-contained. +#include <boost/asio/high_resolution_timer.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "high_resolution_timer", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/io_context.cpp b/src/boost/libs/asio/test/io_context.cpp new file mode 100644 index 000000000..7b2ff982f --- /dev/null +++ b/src/boost/libs/asio/test/io_context.cpp @@ -0,0 +1,362 @@ +// +// io_context.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/io_context.hpp> + +#include <sstream> +#include <boost/asio/bind_executor.hpp> +#include <boost/asio/dispatch.hpp> +#include <boost/asio/post.hpp> +#include <boost/asio/detail/thread.hpp> +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +# include <boost/asio/deadline_timer.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +# include <boost/asio/steady_timer.hpp> +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +using namespace boost::asio; + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = std; +#endif + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +typedef deadline_timer timer; +namespace chronons = boost::posix_time; +#elif defined(BOOST_ASIO_HAS_CHRONO) +typedef steady_timer timer; +namespace chronons = boost::asio::chrono; +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +void increment(int* count) +{ + ++(*count); +} + +void decrement_to_zero(io_context* ioc, int* count) +{ + if (*count > 0) + { + --(*count); + + int before_value = *count; + boost::asio::post(*ioc, bindns::bind(decrement_to_zero, ioc, count)); + + // Handler execution cannot nest, so count value should remain unchanged. + BOOST_ASIO_CHECK(*count == before_value); + } +} + +void nested_decrement_to_zero(io_context* ioc, int* count) +{ + if (*count > 0) + { + --(*count); + + boost::asio::dispatch(*ioc, + bindns::bind(nested_decrement_to_zero, ioc, count)); + + // Handler execution is nested, so count value should now be zero. + BOOST_ASIO_CHECK(*count == 0); + } +} + +void sleep_increment(io_context* ioc, int* count) +{ + timer t(*ioc, chronons::seconds(2)); + t.wait(); + + if (++(*count) < 3) + boost::asio::post(*ioc, bindns::bind(sleep_increment, ioc, count)); +} + +void start_sleep_increments(io_context* ioc, int* count) +{ + // Give all threads a chance to start. + timer t(*ioc, chronons::seconds(2)); + t.wait(); + + // Start the first of three increments. + boost::asio::post(*ioc, bindns::bind(sleep_increment, ioc, count)); +} + +void throw_exception() +{ + throw 1; +} + +void io_context_run(io_context* ioc) +{ + ioc->run(); +} + +void io_context_test() +{ + io_context ioc; + int count = 0; + + boost::asio::post(ioc, bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + boost::asio::post(ioc, bindns::bind(increment, &count)); + boost::asio::post(ioc, bindns::bind(increment, &count)); + boost::asio::post(ioc, bindns::bind(increment, &count)); + boost::asio::post(ioc, bindns::bind(increment, &count)); + boost::asio::post(ioc, bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 5); + + count = 0; + ioc.restart(); + executor_work_guard<io_context::executor_type> w = make_work_guard(ioc); + boost::asio::post(ioc, bindns::bind(&io_context::stop, &ioc)); + BOOST_ASIO_CHECK(!ioc.stopped()); + ioc.run(); + + // The only operation executed should have been to stop run(). + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.restart(); + boost::asio::post(ioc, bindns::bind(increment, &count)); + w.reset(); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 1); + + count = 10; + ioc.restart(); + boost::asio::post(ioc, bindns::bind(decrement_to_zero, &ioc, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 10); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + count = 10; + ioc.restart(); + boost::asio::post(ioc, bindns::bind(nested_decrement_to_zero, &ioc, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 10); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + count = 10; + ioc.restart(); + boost::asio::dispatch(ioc, + bindns::bind(nested_decrement_to_zero, &ioc, &count)); + + // No handlers can be called until run() is called, even though nested + // delivery was specifically allowed in the previous call. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 10); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + + count = 0; + int count2 = 0; + ioc.restart(); + BOOST_ASIO_CHECK(!ioc.stopped()); + boost::asio::post(ioc, bindns::bind(start_sleep_increments, &ioc, &count)); + boost::asio::post(ioc, bindns::bind(start_sleep_increments, &ioc, &count2)); + boost::asio::detail::thread thread1(bindns::bind(io_context_run, &ioc)); + boost::asio::detail::thread thread2(bindns::bind(io_context_run, &ioc)); + thread1.join(); + thread2.join(); + + // The run() calls will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 3); + BOOST_ASIO_CHECK(count2 == 3); + + count = 10; + io_context ioc2; + boost::asio::dispatch(ioc, boost::asio::bind_executor(ioc2, + bindns::bind(decrement_to_zero, &ioc2, &count))); + ioc.restart(); + BOOST_ASIO_CHECK(!ioc.stopped()); + ioc.run(); + + // No decrement_to_zero handlers can be called until run() is called on the + // second io_context object. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 10); + + ioc2.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(count == 0); + + count = 0; + int exception_count = 0; + ioc.restart(); + boost::asio::post(ioc, &throw_exception); + boost::asio::post(ioc, bindns::bind(increment, &count)); + boost::asio::post(ioc, bindns::bind(increment, &count)); + boost::asio::post(ioc, &throw_exception); + boost::asio::post(ioc, bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(!ioc.stopped()); + BOOST_ASIO_CHECK(count == 0); + BOOST_ASIO_CHECK(exception_count == 0); + + for (;;) + { + try + { + ioc.run(); + break; + } + catch (int) + { + ++exception_count; + } + } + + // The run() calls will not return until all work has finished. + BOOST_ASIO_CHECK(ioc.stopped()); + BOOST_ASIO_CHECK(count == 3); + BOOST_ASIO_CHECK(exception_count == 2); +} + +class test_service : public boost::asio::io_context::service +{ +public: + static boost::asio::io_context::id id; + test_service(boost::asio::io_context& s) + : boost::asio::io_context::service(s) {} +private: + virtual void shutdown_service() {} +}; + +boost::asio::io_context::id test_service::id; + +void io_context_service_test() +{ + boost::asio::io_context ioc1; + boost::asio::io_context ioc2; + boost::asio::io_context ioc3; + + // Implicit service registration. + + boost::asio::use_service<test_service>(ioc1); + + BOOST_ASIO_CHECK(boost::asio::has_service<test_service>(ioc1)); + + test_service* svc1 = new test_service(ioc1); + try + { + boost::asio::add_service(ioc1, svc1); + BOOST_ASIO_ERROR("add_service did not throw"); + } + catch (boost::asio::service_already_exists&) + { + } + delete svc1; + + // Explicit service registration. + + test_service* svc2 = new test_service(ioc2); + boost::asio::add_service(ioc2, svc2); + + BOOST_ASIO_CHECK(boost::asio::has_service<test_service>(ioc2)); + BOOST_ASIO_CHECK(&boost::asio::use_service<test_service>(ioc2) == svc2); + + test_service* svc3 = new test_service(ioc2); + try + { + boost::asio::add_service(ioc2, svc3); + BOOST_ASIO_ERROR("add_service did not throw"); + } + catch (boost::asio::service_already_exists&) + { + } + delete svc3; + + // Explicit registration with invalid owner. + + test_service* svc4 = new test_service(ioc2); + try + { + boost::asio::add_service(ioc3, svc4); + BOOST_ASIO_ERROR("add_service did not throw"); + } + catch (boost::asio::invalid_service_owner&) + { + } + delete svc4; + + BOOST_ASIO_CHECK(!boost::asio::has_service<test_service>(ioc3)); +} + +BOOST_ASIO_TEST_SUITE +( + "io_context", + BOOST_ASIO_TEST_CASE(io_context_test) + BOOST_ASIO_TEST_CASE(io_context_service_test) +) diff --git a/src/boost/libs/asio/test/io_context_strand.cpp b/src/boost/libs/asio/test/io_context_strand.cpp new file mode 100644 index 000000000..fec4f3765 --- /dev/null +++ b/src/boost/libs/asio/test/io_context_strand.cpp @@ -0,0 +1,325 @@ +// +// io_context_strand.cpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/io_context_strand.hpp> + +#include <sstream> +#include <boost/asio/io_context.hpp> +#include <boost/asio/dispatch.hpp> +#include <boost/asio/post.hpp> +#include <boost/asio/detail/thread.hpp> +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +# include <boost/asio/deadline_timer.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +# include <boost/asio/steady_timer.hpp> +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +using namespace boost::asio; + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = std; +#endif + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +typedef deadline_timer timer; +namespace chronons = boost::posix_time; +#elif defined(BOOST_ASIO_HAS_CHRONO) +typedef steady_timer timer; +namespace chronons = boost::asio::chrono; +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +void increment(int* count) +{ + ++(*count); +} + +void increment_without_lock(io_context::strand* s, int* count) +{ + BOOST_ASIO_CHECK(!s->running_in_this_thread()); + + int original_count = *count; + + dispatch(*s, bindns::bind(increment, count)); + + // No other functions are currently executing through the locking dispatcher, + // so the previous call to dispatch should have successfully nested. + BOOST_ASIO_CHECK(*count == original_count + 1); +} + +void increment_with_lock(io_context::strand* s, int* count) +{ + BOOST_ASIO_CHECK(s->running_in_this_thread()); + + int original_count = *count; + + dispatch(*s, bindns::bind(increment, count)); + + // The current function already holds the strand's lock, so the + // previous call to dispatch should have successfully nested. + BOOST_ASIO_CHECK(*count == original_count + 1); +} + +void sleep_increment(io_context* ioc, int* count) +{ + timer t(*ioc, chronons::seconds(2)); + t.wait(); + + ++(*count); +} + +void increment_by_a(int* count, int a) +{ + (*count) += a; +} + +void increment_by_a_b(int* count, int a, int b) +{ + (*count) += a + b; +} + +void increment_by_a_b_c(int* count, int a, int b, int c) +{ + (*count) += a + b + c; +} + +void increment_by_a_b_c_d(int* count, int a, int b, int c, int d) +{ + (*count) += a + b + c + d; +} + +void start_sleep_increments(io_context* ioc, io_context::strand* s, int* count) +{ + // Give all threads a chance to start. + timer t(*ioc, chronons::seconds(2)); + t.wait(); + + // Start three increments. + post(*s, bindns::bind(sleep_increment, ioc, count)); + post(*s, bindns::bind(sleep_increment, ioc, count)); + post(*s, bindns::bind(sleep_increment, ioc, count)); +} + +void throw_exception() +{ + throw 1; +} + +void io_context_run(io_context* ioc) +{ + ioc->run(); +} + +void strand_test() +{ + io_context ioc; + io_context::strand s(ioc); + int count = 0; + + post(ioc, bindns::bind(increment_without_lock, &s, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + post(s, bindns::bind(increment_with_lock, &s, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + post(ioc, bindns::bind(start_sleep_increments, &ioc, &s, &count)); + boost::asio::detail::thread thread1(bindns::bind(io_context_run, &ioc)); + boost::asio::detail::thread thread2(bindns::bind(io_context_run, &ioc)); + + // Check all events run one after another even though there are two threads. + timer timer1(ioc, chronons::seconds(3)); + timer1.wait(); + BOOST_ASIO_CHECK(count == 0); +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + timer1.expires_at(timer1.expires_at() + chronons::seconds(2)); +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + timer1.expires_at(timer1.expiry() + chronons::seconds(2)); +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + timer1.wait(); + BOOST_ASIO_CHECK(count == 1); +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + timer1.expires_at(timer1.expires_at() + chronons::seconds(2)); +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + timer1.expires_at(timer1.expiry() + chronons::seconds(2)); +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + timer1.wait(); + BOOST_ASIO_CHECK(count == 2); + + thread1.join(); + thread2.join(); + + // The run() calls will not return until all work has finished. + BOOST_ASIO_CHECK(count == 3); + + count = 0; + int exception_count = 0; + ioc.restart(); + post(s, throw_exception); + post(s, bindns::bind(increment, &count)); + post(s, bindns::bind(increment, &count)); + post(s, throw_exception); + post(s, bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(count == 0); + BOOST_ASIO_CHECK(exception_count == 0); + + for (;;) + { + try + { + ioc.run(); + break; + } + catch (int) + { + ++exception_count; + } + } + + // The run() calls will not return until all work has finished. + BOOST_ASIO_CHECK(count == 3); + BOOST_ASIO_CHECK(exception_count == 2); + + count = 0; + ioc.restart(); + + // Check for clean shutdown when handlers posted through an orphaned strand + // are abandoned. + { + io_context::strand s2(ioc); + post(s2, bindns::bind(increment, &count)); + post(s2, bindns::bind(increment, &count)); + post(s2, bindns::bind(increment, &count)); + } + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(count == 0); +} + +void strand_wrap_test() +{ +#if !defined(BOOST_ASIO_NO_DEPRECATED) + io_context ioc; + io_context::strand s(ioc); + int count = 0; + + s.wrap(bindns::bind(increment, &count))(); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(count == 0); + + ioc.restart(); + ioc.run(); + + // The run() calls will not return until all work has finished. + BOOST_ASIO_CHECK(count == 1); + + count = 0; + s.wrap(increment)(&count); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(count == 0); + + ioc.restart(); + ioc.run(); + + // The run() calls will not return until all work has finished. + BOOST_ASIO_CHECK(count == 1); + + count = 0; + s.wrap(increment_by_a)(&count, 1); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(count == 0); + + ioc.restart(); + ioc.run(); + + // The run() calls will not return until all work has finished. + BOOST_ASIO_CHECK(count == 1); + + count = 0; + s.wrap(increment_by_a_b)(&count, 1, 2); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(count == 0); + + ioc.restart(); + ioc.run(); + + // The run() calls will not return until all work has finished. + BOOST_ASIO_CHECK(count == 3); + + count = 0; + s.wrap(increment_by_a_b_c)(&count, 1, 2, 3); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(count == 0); + + ioc.restart(); + ioc.run(); + + // The run() calls will not return until all work has finished. + BOOST_ASIO_CHECK(count == 6); + + count = 0; + s.wrap(increment_by_a_b_c_d)(&count, 1, 2, 3, 4); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(count == 0); + + ioc.restart(); + ioc.run(); + + // The run() calls will not return until all work has finished. + BOOST_ASIO_CHECK(count == 10); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) +} + +BOOST_ASIO_TEST_SUITE +( + "strand", + BOOST_ASIO_TEST_CASE(strand_test) + BOOST_ASIO_TEST_CASE(strand_wrap_test) +) diff --git a/src/boost/libs/asio/test/ip/address.cpp b/src/boost/libs/asio/test/ip/address.cpp new file mode 100644 index 000000000..c4fc82267 --- /dev/null +++ b/src/boost/libs/asio/test/ip/address.cpp @@ -0,0 +1,144 @@ +// +// address.cpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/address.hpp> + +#include "../unit_test.hpp" +#include <sstream> + +//------------------------------------------------------------------------------ + +// ip_address_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::address compile and link correctly. Runtime failures are ignored. + +namespace ip_address_compile { + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + boost::system::error_code ec; + + // address constructors. + + ip::address addr1; + const ip::address_v4 const_addr_v4; + ip::address addr2(const_addr_v4); + const ip::address_v6 const_addr_v6; + ip::address addr3(const_addr_v6); + + // address functions. + + bool b = addr1.is_v4(); + (void)b; + + b = addr1.is_v6(); + (void)b; + + b = addr1.is_loopback(); + (void)b; + + b = addr1.is_unspecified(); + (void)b; + + b = addr1.is_multicast(); + (void)b; + + ip::address_v4 addr_v4_value = addr1.to_v4(); + (void)addr_v4_value; + + ip::address_v6 addr_v6_value = addr1.to_v6(); + (void)addr_v6_value; + + std::string string_value = addr1.to_string(); +#if !defined(BOOST_ASIO_NO_DEPRECATED) + string_value = addr1.to_string(ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + // address static functions. + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + addr1 = ip::address::from_string("127.0.0.1"); + addr1 = ip::address::from_string("127.0.0.1", ec); + addr1 = ip::address::from_string(string_value); + addr1 = ip::address::from_string(string_value, ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + // address comparisons. + + b = (addr1 == addr2); + (void)b; + + b = (addr1 != addr2); + (void)b; + + b = (addr1 < addr2); + (void)b; + + b = (addr1 > addr2); + (void)b; + + b = (addr1 <= addr2); + (void)b; + + b = (addr1 >= addr2); + (void)b; + + // address creation functions. + + addr1 = ip::make_address("127.0.0.1"); + addr1 = ip::make_address("127.0.0.1", ec); + addr1 = ip::make_address(string_value); + addr1 = ip::make_address(string_value, ec); +#if defined(BOOST_ASIO_HAS_STRING_VIEW) +# if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + std::string_view string_view_value("127.0.0.1"); +# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + std::experimental::string_view string_view_value("127.0.0.1"); +# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + addr1 = ip::make_address(string_view_value); + addr1 = ip::make_address(string_view_value, ec); +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + + // address I/O. + + std::ostringstream os; + os << addr1; + +#if !defined(BOOST_NO_STD_WSTREAMBUF) + std::wostringstream wos; + wos << addr1; +#endif // !defined(BOOST_NO_STD_WSTREAMBUF) + } + catch (std::exception&) + { + } +} + +} // namespace ip_address_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ip/address", + BOOST_ASIO_TEST_CASE(ip_address_compile::test) +) diff --git a/src/boost/libs/asio/test/ip/address_v4.cpp b/src/boost/libs/asio/test/ip/address_v4.cpp new file mode 100644 index 000000000..abe0c34a4 --- /dev/null +++ b/src/boost/libs/asio/test/ip/address_v4.cpp @@ -0,0 +1,324 @@ +// +// address_v4.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/address_v4.hpp> + +#include "../unit_test.hpp" +#include <sstream> + +//------------------------------------------------------------------------------ + +// ip_address_v4_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::address_v4 compile and link correctly. Runtime failures are ignored. + +namespace ip_address_v4_compile { + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + boost::system::error_code ec; + + // address_v4 constructors. + + ip::address_v4 addr1; + const ip::address_v4::bytes_type const_bytes_value = { { 127, 0, 0, 1 } }; + ip::address_v4 addr2(const_bytes_value); + const unsigned long const_ulong_value = 0x7F000001; + ip::address_v4 addr3(const_ulong_value); + + // address_v4 functions. + + bool b = addr1.is_loopback(); + (void)b; + + b = addr1.is_unspecified(); + (void)b; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + b = addr1.is_class_a(); + (void)b; + + b = addr1.is_class_b(); + (void)b; + + b = addr1.is_class_c(); + (void)b; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + b = addr1.is_multicast(); + (void)b; + + ip::address_v4::bytes_type bytes_value = addr1.to_bytes(); + (void)bytes_value; + + ip::address_v4::uint_type uint_value = addr1.to_uint(); + (void)uint_value; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + unsigned long ulong_value = addr1.to_ulong(); + (void)ulong_value; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + std::string string_value = addr1.to_string(); +#if !defined(BOOST_ASIO_NO_DEPRECATED) + string_value = addr1.to_string(ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + // address_v4 static functions. + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + addr1 = ip::address_v4::from_string("127.0.0.1"); + addr1 = ip::address_v4::from_string("127.0.0.1", ec); + addr1 = ip::address_v4::from_string(string_value); + addr1 = ip::address_v4::from_string(string_value, ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + addr1 = ip::address_v4::any(); + + addr1 = ip::address_v4::loopback(); + + addr1 = ip::address_v4::broadcast(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + addr1 = ip::address_v4::broadcast(addr2, addr3); + + addr1 = ip::address_v4::netmask(addr2); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + // address_v4 comparisons. + + b = (addr1 == addr2); + (void)b; + + b = (addr1 != addr2); + (void)b; + + b = (addr1 < addr2); + (void)b; + + b = (addr1 > addr2); + (void)b; + + b = (addr1 <= addr2); + (void)b; + + b = (addr1 >= addr2); + (void)b; + + // address_v4 creation functions. + + addr1 = ip::make_address_v4(const_bytes_value); + addr1 = ip::make_address_v4(const_ulong_value); + addr1 = ip::make_address_v4("127.0.0.1"); + addr1 = ip::make_address_v4("127.0.0.1", ec); + addr1 = ip::make_address_v4(string_value); + addr1 = ip::make_address_v4(string_value, ec); +#if defined(BOOST_ASIO_HAS_STRING_VIEW) +# if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + std::string_view string_view_value("127.0.0.1"); +# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + std::experimental::string_view string_view_value("127.0.0.1"); +# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + addr1 = ip::make_address_v4(string_view_value); + addr1 = ip::make_address_v4(string_view_value, ec); +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + + // address_v4 I/O. + + std::ostringstream os; + os << addr1; + +#if !defined(BOOST_NO_STD_WSTREAMBUF) + std::wostringstream wos; + wos << addr1; +#endif // !defined(BOOST_NO_STD_WSTREAMBUF) + } + catch (std::exception&) + { + } +} + +} // namespace ip_address_v4_compile + +//------------------------------------------------------------------------------ + +// ip_address_v4_runtime test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that the various public member functions meet the +// necessary postconditions. + +namespace ip_address_v4_runtime { + +void test() +{ + using boost::asio::ip::address_v4; + + address_v4 a1; + BOOST_ASIO_CHECK(a1.to_bytes()[0] == 0); + BOOST_ASIO_CHECK(a1.to_bytes()[1] == 0); + BOOST_ASIO_CHECK(a1.to_bytes()[2] == 0); + BOOST_ASIO_CHECK(a1.to_bytes()[3] == 0); + BOOST_ASIO_CHECK(a1.to_uint() == 0); +#if !defined(BOOST_ASIO_NO_DEPRECATED) + BOOST_ASIO_CHECK(a1.to_ulong() == 0); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + address_v4::bytes_type b1 = {{ 1, 2, 3, 4 }}; + address_v4 a2(b1); + BOOST_ASIO_CHECK(a2.to_bytes()[0] == 1); + BOOST_ASIO_CHECK(a2.to_bytes()[1] == 2); + BOOST_ASIO_CHECK(a2.to_bytes()[2] == 3); + BOOST_ASIO_CHECK(a2.to_bytes()[3] == 4); + BOOST_ASIO_CHECK(((a2.to_uint() >> 24) & 0xFF) == b1[0]); + BOOST_ASIO_CHECK(((a2.to_uint() >> 16) & 0xFF) == b1[1]); + BOOST_ASIO_CHECK(((a2.to_uint() >> 8) & 0xFF) == b1[2]); + BOOST_ASIO_CHECK((a2.to_uint() & 0xFF) == b1[3]); +#if !defined(BOOST_ASIO_NO_DEPRECATED) + BOOST_ASIO_CHECK(((a2.to_ulong() >> 24) & 0xFF) == b1[0]); + BOOST_ASIO_CHECK(((a2.to_ulong() >> 16) & 0xFF) == b1[1]); + BOOST_ASIO_CHECK(((a2.to_ulong() >> 8) & 0xFF) == b1[2]); + BOOST_ASIO_CHECK((a2.to_ulong() & 0xFF) == b1[3]); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + address_v4 a3(0x01020304); + BOOST_ASIO_CHECK(a3.to_bytes()[0] == 1); + BOOST_ASIO_CHECK(a3.to_bytes()[1] == 2); + BOOST_ASIO_CHECK(a3.to_bytes()[2] == 3); + BOOST_ASIO_CHECK(a3.to_bytes()[3] == 4); + BOOST_ASIO_CHECK(a3.to_uint() == 0x01020304); +#if !defined(BOOST_ASIO_NO_DEPRECATED) + BOOST_ASIO_CHECK(a3.to_ulong() == 0x01020304); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + BOOST_ASIO_CHECK(address_v4(0x7F000001).is_loopback()); + BOOST_ASIO_CHECK(address_v4(0x7F000002).is_loopback()); + BOOST_ASIO_CHECK(!address_v4(0x00000000).is_loopback()); + BOOST_ASIO_CHECK(!address_v4(0x01020304).is_loopback()); + + BOOST_ASIO_CHECK(address_v4(0x00000000).is_unspecified()); + BOOST_ASIO_CHECK(!address_v4(0x7F000001).is_unspecified()); + BOOST_ASIO_CHECK(!address_v4(0x01020304).is_unspecified()); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + BOOST_ASIO_CHECK(address_v4(0x01000000).is_class_a()); + BOOST_ASIO_CHECK(address_v4(0x7F000000).is_class_a()); + BOOST_ASIO_CHECK(!address_v4(0x80000000).is_class_a()); + BOOST_ASIO_CHECK(!address_v4(0xBFFF0000).is_class_a()); + BOOST_ASIO_CHECK(!address_v4(0xC0000000).is_class_a()); + BOOST_ASIO_CHECK(!address_v4(0xDFFFFF00).is_class_a()); + BOOST_ASIO_CHECK(!address_v4(0xE0000000).is_class_a()); + BOOST_ASIO_CHECK(!address_v4(0xEFFFFFFF).is_class_a()); + BOOST_ASIO_CHECK(!address_v4(0xF0000000).is_class_a()); + BOOST_ASIO_CHECK(!address_v4(0xFFFFFFFF).is_class_a()); + + BOOST_ASIO_CHECK(!address_v4(0x01000000).is_class_b()); + BOOST_ASIO_CHECK(!address_v4(0x7F000000).is_class_b()); + BOOST_ASIO_CHECK(address_v4(0x80000000).is_class_b()); + BOOST_ASIO_CHECK(address_v4(0xBFFF0000).is_class_b()); + BOOST_ASIO_CHECK(!address_v4(0xC0000000).is_class_b()); + BOOST_ASIO_CHECK(!address_v4(0xDFFFFF00).is_class_b()); + BOOST_ASIO_CHECK(!address_v4(0xE0000000).is_class_b()); + BOOST_ASIO_CHECK(!address_v4(0xEFFFFFFF).is_class_b()); + BOOST_ASIO_CHECK(!address_v4(0xF0000000).is_class_b()); + BOOST_ASIO_CHECK(!address_v4(0xFFFFFFFF).is_class_b()); + + BOOST_ASIO_CHECK(!address_v4(0x01000000).is_class_c()); + BOOST_ASIO_CHECK(!address_v4(0x7F000000).is_class_c()); + BOOST_ASIO_CHECK(!address_v4(0x80000000).is_class_c()); + BOOST_ASIO_CHECK(!address_v4(0xBFFF0000).is_class_c()); + BOOST_ASIO_CHECK(address_v4(0xC0000000).is_class_c()); + BOOST_ASIO_CHECK(address_v4(0xDFFFFF00).is_class_c()); + BOOST_ASIO_CHECK(!address_v4(0xE0000000).is_class_c()); + BOOST_ASIO_CHECK(!address_v4(0xEFFFFFFF).is_class_c()); + BOOST_ASIO_CHECK(!address_v4(0xF0000000).is_class_c()); + BOOST_ASIO_CHECK(!address_v4(0xFFFFFFFF).is_class_c()); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + BOOST_ASIO_CHECK(!address_v4(0x01000000).is_multicast()); + BOOST_ASIO_CHECK(!address_v4(0x7F000000).is_multicast()); + BOOST_ASIO_CHECK(!address_v4(0x80000000).is_multicast()); + BOOST_ASIO_CHECK(!address_v4(0xBFFF0000).is_multicast()); + BOOST_ASIO_CHECK(!address_v4(0xC0000000).is_multicast()); + BOOST_ASIO_CHECK(!address_v4(0xDFFFFF00).is_multicast()); + BOOST_ASIO_CHECK(address_v4(0xE0000000).is_multicast()); + BOOST_ASIO_CHECK(address_v4(0xEFFFFFFF).is_multicast()); + BOOST_ASIO_CHECK(!address_v4(0xF0000000).is_multicast()); + BOOST_ASIO_CHECK(!address_v4(0xFFFFFFFF).is_multicast()); + + address_v4 a4 = address_v4::any(); + BOOST_ASIO_CHECK(a4.to_bytes()[0] == 0); + BOOST_ASIO_CHECK(a4.to_bytes()[1] == 0); + BOOST_ASIO_CHECK(a4.to_bytes()[2] == 0); + BOOST_ASIO_CHECK(a4.to_bytes()[3] == 0); + BOOST_ASIO_CHECK(a4.to_uint() == 0); +#if !defined(BOOST_ASIO_NO_DEPRECATED) + BOOST_ASIO_CHECK(a4.to_ulong() == 0); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + address_v4 a5 = address_v4::loopback(); + BOOST_ASIO_CHECK(a5.to_bytes()[0] == 0x7F); + BOOST_ASIO_CHECK(a5.to_bytes()[1] == 0); + BOOST_ASIO_CHECK(a5.to_bytes()[2] == 0); + BOOST_ASIO_CHECK(a5.to_bytes()[3] == 0x01); + BOOST_ASIO_CHECK(a5.to_uint() == 0x7F000001); +#if !defined(BOOST_ASIO_NO_DEPRECATED) + BOOST_ASIO_CHECK(a5.to_ulong() == 0x7F000001); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + address_v4 a6 = address_v4::broadcast(); + BOOST_ASIO_CHECK(a6.to_bytes()[0] == 0xFF); + BOOST_ASIO_CHECK(a6.to_bytes()[1] == 0xFF); + BOOST_ASIO_CHECK(a6.to_bytes()[2] == 0xFF); + BOOST_ASIO_CHECK(a6.to_bytes()[3] == 0xFF); + BOOST_ASIO_CHECK(a6.to_uint() == 0xFFFFFFFF); +#if !defined(BOOST_ASIO_NO_DEPRECATED) + BOOST_ASIO_CHECK(a6.to_ulong() == 0xFFFFFFFF); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + address_v4 class_a_net(0xFF000000); + address_v4 class_b_net(0xFFFF0000); + address_v4 class_c_net(0xFFFFFF00); + address_v4 other_net(0xFFFFFFFF); + BOOST_ASIO_CHECK(address_v4::netmask(address_v4(0x01000000)) == class_a_net); + BOOST_ASIO_CHECK(address_v4::netmask(address_v4(0x7F000000)) == class_a_net); + BOOST_ASIO_CHECK(address_v4::netmask(address_v4(0x80000000)) == class_b_net); + BOOST_ASIO_CHECK(address_v4::netmask(address_v4(0xBFFF0000)) == class_b_net); + BOOST_ASIO_CHECK(address_v4::netmask(address_v4(0xC0000000)) == class_c_net); + BOOST_ASIO_CHECK(address_v4::netmask(address_v4(0xDFFFFF00)) == class_c_net); + BOOST_ASIO_CHECK(address_v4::netmask(address_v4(0xE0000000)) == other_net); + BOOST_ASIO_CHECK(address_v4::netmask(address_v4(0xEFFFFFFF)) == other_net); + BOOST_ASIO_CHECK(address_v4::netmask(address_v4(0xF0000000)) == other_net); + BOOST_ASIO_CHECK(address_v4::netmask(address_v4(0xFFFFFFFF)) == other_net); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) +} + +} // namespace ip_address_v4_runtime + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ip/address_v4", + BOOST_ASIO_TEST_CASE(ip_address_v4_compile::test) + BOOST_ASIO_TEST_CASE(ip_address_v4_runtime::test) +) diff --git a/src/boost/libs/asio/test/ip/address_v4_iterator.cpp b/src/boost/libs/asio/test/ip/address_v4_iterator.cpp new file mode 100644 index 000000000..94d847646 --- /dev/null +++ b/src/boost/libs/asio/test/ip/address_v4_iterator.cpp @@ -0,0 +1,27 @@ +// +// address_v4_iterator.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/address_v4_iterator.hpp> + +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ip/address_v4_iterator", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ip/address_v4_range.cpp b/src/boost/libs/asio/test/ip/address_v4_range.cpp new file mode 100644 index 000000000..1ecaf6d03 --- /dev/null +++ b/src/boost/libs/asio/test/ip/address_v4_range.cpp @@ -0,0 +1,27 @@ +// +// address_v4_range.cpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/address_v4_range.hpp> + +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ip/address_v4_range", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ip/address_v6.cpp b/src/boost/libs/asio/test/ip/address_v6.cpp new file mode 100644 index 000000000..7f35071d0 --- /dev/null +++ b/src/boost/libs/asio/test/ip/address_v6.cpp @@ -0,0 +1,409 @@ +// +// address_v6.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/address_v6.hpp> + +#include "../unit_test.hpp" +#include <sstream> + +//------------------------------------------------------------------------------ + +// ip_address_v6_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::address_v6 compile and link correctly. Runtime failures are ignored. + +namespace ip_address_v6_compile { + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + boost::system::error_code ec; + + // address_v6 constructors. + + ip::address_v6 addr1; + const ip::address_v6::bytes_type const_bytes_value = { { 0 } }; + ip::address_v6 addr2(const_bytes_value); + + // address_v6 functions. + + unsigned long scope_id = addr1.scope_id(); + addr1.scope_id(scope_id); + + bool b = addr1.is_unspecified(); + (void)b; + + b = addr1.is_loopback(); + (void)b; + + b = addr1.is_multicast(); + (void)b; + + b = addr1.is_link_local(); + (void)b; + + b = addr1.is_site_local(); + (void)b; + + b = addr1.is_v4_mapped(); + (void)b; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + b = addr1.is_v4_compatible(); + (void)b; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + b = addr1.is_multicast_node_local(); + (void)b; + + b = addr1.is_multicast_link_local(); + (void)b; + + b = addr1.is_multicast_site_local(); + (void)b; + + b = addr1.is_multicast_org_local(); + (void)b; + + b = addr1.is_multicast_global(); + (void)b; + + ip::address_v6::bytes_type bytes_value = addr1.to_bytes(); + (void)bytes_value; + + std::string string_value = addr1.to_string(); +#if !defined(BOOST_ASIO_NO_DEPRECATED) + string_value = addr1.to_string(ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + ip::address_v4 addr3 = addr1.to_v4(); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + // address_v6 static functions. + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + addr1 = ip::address_v6::from_string("0::0"); + addr1 = ip::address_v6::from_string("0::0", ec); + addr1 = ip::address_v6::from_string(string_value); + addr1 = ip::address_v6::from_string(string_value, ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + addr1 = ip::address_v6::any(); + + addr1 = ip::address_v6::loopback(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + addr1 = ip::address_v6::v4_mapped(addr3); + + addr1 = ip::address_v6::v4_compatible(addr3); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + // address_v6 comparisons. + + b = (addr1 == addr2); + (void)b; + + b = (addr1 != addr2); + (void)b; + + b = (addr1 < addr2); + (void)b; + + b = (addr1 > addr2); + (void)b; + + b = (addr1 <= addr2); + (void)b; + + b = (addr1 >= addr2); + (void)b; + + // address_v6 creation functions. + + addr1 = ip::make_address_v6(const_bytes_value, scope_id); + addr1 = ip::make_address_v6("0::0"); + addr1 = ip::make_address_v6("0::0", ec); + addr1 = ip::make_address_v6(string_value); + addr1 = ip::make_address_v6(string_value, ec); +#if defined(BOOST_ASIO_HAS_STRING_VIEW) +# if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + std::string_view string_view_value("0::0"); +# else // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + std::experimental::string_view string_view_value("0::0"); +# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + addr1 = ip::make_address_v6(string_view_value); + addr1 = ip::make_address_v6(string_view_value, ec); +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + + // address_v6 IPv4-mapped conversion. +#if defined(BOOST_ASIO_NO_DEPRECATED) + ip::address_v4 addr3; +#endif // defined(BOOST_ASIO_NO_DEPRECATED) + addr1 = ip::make_address_v6(ip::v4_mapped, addr3); + addr3 = ip::make_address_v4(ip::v4_mapped, addr1); + + // address_v6 I/O. + + std::ostringstream os; + os << addr1; + +#if !defined(BOOST_NO_STD_WSTREAMBUF) + std::wostringstream wos; + wos << addr1; +#endif // !defined(BOOST_NO_STD_WSTREAMBUF) + } + catch (std::exception&) + { + } +} + +} // namespace ip_address_v6_compile + +//------------------------------------------------------------------------------ + +// ip_address_v6_runtime test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that the various public member functions meet the +// necessary postconditions. + +namespace ip_address_v6_runtime { + +void test() +{ + using boost::asio::ip::address_v6; + + address_v6 a1; + BOOST_ASIO_CHECK(a1.is_unspecified()); + BOOST_ASIO_CHECK(a1.scope_id() == 0); + + address_v6::bytes_type b1 = {{ 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }}; + address_v6 a2(b1, 12345); + BOOST_ASIO_CHECK(a2.to_bytes()[0] == 1); + BOOST_ASIO_CHECK(a2.to_bytes()[1] == 2); + BOOST_ASIO_CHECK(a2.to_bytes()[2] == 3); + BOOST_ASIO_CHECK(a2.to_bytes()[3] == 4); + BOOST_ASIO_CHECK(a2.to_bytes()[4] == 5); + BOOST_ASIO_CHECK(a2.to_bytes()[5] == 6); + BOOST_ASIO_CHECK(a2.to_bytes()[6] == 7); + BOOST_ASIO_CHECK(a2.to_bytes()[7] == 8); + BOOST_ASIO_CHECK(a2.to_bytes()[8] == 9); + BOOST_ASIO_CHECK(a2.to_bytes()[9] == 10); + BOOST_ASIO_CHECK(a2.to_bytes()[10] == 11); + BOOST_ASIO_CHECK(a2.to_bytes()[11] == 12); + BOOST_ASIO_CHECK(a2.to_bytes()[12] == 13); + BOOST_ASIO_CHECK(a2.to_bytes()[13] == 14); + BOOST_ASIO_CHECK(a2.to_bytes()[14] == 15); + BOOST_ASIO_CHECK(a2.to_bytes()[15] == 16); + BOOST_ASIO_CHECK(a2.scope_id() == 12345); + + address_v6 a3; + a3.scope_id(12345); + BOOST_ASIO_CHECK(a3.scope_id() == 12345); + + address_v6 unspecified_address; + address_v6::bytes_type loopback_bytes = {{ 0 }}; + loopback_bytes[15] = 1; + address_v6 loopback_address(loopback_bytes); + address_v6::bytes_type link_local_bytes = {{ 0xFE, 0x80, 1 }}; + address_v6 link_local_address(link_local_bytes); + address_v6::bytes_type site_local_bytes = {{ 0xFE, 0xC0, 1 }}; + address_v6 site_local_address(site_local_bytes); + address_v6::bytes_type v4_mapped_bytes = {{ 0 }}; + v4_mapped_bytes[10] = 0xFF, v4_mapped_bytes[11] = 0xFF; + v4_mapped_bytes[12] = 1, v4_mapped_bytes[13] = 2; + v4_mapped_bytes[14] = 3, v4_mapped_bytes[15] = 4; + address_v6 v4_mapped_address(v4_mapped_bytes); + address_v6::bytes_type v4_compat_bytes = {{ 0 }}; + v4_compat_bytes[12] = 1, v4_compat_bytes[13] = 2; + v4_compat_bytes[14] = 3, v4_compat_bytes[15] = 4; + address_v6 v4_compat_address(v4_compat_bytes); + address_v6::bytes_type mcast_global_bytes = {{ 0xFF, 0x0E, 1 }}; + address_v6 mcast_global_address(mcast_global_bytes); + address_v6::bytes_type mcast_link_local_bytes = {{ 0xFF, 0x02, 1 }}; + address_v6 mcast_link_local_address(mcast_link_local_bytes); + address_v6::bytes_type mcast_node_local_bytes = {{ 0xFF, 0x01, 1 }}; + address_v6 mcast_node_local_address(mcast_node_local_bytes); + address_v6::bytes_type mcast_org_local_bytes = {{ 0xFF, 0x08, 1 }}; + address_v6 mcast_org_local_address(mcast_org_local_bytes); + address_v6::bytes_type mcast_site_local_bytes = {{ 0xFF, 0x05, 1 }}; + address_v6 mcast_site_local_address(mcast_site_local_bytes); + + BOOST_ASIO_CHECK(!unspecified_address.is_loopback()); + BOOST_ASIO_CHECK(loopback_address.is_loopback()); + BOOST_ASIO_CHECK(!link_local_address.is_loopback()); + BOOST_ASIO_CHECK(!site_local_address.is_loopback()); + BOOST_ASIO_CHECK(!v4_mapped_address.is_loopback()); + BOOST_ASIO_CHECK(!v4_compat_address.is_loopback()); + BOOST_ASIO_CHECK(!mcast_global_address.is_loopback()); + BOOST_ASIO_CHECK(!mcast_link_local_address.is_loopback()); + BOOST_ASIO_CHECK(!mcast_node_local_address.is_loopback()); + BOOST_ASIO_CHECK(!mcast_org_local_address.is_loopback()); + BOOST_ASIO_CHECK(!mcast_site_local_address.is_loopback()); + + BOOST_ASIO_CHECK(unspecified_address.is_unspecified()); + BOOST_ASIO_CHECK(!loopback_address.is_unspecified()); + BOOST_ASIO_CHECK(!link_local_address.is_unspecified()); + BOOST_ASIO_CHECK(!site_local_address.is_unspecified()); + BOOST_ASIO_CHECK(!v4_mapped_address.is_unspecified()); + BOOST_ASIO_CHECK(!v4_compat_address.is_unspecified()); + BOOST_ASIO_CHECK(!mcast_global_address.is_unspecified()); + BOOST_ASIO_CHECK(!mcast_link_local_address.is_unspecified()); + BOOST_ASIO_CHECK(!mcast_node_local_address.is_unspecified()); + BOOST_ASIO_CHECK(!mcast_org_local_address.is_unspecified()); + BOOST_ASIO_CHECK(!mcast_site_local_address.is_unspecified()); + + BOOST_ASIO_CHECK(!unspecified_address.is_link_local()); + BOOST_ASIO_CHECK(!loopback_address.is_link_local()); + BOOST_ASIO_CHECK(link_local_address.is_link_local()); + BOOST_ASIO_CHECK(!site_local_address.is_link_local()); + BOOST_ASIO_CHECK(!v4_mapped_address.is_link_local()); + BOOST_ASIO_CHECK(!v4_compat_address.is_link_local()); + BOOST_ASIO_CHECK(!mcast_global_address.is_link_local()); + BOOST_ASIO_CHECK(!mcast_link_local_address.is_link_local()); + BOOST_ASIO_CHECK(!mcast_node_local_address.is_link_local()); + BOOST_ASIO_CHECK(!mcast_org_local_address.is_link_local()); + BOOST_ASIO_CHECK(!mcast_site_local_address.is_link_local()); + + BOOST_ASIO_CHECK(!unspecified_address.is_site_local()); + BOOST_ASIO_CHECK(!loopback_address.is_site_local()); + BOOST_ASIO_CHECK(!link_local_address.is_site_local()); + BOOST_ASIO_CHECK(site_local_address.is_site_local()); + BOOST_ASIO_CHECK(!v4_mapped_address.is_site_local()); + BOOST_ASIO_CHECK(!v4_compat_address.is_site_local()); + BOOST_ASIO_CHECK(!mcast_global_address.is_site_local()); + BOOST_ASIO_CHECK(!mcast_link_local_address.is_site_local()); + BOOST_ASIO_CHECK(!mcast_node_local_address.is_site_local()); + BOOST_ASIO_CHECK(!mcast_org_local_address.is_site_local()); + BOOST_ASIO_CHECK(!mcast_site_local_address.is_site_local()); + + BOOST_ASIO_CHECK(!unspecified_address.is_v4_mapped()); + BOOST_ASIO_CHECK(!loopback_address.is_v4_mapped()); + BOOST_ASIO_CHECK(!link_local_address.is_v4_mapped()); + BOOST_ASIO_CHECK(!site_local_address.is_v4_mapped()); + BOOST_ASIO_CHECK(v4_mapped_address.is_v4_mapped()); + BOOST_ASIO_CHECK(!v4_compat_address.is_v4_mapped()); + BOOST_ASIO_CHECK(!mcast_global_address.is_v4_mapped()); + BOOST_ASIO_CHECK(!mcast_link_local_address.is_v4_mapped()); + BOOST_ASIO_CHECK(!mcast_node_local_address.is_v4_mapped()); + BOOST_ASIO_CHECK(!mcast_org_local_address.is_v4_mapped()); + BOOST_ASIO_CHECK(!mcast_site_local_address.is_v4_mapped()); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + BOOST_ASIO_CHECK(!unspecified_address.is_v4_compatible()); + BOOST_ASIO_CHECK(!loopback_address.is_v4_compatible()); + BOOST_ASIO_CHECK(!link_local_address.is_v4_compatible()); + BOOST_ASIO_CHECK(!site_local_address.is_v4_compatible()); + BOOST_ASIO_CHECK(!v4_mapped_address.is_v4_compatible()); + BOOST_ASIO_CHECK(v4_compat_address.is_v4_compatible()); + BOOST_ASIO_CHECK(!mcast_global_address.is_v4_compatible()); + BOOST_ASIO_CHECK(!mcast_link_local_address.is_v4_compatible()); + BOOST_ASIO_CHECK(!mcast_node_local_address.is_v4_compatible()); + BOOST_ASIO_CHECK(!mcast_org_local_address.is_v4_compatible()); + BOOST_ASIO_CHECK(!mcast_site_local_address.is_v4_compatible()); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + BOOST_ASIO_CHECK(!unspecified_address.is_multicast()); + BOOST_ASIO_CHECK(!loopback_address.is_multicast()); + BOOST_ASIO_CHECK(!link_local_address.is_multicast()); + BOOST_ASIO_CHECK(!site_local_address.is_multicast()); + BOOST_ASIO_CHECK(!v4_mapped_address.is_multicast()); + BOOST_ASIO_CHECK(!v4_compat_address.is_multicast()); + BOOST_ASIO_CHECK(mcast_global_address.is_multicast()); + BOOST_ASIO_CHECK(mcast_link_local_address.is_multicast()); + BOOST_ASIO_CHECK(mcast_node_local_address.is_multicast()); + BOOST_ASIO_CHECK(mcast_org_local_address.is_multicast()); + BOOST_ASIO_CHECK(mcast_site_local_address.is_multicast()); + + BOOST_ASIO_CHECK(!unspecified_address.is_multicast_global()); + BOOST_ASIO_CHECK(!loopback_address.is_multicast_global()); + BOOST_ASIO_CHECK(!link_local_address.is_multicast_global()); + BOOST_ASIO_CHECK(!site_local_address.is_multicast_global()); + BOOST_ASIO_CHECK(!v4_mapped_address.is_multicast_global()); + BOOST_ASIO_CHECK(!v4_compat_address.is_multicast_global()); + BOOST_ASIO_CHECK(mcast_global_address.is_multicast_global()); + BOOST_ASIO_CHECK(!mcast_link_local_address.is_multicast_global()); + BOOST_ASIO_CHECK(!mcast_node_local_address.is_multicast_global()); + BOOST_ASIO_CHECK(!mcast_org_local_address.is_multicast_global()); + BOOST_ASIO_CHECK(!mcast_site_local_address.is_multicast_global()); + + BOOST_ASIO_CHECK(!unspecified_address.is_multicast_link_local()); + BOOST_ASIO_CHECK(!loopback_address.is_multicast_link_local()); + BOOST_ASIO_CHECK(!link_local_address.is_multicast_link_local()); + BOOST_ASIO_CHECK(!site_local_address.is_multicast_link_local()); + BOOST_ASIO_CHECK(!v4_mapped_address.is_multicast_link_local()); + BOOST_ASIO_CHECK(!v4_compat_address.is_multicast_link_local()); + BOOST_ASIO_CHECK(!mcast_global_address.is_multicast_link_local()); + BOOST_ASIO_CHECK(mcast_link_local_address.is_multicast_link_local()); + BOOST_ASIO_CHECK(!mcast_node_local_address.is_multicast_link_local()); + BOOST_ASIO_CHECK(!mcast_org_local_address.is_multicast_link_local()); + BOOST_ASIO_CHECK(!mcast_site_local_address.is_multicast_link_local()); + + BOOST_ASIO_CHECK(!unspecified_address.is_multicast_node_local()); + BOOST_ASIO_CHECK(!loopback_address.is_multicast_node_local()); + BOOST_ASIO_CHECK(!link_local_address.is_multicast_node_local()); + BOOST_ASIO_CHECK(!site_local_address.is_multicast_node_local()); + BOOST_ASIO_CHECK(!v4_mapped_address.is_multicast_node_local()); + BOOST_ASIO_CHECK(!v4_compat_address.is_multicast_node_local()); + BOOST_ASIO_CHECK(!mcast_global_address.is_multicast_node_local()); + BOOST_ASIO_CHECK(!mcast_link_local_address.is_multicast_node_local()); + BOOST_ASIO_CHECK(mcast_node_local_address.is_multicast_node_local()); + BOOST_ASIO_CHECK(!mcast_org_local_address.is_multicast_node_local()); + BOOST_ASIO_CHECK(!mcast_site_local_address.is_multicast_node_local()); + + BOOST_ASIO_CHECK(!unspecified_address.is_multicast_org_local()); + BOOST_ASIO_CHECK(!loopback_address.is_multicast_org_local()); + BOOST_ASIO_CHECK(!link_local_address.is_multicast_org_local()); + BOOST_ASIO_CHECK(!site_local_address.is_multicast_org_local()); + BOOST_ASIO_CHECK(!v4_mapped_address.is_multicast_org_local()); + BOOST_ASIO_CHECK(!v4_compat_address.is_multicast_org_local()); + BOOST_ASIO_CHECK(!mcast_global_address.is_multicast_org_local()); + BOOST_ASIO_CHECK(!mcast_link_local_address.is_multicast_org_local()); + BOOST_ASIO_CHECK(!mcast_node_local_address.is_multicast_org_local()); + BOOST_ASIO_CHECK(mcast_org_local_address.is_multicast_org_local()); + BOOST_ASIO_CHECK(!mcast_site_local_address.is_multicast_org_local()); + + BOOST_ASIO_CHECK(!unspecified_address.is_multicast_site_local()); + BOOST_ASIO_CHECK(!loopback_address.is_multicast_site_local()); + BOOST_ASIO_CHECK(!link_local_address.is_multicast_site_local()); + BOOST_ASIO_CHECK(!site_local_address.is_multicast_site_local()); + BOOST_ASIO_CHECK(!v4_mapped_address.is_multicast_site_local()); + BOOST_ASIO_CHECK(!v4_compat_address.is_multicast_site_local()); + BOOST_ASIO_CHECK(!mcast_global_address.is_multicast_site_local()); + BOOST_ASIO_CHECK(!mcast_link_local_address.is_multicast_site_local()); + BOOST_ASIO_CHECK(!mcast_node_local_address.is_multicast_site_local()); + BOOST_ASIO_CHECK(!mcast_org_local_address.is_multicast_site_local()); + BOOST_ASIO_CHECK(mcast_site_local_address.is_multicast_site_local()); + + BOOST_ASIO_CHECK(address_v6::loopback().is_loopback()); +} + +} // namespace ip_address_v6_runtime + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ip/address_v6", + BOOST_ASIO_TEST_CASE(ip_address_v6_compile::test) + BOOST_ASIO_TEST_CASE(ip_address_v6_runtime::test) +) diff --git a/src/boost/libs/asio/test/ip/address_v6_iterator.cpp b/src/boost/libs/asio/test/ip/address_v6_iterator.cpp new file mode 100644 index 000000000..3c0ef1a22 --- /dev/null +++ b/src/boost/libs/asio/test/ip/address_v6_iterator.cpp @@ -0,0 +1,27 @@ +// +// address_v6_iterator.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/address_v6_iterator.hpp> + +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ip/address_v6_iterator", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ip/address_v6_range.cpp b/src/boost/libs/asio/test/ip/address_v6_range.cpp new file mode 100644 index 000000000..b5210031c --- /dev/null +++ b/src/boost/libs/asio/test/ip/address_v6_range.cpp @@ -0,0 +1,27 @@ +// +// address_v6_range.cpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/address_v6_range.hpp> + +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ip/address_v6_range", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ip/basic_endpoint.cpp b/src/boost/libs/asio/test/ip/basic_endpoint.cpp new file mode 100644 index 000000000..f678e74be --- /dev/null +++ b/src/boost/libs/asio/test/ip/basic_endpoint.cpp @@ -0,0 +1,25 @@ +// +// basic_endpoint.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/basic_endpoint.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ip/basic_endpoint", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ip/basic_resolver.cpp b/src/boost/libs/asio/test/ip/basic_resolver.cpp new file mode 100644 index 000000000..ae194bb8e --- /dev/null +++ b/src/boost/libs/asio/test/ip/basic_resolver.cpp @@ -0,0 +1,25 @@ +// +// basic_resolver.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/basic_resolver.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ip/basic_resolver", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ip/basic_resolver_entry.cpp b/src/boost/libs/asio/test/ip/basic_resolver_entry.cpp new file mode 100644 index 000000000..942a4e8e1 --- /dev/null +++ b/src/boost/libs/asio/test/ip/basic_resolver_entry.cpp @@ -0,0 +1,25 @@ +// +// basic_resolver_entry.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/basic_resolver_entry.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ip/basic_resolver_entry", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ip/basic_resolver_iterator.cpp b/src/boost/libs/asio/test/ip/basic_resolver_iterator.cpp new file mode 100644 index 000000000..da15f5682 --- /dev/null +++ b/src/boost/libs/asio/test/ip/basic_resolver_iterator.cpp @@ -0,0 +1,25 @@ +// +// basic_resolver_iterator.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/basic_resolver_iterator.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ip/basic_resolver_iterator", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ip/basic_resolver_query.cpp b/src/boost/libs/asio/test/ip/basic_resolver_query.cpp new file mode 100644 index 000000000..59a26caf4 --- /dev/null +++ b/src/boost/libs/asio/test/ip/basic_resolver_query.cpp @@ -0,0 +1,25 @@ +// +// basic_resolver_query.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/basic_resolver_query.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ip/basic_resolver_query", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ip/host_name.cpp b/src/boost/libs/asio/test/ip/host_name.cpp new file mode 100644 index 000000000..edeeb448d --- /dev/null +++ b/src/boost/libs/asio/test/ip/host_name.cpp @@ -0,0 +1,55 @@ +// +// host_name.cpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/host_name.hpp> + +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +// ip_host_name_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all host_name functions compile and link +// correctly. Runtime failures are ignored. + +namespace ip_host_name_compile { + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + boost::system::error_code ec; + + std::string host_name = ip::host_name(); + std::string host_name2 = ip::host_name(ec); + } + catch (std::exception&) + { + } +} + +} // namespace ip_host_name_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ip/host_name", + BOOST_ASIO_TEST_CASE(ip_host_name_compile::test) +) diff --git a/src/boost/libs/asio/test/ip/icmp.cpp b/src/boost/libs/asio/test/ip/icmp.cpp new file mode 100644 index 000000000..2dd9e331a --- /dev/null +++ b/src/boost/libs/asio/test/ip/icmp.cpp @@ -0,0 +1,577 @@ +// +// icmp.cpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/icmp.hpp> + +#include <cstring> +#include <boost/asio/io_context.hpp> +#include <boost/asio/placeholders.hpp> +#include "../unit_test.hpp" +#include "../archetypes/async_result.hpp" +#include "../archetypes/gettable_socket_option.hpp" +#include "../archetypes/io_control_command.hpp" +#include "../archetypes/settable_socket_option.hpp" + +//------------------------------------------------------------------------------ + +// ip_icmp_socket_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::icmp::socket compile and link correctly. Runtime failures are ignored. + +namespace ip_icmp_socket_compile { + +struct connect_handler +{ + connect_handler() {} + void operator()(const boost::system::error_code&) {} +#if defined(BOOST_ASIO_HAS_MOVE) + connect_handler(connect_handler&&) {} +private: + connect_handler(const connect_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +struct send_handler +{ + send_handler() {} + void operator()(const boost::system::error_code&, std::size_t) {} +#if defined(BOOST_ASIO_HAS_MOVE) + send_handler(send_handler&&) {} +private: + send_handler(const send_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +struct receive_handler +{ + receive_handler() {} + void operator()(const boost::system::error_code&, std::size_t) {} +#if defined(BOOST_ASIO_HAS_MOVE) + receive_handler(receive_handler&&) {} +private: + receive_handler(const receive_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_context ioc; + const io_context::executor_type ioc_ex = ioc.get_executor(); + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + socket_base::message_flags in_flags = 0; + archetypes::settable_socket_option<void> settable_socket_option1; + archetypes::settable_socket_option<int> settable_socket_option2; + archetypes::settable_socket_option<double> settable_socket_option3; + archetypes::gettable_socket_option<void> gettable_socket_option1; + archetypes::gettable_socket_option<int> gettable_socket_option2; + archetypes::gettable_socket_option<double> gettable_socket_option3; + archetypes::io_control_command io_control_command; + archetypes::lazy_handler lazy; + boost::system::error_code ec; + + // basic_datagram_socket constructors. + + ip::icmp::socket socket1(ioc); + ip::icmp::socket socket2(ioc, ip::icmp::v4()); + ip::icmp::socket socket3(ioc, ip::icmp::v6()); + ip::icmp::socket socket4(ioc, ip::icmp::endpoint(ip::icmp::v4(), 0)); + ip::icmp::socket socket5(ioc, ip::icmp::endpoint(ip::icmp::v6(), 0)); +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + ip::icmp::socket::native_handle_type native_socket1 + = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + ip::icmp::socket socket6(ioc, ip::icmp::v4(), native_socket1); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + + ip::icmp::socket socket7(ioc_ex); + ip::icmp::socket socket8(ioc_ex, ip::icmp::v4()); + ip::icmp::socket socket9(ioc_ex, ip::icmp::v6()); + ip::icmp::socket socket10(ioc_ex, ip::icmp::endpoint(ip::icmp::v4(), 0)); + ip::icmp::socket socket11(ioc_ex, ip::icmp::endpoint(ip::icmp::v6(), 0)); +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + ip::icmp::socket::native_handle_type native_socket2 + = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + ip::icmp::socket socket12(ioc_ex, ip::icmp::v4(), native_socket2); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#if defined(BOOST_ASIO_HAS_MOVE) + ip::icmp::socket socket13(std::move(socket6)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_datagram_socket operators. + +#if defined(BOOST_ASIO_HAS_MOVE) + socket1 = ip::icmp::socket(ioc); + socket1 = std::move(socket2); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_io_object functions. + + ip::icmp::socket::executor_type ex = socket1.get_executor(); + (void)ex; + + // basic_socket functions. + + ip::icmp::socket::lowest_layer_type& lowest_layer = socket1.lowest_layer(); + (void)lowest_layer; + + const ip::icmp::socket& socket14 = socket1; + const ip::icmp::socket::lowest_layer_type& lowest_layer2 + = socket14.lowest_layer(); + (void)lowest_layer2; + + socket1.open(ip::icmp::v4()); + socket1.open(ip::icmp::v6()); + socket1.open(ip::icmp::v4(), ec); + socket1.open(ip::icmp::v6(), ec); + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + ip::icmp::socket::native_handle_type native_socket3 + = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + socket1.assign(ip::icmp::v4(), native_socket3); + ip::icmp::socket::native_handle_type native_socket4 + = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + socket1.assign(ip::icmp::v4(), native_socket4, ec); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + + bool is_open = socket1.is_open(); + (void)is_open; + + socket1.close(); + socket1.close(ec); + + socket1.release(); + socket1.release(ec); + + ip::icmp::socket::native_handle_type native_socket5 + = socket1.native_handle(); + (void)native_socket5; + + socket1.cancel(); + socket1.cancel(ec); + + bool at_mark1 = socket1.at_mark(); + (void)at_mark1; + bool at_mark2 = socket1.at_mark(ec); + (void)at_mark2; + + std::size_t available1 = socket1.available(); + (void)available1; + std::size_t available2 = socket1.available(ec); + (void)available2; + + socket1.bind(ip::icmp::endpoint(ip::icmp::v4(), 0)); + socket1.bind(ip::icmp::endpoint(ip::icmp::v6(), 0)); + socket1.bind(ip::icmp::endpoint(ip::icmp::v4(), 0), ec); + socket1.bind(ip::icmp::endpoint(ip::icmp::v6(), 0), ec); + + socket1.connect(ip::icmp::endpoint(ip::icmp::v4(), 0)); + socket1.connect(ip::icmp::endpoint(ip::icmp::v6(), 0)); + socket1.connect(ip::icmp::endpoint(ip::icmp::v4(), 0), ec); + socket1.connect(ip::icmp::endpoint(ip::icmp::v6(), 0), ec); + + socket1.async_connect(ip::icmp::endpoint(ip::icmp::v4(), 0), + connect_handler()); + socket1.async_connect(ip::icmp::endpoint(ip::icmp::v6(), 0), + connect_handler()); + int i1 = socket1.async_connect(ip::icmp::endpoint(ip::icmp::v4(), 0), lazy); + (void)i1; + int i2 = socket1.async_connect(ip::icmp::endpoint(ip::icmp::v6(), 0), lazy); + (void)i2; + + socket1.set_option(settable_socket_option1); + socket1.set_option(settable_socket_option1, ec); + socket1.set_option(settable_socket_option2); + socket1.set_option(settable_socket_option2, ec); + socket1.set_option(settable_socket_option3); + socket1.set_option(settable_socket_option3, ec); + + socket1.get_option(gettable_socket_option1); + socket1.get_option(gettable_socket_option1, ec); + socket1.get_option(gettable_socket_option2); + socket1.get_option(gettable_socket_option2, ec); + socket1.get_option(gettable_socket_option3); + socket1.get_option(gettable_socket_option3, ec); + + socket1.io_control(io_control_command); + socket1.io_control(io_control_command, ec); + + bool non_blocking1 = socket1.non_blocking(); + (void)non_blocking1; + socket1.non_blocking(true); + socket1.non_blocking(false, ec); + + bool non_blocking2 = socket1.native_non_blocking(); + (void)non_blocking2; + socket1.native_non_blocking(true); + socket1.native_non_blocking(false, ec); + + ip::icmp::endpoint endpoint1 = socket1.local_endpoint(); + (void)endpoint1; + ip::icmp::endpoint endpoint2 = socket1.local_endpoint(ec); + (void)endpoint2; + + ip::icmp::endpoint endpoint3 = socket1.remote_endpoint(); + (void)endpoint3; + ip::icmp::endpoint endpoint4 = socket1.remote_endpoint(ec); + (void)endpoint4; + + socket1.shutdown(socket_base::shutdown_both); + socket1.shutdown(socket_base::shutdown_both, ec); + + // basic_datagram_socket functions. + + socket1.send(buffer(mutable_char_buffer)); + socket1.send(buffer(const_char_buffer)); + socket1.send(null_buffers()); + socket1.send(buffer(mutable_char_buffer), in_flags); + socket1.send(buffer(const_char_buffer), in_flags); + socket1.send(null_buffers(), in_flags); + socket1.send(buffer(mutable_char_buffer), in_flags, ec); + socket1.send(buffer(const_char_buffer), in_flags, ec); + socket1.send(null_buffers(), in_flags, ec); + + socket1.async_send(buffer(mutable_char_buffer), send_handler()); + socket1.async_send(buffer(const_char_buffer), send_handler()); + socket1.async_send(null_buffers(), send_handler()); + socket1.async_send(buffer(mutable_char_buffer), in_flags, send_handler()); + socket1.async_send(buffer(const_char_buffer), in_flags, send_handler()); + socket1.async_send(null_buffers(), in_flags, send_handler()); + int i3 = socket1.async_send(buffer(mutable_char_buffer), lazy); + (void)i3; + int i4 = socket1.async_send(buffer(const_char_buffer), lazy); + (void)i4; + int i5 = socket1.async_send(null_buffers(), lazy); + (void)i5; + int i6 = socket1.async_send(buffer(mutable_char_buffer), in_flags, lazy); + (void)i6; + int i7 = socket1.async_send(buffer(const_char_buffer), in_flags, lazy); + (void)i7; + int i8 = socket1.async_send(null_buffers(), in_flags, lazy); + (void)i8; + + socket1.send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0)); + socket1.send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0)); + socket1.send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0)); + socket1.send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0)); + socket1.send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v4(), 0)); + socket1.send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v6(), 0)); + socket1.send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0), in_flags); + socket1.send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0), in_flags); + socket1.send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0), in_flags); + socket1.send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0), in_flags); + socket1.send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v4(), 0), in_flags); + socket1.send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v6(), 0), in_flags); + socket1.send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0), in_flags, ec); + socket1.send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0), in_flags, ec); + socket1.send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0), in_flags, ec); + socket1.send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0), in_flags, ec); + socket1.send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v4(), 0), in_flags, ec); + socket1.send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v6(), 0), in_flags, ec); + + socket1.async_send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0), send_handler()); + socket1.async_send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0), send_handler()); + socket1.async_send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0), send_handler()); + socket1.async_send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0), send_handler()); + socket1.async_send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v4(), 0), send_handler()); + socket1.async_send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v6(), 0), send_handler()); + socket1.async_send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0), in_flags, send_handler()); + socket1.async_send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0), in_flags, send_handler()); + socket1.async_send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0), in_flags, send_handler()); + socket1.async_send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0), in_flags, send_handler()); + socket1.async_send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v4(), 0), in_flags, send_handler()); + socket1.async_send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v6(), 0), in_flags, send_handler()); + int i9 = socket1.async_send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0), lazy); + (void)i9; + int i10 = socket1.async_send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0), lazy); + (void)i10; + int i11 = socket1.async_send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0), lazy); + (void)i11; + int i12 = socket1.async_send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0), lazy); + (void)i12; + int i13 = socket1.async_send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v4(), 0), lazy); + (void)i13; + int i14 = socket1.async_send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v6(), 0), lazy); + (void)i14; + int i15 = socket1.async_send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0), in_flags, lazy); + (void)i15; + int i16 = socket1.async_send_to(buffer(mutable_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0), in_flags, lazy); + (void)i16; + int i17 = socket1.async_send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v4(), 0), in_flags, lazy); + (void)i17; + int i18 = socket1.async_send_to(buffer(const_char_buffer), + ip::icmp::endpoint(ip::icmp::v6(), 0), in_flags, lazy); + (void)i18; + int i19 = socket1.async_send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v4(), 0), in_flags, lazy); + (void)i19; + int i20 = socket1.async_send_to(null_buffers(), + ip::icmp::endpoint(ip::icmp::v6(), 0), in_flags, lazy); + (void)i20; + + socket1.receive(buffer(mutable_char_buffer)); + socket1.receive(null_buffers()); + socket1.receive(buffer(mutable_char_buffer), in_flags); + socket1.receive(null_buffers(), in_flags); + socket1.receive(buffer(mutable_char_buffer), in_flags, ec); + socket1.receive(null_buffers(), in_flags, ec); + + socket1.async_receive(buffer(mutable_char_buffer), receive_handler()); + socket1.async_receive(null_buffers(), receive_handler()); + socket1.async_receive(buffer(mutable_char_buffer), in_flags, + receive_handler()); + socket1.async_receive(null_buffers(), in_flags, receive_handler()); + int i21 = socket1.async_receive(buffer(mutable_char_buffer), lazy); + (void)i21; + int i22 = socket1.async_receive(null_buffers(), lazy); + (void)i22; + int i23 = socket1.async_receive(buffer(mutable_char_buffer), + in_flags, lazy); + (void)i23; + int i24 = socket1.async_receive(null_buffers(), in_flags, lazy); + (void)i24; + + ip::icmp::endpoint endpoint; + socket1.receive_from(buffer(mutable_char_buffer), endpoint); + socket1.receive_from(null_buffers(), endpoint); + socket1.receive_from(buffer(mutable_char_buffer), endpoint, in_flags); + socket1.receive_from(null_buffers(), endpoint, in_flags); + socket1.receive_from(buffer(mutable_char_buffer), endpoint, in_flags, ec); + socket1.receive_from(null_buffers(), endpoint, in_flags, ec); + + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, receive_handler()); + socket1.async_receive_from(null_buffers(), + endpoint, receive_handler()); + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, in_flags, receive_handler()); + socket1.async_receive_from(null_buffers(), + endpoint, in_flags, receive_handler()); + int i25 = socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, lazy); + (void)i25; + int i26 = socket1.async_receive_from(null_buffers(), + endpoint, lazy); + (void)i26; + int i27 = socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, in_flags, lazy); + (void)i27; + int i28 = socket1.async_receive_from(null_buffers(), + endpoint, in_flags, lazy); + (void)i28; + } + catch (std::exception&) + { + } +} + +} // namespace ip_icmp_socket_compile + +//------------------------------------------------------------------------------ + +// ip_icmp_resolver_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::icmp::resolver compile and link correctly. Runtime failures are ignored. + +namespace ip_icmp_resolver_compile { + +struct resolve_handler +{ + resolve_handler() {} + void operator()(const boost::system::error_code&, + boost::asio::ip::icmp::resolver::results_type) {} +#if defined(BOOST_ASIO_HAS_MOVE) + resolve_handler(resolve_handler&&) {} +private: + resolve_handler(const resolve_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_context ioc; + const io_context::executor_type ioc_ex = ioc.get_executor(); + archetypes::lazy_handler lazy; + boost::system::error_code ec; +#if !defined(BOOST_ASIO_NO_DEPRECATED) + ip::icmp::resolver::query q(ip::icmp::v4(), "localhost", "0"); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + ip::icmp::endpoint e(ip::address_v4::loopback(), 0); + + // basic_resolver constructors. + + ip::icmp::resolver resolver(ioc); + ip::icmp::resolver resolver2(ioc_ex); + +#if defined(BOOST_ASIO_HAS_MOVE) + ip::icmp::resolver resolver3(std::move(resolver)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_resolver operators. + +#if defined(BOOST_ASIO_HAS_MOVE) + resolver = ip::icmp::resolver(ioc); + resolver = std::move(resolver3); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_io_object functions. + + ip::icmp::resolver::executor_type ex = resolver.get_executor(); + (void)ex; + + // basic_resolver functions. + + resolver.cancel(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + ip::icmp::resolver::results_type results1 = resolver.resolve(q); + (void)results1; + + ip::icmp::resolver::results_type results2 = resolver.resolve(q, ec); + (void)results2; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + ip::icmp::resolver::results_type results3 = resolver.resolve("", ""); + (void)results3; + + ip::icmp::resolver::results_type results4 = resolver.resolve("", "", ec); + (void)results4; + + ip::icmp::resolver::results_type results5 = + resolver.resolve("", "", ip::icmp::resolver::flags()); + (void)results5; + + ip::icmp::resolver::results_type results6 = + resolver.resolve("", "", ip::icmp::resolver::flags(), ec); + (void)results6; + + ip::icmp::resolver::results_type results7 = + resolver.resolve(ip::icmp::v4(), "", ""); + (void)results7; + + ip::icmp::resolver::results_type results8 = + resolver.resolve(ip::icmp::v4(), "", "", ec); + (void)results8; + + ip::icmp::resolver::results_type results9 = + resolver.resolve(ip::icmp::v4(), "", "", ip::icmp::resolver::flags()); + (void)results9; + + ip::icmp::resolver::results_type results10 = + resolver.resolve(ip::icmp::v4(), "", "", ip::icmp::resolver::flags(), ec); + (void)results10; + + ip::icmp::resolver::results_type results11 = resolver.resolve(e); + (void)results11; + + ip::icmp::resolver::results_type results12 = resolver.resolve(e, ec); + (void)results12; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + resolver.async_resolve(q, resolve_handler()); + int i1 = resolver.async_resolve(q, lazy); + (void)i1; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + resolver.async_resolve("", "", resolve_handler()); + int i2 = resolver.async_resolve("", "", lazy); + (void)i2; + + resolver.async_resolve("", "", + ip::icmp::resolver::flags(), resolve_handler()); + int i3 = resolver.async_resolve("", "", + ip::icmp::resolver::flags(), lazy); + (void)i3; + resolver.async_resolve(ip::icmp::v4(), "", "", resolve_handler()); + int i4 = resolver.async_resolve(ip::icmp::v4(), "", "", lazy); + (void)i4; + + resolver.async_resolve(ip::icmp::v4(), + "", "", ip::icmp::resolver::flags(), resolve_handler()); + int i5 = resolver.async_resolve(ip::icmp::v4(), + "", "", ip::icmp::resolver::flags(), lazy); + (void)i5; + + resolver.async_resolve(e, resolve_handler()); + int i6 = resolver.async_resolve(e, lazy); + (void)i6; + } + catch (std::exception&) + { + } +} + +} // namespace ip_icmp_resolver_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ip/icmp", + BOOST_ASIO_TEST_CASE(ip_icmp_socket_compile::test) + BOOST_ASIO_TEST_CASE(ip_icmp_resolver_compile::test) +) diff --git a/src/boost/libs/asio/test/ip/multicast.cpp b/src/boost/libs/asio/test/ip/multicast.cpp new file mode 100644 index 000000000..09b0a745e --- /dev/null +++ b/src/boost/libs/asio/test/ip/multicast.cpp @@ -0,0 +1,363 @@ +// +// multicast.cpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/multicast.hpp> + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/udp.hpp> +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +// ip_multicast_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all nested classes, enums and constants in +// ip::multicast compile and link correctly. Runtime failures are ignored. + +namespace ip_multicast_compile { + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_context ioc; + ip::udp::socket sock(ioc); + const ip::address address; + const ip::address_v4 address_v4; + const ip::address_v6 address_v6; + + // join_group class. + + ip::multicast::join_group join_group1; + ip::multicast::join_group join_group2(address); + ip::multicast::join_group join_group3(address_v4); + ip::multicast::join_group join_group4(address_v4, address_v4); + ip::multicast::join_group join_group5(address_v6); + ip::multicast::join_group join_group6(address_v6, 1); + sock.set_option(join_group6); + + // leave_group class. + + ip::multicast::leave_group leave_group1; + ip::multicast::leave_group leave_group2(address); + ip::multicast::leave_group leave_group3(address_v4); + ip::multicast::leave_group leave_group4(address_v4, address_v4); + ip::multicast::leave_group leave_group5(address_v6); + ip::multicast::leave_group leave_group6(address_v6, 1); + sock.set_option(leave_group6); + + // outbound_interface class. + + ip::multicast::outbound_interface outbound_interface1; + ip::multicast::outbound_interface outbound_interface2(address_v4); + ip::multicast::outbound_interface outbound_interface3(1); + sock.set_option(outbound_interface3); + + // hops class. + + ip::multicast::hops hops1(1024); + sock.set_option(hops1); + ip::multicast::hops hops2; + sock.get_option(hops2); + hops1 = 1; + (void)static_cast<int>(hops1.value()); + + // enable_loopback class. + + ip::multicast::enable_loopback enable_loopback1(true); + sock.set_option(enable_loopback1); + ip::multicast::enable_loopback enable_loopback2; + sock.get_option(enable_loopback2); + enable_loopback1 = true; + (void)static_cast<bool>(enable_loopback1); + (void)static_cast<bool>(!enable_loopback1); + (void)static_cast<bool>(enable_loopback1.value()); + } + catch (std::exception&) + { + } +} + +} // namespace ip_multicast_compile + +//------------------------------------------------------------------------------ + +// ip_multicast_runtime test +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks the runtime operation of the socket options defined +// in the ip::multicast namespace. + +namespace ip_multicast_runtime { + +#if defined(__hpux) +// HP-UX doesn't declare this function extern "C", so it is declared again here +// to avoid a linker error about an undefined symbol. +extern "C" unsigned int if_nametoindex(const char*); +#endif // defined(__hpux) + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + io_context ioc; + boost::system::error_code ec; + + ip::udp::endpoint ep_v4(ip::address_v4::loopback(), 0); + ip::udp::socket sock_v4(ioc); + sock_v4.open(ep_v4.protocol(), ec); + sock_v4.bind(ep_v4, ec); + bool have_v4 = !ec; + + ip::udp::endpoint ep_v6(ip::address_v6::loopback(), 0); + ip::udp::socket sock_v6(ioc); + sock_v6.open(ep_v6.protocol(), ec); + sock_v6.bind(ep_v6, ec); + bool have_v6 = !ec; + + BOOST_ASIO_CHECK(have_v4 || have_v6); + +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Windows CE seems to have problems with some multicast group addresses. + // The following address works on CE, but as it is not a private multicast + // address it will not be used on other platforms. + const ip::address multicast_address_v4 = ip::make_address("239.0.0.4", ec); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + const ip::address multicast_address_v4 = ip::make_address("239.255.0.1", ec); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK(!have_v4 || !ec); + +#if (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) + const ip::address multicast_address_v6 = ip::make_address("ff02::1%lo0", ec); +#else // (defined(__MACH__) && defined(__APPLE__)) + // || defined(__FreeBSD__) + // || defined(__NetBSD__) + // || defined(__OpenBSD__) + const ip::address multicast_address_v6 = ip::make_address("ff01::1", ec); +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || defined(__FreeBSD__) + // || defined(__NetBSD__) + // || defined(__OpenBSD__) + BOOST_ASIO_CHECK(!have_v6 || !ec); + + // join_group class. + + if (have_v4) + { + ip::multicast::join_group join_group(multicast_address_v4); + sock_v4.set_option(join_group, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec || ec == error::no_such_device, + ec.value() << ", " << ec.message()); + + if (!ec) + { + // leave_group class. + + ip::multicast::leave_group leave_group(multicast_address_v4); + sock_v4.set_option(leave_group, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + } + } + + if (have_v6) + { + ip::multicast::join_group join_group(multicast_address_v6); + sock_v6.set_option(join_group, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec || ec == error::no_such_device, + ec.value() << ", " << ec.message()); + + if (!ec) + { + // leave_group class. + + ip::multicast::leave_group leave_group(multicast_address_v6); + sock_v6.set_option(leave_group, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + } + } + + // outbound_interface class. + + if (have_v4) + { + ip::multicast::outbound_interface outbound_interface( + ip::address_v4::loopback()); + sock_v4.set_option(outbound_interface, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + } + + if (have_v6) + { +#if defined(__hpux) + ip::multicast::outbound_interface outbound_interface(if_nametoindex("lo0")); +#else + ip::multicast::outbound_interface outbound_interface(1); +#endif + sock_v6.set_option(outbound_interface, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + } + + // hops class. + + if (have_v4) + { + ip::multicast::hops hops1(1); + BOOST_ASIO_CHECK(hops1.value() == 1); + sock_v4.set_option(hops1, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + ip::multicast::hops hops2; + sock_v4.get_option(hops2, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(hops2.value() == 1); + + ip::multicast::hops hops3(0); + BOOST_ASIO_CHECK(hops3.value() == 0); + sock_v4.set_option(hops3, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + ip::multicast::hops hops4; + sock_v4.get_option(hops4, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(hops4.value() == 0); + } + + if (have_v6) + { + ip::multicast::hops hops1(1); + BOOST_ASIO_CHECK(hops1.value() == 1); + sock_v6.set_option(hops1, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + ip::multicast::hops hops2; + sock_v6.get_option(hops2, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(hops2.value() == 1); + + ip::multicast::hops hops3(0); + BOOST_ASIO_CHECK(hops3.value() == 0); + sock_v6.set_option(hops3, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + ip::multicast::hops hops4; + sock_v6.get_option(hops4, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(hops4.value() == 0); + } + + // enable_loopback class. + + if (have_v4) + { + ip::multicast::enable_loopback enable_loopback1(true); + BOOST_ASIO_CHECK(enable_loopback1.value()); + BOOST_ASIO_CHECK(static_cast<bool>(enable_loopback1)); + BOOST_ASIO_CHECK(!!enable_loopback1); + sock_v4.set_option(enable_loopback1, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Option is not supported under Windows CE. + BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, + ec.value() << ", " << ec.message()); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + + ip::multicast::enable_loopback enable_loopback2; + sock_v4.get_option(enable_loopback2, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Not supported under Windows CE but can get value. + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(enable_loopback2.value()); + BOOST_ASIO_CHECK(static_cast<bool>(enable_loopback2)); + BOOST_ASIO_CHECK(!!enable_loopback2); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + + ip::multicast::enable_loopback enable_loopback3(false); + BOOST_ASIO_CHECK(!enable_loopback3.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(enable_loopback3)); + BOOST_ASIO_CHECK(!enable_loopback3); + sock_v4.set_option(enable_loopback3, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Option is not supported under Windows CE. + BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, + ec.value() << ", " << ec.message()); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + + ip::multicast::enable_loopback enable_loopback4; + sock_v4.get_option(enable_loopback4, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Not supported under Windows CE but can get value. + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(!enable_loopback4.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(enable_loopback4)); + BOOST_ASIO_CHECK(!enable_loopback4); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + } + + if (have_v6) + { + ip::multicast::enable_loopback enable_loopback1(true); + BOOST_ASIO_CHECK(enable_loopback1.value()); + BOOST_ASIO_CHECK(static_cast<bool>(enable_loopback1)); + BOOST_ASIO_CHECK(!!enable_loopback1); + sock_v6.set_option(enable_loopback1, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + ip::multicast::enable_loopback enable_loopback2; + sock_v6.get_option(enable_loopback2, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(enable_loopback2.value()); + BOOST_ASIO_CHECK(static_cast<bool>(enable_loopback2)); + BOOST_ASIO_CHECK(!!enable_loopback2); + + ip::multicast::enable_loopback enable_loopback3(false); + BOOST_ASIO_CHECK(!enable_loopback3.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(enable_loopback3)); + BOOST_ASIO_CHECK(!enable_loopback3); + sock_v6.set_option(enable_loopback3, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + ip::multicast::enable_loopback enable_loopback4; + sock_v6.get_option(enable_loopback4, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(!enable_loopback4.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(enable_loopback4)); + BOOST_ASIO_CHECK(!enable_loopback4); + } +} + +} // namespace ip_multicast_runtime + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ip/multicast", + BOOST_ASIO_TEST_CASE(ip_multicast_compile::test) + BOOST_ASIO_TEST_CASE(ip_multicast_runtime::test) +) diff --git a/src/boost/libs/asio/test/ip/network_v4.cpp b/src/boost/libs/asio/test/ip/network_v4.cpp new file mode 100644 index 000000000..59d10dc31 --- /dev/null +++ b/src/boost/libs/asio/test/ip/network_v4.cpp @@ -0,0 +1,314 @@ +// +// network_v4.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/network_v4.hpp> + +#include "../unit_test.hpp" +#include <sstream> + +//------------------------------------------------------------------------------ + +// ip_network_v4_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::network_v4 compile and link correctly. Runtime failures are ignored. + +namespace ip_network_v4_compile { + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + boost::system::error_code ec; + + // network_v4 constructors. + + ip::network_v4 net1(ip::make_address_v4("192.168.1.0"), 32); + ip::network_v4 net2(ip::make_address_v4("192.168.1.0"), + ip::make_address_v4("255.255.255.0")); + + // network_v4 functions. + + ip::address_v4 addr1 = net1.address(); + (void)addr1; + + unsigned short prefix_len = net1.prefix_length(); + (void)prefix_len; + + ip::address_v4 addr2 = net1.netmask(); + (void)addr2; + + ip::address_v4 addr3 = net1.network(); + (void)addr3; + + ip::address_v4 addr4 = net1.broadcast(); + (void)addr4; + + ip::address_v4_range hosts = net1.hosts(); + (void)hosts; + + ip::network_v4 net3 = net1.canonical(); + (void)net3; + + bool b1 = net1.is_host(); + (void)b1; + + bool b2 = net1.is_subnet_of(net2); + (void)b2; + + std::string s1 = net1.to_string(); + (void)s1; + + std::string s2 = net1.to_string(ec); + (void)s2; + + // network_v4 comparisons. + + bool b3 = (net1 == net2); + (void)b3; + + bool b4 = (net1 != net2); + (void)b4; + + // network_v4 creation functions. + + net1 = ip::make_network_v4(ip::address_v4(), 24); + net1 = ip::make_network_v4(ip::address_v4(), ip::address_v4()); + net1 = ip::make_network_v4("10.0.0.0/8"); + net1 = ip::make_network_v4("10.0.0.0/8", ec); + net1 = ip::make_network_v4(s1); + net1 = ip::make_network_v4(s1, ec); +#if defined(BOOST_ASIO_HAS_STRING_VIEW) +# if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + std::string_view string_view_value("10.0.0.0/8"); +# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + std::experimental::string_view string_view_value("10.0.0.0/8"); +# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + net1 = ip::make_network_v4(string_view_value); + net1 = ip::make_network_v4(string_view_value, ec); +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + + // network_v4 I/O. + + std::ostringstream os; + os << net1; + +#if !defined(BOOST_NO_STD_WSTREAMBUF) + std::wostringstream wos; + wos << net1; +#endif // !defined(BOOST_NO_STD_WSTREAMBUF) + } + catch (std::exception&) + { + } +} + +} // namespace ip_network_v4_compile + +//------------------------------------------------------------------------------ + +// ip_network_v4_runtime test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that the various public member functions meet the +// necessary postconditions. + +namespace ip_network_v4_runtime { + +void test() +{ + using boost::asio::ip::address_v4; + using boost::asio::ip::make_address_v4; + using boost::asio::ip::network_v4; + using boost::asio::ip::make_network_v4; + + address_v4 addr = make_address_v4("1.2.3.4"); + + // calculate prefix length + + network_v4 net1(addr, make_address_v4("255.255.255.0")); + BOOST_ASIO_CHECK(net1.prefix_length() == 24); + + network_v4 net2(addr, make_address_v4("255.255.255.192")); + BOOST_ASIO_CHECK(net2.prefix_length() == 26); + + network_v4 net3(addr, make_address_v4("128.0.0.0")); + BOOST_ASIO_CHECK(net3.prefix_length() == 1); + + std::string msg; + try + { + make_network_v4(addr, make_address_v4("255.255.255.1")); + } + catch(std::exception& ex) + { + msg = ex.what(); + } + BOOST_ASIO_CHECK(msg == std::string("non-contiguous netmask")); + + msg.clear(); + try + { + make_network_v4(addr, make_address_v4("0.255.255.0")); + } + catch(std::exception& ex) + { + msg = ex.what(); + } + BOOST_ASIO_CHECK(msg == std::string("non-contiguous netmask")); + + // calculate netmask + + network_v4 net4(addr, 23); + BOOST_ASIO_CHECK(net4.netmask() == make_address_v4("255.255.254.0")); + + network_v4 net5(addr, 12); + BOOST_ASIO_CHECK(net5.netmask() == make_address_v4("255.240.0.0")); + + network_v4 net6(addr, 24); + BOOST_ASIO_CHECK(net6.netmask() == make_address_v4("255.255.255.0")); + + network_v4 net7(addr, 16); + BOOST_ASIO_CHECK(net7.netmask() == make_address_v4("255.255.0.0")); + + network_v4 net8(addr, 8); + BOOST_ASIO_CHECK(net8.netmask() == make_address_v4("255.0.0.0")); + + network_v4 net9(addr, 32); + BOOST_ASIO_CHECK(net9.netmask() == make_address_v4("255.255.255.255")); + + network_v4 net10(addr, 1); + BOOST_ASIO_CHECK(net10.netmask() == make_address_v4("128.0.0.0")); + + network_v4 net11(addr, 0); + BOOST_ASIO_CHECK(net11.netmask() == make_address_v4("0.0.0.0")); + + msg.clear(); + try + { + make_network_v4(addr, 33); + } + catch(std::out_of_range& ex) + { + msg = ex.what(); + } + BOOST_ASIO_CHECK(msg == std::string("prefix length too large")); + + // construct address range from address and prefix length + BOOST_ASIO_CHECK(network_v4(make_address_v4("192.168.77.100"), 32).network() == make_address_v4("192.168.77.100")); + BOOST_ASIO_CHECK(network_v4(make_address_v4("192.168.77.100"), 24).network() == make_address_v4("192.168.77.0")); + BOOST_ASIO_CHECK(network_v4(make_address_v4("192.168.77.128"), 25).network() == make_address_v4("192.168.77.128")); + + // construct address range from string in CIDR notation + BOOST_ASIO_CHECK(make_network_v4("192.168.77.100/32").network() == make_address_v4("192.168.77.100")); + BOOST_ASIO_CHECK(make_network_v4("192.168.77.100/24").network() == make_address_v4("192.168.77.0")); + BOOST_ASIO_CHECK(make_network_v4("192.168.77.128/25").network() == make_address_v4("192.168.77.128")); + + // construct network from invalid string + boost::system::error_code ec; + make_network_v4("10.0.0.256/24", ec); + BOOST_ASIO_CHECK(!!ec); + make_network_v4("10.0.0.0/33", ec); + BOOST_ASIO_CHECK(!!ec); + make_network_v4("10.0.0.0/-1", ec); + BOOST_ASIO_CHECK(!!ec); + make_network_v4("10.0.0.0/", ec); + BOOST_ASIO_CHECK(!!ec); + make_network_v4("10.0.0.0", ec); + BOOST_ASIO_CHECK(!!ec); + + // prefix length + BOOST_ASIO_CHECK(make_network_v4("193.99.144.80/24").prefix_length() == 24); + BOOST_ASIO_CHECK(network_v4(make_address_v4("193.99.144.80"), 24).prefix_length() == 24); + BOOST_ASIO_CHECK(network_v4(make_address_v4("192.168.77.0"), make_address_v4("255.255.255.0")).prefix_length() == 24); + + // to string + std::string a("192.168.77.0/32"); + BOOST_ASIO_CHECK(make_network_v4(a.c_str()).to_string() == a); + BOOST_ASIO_CHECK(network_v4(make_address_v4("192.168.77.10"), 24).to_string() == std::string("192.168.77.10/24")); + + // return host part + BOOST_ASIO_CHECK(make_network_v4("192.168.77.11/24").address() == make_address_v4("192.168.77.11")); + + // return host in CIDR notation + BOOST_ASIO_CHECK(make_network_v4("192.168.78.30/20").address().to_string() == "192.168.78.30"); + + // return network in CIDR notation + BOOST_ASIO_CHECK(make_network_v4("192.168.78.30/20").canonical().to_string() == "192.168.64.0/20"); + + // is host + BOOST_ASIO_CHECK(make_network_v4("192.168.77.0/32").is_host()); + BOOST_ASIO_CHECK(!make_network_v4("192.168.77.0/31").is_host()); + + // is real subnet of + BOOST_ASIO_CHECK(make_network_v4("192.168.0.192/24").is_subnet_of(make_network_v4("192.168.0.0/16"))); + BOOST_ASIO_CHECK(make_network_v4("192.168.0.0/24").is_subnet_of(make_network_v4("192.168.192.168/16"))); + BOOST_ASIO_CHECK(make_network_v4("192.168.0.192/24").is_subnet_of(make_network_v4("192.168.192.168/16"))); + BOOST_ASIO_CHECK(make_network_v4("192.168.0.0/24").is_subnet_of(make_network_v4("192.168.0.0/16"))); + BOOST_ASIO_CHECK(make_network_v4("192.168.0.0/24").is_subnet_of(make_network_v4("192.168.0.0/23"))); + BOOST_ASIO_CHECK(make_network_v4("192.168.0.0/24").is_subnet_of(make_network_v4("192.168.0.0/0"))); + BOOST_ASIO_CHECK(make_network_v4("192.168.0.0/32").is_subnet_of(make_network_v4("192.168.0.0/24"))); + + BOOST_ASIO_CHECK(!make_network_v4("192.168.0.0/32").is_subnet_of(make_network_v4("192.168.0.0/32"))); + BOOST_ASIO_CHECK(!make_network_v4("192.168.0.0/24").is_subnet_of(make_network_v4("192.168.1.0/24"))); + BOOST_ASIO_CHECK(!make_network_v4("192.168.0.0/16").is_subnet_of(make_network_v4("192.168.1.0/24"))); + + network_v4 r(make_network_v4("192.168.0.0/24")); + BOOST_ASIO_CHECK(!r.is_subnet_of(r)); + + network_v4 net12(make_network_v4("192.168.0.2/24")); + network_v4 net13(make_network_v4("192.168.1.1/28")); + network_v4 net14(make_network_v4("192.168.1.21/28")); + // network + BOOST_ASIO_CHECK(net12.network() == make_address_v4("192.168.0.0")); + BOOST_ASIO_CHECK(net13.network() == make_address_v4("192.168.1.0")); + BOOST_ASIO_CHECK(net14.network() == make_address_v4("192.168.1.16")); + // netmask + BOOST_ASIO_CHECK(net12.netmask() == make_address_v4("255.255.255.0")); + BOOST_ASIO_CHECK(net13.netmask() == make_address_v4("255.255.255.240")); + BOOST_ASIO_CHECK(net14.netmask() == make_address_v4("255.255.255.240")); + // broadcast + BOOST_ASIO_CHECK(net12.broadcast() == make_address_v4("192.168.0.255")); + BOOST_ASIO_CHECK(net13.broadcast() == make_address_v4("192.168.1.15")); + BOOST_ASIO_CHECK(net14.broadcast() == make_address_v4("192.168.1.31")); + // iterator + BOOST_ASIO_CHECK(std::distance(net12.hosts().begin(),net12.hosts().end()) == 254); + BOOST_ASIO_CHECK(*net12.hosts().begin() == make_address_v4("192.168.0.1")); + BOOST_ASIO_CHECK(net12.hosts().end() != net12.hosts().find(make_address_v4("192.168.0.10"))); + BOOST_ASIO_CHECK(net12.hosts().end() == net12.hosts().find(make_address_v4("192.168.1.10"))); + BOOST_ASIO_CHECK(std::distance(net13.hosts().begin(),net13.hosts().end()) == 14); + BOOST_ASIO_CHECK(*net13.hosts().begin() == make_address_v4("192.168.1.1")); + BOOST_ASIO_CHECK(net13.hosts().end() != net13.hosts().find(make_address_v4("192.168.1.14"))); + BOOST_ASIO_CHECK(net13.hosts().end() == net13.hosts().find(make_address_v4("192.168.1.15"))); + BOOST_ASIO_CHECK(std::distance(net14.hosts().begin(),net14.hosts().end()) == 14); + BOOST_ASIO_CHECK(*net14.hosts().begin() == make_address_v4("192.168.1.17")); + BOOST_ASIO_CHECK(net14.hosts().end() != net14.hosts().find(make_address_v4("192.168.1.30"))); + BOOST_ASIO_CHECK(net14.hosts().end() == net14.hosts().find(make_address_v4("192.168.1.31"))); +} + +} // namespace ip_network_v4_runtime + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ip/network_v4", + BOOST_ASIO_TEST_CASE(ip_network_v4_compile::test) + BOOST_ASIO_TEST_CASE(ip_network_v4_runtime::test) +) diff --git a/src/boost/libs/asio/test/ip/network_v6.cpp b/src/boost/libs/asio/test/ip/network_v6.cpp new file mode 100644 index 000000000..cfe97ce61 --- /dev/null +++ b/src/boost/libs/asio/test/ip/network_v6.cpp @@ -0,0 +1,238 @@ +// +// network_v6.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/network_v6.hpp> + +#include "../unit_test.hpp" +#include <sstream> + +//------------------------------------------------------------------------------ + +// ip_network_v6_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::network_v6 compile and link correctly. Runtime failures are ignored. + +namespace ip_network_v6_compile { + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + boost::system::error_code ec; + + // network_v6 constructors. + + ip::network_v6 net1(ip::make_address_v6("2001:370::10:7344"), 64); + ip::network_v6 net2(ip::make_address_v6("2001:370::10:7345"), 96); + + // network_v6 functions. + + ip::address_v6 addr1 = net1.address(); + (void)addr1; + + unsigned short prefix_len = net1.prefix_length(); + (void)prefix_len; + + ip::address_v6 addr3 = net1.network(); + (void)addr3; + + ip::address_v6_range hosts = net1.hosts(); + (void)hosts; + + ip::network_v6 net3 = net1.canonical(); + (void)net3; + + bool b1 = net1.is_host(); + (void)b1; + + bool b2 = net1.is_subnet_of(net2); + (void)b2; + + std::string s1 = net1.to_string(); + (void)s1; + + std::string s2 = net1.to_string(ec); + (void)s2; + + // network_v6 comparisons. + + bool b3 = (net1 == net2); + (void)b3; + + bool b4 = (net1 != net2); + (void)b4; + + // network_v6 creation functions. + + net1 = ip::make_network_v6(ip::address_v6(), 24); + net1 = ip::make_network_v6("10.0.0.0/8"); + net1 = ip::make_network_v6("10.0.0.0/8", ec); + net1 = ip::make_network_v6(s1); + net1 = ip::make_network_v6(s1, ec); +#if defined(BOOST_ASIO_HAS_STRING_VIEW) +# if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + std::string_view string_view_value("0::0/8"); +# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + std::experimental::string_view string_view_value("0::0/8"); +# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + net1 = ip::make_network_v6(string_view_value); + net1 = ip::make_network_v6(string_view_value, ec); +#endif // defined(BOOST_ASIO_STD_STRING_VIEW) + + // network_v6 I/O. + + std::ostringstream os; + os << net1; + +#if !defined(BOOST_NO_STD_WSTREAMBUF) + std::wostringstream wos; + wos << net1; +#endif // !defined(BOOST_NO_STD_WSTREAMBUF) + } + catch (std::exception&) + { + } +} + +} // namespace ip_network_v6_compile + +//------------------------------------------------------------------------------ + +// ip_network_v6_runtime test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that the various public member functions meet the +// necessary postconditions. + +namespace ip_network_v6_runtime { + +void test() +{ + using boost::asio::ip::address_v6; + using boost::asio::ip::make_address_v6; + using boost::asio::ip::network_v6; + using boost::asio::ip::make_network_v6; + + address_v6 addr = make_address_v6("2001:370::10:7344"); + + std::string msg; + try + { + make_network_v6(addr, 129); + } + catch(std::out_of_range& ex) + { + msg = ex.what(); + } + BOOST_ASIO_CHECK(msg == std::string("prefix length too large")); + + // construct address range from address and prefix length + BOOST_ASIO_CHECK(network_v6(make_address_v6("2001:370::10:7344"), 128).network() == make_address_v6("2001:370::10:7344")); + BOOST_ASIO_CHECK(network_v6(make_address_v6("2001:370::10:7344"), 64).network() == make_address_v6("2001:370::")); + BOOST_ASIO_CHECK(network_v6(make_address_v6("2001:370::10:7344"), 27).network() == make_address_v6("2001:360::")); + + // construct address range from string in CIDR notation + BOOST_ASIO_CHECK(make_network_v6("2001:370::10:7344/128").network() == make_address_v6("2001:370::10:7344")); + BOOST_ASIO_CHECK(make_network_v6("2001:370::10:7344/64").network() == make_address_v6("2001:370::")); + BOOST_ASIO_CHECK(make_network_v6("2001:370::10:7344/27").network() == make_address_v6("2001:360::")); + + // construct network from invalid string + boost::system::error_code ec; + make_network_v6("a:b/24", ec); + BOOST_ASIO_CHECK(!!ec); + make_network_v6("2001:370::10:7344/129", ec); + BOOST_ASIO_CHECK(!!ec); + make_network_v6("2001:370::10:7344/-1", ec); + BOOST_ASIO_CHECK(!!ec); + make_network_v6("2001:370::10:7344/", ec); + BOOST_ASIO_CHECK(!!ec); + make_network_v6("2001:370::10:7344", ec); + BOOST_ASIO_CHECK(!!ec); + + // prefix length + BOOST_ASIO_CHECK(make_network_v6("2001:370::10:7344/128").prefix_length() == 128); + BOOST_ASIO_CHECK(network_v6(make_address_v6("2001:370::10:7344"), 27).prefix_length() == 27); + + // to string + std::string a("2001:370::10:7344/64"); + BOOST_ASIO_CHECK(make_network_v6(a.c_str()).to_string() == a); + BOOST_ASIO_CHECK(network_v6(make_address_v6("2001:370::10:7344"), 27).to_string() == std::string("2001:370::10:7344/27")); + + // return host part + BOOST_ASIO_CHECK(make_network_v6("2001:370::10:7344/64").address() == make_address_v6("2001:370::10:7344")); + BOOST_ASIO_CHECK(make_network_v6("2001:370::10:7344/27").address().to_string() == "2001:370::10:7344"); + + // return network in CIDR notation + BOOST_ASIO_CHECK(make_network_v6("2001:370::10:7344/27").canonical().to_string() == "2001:360::/27"); + + // is host + BOOST_ASIO_CHECK(make_network_v6("2001:370::10:7344/128").is_host()); + BOOST_ASIO_CHECK(!make_network_v6("2001:370::10:7344/127").is_host()); + + // is real subnet of + BOOST_ASIO_CHECK(make_network_v6("2001:370::10:3744/64").is_subnet_of(make_network_v6("2001:370::/16"))); + BOOST_ASIO_CHECK(make_network_v6("2001:370::/64").is_subnet_of(make_network_v6("2001:370::/16"))); + BOOST_ASIO_CHECK(make_network_v6("2001:0db8:85a3::/64").is_subnet_of(make_network_v6("2001:0d00::/24"))); + + BOOST_ASIO_CHECK(!make_network_v6("2001:370::10:3744/128").is_subnet_of(make_network_v6("2001:370::10:3744/128"))); + BOOST_ASIO_CHECK(make_network_v6("2001:0db8:85a3::/64").is_subnet_of(make_network_v6("2001:0dc0::/24"))); + + network_v6 r(make_network_v6("2001:370::/64")); + BOOST_ASIO_CHECK(!r.is_subnet_of(r)); + + network_v6 net12(make_network_v6("2001:370::10:7344/64")); + network_v6 net13(make_network_v6("2001:0db8::/127")); + network_v6 net14(make_network_v6("2001:0db8::/125")); + network_v6 net15(make_network_v6("2001:0db8::/119")); + + // network + BOOST_ASIO_CHECK(net12.network() == make_address_v6("2001:370::")); + BOOST_ASIO_CHECK(net13.network() == make_address_v6("2001:0db8::")); + BOOST_ASIO_CHECK(net14.network() == make_address_v6("2001:0db8::")); + BOOST_ASIO_CHECK(net15.network() == make_address_v6("2001:0db8::")); + + // iterator + //BOOST_ASIO_CHECK(std::distance(net12.hosts().begin(),net12.hosts().end()) == 18446744073709552000); + BOOST_ASIO_CHECK(std::distance(net13.hosts().begin(),net13.hosts().end()) == 2); + BOOST_ASIO_CHECK(std::distance(net14.hosts().begin(),net14.hosts().end()) == 8); + BOOST_ASIO_CHECK(std::distance(net15.hosts().begin(),net15.hosts().end()) == 512); + BOOST_ASIO_CHECK(*net12.hosts().begin() == make_address_v6("2001:0370::")); + BOOST_ASIO_CHECK(net12.hosts().end() != net12.hosts().find(make_address_v6("2001:0370::ffff:ffff:ffff:ffff"))); + BOOST_ASIO_CHECK(*net13.hosts().begin() == make_address_v6("2001:0db8::")); + BOOST_ASIO_CHECK(net13.hosts().end() != net13.hosts().find(make_address_v6("2001:0db8::1"))); + BOOST_ASIO_CHECK(net13.hosts().end() == net13.hosts().find(make_address_v6("2001:0db8::2"))); + BOOST_ASIO_CHECK(*net14.hosts().begin() == make_address_v6("2001:0db8::")); + BOOST_ASIO_CHECK(net14.hosts().end() != net14.hosts().find(make_address_v6("2001:0db8::7"))); + BOOST_ASIO_CHECK(net14.hosts().end() == net14.hosts().find(make_address_v6("2001:0db8::8"))); + BOOST_ASIO_CHECK(*net15.hosts().begin() == make_address_v6("2001:0db8::")); + BOOST_ASIO_CHECK(net15.hosts().end() != net15.hosts().find(make_address_v6("2001:0db8::01ff"))); + BOOST_ASIO_CHECK(net15.hosts().end() == net15.hosts().find(make_address_v6("2001:0db8::0200"))); +} + +} // namespace ip_network_v6_runtime + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ip/network_v6", + BOOST_ASIO_TEST_CASE(ip_network_v6_compile::test) + BOOST_ASIO_TEST_CASE(ip_network_v6_runtime::test) +) diff --git a/src/boost/libs/asio/test/ip/resolver_query_base.cpp b/src/boost/libs/asio/test/ip/resolver_query_base.cpp new file mode 100644 index 000000000..d955a96ae --- /dev/null +++ b/src/boost/libs/asio/test/ip/resolver_query_base.cpp @@ -0,0 +1,25 @@ +// +// resolver_query_base.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/resolver_query_base.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ip/resolver_query_base", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ip/tcp.cpp b/src/boost/libs/asio/test/ip/tcp.cpp new file mode 100644 index 000000000..fc204ea5d --- /dev/null +++ b/src/boost/libs/asio/test/ip/tcp.cpp @@ -0,0 +1,1346 @@ +// +// tcp.cpp +// ~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Enable cancel() support on Windows. +#define BOOST_ASIO_ENABLE_CANCELIO 1 + +// Test that header file is self-contained. +#include <boost/asio/ip/tcp.hpp> + +#include <cstring> +#include <boost/asio/io_context.hpp> +#include <boost/asio/read.hpp> +#include <boost/asio/write.hpp> +#include "../unit_test.hpp" +#include "../archetypes/async_result.hpp" +#include "../archetypes/gettable_socket_option.hpp" +#include "../archetypes/io_control_command.hpp" +#include "../archetypes/settable_socket_option.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) +# include <boost/array.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_ARRAY) +# include <array> +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +//------------------------------------------------------------------------------ + +// ip_tcp_compile test +// ~~~~~~~~~~~~~~~~~~~ +// The following test checks that all nested classes, enums and constants in +// ip::tcp compile and link correctly. Runtime failures are ignored. + +namespace ip_tcp_compile { + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_context ioc; + ip::tcp::socket sock(ioc); + + // no_delay class. + + ip::tcp::no_delay no_delay1(true); + sock.set_option(no_delay1); + ip::tcp::no_delay no_delay2; + sock.get_option(no_delay2); + no_delay1 = true; + (void)static_cast<bool>(no_delay1); + (void)static_cast<bool>(!no_delay1); + (void)static_cast<bool>(no_delay1.value()); + } + catch (std::exception&) + { + } +} + +} // namespace ip_tcp_compile + +//------------------------------------------------------------------------------ + +// ip_tcp_runtime test +// ~~~~~~~~~~~~~~~~~~~ +// The following test checks the runtime operation of the ip::tcp class. + +namespace ip_tcp_runtime { + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + io_context ioc; + ip::tcp::socket sock(ioc, ip::tcp::v4()); + boost::system::error_code ec; + + // no_delay class. + + ip::tcp::no_delay no_delay1(true); + BOOST_ASIO_CHECK(no_delay1.value()); + BOOST_ASIO_CHECK(static_cast<bool>(no_delay1)); + BOOST_ASIO_CHECK(!!no_delay1); + sock.set_option(no_delay1, ec); + BOOST_ASIO_CHECK(!ec); + + ip::tcp::no_delay no_delay2; + sock.get_option(no_delay2, ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(no_delay2.value()); + BOOST_ASIO_CHECK(static_cast<bool>(no_delay2)); + BOOST_ASIO_CHECK(!!no_delay2); + + ip::tcp::no_delay no_delay3(false); + BOOST_ASIO_CHECK(!no_delay3.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(no_delay3)); + BOOST_ASIO_CHECK(!no_delay3); + sock.set_option(no_delay3, ec); + BOOST_ASIO_CHECK(!ec); + + ip::tcp::no_delay no_delay4; + sock.get_option(no_delay4, ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(!no_delay4.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(no_delay4)); + BOOST_ASIO_CHECK(!no_delay4); +} + +} // namespace ip_tcp_runtime + +//------------------------------------------------------------------------------ + +// ip_tcp_socket_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::tcp::socket compile and link correctly. Runtime failures are ignored. + +namespace ip_tcp_socket_compile { + +struct connect_handler +{ + connect_handler() {} + void operator()(const boost::system::error_code&) {} +#if defined(BOOST_ASIO_HAS_MOVE) + connect_handler(connect_handler&&) {} +private: + connect_handler(const connect_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +struct wait_handler +{ + wait_handler() {} + void operator()(const boost::system::error_code&) {} +#if defined(BOOST_ASIO_HAS_MOVE) + wait_handler(wait_handler&&) {} +private: + wait_handler(const wait_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +struct send_handler +{ + send_handler() {} + void operator()(const boost::system::error_code&, std::size_t) {} +#if defined(BOOST_ASIO_HAS_MOVE) + send_handler(send_handler&&) {} +private: + send_handler(const send_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +struct receive_handler +{ + receive_handler() {} + void operator()(const boost::system::error_code&, std::size_t) {} +#if defined(BOOST_ASIO_HAS_MOVE) + receive_handler(receive_handler&&) {} +private: + receive_handler(const receive_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +struct write_some_handler +{ + write_some_handler() {} + void operator()(const boost::system::error_code&, std::size_t) {} +#if defined(BOOST_ASIO_HAS_MOVE) + write_some_handler(write_some_handler&&) {} +private: + write_some_handler(const write_some_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +struct read_some_handler +{ + read_some_handler() {} + void operator()(const boost::system::error_code&, std::size_t) {} +#if defined(BOOST_ASIO_HAS_MOVE) + read_some_handler(read_some_handler&&) {} +private: + read_some_handler(const read_some_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +void test() +{ +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) + using boost::array; +#else // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + using std::array; +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_context ioc; + const io_context::executor_type ioc_ex = ioc.get_executor(); + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + array<boost::asio::mutable_buffer, 2> mutable_buffers = {{ + boost::asio::buffer(mutable_char_buffer, 10), + boost::asio::buffer(mutable_char_buffer + 10, 10) }}; + array<boost::asio::const_buffer, 2> const_buffers = {{ + boost::asio::buffer(const_char_buffer, 10), + boost::asio::buffer(const_char_buffer + 10, 10) }}; + socket_base::message_flags in_flags = 0; + archetypes::settable_socket_option<void> settable_socket_option1; + archetypes::settable_socket_option<int> settable_socket_option2; + archetypes::settable_socket_option<double> settable_socket_option3; + archetypes::gettable_socket_option<void> gettable_socket_option1; + archetypes::gettable_socket_option<int> gettable_socket_option2; + archetypes::gettable_socket_option<double> gettable_socket_option3; + archetypes::io_control_command io_control_command; + archetypes::lazy_handler lazy; + boost::system::error_code ec; + + // basic_stream_socket constructors. + + ip::tcp::socket socket1(ioc); + ip::tcp::socket socket2(ioc, ip::tcp::v4()); + ip::tcp::socket socket3(ioc, ip::tcp::v6()); + ip::tcp::socket socket4(ioc, ip::tcp::endpoint(ip::tcp::v4(), 0)); + ip::tcp::socket socket5(ioc, ip::tcp::endpoint(ip::tcp::v6(), 0)); +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + ip::tcp::socket::native_handle_type native_socket1 + = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ip::tcp::socket socket6(ioc, ip::tcp::v4(), native_socket1); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + + ip::tcp::socket socket7(ioc_ex); + ip::tcp::socket socket8(ioc_ex, ip::tcp::v4()); + ip::tcp::socket socket9(ioc_ex, ip::tcp::v6()); + ip::tcp::socket socket10(ioc_ex, ip::tcp::endpoint(ip::tcp::v4(), 0)); + ip::tcp::socket socket11(ioc_ex, ip::tcp::endpoint(ip::tcp::v6(), 0)); +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + ip::tcp::socket::native_handle_type native_socket2 + = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ip::tcp::socket socket12(ioc_ex, ip::tcp::v4(), native_socket2); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#if defined(BOOST_ASIO_HAS_MOVE) + ip::tcp::socket socket13(std::move(socket5)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_stream_socket operators. + +#if defined(BOOST_ASIO_HAS_MOVE) + socket1 = ip::tcp::socket(ioc); + socket1 = std::move(socket2); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_io_object functions. + + ip::tcp::socket::executor_type ex = socket1.get_executor(); + (void)ex; + + // basic_socket functions. + + ip::tcp::socket::lowest_layer_type& lowest_layer = socket1.lowest_layer(); + (void)lowest_layer; + + const ip::tcp::socket& socket14 = socket1; + const ip::tcp::socket::lowest_layer_type& lowest_layer2 + = socket14.lowest_layer(); + (void)lowest_layer2; + + socket1.open(ip::tcp::v4()); + socket1.open(ip::tcp::v6()); + socket1.open(ip::tcp::v4(), ec); + socket1.open(ip::tcp::v6(), ec); + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + ip::tcp::socket::native_handle_type native_socket3 + = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + socket1.assign(ip::tcp::v4(), native_socket3); + ip::tcp::socket::native_handle_type native_socket4 + = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + socket1.assign(ip::tcp::v4(), native_socket4, ec); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + + bool is_open = socket1.is_open(); + (void)is_open; + + socket1.close(); + socket1.close(ec); + + socket1.release(); + socket1.release(ec); + + ip::tcp::socket::native_handle_type native_socket5 + = socket1.native_handle(); + (void)native_socket5; + + socket1.cancel(); + socket1.cancel(ec); + + bool at_mark1 = socket1.at_mark(); + (void)at_mark1; + bool at_mark2 = socket1.at_mark(ec); + (void)at_mark2; + + std::size_t available1 = socket1.available(); + (void)available1; + std::size_t available2 = socket1.available(ec); + (void)available2; + + socket1.bind(ip::tcp::endpoint(ip::tcp::v4(), 0)); + socket1.bind(ip::tcp::endpoint(ip::tcp::v6(), 0)); + socket1.bind(ip::tcp::endpoint(ip::tcp::v4(), 0), ec); + socket1.bind(ip::tcp::endpoint(ip::tcp::v6(), 0), ec); + + socket1.connect(ip::tcp::endpoint(ip::tcp::v4(), 0)); + socket1.connect(ip::tcp::endpoint(ip::tcp::v6(), 0)); + socket1.connect(ip::tcp::endpoint(ip::tcp::v4(), 0), ec); + socket1.connect(ip::tcp::endpoint(ip::tcp::v6(), 0), ec); + + socket1.async_connect(ip::tcp::endpoint(ip::tcp::v4(), 0), + connect_handler()); + socket1.async_connect(ip::tcp::endpoint(ip::tcp::v6(), 0), + connect_handler()); + int i1 = socket1.async_connect(ip::tcp::endpoint(ip::tcp::v4(), 0), lazy); + (void)i1; + int i2 = socket1.async_connect(ip::tcp::endpoint(ip::tcp::v6(), 0), lazy); + (void)i2; + + socket1.set_option(settable_socket_option1); + socket1.set_option(settable_socket_option1, ec); + socket1.set_option(settable_socket_option2); + socket1.set_option(settable_socket_option2, ec); + socket1.set_option(settable_socket_option3); + socket1.set_option(settable_socket_option3, ec); + + socket1.get_option(gettable_socket_option1); + socket1.get_option(gettable_socket_option1, ec); + socket1.get_option(gettable_socket_option2); + socket1.get_option(gettable_socket_option2, ec); + socket1.get_option(gettable_socket_option3); + socket1.get_option(gettable_socket_option3, ec); + + socket1.io_control(io_control_command); + socket1.io_control(io_control_command, ec); + + bool non_blocking1 = socket1.non_blocking(); + (void)non_blocking1; + socket1.non_blocking(true); + socket1.non_blocking(false, ec); + + bool non_blocking2 = socket1.native_non_blocking(); + (void)non_blocking2; + socket1.native_non_blocking(true); + socket1.native_non_blocking(false, ec); + + ip::tcp::endpoint endpoint1 = socket1.local_endpoint(); + (void)endpoint1; + ip::tcp::endpoint endpoint2 = socket1.local_endpoint(ec); + (void)endpoint2; + + ip::tcp::endpoint endpoint3 = socket1.remote_endpoint(); + (void)endpoint3; + ip::tcp::endpoint endpoint4 = socket1.remote_endpoint(ec); + (void)endpoint4; + + socket1.shutdown(socket_base::shutdown_both); + socket1.shutdown(socket_base::shutdown_both, ec); + + socket1.wait(socket_base::wait_read); + socket1.wait(socket_base::wait_write, ec); + + socket1.async_wait(socket_base::wait_read, wait_handler()); + int i3 = socket1.async_wait(socket_base::wait_write, lazy); + (void)i3; + + // basic_stream_socket functions. + + socket1.send(buffer(mutable_char_buffer)); + socket1.send(buffer(const_char_buffer)); + socket1.send(mutable_buffers); + socket1.send(const_buffers); + socket1.send(null_buffers()); + socket1.send(buffer(mutable_char_buffer), in_flags); + socket1.send(buffer(const_char_buffer), in_flags); + socket1.send(mutable_buffers, in_flags); + socket1.send(const_buffers, in_flags); + socket1.send(null_buffers(), in_flags); + socket1.send(buffer(mutable_char_buffer), in_flags, ec); + socket1.send(buffer(const_char_buffer), in_flags, ec); + socket1.send(mutable_buffers, in_flags, ec); + socket1.send(const_buffers, in_flags, ec); + socket1.send(null_buffers(), in_flags, ec); + + socket1.async_send(buffer(mutable_char_buffer), send_handler()); + socket1.async_send(buffer(const_char_buffer), send_handler()); + socket1.async_send(mutable_buffers, send_handler()); + socket1.async_send(const_buffers, send_handler()); + socket1.async_send(null_buffers(), send_handler()); + socket1.async_send(buffer(mutable_char_buffer), in_flags, send_handler()); + socket1.async_send(buffer(const_char_buffer), in_flags, send_handler()); + socket1.async_send(mutable_buffers, in_flags, send_handler()); + socket1.async_send(const_buffers, in_flags, send_handler()); + socket1.async_send(null_buffers(), in_flags, send_handler()); + int i4 = socket1.async_send(buffer(mutable_char_buffer), lazy); + (void)i4; + int i5 = socket1.async_send(buffer(const_char_buffer), lazy); + (void)i5; + int i6 = socket1.async_send(mutable_buffers, lazy); + (void)i6; + int i7 = socket1.async_send(const_buffers, lazy); + (void)i7; + int i8 = socket1.async_send(null_buffers(), lazy); + (void)i8; + int i9 = socket1.async_send(buffer(mutable_char_buffer), in_flags, lazy); + (void)i9; + int i10 = socket1.async_send(buffer(const_char_buffer), in_flags, lazy); + (void)i10; + int i11 = socket1.async_send(mutable_buffers, in_flags, lazy); + (void)i11; + int i12 = socket1.async_send(const_buffers, in_flags, lazy); + (void)i12; + int i13 = socket1.async_send(null_buffers(), in_flags, lazy); + (void)i13; + + socket1.receive(buffer(mutable_char_buffer)); + socket1.receive(mutable_buffers); + socket1.receive(null_buffers()); + socket1.receive(buffer(mutable_char_buffer), in_flags); + socket1.receive(mutable_buffers, in_flags); + socket1.receive(null_buffers(), in_flags); + socket1.receive(buffer(mutable_char_buffer), in_flags, ec); + socket1.receive(mutable_buffers, in_flags, ec); + socket1.receive(null_buffers(), in_flags, ec); + + socket1.async_receive(buffer(mutable_char_buffer), receive_handler()); + socket1.async_receive(mutable_buffers, receive_handler()); + socket1.async_receive(null_buffers(), receive_handler()); + socket1.async_receive(buffer(mutable_char_buffer), in_flags, + receive_handler()); + socket1.async_receive(mutable_buffers, in_flags, receive_handler()); + socket1.async_receive(null_buffers(), in_flags, receive_handler()); + int i14 = socket1.async_receive(buffer(mutable_char_buffer), lazy); + (void)i14; + int i15 = socket1.async_receive(mutable_buffers, lazy); + (void)i15; + int i16 = socket1.async_receive(null_buffers(), lazy); + (void)i16; + int i17 = socket1.async_receive(buffer(mutable_char_buffer), in_flags, + lazy); + (void)i17; + int i18 = socket1.async_receive(mutable_buffers, in_flags, lazy); + (void)i18; + int i19 = socket1.async_receive(null_buffers(), in_flags, lazy); + (void)i19; + + socket1.write_some(buffer(mutable_char_buffer)); + socket1.write_some(buffer(const_char_buffer)); + socket1.write_some(mutable_buffers); + socket1.write_some(const_buffers); + socket1.write_some(null_buffers()); + socket1.write_some(buffer(mutable_char_buffer), ec); + socket1.write_some(buffer(const_char_buffer), ec); + socket1.write_some(mutable_buffers, ec); + socket1.write_some(const_buffers, ec); + socket1.write_some(null_buffers(), ec); + + socket1.async_write_some(buffer(mutable_char_buffer), write_some_handler()); + socket1.async_write_some(buffer(const_char_buffer), write_some_handler()); + socket1.async_write_some(mutable_buffers, write_some_handler()); + socket1.async_write_some(const_buffers, write_some_handler()); + socket1.async_write_some(null_buffers(), write_some_handler()); + int i20 = socket1.async_write_some(buffer(mutable_char_buffer), lazy); + (void)i20; + int i21 = socket1.async_write_some(buffer(const_char_buffer), lazy); + (void)i21; + int i22 = socket1.async_write_some(mutable_buffers, lazy); + (void)i22; + int i23 = socket1.async_write_some(const_buffers, lazy); + (void)i23; + int i24 = socket1.async_write_some(null_buffers(), lazy); + (void)i24; + + socket1.read_some(buffer(mutable_char_buffer)); + socket1.read_some(mutable_buffers); + socket1.read_some(null_buffers()); + socket1.read_some(buffer(mutable_char_buffer), ec); + socket1.read_some(mutable_buffers, ec); + socket1.read_some(null_buffers(), ec); + + socket1.async_read_some(buffer(mutable_char_buffer), read_some_handler()); + socket1.async_read_some(mutable_buffers, read_some_handler()); + socket1.async_read_some(null_buffers(), read_some_handler()); + int i25 = socket1.async_read_some(buffer(mutable_char_buffer), lazy); + (void)i25; + int i26 = socket1.async_read_some(mutable_buffers, lazy); + (void)i26; + int i27 = socket1.async_read_some(null_buffers(), lazy); + (void)i27; + } + catch (std::exception&) + { + } +} + +} // namespace ip_tcp_socket_compile + +//------------------------------------------------------------------------------ + +// ip_tcp_socket_runtime test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks the runtime operation of the ip::tcp::socket class. + +namespace ip_tcp_socket_runtime { + +static const char write_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +void handle_read_noop(const boost::system::error_code& err, + size_t bytes_transferred, bool* called) +{ + *called = true; + BOOST_ASIO_CHECK(!err); + BOOST_ASIO_CHECK(bytes_transferred == 0); +} + +void handle_write_noop(const boost::system::error_code& err, + size_t bytes_transferred, bool* called) +{ + *called = true; + BOOST_ASIO_CHECK(!err); + BOOST_ASIO_CHECK(bytes_transferred == 0); +} + +void handle_read(const boost::system::error_code& err, + size_t bytes_transferred, bool* called) +{ + *called = true; + BOOST_ASIO_CHECK(!err); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); +} + +void handle_write(const boost::system::error_code& err, + size_t bytes_transferred, bool* called) +{ + *called = true; + BOOST_ASIO_CHECK(!err); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); +} + +void handle_read_cancel(const boost::system::error_code& err, + size_t bytes_transferred, bool* called) +{ + *called = true; + BOOST_ASIO_CHECK(err == boost::asio::error::operation_aborted); + BOOST_ASIO_CHECK(bytes_transferred == 0); +} + +void handle_read_eof(const boost::system::error_code& err, + size_t bytes_transferred, bool* called) +{ + *called = true; + BOOST_ASIO_CHECK(err == boost::asio::error::eof); + BOOST_ASIO_CHECK(bytes_transferred == 0); +} + +void test() +{ + using namespace std; // For memcmp. + using namespace boost::asio; + namespace ip = boost::asio::ip; + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + io_context ioc; + + ip::tcp::acceptor acceptor(ioc, ip::tcp::endpoint(ip::tcp::v4(), 0)); + ip::tcp::endpoint server_endpoint = acceptor.local_endpoint(); + server_endpoint.address(ip::address_v4::loopback()); + + ip::tcp::socket client_side_socket(ioc); + ip::tcp::socket server_side_socket(ioc); + + client_side_socket.connect(server_endpoint); + acceptor.accept(server_side_socket); + + // No-op read. + + bool read_noop_completed = false; + client_side_socket.async_read_some( + boost::asio::mutable_buffer(0, 0), + bindns::bind(handle_read_noop, + _1, _2, &read_noop_completed)); + + ioc.run(); + BOOST_ASIO_CHECK(read_noop_completed); + + // No-op write. + + bool write_noop_completed = false; + client_side_socket.async_write_some( + boost::asio::const_buffer(0, 0), + bindns::bind(handle_write_noop, + _1, _2, &write_noop_completed)); + + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(write_noop_completed); + + // Read and write to transfer data. + + char read_buffer[sizeof(write_data)]; + bool read_completed = false; + boost::asio::async_read(client_side_socket, + boost::asio::buffer(read_buffer), + bindns::bind(handle_read, + _1, _2, &read_completed)); + + bool write_completed = false; + boost::asio::async_write(server_side_socket, + boost::asio::buffer(write_data), + bindns::bind(handle_write, + _1, _2, &write_completed)); + + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(read_completed); + BOOST_ASIO_CHECK(write_completed); + BOOST_ASIO_CHECK(memcmp(read_buffer, write_data, sizeof(write_data)) == 0); + + // Cancelled read. + + bool read_cancel_completed = false; + boost::asio::async_read(server_side_socket, + boost::asio::buffer(read_buffer), + bindns::bind(handle_read_cancel, + _1, _2, &read_cancel_completed)); + + ioc.restart(); + ioc.poll(); + BOOST_ASIO_CHECK(!read_cancel_completed); + + server_side_socket.cancel(); + + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(read_cancel_completed); + + // A read when the peer closes socket should fail with eof. + + bool read_eof_completed = false; + boost::asio::async_read(client_side_socket, + boost::asio::buffer(read_buffer), + bindns::bind(handle_read_eof, + _1, _2, &read_eof_completed)); + + server_side_socket.close(); + + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(read_eof_completed); +} + +} // namespace ip_tcp_socket_runtime + +//------------------------------------------------------------------------------ + +// ip_tcp_acceptor_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::tcp::acceptor compile and link correctly. Runtime failures are ignored. + +namespace ip_tcp_acceptor_compile { + +struct wait_handler +{ + wait_handler() {} + void operator()(const boost::system::error_code&) {} +#if defined(BOOST_ASIO_HAS_MOVE) + wait_handler(wait_handler&&) {} +private: + wait_handler(const wait_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +struct accept_handler +{ + accept_handler() {} + void operator()(const boost::system::error_code&) {} +#if defined(BOOST_ASIO_HAS_MOVE) + accept_handler(accept_handler&&) {} +private: + accept_handler(const accept_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +#if defined(BOOST_ASIO_HAS_MOVE) +struct move_accept_handler +{ + move_accept_handler() {} + void operator()( + const boost::system::error_code&, boost::asio::ip::tcp::socket) {} + move_accept_handler(move_accept_handler&&) {} +private: + move_accept_handler(const move_accept_handler&) {} +}; + +struct move_accept_ioc_handler +{ + move_accept_ioc_handler() {} + void operator()(const boost::system::error_code&, + boost::asio::basic_stream_socket<boost::asio::ip::tcp, + boost::asio::io_context::executor_type>) {} + move_accept_ioc_handler(move_accept_handler&&) {} +private: + move_accept_ioc_handler(const move_accept_handler&) {} +}; +#endif // defined(BOOST_ASIO_HAS_MOVE) + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_context ioc; + const io_context::executor_type ioc_ex = ioc.get_executor(); + ip::tcp::socket peer_socket1(ioc); + boost::asio::basic_stream_socket<ip::tcp, + io_context::executor_type> peer_socket2(ioc); + ip::tcp::endpoint peer_endpoint; + archetypes::settable_socket_option<void> settable_socket_option1; + archetypes::settable_socket_option<int> settable_socket_option2; + archetypes::settable_socket_option<double> settable_socket_option3; + archetypes::gettable_socket_option<void> gettable_socket_option1; + archetypes::gettable_socket_option<int> gettable_socket_option2; + archetypes::gettable_socket_option<double> gettable_socket_option3; + archetypes::io_control_command io_control_command; + archetypes::lazy_handler lazy; + boost::system::error_code ec; + + // basic_socket_acceptor constructors. + + ip::tcp::acceptor acceptor1(ioc); + ip::tcp::acceptor acceptor2(ioc, ip::tcp::v4()); + ip::tcp::acceptor acceptor3(ioc, ip::tcp::v6()); + ip::tcp::acceptor acceptor4(ioc, ip::tcp::endpoint(ip::tcp::v4(), 0)); + ip::tcp::acceptor acceptor5(ioc, ip::tcp::endpoint(ip::tcp::v6(), 0)); +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + ip::tcp::acceptor::native_handle_type native_acceptor1 + = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ip::tcp::acceptor acceptor6(ioc, ip::tcp::v4(), native_acceptor1); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + + ip::tcp::acceptor acceptor7(ioc_ex); + ip::tcp::acceptor acceptor8(ioc_ex, ip::tcp::v4()); + ip::tcp::acceptor acceptor9(ioc_ex, ip::tcp::v6()); + ip::tcp::acceptor acceptor10(ioc_ex, ip::tcp::endpoint(ip::tcp::v4(), 0)); + ip::tcp::acceptor acceptor11(ioc_ex, ip::tcp::endpoint(ip::tcp::v6(), 0)); +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + ip::tcp::acceptor::native_handle_type native_acceptor2 + = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ip::tcp::acceptor acceptor12(ioc_ex, ip::tcp::v4(), native_acceptor2); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#if defined(BOOST_ASIO_HAS_MOVE) + ip::tcp::acceptor acceptor13(std::move(acceptor5)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_socket_acceptor operators. + +#if defined(BOOST_ASIO_HAS_MOVE) + acceptor1 = ip::tcp::acceptor(ioc); + acceptor1 = std::move(acceptor2); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_io_object functions. + + ip::tcp::acceptor::executor_type ex = acceptor1.get_executor(); + (void)ex; + + // basic_socket_acceptor functions. + + acceptor1.open(ip::tcp::v4()); + acceptor1.open(ip::tcp::v6()); + acceptor1.open(ip::tcp::v4(), ec); + acceptor1.open(ip::tcp::v6(), ec); + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + ip::tcp::acceptor::native_handle_type native_acceptor3 + = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + acceptor1.assign(ip::tcp::v4(), native_acceptor3); + ip::tcp::acceptor::native_handle_type native_acceptor4 + = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + acceptor1.assign(ip::tcp::v4(), native_acceptor4, ec); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + + bool is_open = acceptor1.is_open(); + (void)is_open; + + acceptor1.close(); + acceptor1.close(ec); + + acceptor1.release(); + acceptor1.release(ec); + + ip::tcp::acceptor::native_handle_type native_acceptor5 + = acceptor1.native_handle(); + (void)native_acceptor5; + + acceptor1.cancel(); + acceptor1.cancel(ec); + + acceptor1.bind(ip::tcp::endpoint(ip::tcp::v4(), 0)); + acceptor1.bind(ip::tcp::endpoint(ip::tcp::v6(), 0)); + acceptor1.bind(ip::tcp::endpoint(ip::tcp::v4(), 0), ec); + acceptor1.bind(ip::tcp::endpoint(ip::tcp::v6(), 0), ec); + + acceptor1.set_option(settable_socket_option1); + acceptor1.set_option(settable_socket_option1, ec); + acceptor1.set_option(settable_socket_option2); + acceptor1.set_option(settable_socket_option2, ec); + acceptor1.set_option(settable_socket_option3); + acceptor1.set_option(settable_socket_option3, ec); + + acceptor1.get_option(gettable_socket_option1); + acceptor1.get_option(gettable_socket_option1, ec); + acceptor1.get_option(gettable_socket_option2); + acceptor1.get_option(gettable_socket_option2, ec); + acceptor1.get_option(gettable_socket_option3); + acceptor1.get_option(gettable_socket_option3, ec); + + acceptor1.io_control(io_control_command); + acceptor1.io_control(io_control_command, ec); + + bool non_blocking1 = acceptor1.non_blocking(); + (void)non_blocking1; + acceptor1.non_blocking(true); + acceptor1.non_blocking(false, ec); + + bool non_blocking2 = acceptor1.native_non_blocking(); + (void)non_blocking2; + acceptor1.native_non_blocking(true); + acceptor1.native_non_blocking(false, ec); + + ip::tcp::endpoint endpoint1 = acceptor1.local_endpoint(); + (void)endpoint1; + ip::tcp::endpoint endpoint2 = acceptor1.local_endpoint(ec); + (void)endpoint2; + + acceptor1.wait(socket_base::wait_read); + acceptor1.wait(socket_base::wait_write, ec); + + acceptor1.async_wait(socket_base::wait_read, wait_handler()); + int i1 = acceptor1.async_wait(socket_base::wait_write, lazy); + (void)i1; + + acceptor1.accept(peer_socket1); + acceptor1.accept(peer_socket1, ec); + acceptor1.accept(peer_socket1, peer_endpoint); + acceptor1.accept(peer_socket1, peer_endpoint, ec); + + acceptor1.accept(peer_socket2); + acceptor1.accept(peer_socket2, ec); + acceptor1.accept(peer_socket2, peer_endpoint); + acceptor1.accept(peer_socket2, peer_endpoint, ec); + +#if defined(BOOST_ASIO_HAS_MOVE) + peer_socket1 = acceptor1.accept(); + peer_socket1 = acceptor1.accept(ioc); + peer_socket1 = acceptor1.accept(ioc_ex); + peer_socket1 = acceptor1.accept(peer_endpoint); + peer_socket1 = acceptor1.accept(ioc, peer_endpoint); + peer_socket1 = acceptor1.accept(ioc_ex, peer_endpoint); + (void)peer_socket1; + + peer_socket2 = acceptor1.accept(ioc); + peer_socket2 = acceptor1.accept(ioc_ex); + peer_socket2 = acceptor1.accept(ioc, peer_endpoint); + peer_socket2 = acceptor1.accept(ioc_ex, peer_endpoint); + (void)peer_socket2; +#endif // defined(BOOST_ASIO_HAS_MOVE) + + acceptor1.async_accept(peer_socket1, accept_handler()); + acceptor1.async_accept(peer_socket1, peer_endpoint, accept_handler()); + int i2 = acceptor1.async_accept(peer_socket1, lazy); + (void)i2; + int i3 = acceptor1.async_accept(peer_socket1, peer_endpoint, lazy); + (void)i3; + + acceptor1.async_accept(peer_socket2, accept_handler()); + acceptor1.async_accept(peer_socket2, peer_endpoint, accept_handler()); + int i4 = acceptor1.async_accept(peer_socket2, lazy); + (void)i4; + int i5 = acceptor1.async_accept(peer_socket2, peer_endpoint, lazy); + (void)i5; + +#if defined(BOOST_ASIO_HAS_MOVE) + acceptor1.async_accept(move_accept_handler()); + acceptor1.async_accept(ioc, move_accept_handler()); + acceptor1.async_accept(ioc_ex, move_accept_handler()); + acceptor1.async_accept(ioc_ex, move_accept_ioc_handler()); + acceptor1.async_accept(peer_endpoint, move_accept_handler()); + acceptor1.async_accept(ioc, peer_endpoint, move_accept_handler()); + acceptor1.async_accept(ioc_ex, peer_endpoint, move_accept_handler()); + acceptor1.async_accept(ioc_ex, peer_endpoint, move_accept_ioc_handler()); +#endif // defined(BOOST_ASIO_HAS_MOVE) + } + catch (std::exception&) + { + } +} + +} // namespace ip_tcp_acceptor_compile + +//------------------------------------------------------------------------------ + +// ip_tcp_acceptor_runtime test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks the runtime operation of the ip::tcp::acceptor +// class. + +namespace ip_tcp_acceptor_runtime { + +void handle_accept(const boost::system::error_code& err) +{ + BOOST_ASIO_CHECK(!err); +} + +void handle_connect(const boost::system::error_code& err) +{ + BOOST_ASIO_CHECK(!err); +} + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + io_context ioc; + + ip::tcp::acceptor acceptor(ioc, ip::tcp::endpoint(ip::tcp::v4(), 0)); + ip::tcp::endpoint server_endpoint = acceptor.local_endpoint(); + server_endpoint.address(ip::address_v4::loopback()); + + ip::tcp::socket client_side_socket(ioc); + ip::tcp::socket server_side_socket(ioc); + + client_side_socket.connect(server_endpoint); + acceptor.accept(server_side_socket); + + client_side_socket.close(); + server_side_socket.close(); + + client_side_socket.connect(server_endpoint); + ip::tcp::endpoint client_endpoint; + acceptor.accept(server_side_socket, client_endpoint); + + ip::tcp::endpoint client_side_local_endpoint + = client_side_socket.local_endpoint(); + BOOST_ASIO_CHECK(client_side_local_endpoint.port() == client_endpoint.port()); + + ip::tcp::endpoint server_side_remote_endpoint + = server_side_socket.remote_endpoint(); + BOOST_ASIO_CHECK(server_side_remote_endpoint.port() + == client_endpoint.port()); + + client_side_socket.close(); + server_side_socket.close(); + + acceptor.async_accept(server_side_socket, &handle_accept); + client_side_socket.async_connect(server_endpoint, &handle_connect); + + ioc.run(); + + client_side_socket.close(); + server_side_socket.close(); + + acceptor.async_accept(server_side_socket, client_endpoint, &handle_accept); + client_side_socket.async_connect(server_endpoint, &handle_connect); + + ioc.restart(); + ioc.run(); + + client_side_local_endpoint = client_side_socket.local_endpoint(); + BOOST_ASIO_CHECK(client_side_local_endpoint.port() == client_endpoint.port()); + + server_side_remote_endpoint = server_side_socket.remote_endpoint(); + BOOST_ASIO_CHECK(server_side_remote_endpoint.port() + == client_endpoint.port()); +} + +} // namespace ip_tcp_acceptor_runtime + +//------------------------------------------------------------------------------ + +// ip_tcp_resolver_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::tcp::resolver compile and link correctly. Runtime failures are ignored. + +namespace ip_tcp_resolver_compile { + +struct resolve_handler +{ + resolve_handler() {} + void operator()(const boost::system::error_code&, + boost::asio::ip::tcp::resolver::results_type) {} +#if defined(BOOST_ASIO_HAS_MOVE) + resolve_handler(resolve_handler&&) {} +private: + resolve_handler(const resolve_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +struct legacy_resolve_handler +{ + legacy_resolve_handler() {} + void operator()(const boost::system::error_code&, + boost::asio::ip::tcp::resolver::iterator) {} +#if defined(BOOST_ASIO_HAS_MOVE) + legacy_resolve_handler(legacy_resolve_handler&&) {} +private: + legacy_resolve_handler(const legacy_resolve_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_context ioc; + const io_context::executor_type ioc_ex = ioc.get_executor(); + archetypes::lazy_handler lazy; + boost::system::error_code ec; +#if !defined(BOOST_ASIO_NO_DEPRECATED) + ip::tcp::resolver::query q(ip::tcp::v4(), "localhost", "0"); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + ip::tcp::endpoint e(ip::address_v4::loopback(), 0); + + // basic_resolver constructors. + + ip::tcp::resolver resolver(ioc); + ip::tcp::resolver resolver2(ioc_ex); + +#if defined(BOOST_ASIO_HAS_MOVE) + ip::tcp::resolver resolver3(std::move(resolver)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_resolver operators. + +#if defined(BOOST_ASIO_HAS_MOVE) + resolver = ip::tcp::resolver(ioc); + resolver = std::move(resolver3); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_io_object functions. + + ip::tcp::resolver::executor_type ex = resolver.get_executor(); + (void)ex; + + // basic_resolver functions. + + resolver.cancel(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + ip::tcp::resolver::results_type results1 = resolver.resolve(q); + (void)results1; + + ip::tcp::resolver::results_type results2 = resolver.resolve(q, ec); + (void)results2; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + ip::tcp::resolver::results_type results3 = resolver.resolve("", ""); + (void)results3; + + ip::tcp::resolver::results_type results4 = resolver.resolve("", "", ec); + (void)results4; + + ip::tcp::resolver::results_type results5 = + resolver.resolve("", "", ip::tcp::resolver::flags()); + (void)results5; + + ip::tcp::resolver::results_type results6 = + resolver.resolve("", "", ip::tcp::resolver::flags(), ec); + (void)results6; + + ip::tcp::resolver::results_type results7 = + resolver.resolve(ip::tcp::v4(), "", ""); + (void)results7; + + ip::tcp::resolver::results_type results8 = + resolver.resolve(ip::tcp::v4(), "", "", ec); + (void)results8; + + ip::tcp::resolver::results_type results9 = + resolver.resolve(ip::tcp::v4(), "", "", ip::tcp::resolver::flags()); + (void)results9; + + ip::tcp::resolver::results_type results10 = + resolver.resolve(ip::tcp::v4(), "", "", ip::tcp::resolver::flags(), ec); + (void)results10; + + ip::tcp::resolver::results_type results11 = resolver.resolve(e); + (void)results11; + + ip::tcp::resolver::results_type results12 = resolver.resolve(e, ec); + (void)results12; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + resolver.async_resolve(q, resolve_handler()); + resolver.async_resolve(q, legacy_resolve_handler()); + int i1 = resolver.async_resolve(q, lazy); + (void)i1; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + resolver.async_resolve("", "", resolve_handler()); +#if !defined(BOOST_ASIO_NO_DEPRECATED) + resolver.async_resolve("", "", legacy_resolve_handler()); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + int i2 = resolver.async_resolve("", "", lazy); + (void)i2; + + resolver.async_resolve("", "", + ip::tcp::resolver::flags(), resolve_handler()); +#if !defined(BOOST_ASIO_NO_DEPRECATED) + resolver.async_resolve("", "", + ip::tcp::resolver::flags(), legacy_resolve_handler()); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + int i3 = resolver.async_resolve("", "", + ip::tcp::resolver::flags(), lazy); + (void)i3; + + resolver.async_resolve(ip::tcp::v4(), "", "", resolve_handler()); +#if !defined(BOOST_ASIO_NO_DEPRECATED) + resolver.async_resolve(ip::tcp::v4(), "", "", legacy_resolve_handler()); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + int i4 = resolver.async_resolve(ip::tcp::v4(), "", "", lazy); + (void)i4; + + resolver.async_resolve(ip::tcp::v4(), + "", "", ip::tcp::resolver::flags(), resolve_handler()); +#if !defined(BOOST_ASIO_NO_DEPRECATED) + resolver.async_resolve(ip::tcp::v4(), + "", "", ip::tcp::resolver::flags(), legacy_resolve_handler()); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + int i5 = resolver.async_resolve(ip::tcp::v4(), + "", "", ip::tcp::resolver::flags(), lazy); + (void)i5; + + resolver.async_resolve(e, resolve_handler()); +#if !defined(BOOST_ASIO_NO_DEPRECATED) + resolver.async_resolve(e, legacy_resolve_handler()); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + int i6 = resolver.async_resolve(e, lazy); + (void)i6; + } + catch (std::exception&) + { + } +} + +} // namespace ip_tcp_resolver_compile + +//------------------------------------------------------------------------------ + +// ip_tcp_resolver_entry_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::tcp::resolver::entry compile and link correctly. Runtime failures are +// ignored. + +namespace ip_tcp_resolver_entry_compile { + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + const ip::tcp::endpoint endpoint; + const std::string host_name; + const std::string service_name; + const std::allocator<char> alloc; + + try + { + // basic_resolver_entry constructors. + + const ip::basic_resolver_entry<ip::tcp> entry1; + ip::basic_resolver_entry<ip::tcp> entry2(endpoint, host_name, service_name); + ip::basic_resolver_entry<ip::tcp> entry3(entry1); +#if defined(BOOST_ASIO_HAS_MOVE) + ip::basic_resolver_entry<ip::tcp> entry4(std::move(entry2)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_resolver_entry functions. + + ip::tcp::endpoint e1 = entry1.endpoint(); + (void)e1; + + ip::tcp::endpoint e2 = entry1; + (void)e2; + + std::string s1 = entry1.host_name(); + (void)s1; + + std::string s2 = entry1.host_name(alloc); + (void)s2; + + std::string s3 = entry1.service_name(); + (void)s3; + + std::string s4 = entry1.service_name(alloc); + (void)s4; + } + catch (std::exception&) + { + } +} + +} // namespace ip_tcp_resolver_entry_compile + +//------------------------------------------------------------------------------ + +// ip_tcp_iostream_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public types and member functions on the +// class ip::tcp::iostream compile and link correctly. Runtime failures are +// ignored. + +namespace ip_tcp_iostream_compile { + +void test() +{ +#if !defined(BOOST_ASIO_NO_IOSTREAM) + using namespace boost::asio; + namespace ip = boost::asio::ip; + + boost::asio::io_context ioc; + boost::asio::ip::tcp::socket sock(ioc); + + // basic_socket_iostream typedefs. + + (void)static_cast<ip::tcp::iostream::protocol_type*>(0); + (void)static_cast<ip::tcp::iostream::endpoint_type*>(0); + (void)static_cast<ip::tcp::iostream::clock_type*>(0); + (void)static_cast<ip::tcp::iostream::time_point*>(0); + (void)static_cast<ip::tcp::iostream::duration*>(0); + (void)static_cast<ip::tcp::iostream::traits_type*>(0); + + // basic_socket_iostream constructors. + + ip::tcp::iostream ios1; + +#if defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) + ip::tcp::iostream ios2(std::move(sock)); +#endif // defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) + + ip::tcp::iostream ios3("hostname", "service"); + + // basic_socket_iostream operators. + +#if defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) + ios1 = ip::tcp::iostream(); + + ios2 = std::move(ios1); +#endif // defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) + + // basic_socket_iostream members. + + ios1.connect("hostname", "service"); + + ios1.close(); + + (void)static_cast<std::streambuf*>(ios1.rdbuf()); + + basic_socket<ip::tcp>& sref = ios1.socket(); + (void)sref; + + boost::system::error_code ec = ios1.error(); + (void)ec; + + ip::tcp::iostream::time_point tp = ios1.expiry(); + (void)tp; + + ios1.expires_at(tp); + + ip::tcp::iostream::duration d; + ios1.expires_after(d); + + // iostream operators. + + int i = 0; + ios1 >> i; + ios1 << i; +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +} + +} // namespace ip_tcp_iostream_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ip/tcp", + BOOST_ASIO_TEST_CASE(ip_tcp_compile::test) + BOOST_ASIO_TEST_CASE(ip_tcp_runtime::test) + BOOST_ASIO_TEST_CASE(ip_tcp_socket_compile::test) + BOOST_ASIO_TEST_CASE(ip_tcp_socket_runtime::test) + BOOST_ASIO_TEST_CASE(ip_tcp_acceptor_compile::test) + BOOST_ASIO_TEST_CASE(ip_tcp_acceptor_runtime::test) + BOOST_ASIO_TEST_CASE(ip_tcp_resolver_compile::test) + BOOST_ASIO_TEST_CASE(ip_tcp_resolver_entry_compile::test) + BOOST_ASIO_TEST_CASE(ip_tcp_resolver_entry_compile::test) + BOOST_ASIO_COMPILE_TEST_CASE(ip_tcp_iostream_compile::test) +) diff --git a/src/boost/libs/asio/test/ip/udp.cpp b/src/boost/libs/asio/test/ip/udp.cpp new file mode 100644 index 000000000..cd2ceb536 --- /dev/null +++ b/src/boost/libs/asio/test/ip/udp.cpp @@ -0,0 +1,673 @@ +// +// udp.cpp +// ~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/udp.hpp> + +#include <cstring> +#include <boost/asio/io_context.hpp> +#include "../unit_test.hpp" +#include "../archetypes/async_result.hpp" +#include "../archetypes/gettable_socket_option.hpp" +#include "../archetypes/io_control_command.hpp" +#include "../archetypes/settable_socket_option.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +//------------------------------------------------------------------------------ + +// ip_udp_socket_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::udp::socket compile and link correctly. Runtime failures are ignored. + +namespace ip_udp_socket_compile { + +struct connect_handler +{ + connect_handler() {} + void operator()(const boost::system::error_code&) {} +#if defined(BOOST_ASIO_HAS_MOVE) + connect_handler(connect_handler&&) {} +private: + connect_handler(const connect_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +struct wait_handler +{ + wait_handler() {} + void operator()(const boost::system::error_code&) {} +#if defined(BOOST_ASIO_HAS_MOVE) + wait_handler(wait_handler&&) {} +private: + wait_handler(const wait_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +struct send_handler +{ + send_handler() {} + void operator()(const boost::system::error_code&, std::size_t) {} +#if defined(BOOST_ASIO_HAS_MOVE) + send_handler(send_handler&&) {} +private: + send_handler(const send_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +struct receive_handler +{ + receive_handler() {} + void operator()(const boost::system::error_code&, std::size_t) {} +#if defined(BOOST_ASIO_HAS_MOVE) + receive_handler(receive_handler&&) {} +private: + receive_handler(const receive_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_context ioc; + const io_context::executor_type ioc_ex = ioc.get_executor(); + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + socket_base::message_flags in_flags = 0; + archetypes::settable_socket_option<void> settable_socket_option1; + archetypes::settable_socket_option<int> settable_socket_option2; + archetypes::settable_socket_option<double> settable_socket_option3; + archetypes::gettable_socket_option<void> gettable_socket_option1; + archetypes::gettable_socket_option<int> gettable_socket_option2; + archetypes::gettable_socket_option<double> gettable_socket_option3; + archetypes::io_control_command io_control_command; + archetypes::lazy_handler lazy; + boost::system::error_code ec; + + // basic_datagram_socket constructors. + + ip::udp::socket socket1(ioc); + ip::udp::socket socket2(ioc, ip::udp::v4()); + ip::udp::socket socket3(ioc, ip::udp::v6()); + ip::udp::socket socket4(ioc, ip::udp::endpoint(ip::udp::v4(), 0)); + ip::udp::socket socket5(ioc, ip::udp::endpoint(ip::udp::v6(), 0)); +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + ip::udp::socket::native_handle_type native_socket1 + = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + ip::udp::socket socket6(ioc, ip::udp::v4(), native_socket1); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + + ip::udp::socket socket7(ioc_ex); + ip::udp::socket socket8(ioc_ex, ip::udp::v4()); + ip::udp::socket socket9(ioc_ex, ip::udp::v6()); + ip::udp::socket socket10(ioc_ex, ip::udp::endpoint(ip::udp::v4(), 0)); + ip::udp::socket socket11(ioc_ex, ip::udp::endpoint(ip::udp::v6(), 0)); +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + ip::udp::socket::native_handle_type native_socket2 + = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + ip::udp::socket socket12(ioc_ex, ip::udp::v4(), native_socket2); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#if defined(BOOST_ASIO_HAS_MOVE) + ip::udp::socket socket13(std::move(socket6)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_datagram_socket operators. + +#if defined(BOOST_ASIO_HAS_MOVE) + socket1 = ip::udp::socket(ioc); + socket1 = std::move(socket2); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_io_object functions. + + ip::udp::socket::executor_type ex = socket1.get_executor(); + (void)ex; + + // basic_socket functions. + + ip::udp::socket::lowest_layer_type& lowest_layer = socket1.lowest_layer(); + (void)lowest_layer; + + const ip::udp::socket& socket14 = socket1; + const ip::udp::socket::lowest_layer_type& lowest_layer2 + = socket14.lowest_layer(); + (void)lowest_layer2; + + socket1.open(ip::udp::v4()); + socket1.open(ip::udp::v6()); + socket1.open(ip::udp::v4(), ec); + socket1.open(ip::udp::v6(), ec); + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + ip::udp::socket::native_handle_type native_socket3 + = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + socket1.assign(ip::udp::v4(), native_socket3); + ip::udp::socket::native_handle_type native_socket4 + = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + socket1.assign(ip::udp::v4(), native_socket4, ec); +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + + bool is_open = socket1.is_open(); + (void)is_open; + + socket1.close(); + socket1.close(ec); + + socket1.release(); + socket1.release(ec); + + ip::udp::socket::native_handle_type native_socket5 + = socket1.native_handle(); + (void)native_socket5; + + socket1.cancel(); + socket1.cancel(ec); + + bool at_mark1 = socket1.at_mark(); + (void)at_mark1; + bool at_mark2 = socket1.at_mark(ec); + (void)at_mark2; + + std::size_t available1 = socket1.available(); + (void)available1; + std::size_t available2 = socket1.available(ec); + (void)available2; + + socket1.bind(ip::udp::endpoint(ip::udp::v4(), 0)); + socket1.bind(ip::udp::endpoint(ip::udp::v6(), 0)); + socket1.bind(ip::udp::endpoint(ip::udp::v4(), 0), ec); + socket1.bind(ip::udp::endpoint(ip::udp::v6(), 0), ec); + + socket1.connect(ip::udp::endpoint(ip::udp::v4(), 0)); + socket1.connect(ip::udp::endpoint(ip::udp::v6(), 0)); + socket1.connect(ip::udp::endpoint(ip::udp::v4(), 0), ec); + socket1.connect(ip::udp::endpoint(ip::udp::v6(), 0), ec); + + socket1.async_connect(ip::udp::endpoint(ip::udp::v4(), 0), + connect_handler()); + socket1.async_connect(ip::udp::endpoint(ip::udp::v6(), 0), + connect_handler()); + int i1 = socket1.async_connect(ip::udp::endpoint(ip::udp::v4(), 0), lazy); + (void)i1; + int i2 = socket1.async_connect(ip::udp::endpoint(ip::udp::v6(), 0), lazy); + (void)i2; + + socket1.set_option(settable_socket_option1); + socket1.set_option(settable_socket_option1, ec); + socket1.set_option(settable_socket_option2); + socket1.set_option(settable_socket_option2, ec); + socket1.set_option(settable_socket_option3); + socket1.set_option(settable_socket_option3, ec); + + socket1.get_option(gettable_socket_option1); + socket1.get_option(gettable_socket_option1, ec); + socket1.get_option(gettable_socket_option2); + socket1.get_option(gettable_socket_option2, ec); + socket1.get_option(gettable_socket_option3); + socket1.get_option(gettable_socket_option3, ec); + + socket1.io_control(io_control_command); + socket1.io_control(io_control_command, ec); + + bool non_blocking1 = socket1.non_blocking(); + (void)non_blocking1; + socket1.non_blocking(true); + socket1.non_blocking(false, ec); + + bool non_blocking2 = socket1.native_non_blocking(); + (void)non_blocking2; + socket1.native_non_blocking(true); + socket1.native_non_blocking(false, ec); + + ip::udp::endpoint endpoint1 = socket1.local_endpoint(); + (void)endpoint1; + ip::udp::endpoint endpoint2 = socket1.local_endpoint(ec); + (void)endpoint2; + + ip::udp::endpoint endpoint3 = socket1.remote_endpoint(); + (void)endpoint3; + ip::udp::endpoint endpoint4 = socket1.remote_endpoint(ec); + (void)endpoint4; + + socket1.shutdown(socket_base::shutdown_both); + socket1.shutdown(socket_base::shutdown_both, ec); + + socket1.wait(socket_base::wait_read); + socket1.wait(socket_base::wait_write, ec); + + socket1.async_wait(socket_base::wait_read, wait_handler()); + int i3 = socket1.async_wait(socket_base::wait_write, lazy); + (void)i3; + + // basic_datagram_socket functions. + + socket1.send(buffer(mutable_char_buffer)); + socket1.send(buffer(const_char_buffer)); + socket1.send(null_buffers()); + socket1.send(buffer(mutable_char_buffer), in_flags); + socket1.send(buffer(const_char_buffer), in_flags); + socket1.send(null_buffers(), in_flags); + socket1.send(buffer(mutable_char_buffer), in_flags, ec); + socket1.send(buffer(const_char_buffer), in_flags, ec); + socket1.send(null_buffers(), in_flags, ec); + + socket1.async_send(buffer(mutable_char_buffer), send_handler()); + socket1.async_send(buffer(const_char_buffer), send_handler()); + socket1.async_send(null_buffers(), send_handler()); + socket1.async_send(buffer(mutable_char_buffer), in_flags, send_handler()); + socket1.async_send(buffer(const_char_buffer), in_flags, send_handler()); + socket1.async_send(null_buffers(), in_flags, send_handler()); + int i4 = socket1.async_send(buffer(mutable_char_buffer), lazy); + (void)i4; + int i5 = socket1.async_send(buffer(const_char_buffer), lazy); + (void)i5; + int i6 = socket1.async_send(null_buffers(), lazy); + (void)i6; + int i7 = socket1.async_send(buffer(mutable_char_buffer), in_flags, lazy); + (void)i7; + int i8 = socket1.async_send(buffer(const_char_buffer), in_flags, lazy); + (void)i8; + int i9 = socket1.async_send(null_buffers(), in_flags, lazy); + (void)i9; + + socket1.send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0)); + socket1.send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0)); + socket1.send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0)); + socket1.send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0)); + socket1.send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v4(), 0)); + socket1.send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v6(), 0)); + socket1.send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0), in_flags); + socket1.send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0), in_flags); + socket1.send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0), in_flags); + socket1.send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0), in_flags); + socket1.send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v4(), 0), in_flags); + socket1.send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v6(), 0), in_flags); + socket1.send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0), in_flags, ec); + socket1.send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0), in_flags, ec); + socket1.send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0), in_flags, ec); + socket1.send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0), in_flags, ec); + socket1.send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v4(), 0), in_flags, ec); + socket1.send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v6(), 0), in_flags, ec); + + socket1.async_send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0), send_handler()); + socket1.async_send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0), send_handler()); + socket1.async_send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0), send_handler()); + socket1.async_send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0), send_handler()); + socket1.async_send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v4(), 0), send_handler()); + socket1.async_send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v6(), 0), send_handler()); + socket1.async_send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0), in_flags, send_handler()); + socket1.async_send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0), in_flags, send_handler()); + socket1.async_send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0), in_flags, send_handler()); + socket1.async_send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0), in_flags, send_handler()); + socket1.async_send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v4(), 0), in_flags, send_handler()); + socket1.async_send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v6(), 0), in_flags, send_handler()); + int i10 = socket1.async_send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0), lazy); + (void)i10; + int i11 = socket1.async_send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0), lazy); + (void)i11; + int i12 = socket1.async_send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0), lazy); + (void)i12; + int i13 = socket1.async_send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0), lazy); + (void)i13; + int i14 = socket1.async_send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v4(), 0), lazy); + (void)i14; + int i15 = socket1.async_send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v6(), 0), lazy); + (void)i15; + int i16 = socket1.async_send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0), in_flags, lazy); + (void)i16; + int i17 = socket1.async_send_to(buffer(mutable_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0), in_flags, lazy); + (void)i17; + int i18 = socket1.async_send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v4(), 0), in_flags, lazy); + (void)i18; + int i19 = socket1.async_send_to(buffer(const_char_buffer), + ip::udp::endpoint(ip::udp::v6(), 0), in_flags, lazy); + (void)i19; + int i20 = socket1.async_send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v4(), 0), in_flags, lazy); + (void)i20; + int i21 = socket1.async_send_to(null_buffers(), + ip::udp::endpoint(ip::udp::v6(), 0), in_flags, lazy); + (void)i21; + + socket1.receive(buffer(mutable_char_buffer)); + socket1.receive(null_buffers()); + socket1.receive(buffer(mutable_char_buffer), in_flags); + socket1.receive(null_buffers(), in_flags); + socket1.receive(buffer(mutable_char_buffer), in_flags, ec); + socket1.receive(null_buffers(), in_flags, ec); + + socket1.async_receive(buffer(mutable_char_buffer), receive_handler()); + socket1.async_receive(null_buffers(), receive_handler()); + socket1.async_receive(buffer(mutable_char_buffer), in_flags, + receive_handler()); + socket1.async_receive(null_buffers(), in_flags, receive_handler()); + int i22 = socket1.async_receive(buffer(mutable_char_buffer), lazy); + (void)i22; + int i23 = socket1.async_receive(null_buffers(), lazy); + (void)i23; + int i24 = socket1.async_receive(buffer(mutable_char_buffer), + in_flags, lazy); + (void)i24; + int i25 = socket1.async_receive(null_buffers(), in_flags, lazy); + (void)i25; + + ip::udp::endpoint endpoint; + socket1.receive_from(buffer(mutable_char_buffer), endpoint); + socket1.receive_from(null_buffers(), endpoint); + socket1.receive_from(buffer(mutable_char_buffer), endpoint, in_flags); + socket1.receive_from(null_buffers(), endpoint, in_flags); + socket1.receive_from(buffer(mutable_char_buffer), endpoint, in_flags, ec); + socket1.receive_from(null_buffers(), endpoint, in_flags, ec); + + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, receive_handler()); + socket1.async_receive_from(null_buffers(), + endpoint, receive_handler()); + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, in_flags, receive_handler()); + socket1.async_receive_from(null_buffers(), + endpoint, in_flags, receive_handler()); + int i26 = socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, lazy); + (void)i26; + int i27 = socket1.async_receive_from(null_buffers(), + endpoint, lazy); + (void)i27; + int i28 = socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, in_flags, lazy); + (void)i28; + int i29 = socket1.async_receive_from(null_buffers(), + endpoint, in_flags, lazy); + (void)i29; + } + catch (std::exception&) + { + } +} + +} // namespace ip_udp_socket_compile + +//------------------------------------------------------------------------------ + +// ip_udp_socket_runtime test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks the runtime operation of the ip::udp::socket class. + +namespace ip_udp_socket_runtime { + +void handle_send(size_t expected_bytes_sent, + const boost::system::error_code& err, size_t bytes_sent) +{ + BOOST_ASIO_CHECK(!err); + BOOST_ASIO_CHECK(expected_bytes_sent == bytes_sent); +} + +void handle_recv(size_t expected_bytes_recvd, + const boost::system::error_code& err, size_t bytes_recvd) +{ + BOOST_ASIO_CHECK(!err); + BOOST_ASIO_CHECK(expected_bytes_recvd == bytes_recvd); +} + +void test() +{ + using namespace std; // For memcmp and memset. + using namespace boost::asio; + namespace ip = boost::asio::ip; + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + io_context ioc; + + ip::udp::socket s1(ioc, ip::udp::endpoint(ip::udp::v4(), 0)); + ip::udp::endpoint target_endpoint = s1.local_endpoint(); + target_endpoint.address(ip::address_v4::loopback()); + + ip::udp::socket s2(ioc); + s2.open(ip::udp::v4()); + s2.bind(ip::udp::endpoint(ip::udp::v4(), 0)); + char send_msg[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + s2.send_to(buffer(send_msg, sizeof(send_msg)), target_endpoint); + + char recv_msg[sizeof(send_msg)]; + ip::udp::endpoint sender_endpoint; + size_t bytes_recvd = s1.receive_from(buffer(recv_msg, sizeof(recv_msg)), + sender_endpoint); + + BOOST_ASIO_CHECK(bytes_recvd == sizeof(send_msg)); + BOOST_ASIO_CHECK(memcmp(send_msg, recv_msg, sizeof(send_msg)) == 0); + + memset(recv_msg, 0, sizeof(recv_msg)); + + target_endpoint = sender_endpoint; + s1.async_send_to(buffer(send_msg, sizeof(send_msg)), target_endpoint, + bindns::bind(handle_send, sizeof(send_msg), _1, _2)); + s2.async_receive_from(buffer(recv_msg, sizeof(recv_msg)), sender_endpoint, + bindns::bind(handle_recv, sizeof(recv_msg), _1, _2)); + + ioc.run(); + + BOOST_ASIO_CHECK(memcmp(send_msg, recv_msg, sizeof(send_msg)) == 0); +} + +} // namespace ip_udp_socket_runtime + +//------------------------------------------------------------------------------ + +// ip_udp_resolver_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ip::udp::resolver compile and link correctly. Runtime failures are ignored. + +namespace ip_udp_resolver_compile { + +struct resolve_handler +{ + resolve_handler() {} + void operator()(const boost::system::error_code&, + boost::asio::ip::udp::resolver::results_type) {} +#if defined(BOOST_ASIO_HAS_MOVE) + resolve_handler(resolve_handler&&) {} +private: + resolve_handler(const resolve_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_context ioc; + const io_context::executor_type ioc_ex = ioc.get_executor(); + archetypes::lazy_handler lazy; + boost::system::error_code ec; +#if !defined(BOOST_ASIO_NO_DEPRECATED) + ip::udp::resolver::query q(ip::udp::v4(), "localhost", "0"); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + ip::udp::endpoint e(ip::address_v4::loopback(), 0); + + // basic_resolver constructors. + + ip::udp::resolver resolver(ioc); + ip::udp::resolver resolver2(ioc_ex); + +#if defined(BOOST_ASIO_HAS_MOVE) + ip::udp::resolver resolver3(std::move(resolver)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_resolver operators. + +#if defined(BOOST_ASIO_HAS_MOVE) + resolver = ip::udp::resolver(ioc); + resolver = std::move(resolver3); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_io_object functions. + + ip::udp::resolver::executor_type ex = resolver.get_executor(); + (void)ex; + + // basic_resolver functions. + + resolver.cancel(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + ip::udp::resolver::results_type results1 = resolver.resolve(q); + (void)results1; + + ip::udp::resolver::results_type results2 = resolver.resolve(q, ec); + (void)results2; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + ip::udp::resolver::results_type results3 = resolver.resolve("", ""); + (void)results3; + + ip::udp::resolver::results_type results4 = resolver.resolve("", "", ec); + (void)results4; + + ip::udp::resolver::results_type results5 = + resolver.resolve("", "", ip::udp::resolver::flags()); + (void)results5; + + ip::udp::resolver::results_type results6 = + resolver.resolve("", "", ip::udp::resolver::flags(), ec); + (void)results6; + + ip::udp::resolver::results_type results7 = + resolver.resolve(ip::udp::v4(), "", ""); + (void)results7; + + ip::udp::resolver::results_type results8 = + resolver.resolve(ip::udp::v4(), "", "", ec); + (void)results8; + + ip::udp::resolver::results_type results9 = + resolver.resolve(ip::udp::v4(), "", "", ip::udp::resolver::flags()); + (void)results9; + + ip::udp::resolver::results_type results10 = + resolver.resolve(ip::udp::v4(), "", "", ip::udp::resolver::flags(), ec); + (void)results10; + + ip::udp::resolver::results_type results11 = resolver.resolve(e); + (void)results11; + + ip::udp::resolver::results_type results12 = resolver.resolve(e, ec); + (void)results12; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + resolver.async_resolve(q, resolve_handler()); + int i1 = resolver.async_resolve(q, lazy); + (void)i1; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + resolver.async_resolve("", "", resolve_handler()); + int i2 = resolver.async_resolve("", "", lazy); + (void)i2; + + resolver.async_resolve("", "", + ip::udp::resolver::flags(), resolve_handler()); + int i3 = resolver.async_resolve("", "", + ip::udp::resolver::flags(), lazy); + (void)i3; + + resolver.async_resolve(ip::udp::v4(), "", "", resolve_handler()); + int i4 = resolver.async_resolve(ip::udp::v4(), "", "", lazy); + (void)i4; + + resolver.async_resolve(ip::udp::v4(), + "", "", ip::udp::resolver::flags(), resolve_handler()); + int i5 = resolver.async_resolve(ip::udp::v4(), + "", "", ip::udp::resolver::flags(), lazy); + (void)i5; + + resolver.async_resolve(e, resolve_handler()); + int i6 = resolver.async_resolve(e, lazy); + (void)i6; + } + catch (std::exception&) + { + } +} + +} // namespace ip_udp_resolver_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ip/udp", + BOOST_ASIO_TEST_CASE(ip_udp_socket_compile::test) + BOOST_ASIO_TEST_CASE(ip_udp_socket_runtime::test) + BOOST_ASIO_TEST_CASE(ip_udp_resolver_compile::test) +) diff --git a/src/boost/libs/asio/test/ip/unicast.cpp b/src/boost/libs/asio/test/ip/unicast.cpp new file mode 100644 index 000000000..1a48fab11 --- /dev/null +++ b/src/boost/libs/asio/test/ip/unicast.cpp @@ -0,0 +1,171 @@ +// +// unicast.cpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/unicast.hpp> + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/udp.hpp> +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +// ip_unicast_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all nested classes, enums and constants in +// ip::unicast compile and link correctly. Runtime failures are ignored. + +namespace ip_unicast_compile { + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_context ioc; + ip::udp::socket sock(ioc); + + // hops class. + + ip::unicast::hops hops1(1024); + sock.set_option(hops1); + ip::unicast::hops hops2; + sock.get_option(hops2); + hops1 = 1; + (void)static_cast<int>(hops1.value()); + } + catch (std::exception&) + { + } +} + +} // namespace ip_unicast_compile + +//------------------------------------------------------------------------------ + +// ip_unicast_runtime test +// ~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks the runtime operation of the socket options defined +// in the ip::unicast namespace. + +namespace ip_unicast_runtime { + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + io_context ioc; + boost::system::error_code ec; + + ip::udp::endpoint ep_v4(ip::address_v4::loopback(), 0); + ip::udp::socket sock_v4(ioc); + sock_v4.open(ep_v4.protocol(), ec); + sock_v4.bind(ep_v4, ec); + bool have_v4 = !ec; + + ip::udp::endpoint ep_v6(ip::address_v6::loopback(), 0); + ip::udp::socket sock_v6(ioc); + sock_v6.open(ep_v6.protocol(), ec); + sock_v6.bind(ep_v6, ec); + bool have_v6 = !ec; + + BOOST_ASIO_CHECK(have_v4 || have_v6); + + // hops class. + + if (have_v4) + { + ip::unicast::hops hops1(1); + BOOST_ASIO_CHECK(hops1.value() == 1); + sock_v4.set_option(hops1, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Option is not supported under Windows CE. + BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, + ec.value() << ", " << ec.message()); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK(!ec); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + + ip::unicast::hops hops2; + sock_v4.get_option(hops2, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Option is not supported under Windows CE. + BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, + ec.value() << ", " << ec.message()); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(hops2.value() == 1); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + + ip::unicast::hops hops3(255); + BOOST_ASIO_CHECK(hops3.value() == 255); + sock_v4.set_option(hops3, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Option is not supported under Windows CE. + BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, + ec.value() << ", " << ec.message()); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK(!ec); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + + ip::unicast::hops hops4; + sock_v4.get_option(hops4, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Option is not supported under Windows CE. + BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, + ec.value() << ", " << ec.message()); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(hops4.value() == 255); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + } + + if (have_v6) + { + ip::unicast::hops hops1(1); + BOOST_ASIO_CHECK(hops1.value() == 1); + sock_v6.set_option(hops1, ec); + BOOST_ASIO_CHECK(!ec); + + ip::unicast::hops hops2; + sock_v6.get_option(hops2, ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(hops2.value() == 1); + + ip::unicast::hops hops3(255); + BOOST_ASIO_CHECK(hops3.value() == 255); + sock_v6.set_option(hops3, ec); + BOOST_ASIO_CHECK(!ec); + + ip::unicast::hops hops4; + sock_v6.get_option(hops4, ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(hops4.value() == 255); + } +} + +} // namespace ip_unicast_runtime + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ip/unicast", + BOOST_ASIO_TEST_CASE(ip_unicast_compile::test) + BOOST_ASIO_TEST_CASE(ip_unicast_runtime::test) +) diff --git a/src/boost/libs/asio/test/ip/v6_only.cpp b/src/boost/libs/asio/test/ip/v6_only.cpp new file mode 100644 index 000000000..570781266 --- /dev/null +++ b/src/boost/libs/asio/test/ip/v6_only.cpp @@ -0,0 +1,135 @@ +// +// v6_only.cpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ip/v6_only.hpp> + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/ip/udp.hpp> +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +// ip_v6_only_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that the ip::v6_only socket option compiles and +// link correctly. Runtime failures are ignored. + +namespace ip_v6_only_compile { + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_context ioc; + ip::udp::socket sock(ioc); + + // v6_only class. + + ip::v6_only v6_only1(true); + sock.set_option(v6_only1); + ip::v6_only v6_only2; + sock.get_option(v6_only2); + v6_only1 = true; + (void)static_cast<bool>(v6_only1); + (void)static_cast<bool>(!v6_only1); + (void)static_cast<bool>(v6_only1.value()); + } + catch (std::exception&) + { + } +} + +} // namespace ip_v6_only_compile + +//------------------------------------------------------------------------------ + +// ip_v6_only_runtime test +// ~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks the runtime operation of the ip::v6_only socket +// option. + +namespace ip_v6_only_runtime { + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + io_context ioc; + boost::system::error_code ec; + + ip::tcp::endpoint ep_v6(ip::address_v6::loopback(), 0); + ip::tcp::acceptor acceptor_v6(ioc); + acceptor_v6.open(ep_v6.protocol(), ec); + acceptor_v6.bind(ep_v6, ec); + bool have_v6 = !ec; + acceptor_v6.close(ec); + acceptor_v6.open(ep_v6.protocol(), ec); + + if (have_v6) + { + ip::v6_only v6_only1; + acceptor_v6.get_option(v6_only1, ec); + BOOST_ASIO_CHECK(!ec); + bool have_dual_stack = !v6_only1.value(); + + if (have_dual_stack) + { + ip::v6_only v6_only2(false); + BOOST_ASIO_CHECK(!v6_only2.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(v6_only2)); + BOOST_ASIO_CHECK(!v6_only2); + acceptor_v6.set_option(v6_only2, ec); + BOOST_ASIO_CHECK(!ec); + + ip::v6_only v6_only3; + acceptor_v6.get_option(v6_only3, ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(!v6_only3.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(v6_only3)); + BOOST_ASIO_CHECK(!v6_only3); + + ip::v6_only v6_only4(true); + BOOST_ASIO_CHECK(v6_only4.value()); + BOOST_ASIO_CHECK(static_cast<bool>(v6_only4)); + BOOST_ASIO_CHECK(!!v6_only4); + acceptor_v6.set_option(v6_only4, ec); + BOOST_ASIO_CHECK(!ec); + + ip::v6_only v6_only5; + acceptor_v6.get_option(v6_only5, ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(v6_only5.value()); + BOOST_ASIO_CHECK(static_cast<bool>(v6_only5)); + BOOST_ASIO_CHECK(!!v6_only5); + } + } +} + +} // namespace ip_v6_only_runtime + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ip/v6_only", + BOOST_ASIO_TEST_CASE(ip_v6_only_compile::test) + BOOST_ASIO_TEST_CASE(ip_v6_only_runtime::test) +) diff --git a/src/boost/libs/asio/test/is_read_buffered.cpp b/src/boost/libs/asio/test/is_read_buffered.cpp new file mode 100644 index 000000000..868c64644 --- /dev/null +++ b/src/boost/libs/asio/test/is_read_buffered.cpp @@ -0,0 +1,129 @@ +// +// is_read_buffered.cpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/is_read_buffered.hpp> + +#include <boost/asio/buffered_read_stream.hpp> +#include <boost/asio/buffered_write_stream.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include "unit_test.hpp" + +using namespace std; // For memcmp, memcpy and memset. + +class test_stream +{ +public: + typedef boost::asio::io_context io_context_type; + + typedef test_stream lowest_layer_type; + + typedef io_context_type::executor_type executor_type; + + test_stream(boost::asio::io_context& io_context) + : io_context_(io_context) + { + } + + io_context_type& io_context() + { + return io_context_; + } + + lowest_layer_type& lowest_layer() + { + return *this; + } + + template <typename Const_Buffers> + size_t write(const Const_Buffers&) + { + return 0; + } + + template <typename Const_Buffers> + size_t write(const Const_Buffers&, boost::system::error_code& ec) + { + ec = boost::system::error_code(); + return 0; + } + + template <typename Const_Buffers, typename Handler> + void async_write(const Const_Buffers&, Handler handler) + { + boost::system::error_code error; + boost::asio::post(io_context_, + boost::asio::detail::bind_handler(handler, error, 0)); + } + + template <typename Mutable_Buffers> + size_t read(const Mutable_Buffers&) + { + return 0; + } + + template <typename Mutable_Buffers> + size_t read(const Mutable_Buffers&, boost::system::error_code& ec) + { + ec = boost::system::error_code(); + return 0; + } + + template <typename Mutable_Buffers, typename Handler> + void async_read(const Mutable_Buffers&, Handler handler) + { + boost::system::error_code error; + boost::asio::post(io_context_, + boost::asio::detail::bind_handler(handler, error, 0)); + } + +private: + io_context_type& io_context_; +}; + +void is_read_buffered_test() +{ + BOOST_ASIO_CHECK(!boost::asio::is_read_buffered< + boost::asio::ip::tcp::socket>::value); + + BOOST_ASIO_CHECK(!!boost::asio::is_read_buffered< + boost::asio::buffered_read_stream< + boost::asio::ip::tcp::socket> >::value); + + BOOST_ASIO_CHECK(!boost::asio::is_read_buffered< + boost::asio::buffered_write_stream< + boost::asio::ip::tcp::socket> >::value); + + BOOST_ASIO_CHECK(!!boost::asio::is_read_buffered< + boost::asio::buffered_stream<boost::asio::ip::tcp::socket> >::value); + + BOOST_ASIO_CHECK(!boost::asio::is_read_buffered<test_stream>::value); + + BOOST_ASIO_CHECK(!!boost::asio::is_read_buffered< + boost::asio::buffered_read_stream<test_stream> >::value); + + BOOST_ASIO_CHECK(!boost::asio::is_read_buffered< + boost::asio::buffered_write_stream<test_stream> >::value); + + BOOST_ASIO_CHECK(!!boost::asio::is_read_buffered< + boost::asio::buffered_stream<test_stream> >::value); +} + +BOOST_ASIO_TEST_SUITE +( + "is_read_buffered", + BOOST_ASIO_TEST_CASE(is_read_buffered_test) +) diff --git a/src/boost/libs/asio/test/is_write_buffered.cpp b/src/boost/libs/asio/test/is_write_buffered.cpp new file mode 100644 index 000000000..c00c39b4a --- /dev/null +++ b/src/boost/libs/asio/test/is_write_buffered.cpp @@ -0,0 +1,129 @@ +// +// is_write_buffered.cpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/is_write_buffered.hpp> + +#include <boost/asio/buffered_read_stream.hpp> +#include <boost/asio/buffered_write_stream.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include "unit_test.hpp" + +using namespace std; // For memcmp, memcpy and memset. + +class test_stream +{ +public: + typedef boost::asio::io_context io_context_type; + + typedef test_stream lowest_layer_type; + + typedef io_context_type::executor_type executor_type; + + test_stream(boost::asio::io_context& io_context) + : io_context_(io_context) + { + } + + io_context_type& io_context() + { + return io_context_; + } + + lowest_layer_type& lowest_layer() + { + return *this; + } + + template <typename Const_Buffers> + size_t write(const Const_Buffers&) + { + return 0; + } + + template <typename Const_Buffers> + size_t write(const Const_Buffers&, boost::system::error_code& ec) + { + ec = boost::system::error_code(); + return 0; + } + + template <typename Const_Buffers, typename Handler> + void async_write(const Const_Buffers&, Handler handler) + { + boost::system::error_code error; + boost::asio::post(io_context_, + boost::asio::detail::bind_handler(handler, error, 0)); + } + + template <typename Mutable_Buffers> + size_t read(const Mutable_Buffers&) + { + return 0; + } + + template <typename Mutable_Buffers> + size_t read(const Mutable_Buffers&, boost::system::error_code& ec) + { + ec = boost::system::error_code(); + return 0; + } + + template <typename Mutable_Buffers, typename Handler> + void async_read(const Mutable_Buffers&, Handler handler) + { + boost::system::error_code error; + boost::asio::post(io_context_, + boost::asio::detail::bind_handler(handler, error, 0)); + } + +private: + io_context_type& io_context_; +}; + +void is_write_buffered_test() +{ + BOOST_ASIO_CHECK(!boost::asio::is_write_buffered< + boost::asio::ip::tcp::socket>::value); + + BOOST_ASIO_CHECK(!boost::asio::is_write_buffered< + boost::asio::buffered_read_stream< + boost::asio::ip::tcp::socket> >::value); + + BOOST_ASIO_CHECK(!!boost::asio::is_write_buffered< + boost::asio::buffered_write_stream< + boost::asio::ip::tcp::socket> >::value); + + BOOST_ASIO_CHECK(!!boost::asio::is_write_buffered< + boost::asio::buffered_stream<boost::asio::ip::tcp::socket> >::value); + + BOOST_ASIO_CHECK(!boost::asio::is_write_buffered<test_stream>::value); + + BOOST_ASIO_CHECK(!boost::asio::is_write_buffered< + boost::asio::buffered_read_stream<test_stream> >::value); + + BOOST_ASIO_CHECK(!!boost::asio::is_write_buffered< + boost::asio::buffered_write_stream<test_stream> >::value); + + BOOST_ASIO_CHECK(!!boost::asio::is_write_buffered< + boost::asio::buffered_stream<test_stream> >::value); +} + +BOOST_ASIO_TEST_SUITE +( + "is_write_buffered", + BOOST_ASIO_TEST_CASE(is_write_buffered_test) +) diff --git a/src/boost/libs/asio/test/latency/Jamfile.v2 b/src/boost/libs/asio/test/latency/Jamfile.v2 new file mode 100644 index 000000000..cd6c88cc3 --- /dev/null +++ b/src/boost/libs/asio/test/latency/Jamfile.v2 @@ -0,0 +1,36 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +project + : requirements + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <library>/boost/thread//boost_thread + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +exe tcp_server : tcp_server.cpp ; +exe tcp_client : tcp_client.cpp ; +exe udp_server : udp_server.cpp ; +exe udp_client : udp_client.cpp ; diff --git a/src/boost/libs/asio/test/latency/allocator.hpp b/src/boost/libs/asio/test/latency/allocator.hpp new file mode 100644 index 000000000..33cdfbf8f --- /dev/null +++ b/src/boost/libs/asio/test/latency/allocator.hpp @@ -0,0 +1,52 @@ +// +// allocator.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ALLOCATOR_HPP +#define ALLOCATOR_HPP + +#include <boost/aligned_storage.hpp> + +// Represents a single connection from a client. +class allocator +{ +public: + allocator() + : in_use_(false) + { + } + + void* allocate(std::size_t n) + { + if (in_use_ || n >= 1024) + return ::operator new(n); + in_use_ = true; + return static_cast<void*>(&space_); + } + + void deallocate(void* p) + { + if (p != static_cast<void*>(&space_)) + ::operator delete(p); + else + in_use_ = false; + } + +private: + allocator(const allocator&); + allocator& operator=(const allocator&); + + // Whether the reusable memory space is currently in use. + bool in_use_; + + // The reusable memory space made available by the allocator. + boost::aligned_storage<1024>::type space_; +}; + +#endif // ALLOCATOR_HPP diff --git a/src/boost/libs/asio/test/latency/high_res_clock.hpp b/src/boost/libs/asio/test/latency/high_res_clock.hpp new file mode 100644 index 000000000..afc33ccef --- /dev/null +++ b/src/boost/libs/asio/test/latency/high_res_clock.hpp @@ -0,0 +1,53 @@ +// +// high_res_clock.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef HIGH_RES_CLOCK_HPP +#define HIGH_RES_CLOCK_HPP + +#include <boost/config.hpp> +#include <boost/cstdint.hpp> + +#if defined(BOOST_ASIO_WINDOWS) + +inline boost::uint64_t high_res_clock() +{ + LARGE_INTEGER i; + QueryPerformanceCounter(&i); + return i.QuadPart; +} + +#elif defined(__GNUC__) && defined(__x86_64__) + +inline boost::uint64_t high_res_clock() +{ + unsigned long low, high; + __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)); + return (((boost::uint64_t)high) << 32) | low; +} + +#else + +#include <boost/date_time/posix_time/posix_time_types.hpp> + +inline boost::uint64_t high_res_clock() +{ + boost::posix_time::ptime now = + boost::posix_time::microsec_clock::universal_time(); + + boost::posix_time::ptime epoch( + boost::gregorian::date(1970, 1, 1), + boost::posix_time::seconds(0)); + + return (now - epoch).total_microseconds(); +} + +#endif + +#endif // HIGH_RES_CLOCK_HPP diff --git a/src/boost/libs/asio/test/latency/tcp_client.cpp b/src/boost/libs/asio/test/latency/tcp_client.cpp new file mode 100644 index 000000000..bdcdcf2df --- /dev/null +++ b/src/boost/libs/asio/test/latency/tcp_client.cpp @@ -0,0 +1,124 @@ +// +// tcp_client.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/read.hpp> +#include <boost/asio/write.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include <boost/shared_ptr.hpp> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <vector> +#include "high_res_clock.hpp" + +using boost::asio::ip::tcp; +using boost::posix_time::ptime; +using boost::posix_time::microsec_clock; + +const int num_samples = 100000; + +struct transfer_all +{ + typedef std::size_t result_type; + std::size_t operator()(const boost::system::error_code& ec, std::size_t) + { + return (ec && ec != boost::asio::error::would_block) ? 0 : ~0; + } +}; + +int main(int argc, char* argv[]) +{ + if (argc != 6) + { + std::fprintf(stderr, + "Usage: tcp_client <ip> <port> " + "<nconns> <bufsize> {spin|block}\n"); + return 1; + } + + const char* ip = argv[1]; + unsigned short port = static_cast<unsigned short>(std::atoi(argv[2])); + int num_connections = std::atoi(argv[3]); + std::size_t buf_size = static_cast<std::size_t>(std::atoi(argv[4])); + bool spin = (std::strcmp(argv[5], "spin") == 0); + + boost::asio::io_context io_context; + std::vector<boost::shared_ptr<tcp::socket> > sockets; + + for (int i = 0; i < num_connections; ++i) + { + boost::shared_ptr<tcp::socket> s(new tcp::socket(io_context)); + + tcp::endpoint target(boost::asio::ip::make_address(ip), port); + s->connect(target); + + s->set_option(tcp::no_delay(true)); + + if (spin) + { + s->non_blocking(true); + } + + sockets.push_back(s); + } + + std::vector<unsigned char> write_buf(buf_size); + std::vector<unsigned char> read_buf(buf_size); + + ptime start = microsec_clock::universal_time(); + boost::uint64_t start_hr = high_res_clock(); + + boost::uint64_t samples[num_samples]; + for (int i = 0; i < num_samples; ++i) + { + tcp::socket& socket = *sockets[i % num_connections]; + + boost::uint64_t t = high_res_clock(); + + boost::system::error_code ec; + boost::asio::write(socket, + boost::asio::buffer(write_buf), + transfer_all(), ec); + + boost::asio::read(socket, + boost::asio::buffer(read_buf), + transfer_all(), ec); + + samples[i] = high_res_clock() - t; + } + + ptime stop = microsec_clock::universal_time(); + boost::uint64_t stop_hr = high_res_clock(); + boost::uint64_t elapsed_usec = (stop - start).total_microseconds(); + boost::uint64_t elapsed_hr = stop_hr - start_hr; + double scale = 1.0 * elapsed_usec / elapsed_hr; + + std::sort(samples, samples + num_samples); + std::printf(" 0.0%%\t%f\n", samples[0] * scale); + std::printf(" 0.1%%\t%f\n", samples[num_samples / 1000 - 1] * scale); + std::printf(" 1.0%%\t%f\n", samples[num_samples / 100 - 1] * scale); + std::printf(" 10.0%%\t%f\n", samples[num_samples / 10 - 1] * scale); + std::printf(" 20.0%%\t%f\n", samples[num_samples * 2 / 10 - 1] * scale); + std::printf(" 30.0%%\t%f\n", samples[num_samples * 3 / 10 - 1] * scale); + std::printf(" 40.0%%\t%f\n", samples[num_samples * 4 / 10 - 1] * scale); + std::printf(" 50.0%%\t%f\n", samples[num_samples * 5 / 10 - 1] * scale); + std::printf(" 60.0%%\t%f\n", samples[num_samples * 6 / 10 - 1] * scale); + std::printf(" 70.0%%\t%f\n", samples[num_samples * 7 / 10 - 1] * scale); + std::printf(" 80.0%%\t%f\n", samples[num_samples * 8 / 10 - 1] * scale); + std::printf(" 90.0%%\t%f\n", samples[num_samples * 9 / 10 - 1] * scale); + std::printf(" 99.0%%\t%f\n", samples[num_samples * 99 / 100 - 1] * scale); + std::printf(" 99.9%%\t%f\n", samples[num_samples * 999 / 1000 - 1] * scale); + std::printf("100.0%%\t%f\n", samples[num_samples - 1] * scale); + + double total = 0.0; + for (int i = 0; i < num_samples; ++i) total += samples[i] * scale; + std::printf(" mean\t%f\n", total / num_samples); +} diff --git a/src/boost/libs/asio/test/latency/tcp_server.cpp b/src/boost/libs/asio/test/latency/tcp_server.cpp new file mode 100644 index 000000000..587d774f0 --- /dev/null +++ b/src/boost/libs/asio/test/latency/tcp_server.cpp @@ -0,0 +1,114 @@ +// +// tcp_server.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/read.hpp> +#include <boost/asio/write.hpp> +#include <boost/shared_ptr.hpp> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <vector> + +using boost::asio::ip::tcp; + +#include <boost/asio/yield.hpp> + +class tcp_server : boost::asio::coroutine +{ +public: + tcp_server(tcp::acceptor& acceptor, std::size_t buf_size) : + acceptor_(acceptor), + socket_(acceptor_.get_executor()), + buffer_(buf_size) + { + } + + void operator()(boost::system::error_code ec, std::size_t n = 0) + { + reenter (this) for (;;) + { + yield acceptor_.async_accept(socket_, ref(this)); + + while (!ec) + { + yield boost::asio::async_read(socket_, + boost::asio::buffer(buffer_), ref(this)); + + if (!ec) + { + for (std::size_t i = 0; i < n; ++i) buffer_[i] = ~buffer_[i]; + + yield boost::asio::async_write(socket_, + boost::asio::buffer(buffer_), ref(this)); + } + } + + socket_.close(); + } + } + + struct ref + { + explicit ref(tcp_server* p) + : p_(p) + { + } + + void operator()(boost::system::error_code ec, std::size_t n = 0) + { + (*p_)(ec, n); + } + + private: + tcp_server* p_; + }; + +private: + tcp::acceptor& acceptor_; + tcp::socket socket_; + std::vector<unsigned char> buffer_; + tcp::endpoint sender_; +}; + +#include <boost/asio/unyield.hpp> + +int main(int argc, char* argv[]) +{ + if (argc != 5) + { + std::fprintf(stderr, + "Usage: tcp_server <port> <nconns> " + "<bufsize> {spin|block}\n"); + return 1; + } + + unsigned short port = static_cast<unsigned short>(std::atoi(argv[1])); + int max_connections = std::atoi(argv[2]); + std::size_t buf_size = std::atoi(argv[3]); + bool spin = (std::strcmp(argv[4], "spin") == 0); + + boost::asio::io_context io_context(1); + tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), port)); + std::vector<boost::shared_ptr<tcp_server> > servers; + + for (int i = 0; i < max_connections; ++i) + { + boost::shared_ptr<tcp_server> s(new tcp_server(acceptor, buf_size)); + servers.push_back(s); + (*s)(boost::system::error_code()); + } + + if (spin) + for (;;) io_context.poll(); + else + io_context.run(); +} diff --git a/src/boost/libs/asio/test/latency/udp_client.cpp b/src/boost/libs/asio/test/latency/udp_client.cpp new file mode 100644 index 000000000..e2ac4396d --- /dev/null +++ b/src/boost/libs/asio/test/latency/udp_client.cpp @@ -0,0 +1,104 @@ +// +// udp_client.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/ip/udp.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> +#include <algorithm> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <vector> +#include "high_res_clock.hpp" + +using boost::asio::ip::udp; +using boost::posix_time::ptime; +using boost::posix_time::microsec_clock; + +const int num_samples = 100000; + +int main(int argc, char* argv[]) +{ + if (argc != 6) + { + std::fprintf(stderr, + "Usage: udp_client <ip> <port1> " + "<nports> <bufsize> {spin|block}\n"); + return 1; + } + + const char* ip = argv[1]; + unsigned short first_port = static_cast<unsigned short>(std::atoi(argv[2])); + unsigned short num_ports = static_cast<unsigned short>(std::atoi(argv[3])); + std::size_t buf_size = static_cast<std::size_t>(std::atoi(argv[4])); + bool spin = (std::strcmp(argv[5], "spin") == 0); + + boost::asio::io_context io_context; + + udp::socket socket(io_context, udp::endpoint(udp::v4(), 0)); + + if (spin) + { + socket.non_blocking(true); + } + + udp::endpoint target(boost::asio::ip::make_address(ip), first_port); + unsigned short last_port = first_port + num_ports - 1; + std::vector<unsigned char> write_buf(buf_size); + std::vector<unsigned char> read_buf(buf_size); + + ptime start = microsec_clock::universal_time(); + boost::uint64_t start_hr = high_res_clock(); + + boost::uint64_t samples[num_samples]; + for (int i = 0; i < num_samples; ++i) + { + boost::uint64_t t = high_res_clock(); + + boost::system::error_code ec; + socket.send_to(boost::asio::buffer(write_buf), target, 0, ec); + + do socket.receive(boost::asio::buffer(read_buf), 0, ec); + while (ec == boost::asio::error::would_block); + + samples[i] = high_res_clock() - t; + + if (target.port() == last_port) + target.port(first_port); + else + target.port(target.port() + 1); + } + + ptime stop = microsec_clock::universal_time(); + boost::uint64_t stop_hr = high_res_clock(); + boost::uint64_t elapsed_usec = (stop - start).total_microseconds(); + boost::uint64_t elapsed_hr = stop_hr - start_hr; + double scale = 1.0 * elapsed_usec / elapsed_hr; + + std::sort(samples, samples + num_samples); + std::printf(" 0.0%%\t%f\n", samples[0] * scale); + std::printf(" 0.1%%\t%f\n", samples[num_samples / 1000 - 1] * scale); + std::printf(" 1.0%%\t%f\n", samples[num_samples / 100 - 1] * scale); + std::printf(" 10.0%%\t%f\n", samples[num_samples / 10 - 1] * scale); + std::printf(" 20.0%%\t%f\n", samples[num_samples * 2 / 10 - 1] * scale); + std::printf(" 30.0%%\t%f\n", samples[num_samples * 3 / 10 - 1] * scale); + std::printf(" 40.0%%\t%f\n", samples[num_samples * 4 / 10 - 1] * scale); + std::printf(" 50.0%%\t%f\n", samples[num_samples * 5 / 10 - 1] * scale); + std::printf(" 60.0%%\t%f\n", samples[num_samples * 6 / 10 - 1] * scale); + std::printf(" 70.0%%\t%f\n", samples[num_samples * 7 / 10 - 1] * scale); + std::printf(" 80.0%%\t%f\n", samples[num_samples * 8 / 10 - 1] * scale); + std::printf(" 90.0%%\t%f\n", samples[num_samples * 9 / 10 - 1] * scale); + std::printf(" 99.0%%\t%f\n", samples[num_samples * 99 / 100 - 1] * scale); + std::printf(" 99.9%%\t%f\n", samples[num_samples * 999 / 1000 - 1] * scale); + std::printf("100.0%%\t%f\n", samples[num_samples - 1] * scale); + + double total = 0.0; + for (int i = 0; i < num_samples; ++i) total += samples[i] * scale; + std::printf(" mean\t%f\n", total / num_samples); +} diff --git a/src/boost/libs/asio/test/latency/udp_server.cpp b/src/boost/libs/asio/test/latency/udp_server.cpp new file mode 100644 index 000000000..4bba70059 --- /dev/null +++ b/src/boost/libs/asio/test/latency/udp_server.cpp @@ -0,0 +1,125 @@ +// +// udp_server.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/udp.hpp> +#include <boost/shared_ptr.hpp> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <vector> +#include "allocator.hpp" + +using boost::asio::ip::udp; + +#include <boost/asio/yield.hpp> + +class udp_server : boost::asio::coroutine +{ +public: + udp_server(boost::asio::io_context& io_context, + unsigned short port, std::size_t buf_size) : + socket_(io_context, udp::endpoint(udp::v4(), port)), + buffer_(buf_size) + { + } + + void operator()(boost::system::error_code ec, std::size_t n = 0) + { + reenter (this) for (;;) + { + yield socket_.async_receive_from( + boost::asio::buffer(buffer_), + sender_, ref(this)); + + if (!ec) + { + for (std::size_t i = 0; i < n; ++i) buffer_[i] = ~buffer_[i]; + socket_.send_to(boost::asio::buffer(buffer_, n), sender_, 0, ec); + } + } + } + + friend void* asio_handler_allocate(std::size_t n, udp_server* s) + { + return s->allocator_.allocate(n); + } + + friend void asio_handler_deallocate(void* p, std::size_t, udp_server* s) + { + s->allocator_.deallocate(p); + } + + struct ref + { + explicit ref(udp_server* p) + : p_(p) + { + } + + void operator()(boost::system::error_code ec, std::size_t n = 0) + { + (*p_)(ec, n); + } + + private: + udp_server* p_; + + friend void* asio_handler_allocate(std::size_t n, ref* r) + { + return asio_handler_allocate(n, r->p_); + } + + friend void asio_handler_deallocate(void* p, std::size_t n, ref* r) + { + asio_handler_deallocate(p, n, r->p_); + } + }; + +private: + udp::socket socket_; + std::vector<unsigned char> buffer_; + udp::endpoint sender_; + allocator allocator_; +}; + +#include <boost/asio/unyield.hpp> + +int main(int argc, char* argv[]) +{ + if (argc != 5) + { + std::fprintf(stderr, + "Usage: udp_server <port1> <nports> " + "<bufsize> {spin|block}\n"); + return 1; + } + + unsigned short first_port = static_cast<unsigned short>(std::atoi(argv[1])); + unsigned short num_ports = static_cast<unsigned short>(std::atoi(argv[2])); + std::size_t buf_size = std::atoi(argv[3]); + bool spin = (std::strcmp(argv[4], "spin") == 0); + + boost::asio::io_context io_context(1); + std::vector<boost::shared_ptr<udp_server> > servers; + + for (unsigned short i = 0; i < num_ports; ++i) + { + unsigned short port = first_port + i; + boost::shared_ptr<udp_server> s(new udp_server(io_context, port, buf_size)); + servers.push_back(s); + (*s)(boost::system::error_code()); + } + + if (spin) + for (;;) io_context.poll(); + else + io_context.run(); +} diff --git a/src/boost/libs/asio/test/local/basic_endpoint.cpp b/src/boost/libs/asio/test/local/basic_endpoint.cpp new file mode 100644 index 000000000..15ed7cedd --- /dev/null +++ b/src/boost/libs/asio/test/local/basic_endpoint.cpp @@ -0,0 +1,25 @@ +// +// basic_endpoint.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/local/basic_endpoint.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "local/basic_endpoint", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/local/connect_pair.cpp b/src/boost/libs/asio/test/local/connect_pair.cpp new file mode 100644 index 000000000..a2faad90c --- /dev/null +++ b/src/boost/libs/asio/test/local/connect_pair.cpp @@ -0,0 +1,76 @@ +// +// connect_pair.cpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/local/connect_pair.hpp> + +#include <boost/asio/io_context.hpp> +#include <boost/asio/local/datagram_protocol.hpp> +#include <boost/asio/local/stream_protocol.hpp> +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +// local_connect_pair_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all host_name functions compile and link +// correctly. Runtime failures are ignored. + +namespace local_connect_pair_compile { + +void test() +{ +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + using namespace boost::asio; + namespace local = boost::asio::local; + typedef local::datagram_protocol dp; + typedef local::stream_protocol sp; + + try + { + boost::asio::io_context io_context; + boost::system::error_code ec1; + + dp::socket s1(io_context); + dp::socket s2(io_context); + local::connect_pair(s1, s2); + + dp::socket s3(io_context); + dp::socket s4(io_context); + local::connect_pair(s3, s4, ec1); + + sp::socket s5(io_context); + sp::socket s6(io_context); + local::connect_pair(s5, s6); + + sp::socket s7(io_context); + sp::socket s8(io_context); + local::connect_pair(s7, s8, ec1); + } + catch (std::exception&) + { + } +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +} + +} // namespace local_connect_pair_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "local/connect_pair", + BOOST_ASIO_TEST_CASE(local_connect_pair_compile::test) +) diff --git a/src/boost/libs/asio/test/local/datagram_protocol.cpp b/src/boost/libs/asio/test/local/datagram_protocol.cpp new file mode 100644 index 000000000..d85e09ec7 --- /dev/null +++ b/src/boost/libs/asio/test/local/datagram_protocol.cpp @@ -0,0 +1,242 @@ +// +// datagram_protocol.cpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/local/datagram_protocol.hpp> + +#include <cstring> +#include <boost/asio/io_context.hpp> +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +// local_datagram_protocol_socket_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// local::datagram_socket::socket compile and link correctly. Runtime failures +// are ignored. + +namespace local_datagram_protocol_socket_compile { + +void connect_handler(const boost::system::error_code&) +{ +} + +void send_handler(const boost::system::error_code&, std::size_t) +{ +} + +void receive_handler(const boost::system::error_code&, std::size_t) +{ +} + +void test() +{ +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + using namespace boost::asio; + namespace local = boost::asio::local; + typedef local::datagram_protocol dp; + + try + { + io_context ioc; + const io_context::executor_type ioc_ex = ioc.get_executor(); + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + socket_base::message_flags in_flags = 0; + socket_base::send_buffer_size socket_option; + socket_base::bytes_readable io_control_command; + boost::system::error_code ec; + + // basic_datagram_socket constructors. + + dp::socket socket1(ioc); + dp::socket socket2(ioc, dp()); + dp::socket socket3(ioc, dp::endpoint("")); + int native_socket1 = ::socket(AF_UNIX, SOCK_DGRAM, 0); + dp::socket socket4(ioc, dp(), native_socket1); + + dp::socket socket5(ioc_ex); + dp::socket socket6(ioc_ex, dp()); + dp::socket socket7(ioc_ex, dp::endpoint("")); + int native_socket2 = ::socket(AF_UNIX, SOCK_DGRAM, 0); + dp::socket socket8(ioc_ex, dp(), native_socket2); + + // basic_io_object functions. + + dp::socket::executor_type ex = socket1.get_executor(); + (void)ex; + + // basic_socket functions. + + dp::socket::lowest_layer_type& lowest_layer = socket1.lowest_layer(); + (void)lowest_layer; + + socket1.open(dp()); + socket1.open(dp(), ec); + + int native_socket3 = ::socket(AF_UNIX, SOCK_DGRAM, 0); + socket1.assign(dp(), native_socket3); + int native_socket4 = ::socket(AF_UNIX, SOCK_DGRAM, 0); + socket1.assign(dp(), native_socket4, ec); + + bool is_open = socket1.is_open(); + (void)is_open; + + socket1.close(); + socket1.close(ec); + + dp::socket::native_handle_type native_socket5 = socket1.native_handle(); + (void)native_socket5; + + socket1.cancel(); + socket1.cancel(ec); + + bool at_mark1 = socket1.at_mark(); + (void)at_mark1; + bool at_mark2 = socket1.at_mark(ec); + (void)at_mark2; + + std::size_t available1 = socket1.available(); + (void)available1; + std::size_t available2 = socket1.available(ec); + (void)available2; + + socket1.bind(dp::endpoint("")); + socket1.bind(dp::endpoint(""), ec); + + socket1.connect(dp::endpoint("")); + socket1.connect(dp::endpoint(""), ec); + + socket1.async_connect(dp::endpoint(""), connect_handler); + + socket1.set_option(socket_option); + socket1.set_option(socket_option, ec); + + socket1.get_option(socket_option); + socket1.get_option(socket_option, ec); + + socket1.io_control(io_control_command); + socket1.io_control(io_control_command, ec); + + dp::endpoint endpoint1 = socket1.local_endpoint(); + (void)endpoint1; + dp::endpoint endpoint2 = socket1.local_endpoint(ec); + (void)endpoint2; + + dp::endpoint endpoint3 = socket1.remote_endpoint(); + (void)endpoint3; + dp::endpoint endpoint4 = socket1.remote_endpoint(ec); + (void)endpoint4; + + socket1.shutdown(socket_base::shutdown_both); + socket1.shutdown(socket_base::shutdown_both, ec); + + // basic_datagram_socket functions. + + socket1.send(buffer(mutable_char_buffer)); + socket1.send(buffer(const_char_buffer)); + socket1.send(null_buffers()); + socket1.send(buffer(mutable_char_buffer), in_flags); + socket1.send(buffer(const_char_buffer), in_flags); + socket1.send(null_buffers(), in_flags); + socket1.send(buffer(mutable_char_buffer), in_flags, ec); + socket1.send(buffer(const_char_buffer), in_flags, ec); + socket1.send(null_buffers(), in_flags, ec); + + socket1.async_send(buffer(mutable_char_buffer), send_handler); + socket1.async_send(buffer(const_char_buffer), send_handler); + socket1.async_send(null_buffers(), send_handler); + socket1.async_send(buffer(mutable_char_buffer), in_flags, send_handler); + socket1.async_send(buffer(const_char_buffer), in_flags, send_handler); + socket1.async_send(null_buffers(), in_flags, send_handler); + + socket1.send_to(buffer(mutable_char_buffer), + dp::endpoint("")); + socket1.send_to(buffer(const_char_buffer), + dp::endpoint("")); + socket1.send_to(null_buffers(), + dp::endpoint("")); + socket1.send_to(buffer(mutable_char_buffer), + dp::endpoint(""), in_flags); + socket1.send_to(buffer(const_char_buffer), + dp::endpoint(""), in_flags); + socket1.send_to(null_buffers(), + dp::endpoint(""), in_flags); + socket1.send_to(buffer(mutable_char_buffer), + dp::endpoint(""), in_flags, ec); + socket1.send_to(buffer(const_char_buffer), + dp::endpoint(""), in_flags, ec); + socket1.send_to(null_buffers(), + dp::endpoint(""), in_flags, ec); + + socket1.async_send_to(buffer(mutable_char_buffer), + dp::endpoint(""), send_handler); + socket1.async_send_to(buffer(const_char_buffer), + dp::endpoint(""), send_handler); + socket1.async_send_to(null_buffers(), + dp::endpoint(""), send_handler); + socket1.async_send_to(buffer(mutable_char_buffer), + dp::endpoint(""), in_flags, send_handler); + socket1.async_send_to(buffer(const_char_buffer), + dp::endpoint(""), in_flags, send_handler); + socket1.async_send_to(null_buffers(), + dp::endpoint(""), in_flags, send_handler); + + socket1.receive(buffer(mutable_char_buffer)); + socket1.receive(null_buffers()); + socket1.receive(buffer(mutable_char_buffer), in_flags); + socket1.receive(null_buffers(), in_flags); + socket1.receive(buffer(mutable_char_buffer), in_flags, ec); + socket1.receive(null_buffers(), in_flags, ec); + + socket1.async_receive(buffer(mutable_char_buffer), receive_handler); + socket1.async_receive(null_buffers(), receive_handler); + socket1.async_receive(buffer(mutable_char_buffer), in_flags, + receive_handler); + socket1.async_receive(null_buffers(), in_flags, receive_handler); + + dp::endpoint endpoint; + socket1.receive_from(buffer(mutable_char_buffer), endpoint); + socket1.receive_from(null_buffers(), endpoint); + socket1.receive_from(buffer(mutable_char_buffer), endpoint, in_flags); + socket1.receive_from(null_buffers(), endpoint, in_flags); + socket1.receive_from(buffer(mutable_char_buffer), endpoint, in_flags, ec); + socket1.receive_from(null_buffers(), endpoint, in_flags, ec); + + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, receive_handler); + socket1.async_receive_from(null_buffers(), + endpoint, receive_handler); + socket1.async_receive_from(buffer(mutable_char_buffer), + endpoint, in_flags, receive_handler); + socket1.async_receive_from(null_buffers(), + endpoint, in_flags, receive_handler); + } + catch (std::exception&) + { + } +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +} + +} // namespace local_datagram_protocol_socket_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "local/datagram_protocol", + BOOST_ASIO_TEST_CASE(local_datagram_protocol_socket_compile::test) +) diff --git a/src/boost/libs/asio/test/local/stream_protocol.cpp b/src/boost/libs/asio/test/local/stream_protocol.cpp new file mode 100644 index 000000000..6728393c0 --- /dev/null +++ b/src/boost/libs/asio/test/local/stream_protocol.cpp @@ -0,0 +1,219 @@ +// +// stream_protocol.cpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/local/stream_protocol.hpp> + +#include <cstring> +#include <boost/asio/io_context.hpp> +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +// local_stream_protocol_socket_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// local::stream_protocol::socket compile and link correctly. Runtime failures +// are ignored. + +namespace local_stream_protocol_socket_compile { + +void connect_handler(const boost::system::error_code&) +{ +} + +void send_handler(const boost::system::error_code&, std::size_t) +{ +} + +void receive_handler(const boost::system::error_code&, std::size_t) +{ +} + +void write_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void read_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void test() +{ +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + using namespace boost::asio; + namespace local = boost::asio::local; + typedef local::stream_protocol sp; + + try + { + io_context ioc; + const io_context::executor_type ioc_ex = ioc.get_executor(); + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + socket_base::message_flags in_flags = 0; + socket_base::keep_alive socket_option; + socket_base::bytes_readable io_control_command; + boost::system::error_code ec; + + // basic_stream_socket constructors. + + sp::socket socket1(ioc); + sp::socket socket2(ioc, sp()); + sp::socket socket3(ioc, sp::endpoint("")); + int native_socket1 = ::socket(AF_UNIX, SOCK_STREAM, 0); + sp::socket socket4(ioc, sp(), native_socket1); + + sp::socket socket5(ioc_ex); + sp::socket socket6(ioc_ex, sp()); + sp::socket socket7(ioc_ex, sp::endpoint("")); + int native_socket2 = ::socket(AF_UNIX, SOCK_STREAM, 0); + sp::socket socket8(ioc_ex, sp(), native_socket2); + + // basic_io_object functions. + + sp::socket::executor_type ex = socket1.get_executor(); + (void)ex; + + // basic_socket functions. + + sp::socket::lowest_layer_type& lowest_layer = socket1.lowest_layer(); + (void)lowest_layer; + + socket1.open(sp()); + socket1.open(sp(), ec); + + int native_socket3 = ::socket(AF_UNIX, SOCK_STREAM, 0); + socket1.assign(sp(), native_socket3); + int native_socket4 = ::socket(AF_UNIX, SOCK_STREAM, 0); + socket1.assign(sp(), native_socket4, ec); + + bool is_open = socket1.is_open(); + (void)is_open; + + socket1.close(); + socket1.close(ec); + + sp::socket::native_handle_type native_socket5 = socket1.native_handle(); + (void)native_socket5; + + socket1.cancel(); + socket1.cancel(ec); + + bool at_mark1 = socket1.at_mark(); + (void)at_mark1; + bool at_mark2 = socket1.at_mark(ec); + (void)at_mark2; + + std::size_t available1 = socket1.available(); + (void)available1; + std::size_t available2 = socket1.available(ec); + (void)available2; + + socket1.bind(sp::endpoint("")); + socket1.bind(sp::endpoint(""), ec); + + socket1.connect(sp::endpoint("")); + socket1.connect(sp::endpoint(""), ec); + + socket1.async_connect(sp::endpoint(""), connect_handler); + + socket1.set_option(socket_option); + socket1.set_option(socket_option, ec); + + socket1.get_option(socket_option); + socket1.get_option(socket_option, ec); + + socket1.io_control(io_control_command); + socket1.io_control(io_control_command, ec); + + sp::endpoint endpoint1 = socket1.local_endpoint(); + (void)endpoint1; + sp::endpoint endpoint2 = socket1.local_endpoint(ec); + (void)endpoint2; + + sp::endpoint endpoint3 = socket1.remote_endpoint(); + (void)endpoint3; + sp::endpoint endpoint4 = socket1.remote_endpoint(ec); + (void)endpoint4; + + socket1.shutdown(socket_base::shutdown_both); + socket1.shutdown(socket_base::shutdown_both, ec); + + // basic_stream_socket functions. + + socket1.send(buffer(mutable_char_buffer)); + socket1.send(buffer(const_char_buffer)); + socket1.send(null_buffers()); + socket1.send(buffer(mutable_char_buffer), in_flags); + socket1.send(buffer(const_char_buffer), in_flags); + socket1.send(null_buffers(), in_flags); + socket1.send(buffer(mutable_char_buffer), in_flags, ec); + socket1.send(buffer(const_char_buffer), in_flags, ec); + socket1.send(null_buffers(), in_flags, ec); + + socket1.async_send(buffer(mutable_char_buffer), send_handler); + socket1.async_send(buffer(const_char_buffer), send_handler); + socket1.async_send(null_buffers(), send_handler); + socket1.async_send(buffer(mutable_char_buffer), in_flags, send_handler); + socket1.async_send(buffer(const_char_buffer), in_flags, send_handler); + socket1.async_send(null_buffers(), in_flags, send_handler); + + socket1.receive(buffer(mutable_char_buffer)); + socket1.receive(null_buffers()); + socket1.receive(buffer(mutable_char_buffer), in_flags); + socket1.receive(null_buffers(), in_flags); + socket1.receive(buffer(mutable_char_buffer), in_flags, ec); + socket1.receive(null_buffers(), in_flags, ec); + + socket1.async_receive(buffer(mutable_char_buffer), receive_handler); + socket1.async_receive(null_buffers(), receive_handler); + socket1.async_receive(buffer(mutable_char_buffer), in_flags, + receive_handler); + socket1.async_receive(null_buffers(), in_flags, receive_handler); + + socket1.write_some(buffer(mutable_char_buffer)); + socket1.write_some(buffer(const_char_buffer)); + socket1.write_some(null_buffers()); + socket1.write_some(buffer(mutable_char_buffer), ec); + socket1.write_some(buffer(const_char_buffer), ec); + socket1.write_some(null_buffers(), ec); + + socket1.async_write_some(buffer(mutable_char_buffer), write_some_handler); + socket1.async_write_some(buffer(const_char_buffer), write_some_handler); + socket1.async_write_some(null_buffers(), write_some_handler); + + socket1.read_some(buffer(mutable_char_buffer)); + socket1.read_some(buffer(mutable_char_buffer), ec); + socket1.read_some(null_buffers(), ec); + + socket1.async_read_some(buffer(mutable_char_buffer), read_some_handler); + socket1.async_read_some(null_buffers(), read_some_handler); + } + catch (std::exception&) + { + } +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +} + +} // namespace local_stream_protocol_socket_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "local/stream_protocol", + BOOST_ASIO_TEST_CASE(local_stream_protocol_socket_compile::test) +) diff --git a/src/boost/libs/asio/test/packaged_task.cpp b/src/boost/libs/asio/test/packaged_task.cpp new file mode 100644 index 000000000..ba6494aed --- /dev/null +++ b/src/boost/libs/asio/test/packaged_task.cpp @@ -0,0 +1,25 @@ +// +// packaged_task.cpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/packaged_task.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "packaged_task", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/placeholders.cpp b/src/boost/libs/asio/test/placeholders.cpp new file mode 100644 index 000000000..7524929da --- /dev/null +++ b/src/boost/libs/asio/test/placeholders.cpp @@ -0,0 +1,25 @@ +// +// placeholders.cpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/placeholders.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "placeholders", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/posix/basic_descriptor.cpp b/src/boost/libs/asio/test/posix/basic_descriptor.cpp new file mode 100644 index 000000000..ffde113eb --- /dev/null +++ b/src/boost/libs/asio/test/posix/basic_descriptor.cpp @@ -0,0 +1,25 @@ +// +// basic_descriptor.cpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/posix/basic_descriptor.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "posix/basic_descriptor", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/posix/basic_stream_descriptor.cpp b/src/boost/libs/asio/test/posix/basic_stream_descriptor.cpp new file mode 100644 index 000000000..55581a849 --- /dev/null +++ b/src/boost/libs/asio/test/posix/basic_stream_descriptor.cpp @@ -0,0 +1,25 @@ +// +// basic_stream_descriptor.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/posix/basic_stream_descriptor.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "posix/basic_stream_descriptor", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/posix/descriptor.cpp b/src/boost/libs/asio/test/posix/descriptor.cpp new file mode 100644 index 000000000..76fa56f7d --- /dev/null +++ b/src/boost/libs/asio/test/posix/descriptor.cpp @@ -0,0 +1,25 @@ +// +// descriptor.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/posix/descriptor.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "posix/descriptor", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/posix/descriptor_base.cpp b/src/boost/libs/asio/test/posix/descriptor_base.cpp new file mode 100644 index 000000000..5e1cfa597 --- /dev/null +++ b/src/boost/libs/asio/test/posix/descriptor_base.cpp @@ -0,0 +1,25 @@ +// +// descriptor_base.cpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/posix/descriptor_base.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "posix/descriptor_base", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/posix/stream_descriptor.cpp b/src/boost/libs/asio/test/posix/stream_descriptor.cpp new file mode 100644 index 000000000..4d0b9c84f --- /dev/null +++ b/src/boost/libs/asio/test/posix/stream_descriptor.cpp @@ -0,0 +1,183 @@ +// +// stream_descriptor.cpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/posix/stream_descriptor.hpp> + +#include <boost/asio/io_context.hpp> +#include "../archetypes/async_result.hpp" +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +// posix_stream_descriptor_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// posix::stream_descriptor compile and link correctly. Runtime failures are +// ignored. + +namespace posix_stream_descriptor_compile { + +void wait_handler(const boost::system::error_code&) +{ +} + +void write_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void read_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void test() +{ +#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + using namespace boost::asio; + namespace posix = boost::asio::posix; + + try + { + io_context ioc; + const io_context::executor_type ioc_ex = ioc.get_executor(); + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + posix::descriptor_base::bytes_readable io_control_command; + archetypes::lazy_handler lazy; + boost::system::error_code ec; + + // basic_stream_descriptor constructors. + + posix::stream_descriptor descriptor1(ioc); + posix::stream_descriptor descriptor2(ioc_ex); + int native_descriptor1 = -1; + posix::stream_descriptor descriptor3(ioc, native_descriptor1); + posix::stream_descriptor descriptor4(ioc_ex, native_descriptor1); + +#if defined(BOOST_ASIO_HAS_MOVE) + posix::stream_descriptor descriptor5(std::move(descriptor2)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_stream_descriptor operators. + +#if defined(BOOST_ASIO_HAS_MOVE) + descriptor1 = posix::stream_descriptor(ioc); + descriptor1 = std::move(descriptor2); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_io_object functions. + + posix::stream_descriptor::executor_type ex = descriptor1.get_executor(); + (void)ex; + + // basic_descriptor functions. + + posix::stream_descriptor::lowest_layer_type& lowest_layer + = descriptor1.lowest_layer(); + (void)lowest_layer; + + const posix::stream_descriptor& descriptor6 = descriptor1; + const posix::stream_descriptor::lowest_layer_type& lowest_layer2 + = descriptor6.lowest_layer(); + (void)lowest_layer2; + + int native_descriptor2 = -1; + descriptor1.assign(native_descriptor2); + + bool is_open = descriptor1.is_open(); + (void)is_open; + + descriptor1.close(); + descriptor1.close(ec); + + posix::stream_descriptor::native_handle_type native_descriptor3 + = descriptor1.native_handle(); + (void)native_descriptor3; + + posix::stream_descriptor::native_handle_type native_descriptor4 + = descriptor1.release(); + (void)native_descriptor4; + + descriptor1.cancel(); + descriptor1.cancel(ec); + + descriptor1.io_control(io_control_command); + descriptor1.io_control(io_control_command, ec); + + bool non_blocking1 = descriptor1.non_blocking(); + (void)non_blocking1; + descriptor1.non_blocking(true); + descriptor1.non_blocking(false, ec); + + bool non_blocking2 = descriptor1.native_non_blocking(); + (void)non_blocking2; + descriptor1.native_non_blocking(true); + descriptor1.native_non_blocking(false, ec); + + descriptor1.wait(posix::descriptor_base::wait_read); + descriptor1.wait(posix::descriptor_base::wait_write, ec); + + descriptor1.async_wait(posix::descriptor_base::wait_read, &wait_handler); + int i1 = descriptor1.async_wait(posix::descriptor_base::wait_write, lazy); + (void)i1; + + // basic_stream_descriptor functions. + + descriptor1.write_some(buffer(mutable_char_buffer)); + descriptor1.write_some(buffer(const_char_buffer)); + descriptor1.write_some(null_buffers()); + descriptor1.write_some(buffer(mutable_char_buffer), ec); + descriptor1.write_some(buffer(const_char_buffer), ec); + descriptor1.write_some(null_buffers(), ec); + + descriptor1.async_write_some(buffer(mutable_char_buffer), + write_some_handler); + descriptor1.async_write_some(buffer(const_char_buffer), + write_some_handler); + descriptor1.async_write_some(null_buffers(), + write_some_handler); + int i2 = descriptor1.async_write_some(buffer(mutable_char_buffer), lazy); + (void)i2; + int i3 = descriptor1.async_write_some(buffer(const_char_buffer), lazy); + (void)i3; + int i4 = descriptor1.async_write_some(null_buffers(), lazy); + (void)i4; + + descriptor1.read_some(buffer(mutable_char_buffer)); + descriptor1.read_some(buffer(mutable_char_buffer), ec); + descriptor1.read_some(null_buffers(), ec); + + descriptor1.async_read_some(buffer(mutable_char_buffer), read_some_handler); + descriptor1.async_read_some(null_buffers(), read_some_handler); + int i5 = descriptor1.async_read_some(buffer(mutable_char_buffer), lazy); + (void)i5; + int i6 = descriptor1.async_read_some(null_buffers(), lazy); + (void)i6; + } + catch (std::exception&) + { + } +#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) +} + +} // namespace posix_stream_descriptor_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "posix/stream_descriptor", + BOOST_ASIO_TEST_CASE(posix_stream_descriptor_compile::test) +) diff --git a/src/boost/libs/asio/test/post.cpp b/src/boost/libs/asio/test/post.cpp new file mode 100644 index 000000000..f02680b45 --- /dev/null +++ b/src/boost/libs/asio/test/post.cpp @@ -0,0 +1,25 @@ +// +// post.cpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/post.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "post", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/read.cpp b/src/boost/libs/asio/test/read.cpp new file mode 100644 index 000000000..bd099c1c2 --- /dev/null +++ b/src/boost/libs/asio/test/read.cpp @@ -0,0 +1,4997 @@ +// +// read.cpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/read.hpp> + +#include <cstring> +#include <vector> +#include "archetypes/async_result.hpp" +#include <boost/asio/io_context.hpp> +#include <boost/asio/post.hpp> +#include <boost/asio/streambuf.hpp> +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) +#include <boost/array.hpp> +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) +# include <array> +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + +using namespace std; // For memcmp, memcpy and memset. + +class test_stream +{ +public: + typedef boost::asio::io_context::executor_type executor_type; + + test_stream(boost::asio::io_context& io_context) + : io_context_(io_context), + length_(0), + position_(0), + next_read_length_(0) + { + } + + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return io_context_.get_executor(); + } + + void reset(const void* data, size_t length) + { + BOOST_ASIO_CHECK(length <= max_length); + + memcpy(data_, data, length); + length_ = length; + position_ = 0; + next_read_length_ = length; + } + + void next_read_length(size_t length) + { + next_read_length_ = length; + } + + template <typename Iterator> + bool check_buffers(Iterator begin, Iterator end, size_t length) + { + if (length != position_) + return false; + + Iterator iter = begin; + size_t checked_length = 0; + for (; iter != end && checked_length < length; ++iter) + { + size_t buffer_length = boost::asio::buffer_size(*iter); + if (buffer_length > length - checked_length) + buffer_length = length - checked_length; + if (memcmp(data_ + checked_length, iter->data(), buffer_length) != 0) + return false; + checked_length += buffer_length; + } + + return true; + } + + template <typename Const_Buffers> + bool check_buffers(const Const_Buffers& buffers, size_t length) + { + return check_buffers(boost::asio::buffer_sequence_begin(buffers), + boost::asio::buffer_sequence_end(buffers), length); + } + + template <typename Mutable_Buffers> + size_t read_some(const Mutable_Buffers& buffers) + { + size_t n = boost::asio::buffer_copy(buffers, + boost::asio::buffer(data_, length_) + position_, + next_read_length_); + position_ += n; + return n; + } + + template <typename Mutable_Buffers> + size_t read_some(const Mutable_Buffers& buffers, + boost::system::error_code& ec) + { + ec = boost::system::error_code(); + return read_some(buffers); + } + + template <typename Mutable_Buffers, typename Handler> + void async_read_some(const Mutable_Buffers& buffers, + BOOST_ASIO_MOVE_ARG(Handler) handler) + { + size_t bytes_transferred = read_some(buffers); + boost::asio::post(get_executor(), + boost::asio::detail::bind_handler( + BOOST_ASIO_MOVE_CAST(Handler)(handler), + boost::system::error_code(), bytes_transferred)); + } + +private: + boost::asio::io_context& io_context_; + enum { max_length = 8192 }; + char data_[max_length]; + size_t length_; + size_t position_; + size_t next_read_length_; +}; + +static const char read_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +void test_2_arg_zero_buffers_read() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::vector<boost::asio::mutable_buffer> buffers; + + size_t bytes_transferred = boost::asio::read(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == 0); +} + +void test_2_arg_mutable_buffer_read() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + char read_buf[sizeof(read_data)]; + boost::asio::mutable_buffer buffers + = boost::asio::buffer(read_buf, sizeof(read_buf)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + size_t bytes_transferred = boost::asio::read(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); +} + +void test_2_arg_vector_buffers_read() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + char read_buf[sizeof(read_data)]; + std::vector<boost::asio::mutable_buffer> buffers; + buffers.push_back(boost::asio::buffer(read_buf, 32)); + buffers.push_back(boost::asio::buffer(read_buf, 39) + 32); + buffers.push_back(boost::asio::buffer(read_buf) + 39); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + size_t bytes_transferred = boost::asio::read(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); +} + +void test_2_arg_dynamic_string_read() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb + = boost::asio::dynamic_buffer(data, sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + size_t bytes_transferred = boost::asio::read(s, sb); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); +} + +void test_2_arg_streambuf_read() +{ +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + size_t bytes_transferred = boost::asio::read(s, sb); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +} + +void test_3_arg_nothrow_zero_buffers_read() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::vector<boost::asio::mutable_buffer> buffers; + + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == 0); + BOOST_ASIO_CHECK(!error); +} + +void test_3_arg_nothrow_mutable_buffer_read() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + char read_buf[sizeof(read_data)]; + boost::asio::mutable_buffer buffers + = boost::asio::buffer(read_buf, sizeof(read_buf)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_3_arg_nothrow_vector_buffers_read() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + char read_buf[sizeof(read_data)]; + std::vector<boost::asio::mutable_buffer> buffers; + buffers.push_back(boost::asio::buffer(read_buf, 32)); + buffers.push_back(boost::asio::buffer(read_buf, 39) + 32); + buffers.push_back(boost::asio::buffer(read_buf) + 39); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_3_arg_nothrow_dynamic_string_read() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb + = boost::asio::dynamic_buffer(data, sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read(s, sb, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_3_arg_nothrow_streambuf_read() +{ +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read(s, sb, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +} + +bool old_style_transfer_all(const boost::system::error_code& ec, + size_t /*bytes_transferred*/) +{ + return !!ec; +} + +struct short_transfer +{ + short_transfer() {} +#if defined(BOOST_ASIO_HAS_MOVE) + short_transfer(short_transfer&&) {} +#else // defined(BOOST_ASIO_HAS_MOVE) + short_transfer(const short_transfer&) {} +#endif // defined(BOOST_ASIO_HAS_MOVE) + size_t operator()(const boost::system::error_code& ec, + size_t /*bytes_transferred*/) + { + return !!ec ? 0 : 3; + } +}; + +void test_3_arg_mutable_buffer_read() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + char read_buf[sizeof(read_data)]; + boost::asio::mutable_buffer buffers + = boost::asio::buffer(read_buf, sizeof(read_buf)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + size_t bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); +} + +void test_3_arg_vector_buffers_read() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + char read_buf[sizeof(read_data)]; + std::vector<boost::asio::mutable_buffer> buffers; + buffers.push_back(boost::asio::buffer(read_buf, 32)); + buffers.push_back(boost::asio::buffer(read_buf, 39) + 32); + buffers.push_back(boost::asio::buffer(read_buf) + 39); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + size_t bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); +} + +void test_3_arg_dynamic_string_read() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb + = boost::asio::dynamic_buffer(data, sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + size_t bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(sb.size() == 50); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 50)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 1)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 42)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); +} + +void test_3_arg_streambuf_read() +{ +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + size_t bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(sb.size() == 50); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 50)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +} + +void test_4_arg_mutable_buffer_read() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + char read_buf[sizeof(read_data)]; + boost::asio::mutable_buffer buffers + = boost::asio::buffer(read_buf, sizeof(read_buf)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_4_arg_vector_buffers_read() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + char read_buf[sizeof(read_data)]; + std::vector<boost::asio::mutable_buffer> buffers; + buffers.push_back(boost::asio::buffer(read_buf, 32)); + buffers.push_back(boost::asio::buffer(read_buf, 39) + 32); + buffers.push_back(boost::asio::buffer(read_buf) + 39); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read(s, buffers, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, buffers, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_4_arg_dynamic_string_read() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb + = boost::asio::dynamic_buffer(data, sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(sb.size() == 50); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_4_arg_streambuf_read() +{ +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(sb.size() == 50); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read(s, sb, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read(s, sb, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +} + +void async_read_handler(const boost::system::error_code& e, + size_t bytes_transferred, size_t expected_bytes_transferred, bool* called) +{ + *called = true; + BOOST_ASIO_CHECK(!e); + BOOST_ASIO_CHECK(bytes_transferred == expected_bytes_transferred); +} + +void test_3_arg_mutable_buffer_async_read() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + char read_buf[sizeof(read_data)]; + boost::asio::mutable_buffer buffers + = boost::asio::buffer(read_buf, sizeof(read_buf)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read(s, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + int i = boost::asio::async_read(s, buffers, archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); +} + +void test_3_arg_boost_array_buffers_async_read() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) + boost::asio::io_context ioc; + test_stream s(ioc); + char read_buf[sizeof(read_data)]; + boost::array<boost::asio::mutable_buffer, 2> buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read(s, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + int i = boost::asio::async_read(s, buffers, archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) +} + +void test_3_arg_std_array_buffers_async_read() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + boost::asio::io_context ioc; + test_stream s(ioc); + char read_buf[sizeof(read_data)]; + std::array<boost::asio::mutable_buffer, 2> buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read(s, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + int i = boost::asio::async_read(s, buffers, archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) +} + +void test_3_arg_vector_buffers_async_read() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + char read_buf[sizeof(read_data)]; + std::vector<boost::asio::mutable_buffer> buffers; + buffers.push_back(boost::asio::buffer(read_buf, 32)); + buffers.push_back(boost::asio::buffer(read_buf, 39) + 32); + buffers.push_back(boost::asio::buffer(read_buf) + 39); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read(s, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + int i = boost::asio::async_read(s, buffers, archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); +} + +void test_3_arg_dynamic_string_async_read() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb + = boost::asio::dynamic_buffer(data, sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bool called = false; + boost::asio::async_read(s, sb, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + int i = boost::asio::async_read(s, sb, archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); +} + +void test_3_arg_streambuf_async_read() +{ +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bool called = false; + boost::asio::async_read(s, sb, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + int i = boost::asio::async_read(s, sb, archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +} + +void test_4_arg_mutable_buffer_async_read() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + char read_buf[sizeof(read_data)]; + boost::asio::mutable_buffer buffers + = boost::asio::buffer(read_buf, sizeof(read_buf)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + int i = boost::asio::async_read(s, buffers, + short_transfer(), archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); +} + +void test_4_arg_boost_array_buffers_async_read() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) + boost::asio::io_context ioc; + test_stream s(ioc); + char read_buf[sizeof(read_data)]; + boost::array<boost::asio::mutable_buffer, 2> buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + int i = boost::asio::async_read(s, buffers, + short_transfer(), archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) +} + +void test_4_arg_std_array_buffers_async_read() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + boost::asio::io_context ioc; + test_stream s(ioc); + char read_buf[sizeof(read_data)]; + std::array<boost::asio::mutable_buffer, 2> buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + int i = boost::asio::async_read(s, buffers, + short_transfer(), archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) +} + +void test_4_arg_vector_buffers_async_read() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + char read_buf[sizeof(read_data)]; + std::vector<boost::asio::mutable_buffer> buffers; + buffers.push_back(boost::asio::buffer(read_buf, 32)); + buffers.push_back(boost::asio::buffer(read_buf, 39) + 32); + buffers.push_back(boost::asio::buffer(read_buf) + 39); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read(s, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + int i = boost::asio::async_read(s, buffers, + short_transfer(), archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(read_data))); +} + +void test_4_arg_dynamic_string_async_read() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb + = boost::asio::dynamic_buffer(data, sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bool called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 50); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 50)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 1)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), 42)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + int i = boost::asio::async_read(s, sb, + short_transfer(), archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(0, sb.size()), sizeof(read_data))); +} + +void test_4_arg_streambuf_async_read() +{ +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bool called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 50); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 50)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read(s, sb, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + int i = boost::asio::async_read(s, sb, + short_transfer(), archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(sb.data(), sizeof(read_data))); +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +} + +BOOST_ASIO_TEST_SUITE +( + "read", + BOOST_ASIO_TEST_CASE(test_2_arg_zero_buffers_read) + BOOST_ASIO_TEST_CASE(test_2_arg_mutable_buffer_read) + BOOST_ASIO_TEST_CASE(test_2_arg_vector_buffers_read) + BOOST_ASIO_TEST_CASE(test_2_arg_dynamic_string_read) + BOOST_ASIO_TEST_CASE(test_2_arg_streambuf_read) + BOOST_ASIO_TEST_CASE(test_3_arg_nothrow_zero_buffers_read) + BOOST_ASIO_TEST_CASE(test_3_arg_nothrow_mutable_buffer_read) + BOOST_ASIO_TEST_CASE(test_3_arg_nothrow_vector_buffers_read) + BOOST_ASIO_TEST_CASE(test_3_arg_nothrow_dynamic_string_read) + BOOST_ASIO_TEST_CASE(test_3_arg_nothrow_streambuf_read) + BOOST_ASIO_TEST_CASE(test_3_arg_mutable_buffer_read) + BOOST_ASIO_TEST_CASE(test_3_arg_vector_buffers_read) + BOOST_ASIO_TEST_CASE(test_3_arg_dynamic_string_read) + BOOST_ASIO_TEST_CASE(test_3_arg_streambuf_read) + BOOST_ASIO_TEST_CASE(test_4_arg_mutable_buffer_read) + BOOST_ASIO_TEST_CASE(test_4_arg_vector_buffers_read) + BOOST_ASIO_TEST_CASE(test_4_arg_dynamic_string_read) + BOOST_ASIO_TEST_CASE(test_4_arg_streambuf_read) + BOOST_ASIO_TEST_CASE(test_3_arg_mutable_buffer_async_read) + BOOST_ASIO_TEST_CASE(test_3_arg_boost_array_buffers_async_read) + BOOST_ASIO_TEST_CASE(test_3_arg_std_array_buffers_async_read) + BOOST_ASIO_TEST_CASE(test_3_arg_vector_buffers_async_read) + BOOST_ASIO_TEST_CASE(test_3_arg_dynamic_string_async_read) + BOOST_ASIO_TEST_CASE(test_3_arg_streambuf_async_read) + BOOST_ASIO_TEST_CASE(test_4_arg_mutable_buffer_async_read) + BOOST_ASIO_TEST_CASE(test_4_arg_vector_buffers_async_read) + BOOST_ASIO_TEST_CASE(test_4_arg_boost_array_buffers_async_read) + BOOST_ASIO_TEST_CASE(test_4_arg_std_array_buffers_async_read) + BOOST_ASIO_TEST_CASE(test_4_arg_dynamic_string_async_read) + BOOST_ASIO_TEST_CASE(test_4_arg_streambuf_async_read) +) diff --git a/src/boost/libs/asio/test/read_at.cpp b/src/boost/libs/asio/test/read_at.cpp new file mode 100644 index 000000000..2d8abe239 --- /dev/null +++ b/src/boost/libs/asio/test/read_at.cpp @@ -0,0 +1,7502 @@ +// +// read_at.cpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/read_at.hpp> + +#include <cstring> +#include "archetypes/async_result.hpp" +#include <boost/asio/io_context.hpp> +#include <boost/asio/post.hpp> +#include <boost/asio/streambuf.hpp> +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) +#include <boost/array.hpp> +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) +# include <array> +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + +using namespace std; // For memcmp, memcpy and memset. + +class test_random_access_device +{ +public: + typedef boost::asio::io_context::executor_type executor_type; + + test_random_access_device(boost::asio::io_context& io_context) + : io_context_(io_context), + length_(0), + next_read_length_(0) + { + } + + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return io_context_.get_executor(); + } + + void reset(const void* data, size_t length) + { + BOOST_ASIO_CHECK(length <= max_length); + + length_ = 0; + while (length_ + length < max_length) + { + memcpy(data_ + length_, data, length); + length_ += length; + } + + next_read_length_ = length; + } + + void next_read_length(size_t length) + { + next_read_length_ = length; + } + + template <typename Iterator> + bool check_buffers(boost::asio::uint64_t offset, + Iterator begin, Iterator end, size_t length) + { + if (offset + length > max_length) + return false; + + Iterator iter = begin; + size_t checked_length = 0; + for (; iter != end && checked_length < length; ++iter) + { + size_t buffer_length = boost::asio::buffer_size(*iter); + if (buffer_length > length - checked_length) + buffer_length = length - checked_length; + if (memcmp(data_ + offset + checked_length, + iter->data(), buffer_length) != 0) + return false; + checked_length += buffer_length; + } + + return true; + } + + template <typename Const_Buffers> + bool check_buffers(boost::asio::uint64_t offset, + const Const_Buffers& buffers, size_t length) + { + return check_buffers(offset, boost::asio::buffer_sequence_begin(buffers), + boost::asio::buffer_sequence_end(buffers), length); + } + + template <typename Mutable_Buffers> + size_t read_some_at(boost::asio::uint64_t offset, + const Mutable_Buffers& buffers) + { + return boost::asio::buffer_copy(buffers, + boost::asio::buffer(data_, length_) + offset, + next_read_length_); + } + + template <typename Mutable_Buffers> + size_t read_some_at(boost::asio::uint64_t offset, + const Mutable_Buffers& buffers, boost::system::error_code& ec) + { + ec = boost::system::error_code(); + return read_some_at(offset, buffers); + } + + template <typename Mutable_Buffers, typename Handler> + void async_read_some_at(boost::asio::uint64_t offset, + const Mutable_Buffers& buffers, BOOST_ASIO_MOVE_ARG(Handler) handler) + { + size_t bytes_transferred = read_some_at(offset, buffers); + boost::asio::post(get_executor(), + boost::asio::detail::bind_handler( + BOOST_ASIO_MOVE_CAST(Handler)(handler), + boost::system::error_code(), bytes_transferred)); + } + +private: + boost::asio::io_context& io_context_; + enum { max_length = 8192 }; + char data_[max_length]; + size_t length_; + size_t next_read_length_; +}; + +static const char read_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +void test_3_arg_mutable_buffer_read_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + char read_buf[sizeof(read_data)]; + boost::asio::mutable_buffer buffers + = boost::asio::buffer(read_buf, sizeof(read_buf)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + size_t bytes_transferred = boost::asio::read_at(s, 0, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_3_arg_vector_buffers_read_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + char read_buf[sizeof(read_data)]; + std::vector<boost::asio::mutable_buffer> buffers; + buffers.push_back(boost::asio::buffer(read_buf, 32)); + buffers.push_back(boost::asio::buffer(read_buf) + 32); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + size_t bytes_transferred = boost::asio::read_at(s, 0, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_3_arg_streambuf_read_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + size_t bytes_transferred = boost::asio::read_at(s, 0, sb); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); +} + +void test_4_arg_nothrow_mutable_buffer_read_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + char read_buf[sizeof(read_data)]; + boost::asio::mutable_buffer buffers + = boost::asio::buffer(read_buf, sizeof(read_buf)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read_at(s, 0, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_4_arg_nothrow_vector_buffers_read_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + char read_buf[sizeof(read_data)]; + std::vector<boost::asio::mutable_buffer> buffers; + buffers.push_back(boost::asio::buffer(read_buf, 32)); + buffers.push_back(boost::asio::buffer(read_buf) + 32); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read_at(s, 0, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_4_arg_nothrow_streambuf_read_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read_at(s, 0, sb, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); +} + +bool old_style_transfer_all(const boost::system::error_code& ec, + size_t /*bytes_transferred*/) +{ + return !!ec; +} + +struct short_transfer +{ + short_transfer() {} +#if defined(BOOST_ASIO_HAS_MOVE) + short_transfer(short_transfer&&) {} +#else // defined(BOOST_ASIO_HAS_MOVE) + short_transfer(const short_transfer&) {} +#endif // defined(BOOST_ASIO_HAS_MOVE) + size_t operator()(const boost::system::error_code& ec, + size_t /*bytes_transferred*/) + { + return !!ec ? 0 : 3; + } +}; + +void test_4_arg_mutable_buffer_read_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + char read_buf[sizeof(read_data)]; + boost::asio::mutable_buffer buffers + = boost::asio::buffer(read_buf, sizeof(read_buf)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + size_t bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_4_arg_vector_buffers_read_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + char read_buf[sizeof(read_data)]; + std::vector<boost::asio::mutable_buffer> buffers; + buffers.push_back(boost::asio::buffer(read_buf, 32)); + buffers.push_back(boost::asio::buffer(read_buf) + 32); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + size_t bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_4_arg_streambuf_read_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + size_t bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(sb.size() == 50); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 50)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(sb.size() == 50); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 50)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); +} + +void test_5_arg_mutable_buffer_read_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + char read_buf[sizeof(read_data)]; + boost::asio::mutable_buffer buffers + = boost::asio::buffer(read_buf, sizeof(read_buf)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_5_arg_vector_buffers_read_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + char read_buf[sizeof(read_data)]; + std::vector<boost::asio::mutable_buffer> buffers; + buffers.push_back(boost::asio::buffer(read_buf, 32)); + buffers.push_back(boost::asio::buffer(read_buf) + 32); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_5_arg_streambuf_read_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(sb.size() == 50); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(sb.size() == 50); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 0, sb, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 0, sb, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + error = boost::system::error_code(); + bytes_transferred = boost::asio::read_at(s, 1234, sb, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(read_data)); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + BOOST_ASIO_CHECK(!error); +} + +void async_read_handler(const boost::system::error_code& e, + size_t bytes_transferred, size_t expected_bytes_transferred, bool* called) +{ + *called = true; + BOOST_ASIO_CHECK(!e); + BOOST_ASIO_CHECK(bytes_transferred == expected_bytes_transferred); +} + +void test_4_arg_mutable_buffer_async_read_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_random_access_device s(ioc); + char read_buf[sizeof(read_data)]; + boost::asio::mutable_buffer buffers + = boost::asio::buffer(read_buf, sizeof(read_buf)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read_at(s, 0, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + int i = boost::asio::async_read_at(s, 1234, buffers, + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_4_arg_boost_array_buffers_async_read_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) + boost::asio::io_context ioc; + test_random_access_device s(ioc); + char read_buf[sizeof(read_data)]; + boost::array<boost::asio::mutable_buffer, 2> buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read_at(s, 0, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + int i = boost::asio::async_read_at(s, 1234, buffers, + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) +} + +void test_4_arg_std_array_buffers_async_read_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + boost::asio::io_context ioc; + test_random_access_device s(ioc); + char read_buf[sizeof(read_data)]; + std::array<boost::asio::mutable_buffer, 2> buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read_at(s, 0, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + int i = boost::asio::async_read_at(s, 1234, buffers, + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) +} + +void test_4_arg_vector_buffers_async_read_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_random_access_device s(ioc); + char read_buf[sizeof(read_data)]; + std::vector<boost::asio::mutable_buffer> buffers; + buffers.push_back(boost::asio::buffer(read_buf, 32)); + buffers.push_back(boost::asio::buffer(read_buf) + 32); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read_at(s, 0, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + int i = boost::asio::async_read_at(s, 1234, buffers, + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_4_arg_streambuf_async_read_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bool called = false; + boost::asio::async_read_at(s, 0, sb, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + int i = boost::asio::async_read_at(s, 1234, sb, + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); +} + +void test_5_arg_mutable_buffer_async_read_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_random_access_device s(ioc); + char read_buf[sizeof(read_data)]; + boost::asio::mutable_buffer buffers + = boost::asio::buffer(read_buf, sizeof(read_buf)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + int i = boost::asio::async_read_at(s, 1234, buffers, + short_transfer(), archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_5_arg_boost_array_buffers_async_read_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) + boost::asio::io_context ioc; + test_random_access_device s(ioc); + char read_buf[sizeof(read_data)]; + boost::array<boost::asio::mutable_buffer, 2> buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + int i = boost::asio::async_read_at(s, 1234, buffers, + short_transfer(), archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) +} + +void test_5_arg_std_array_buffers_async_read_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + boost::asio::io_context ioc; + test_random_access_device s(ioc); + char read_buf[sizeof(read_data)]; + std::array<boost::asio::mutable_buffer, 2> buffers = { { + boost::asio::buffer(read_buf, 32), + boost::asio::buffer(read_buf) + 32 } }; + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + int i = boost::asio::async_read_at(s, 1234, buffers, + short_transfer(), archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) +} + +void test_5_arg_vector_buffers_async_read_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_random_access_device s(ioc); + char read_buf[sizeof(read_data)]; + std::vector<boost::asio::mutable_buffer> buffers; + buffers.push_back(boost::asio::buffer(read_buf, 32)); + buffers.push_back(boost::asio::buffer(read_buf) + 32); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + bool called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 0, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + memset(read_buf, 0, sizeof(read_buf)); + called = false; + boost::asio::async_read_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + memset(read_buf, 0, sizeof(read_buf)); + int i = boost::asio::async_read_at(s, 1234, buffers, + short_transfer(), archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(read_data))); +} + +void test_5_arg_streambuf_async_read_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::streambuf sb(sizeof(read_data)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + bool called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_all(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(1), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 50); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 50)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_at_least(42), + bindns::bind(async_read_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 50); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 50)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_exactly(1), + bindns::bind(async_read_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 1)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_exactly(10), + bindns::bind(async_read_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 10)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, + boost::asio::transfer_exactly(42), + bindns::bind(async_read_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), 42)); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, old_style_transfer_all, + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 0, sb, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb.consume(sb.size()); + called = false; + boost::asio::async_read_at(s, 1234, sb, short_transfer(), + bindns::bind(async_read_handler, + _1, _2, sizeof(read_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(sb.size() == sizeof(read_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); + + s.reset(read_data, sizeof(read_data)); + sb.consume(sb.size()); + int i = boost::asio::async_read_at(s, 1234, sb, + short_transfer(), archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(1234, sb.data(), sizeof(read_data))); +} + +BOOST_ASIO_TEST_SUITE +( + "read_at", + BOOST_ASIO_TEST_CASE(test_3_arg_mutable_buffer_read_at) + BOOST_ASIO_TEST_CASE(test_3_arg_vector_buffers_read_at) + BOOST_ASIO_TEST_CASE(test_3_arg_streambuf_read_at) + BOOST_ASIO_TEST_CASE(test_4_arg_nothrow_mutable_buffer_read_at) + BOOST_ASIO_TEST_CASE(test_4_arg_nothrow_vector_buffers_read_at) + BOOST_ASIO_TEST_CASE(test_4_arg_nothrow_streambuf_read_at) + BOOST_ASIO_TEST_CASE(test_4_arg_mutable_buffer_read_at) + BOOST_ASIO_TEST_CASE(test_4_arg_vector_buffers_read_at) + BOOST_ASIO_TEST_CASE(test_4_arg_streambuf_read_at) + BOOST_ASIO_TEST_CASE(test_5_arg_mutable_buffer_read_at) + BOOST_ASIO_TEST_CASE(test_5_arg_vector_buffers_read_at) + BOOST_ASIO_TEST_CASE(test_5_arg_streambuf_read_at) + BOOST_ASIO_TEST_CASE(test_4_arg_mutable_buffer_async_read_at) + BOOST_ASIO_TEST_CASE(test_4_arg_boost_array_buffers_async_read_at) + BOOST_ASIO_TEST_CASE(test_4_arg_std_array_buffers_async_read_at) + BOOST_ASIO_TEST_CASE(test_4_arg_vector_buffers_async_read_at) + BOOST_ASIO_TEST_CASE(test_4_arg_streambuf_async_read_at) + BOOST_ASIO_TEST_CASE(test_5_arg_mutable_buffer_async_read_at) + BOOST_ASIO_TEST_CASE(test_5_arg_boost_array_buffers_async_read_at) + BOOST_ASIO_TEST_CASE(test_5_arg_std_array_buffers_async_read_at) + BOOST_ASIO_TEST_CASE(test_5_arg_vector_buffers_async_read_at) + BOOST_ASIO_TEST_CASE(test_5_arg_streambuf_async_read_at) +) diff --git a/src/boost/libs/asio/test/read_until.cpp b/src/boost/libs/asio/test/read_until.cpp new file mode 100644 index 000000000..78d3d38e9 --- /dev/null +++ b/src/boost/libs/asio/test/read_until.cpp @@ -0,0 +1,1660 @@ +// +// read_until.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/read_until.hpp> + +#include <cstring> +#include "archetypes/async_result.hpp" +#include <boost/asio/io_context.hpp> +#include <boost/asio/post.hpp> +#include <boost/asio/streambuf.hpp> +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +class test_stream +{ +public: + typedef boost::asio::io_context::executor_type executor_type; + + test_stream(boost::asio::io_context& io_context) + : io_context_(io_context), + length_(0), + position_(0), + next_read_length_(0) + { + } + + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return io_context_.get_executor(); + } + + void reset(const void* data, size_t length) + { + using namespace std; // For memcpy. + + BOOST_ASIO_CHECK(length <= max_length); + + memcpy(data_, data, length); + length_ = length; + position_ = 0; + next_read_length_ = length; + } + + void next_read_length(size_t length) + { + next_read_length_ = length; + } + + template <typename Mutable_Buffers> + size_t read_some(const Mutable_Buffers& buffers) + { + size_t n = boost::asio::buffer_copy(buffers, + boost::asio::buffer(data_, length_) + position_, + next_read_length_); + position_ += n; + return n; + } + + template <typename Mutable_Buffers> + size_t read_some(const Mutable_Buffers& buffers, + boost::system::error_code& ec) + { + ec = boost::system::error_code(); + return read_some(buffers); + } + + template <typename Mutable_Buffers, typename Handler> + void async_read_some(const Mutable_Buffers& buffers, Handler handler) + { + size_t bytes_transferred = read_some(buffers); + boost::asio::post(get_executor(), + boost::asio::detail::bind_handler( + BOOST_ASIO_MOVE_CAST(Handler)(handler), + boost::system::error_code(), bytes_transferred)); + } + +private: + boost::asio::io_context& io_context_; + enum { max_length = 8192 }; + char data_[max_length]; + size_t length_; + size_t position_; + size_t next_read_length_; +}; + +static const char read_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +void test_dynamic_string_read_until_char() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data1, data2; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb1 = boost::asio::dynamic_buffer(data1); + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb2 = boost::asio::dynamic_buffer(data2, 25); + boost::system::error_code ec; + + s.reset(read_data, sizeof(read_data)); + sb1.consume(sb1.size()); + std::size_t length = boost::asio::read_until(s, sb1, 'Z'); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, 'Z'); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, 'Z'); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, 'Z', ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, 'Z', ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, 'Z', ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, 'Z', ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, 'Z', ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, 'Z', ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, 'Y', ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, 'Y', ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, 'Y', ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); +} + +void test_streambuf_read_until_char() +{ +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::streambuf sb1; + boost::asio::streambuf sb2(25); + boost::system::error_code ec; + + s.reset(read_data, sizeof(read_data)); + sb1.consume(sb1.size()); + std::size_t length = boost::asio::read_until(s, sb1, 'Z'); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, 'Z'); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, 'Z'); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, 'Z', ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, 'Z', ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, 'Z', ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, 'Z', ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, 'Z', ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, 'Z', ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, 'Y', ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, 'Y', ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, 'Y', ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +} + +void test_dynamic_string_read_until_string() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data1, data2; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb1 = boost::asio::dynamic_buffer(data1); + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb2 = boost::asio::dynamic_buffer(data2, 25); + boost::system::error_code ec; + + s.reset(read_data, sizeof(read_data)); + sb1.consume(sb1.size()); + std::size_t length = boost::asio::read_until(s, sb1, "XYZ"); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, "XYZ"); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, "XYZ"); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, "XYZ", ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, "XYZ", ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, "XYZ", ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, "XYZ", ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, "XYZ", ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, "XYZ", ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, "WXY", ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, "WXY", ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, "WXY", ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); +} + +void test_streambuf_read_until_string() +{ +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::streambuf sb1; + boost::asio::streambuf sb2(25); + boost::system::error_code ec; + + s.reset(read_data, sizeof(read_data)); + sb1.consume(sb1.size()); + std::size_t length = boost::asio::read_until(s, sb1, "XYZ"); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, "XYZ"); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, "XYZ"); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, "XYZ", ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, "XYZ", ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, "XYZ", ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, "XYZ", ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, "XYZ", ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, "XYZ", ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, "WXY", ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, "WXY", ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, "WXY", ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +} + +class match_char +{ +public: + explicit match_char(char c) : c_(c) {} + + template <typename Iterator> + std::pair<Iterator, bool> operator()( + Iterator begin, Iterator end) const + { + Iterator i = begin; + while (i != end) + if (c_ == *i++) + return std::make_pair(i, true); + return std::make_pair(i, false); + } + +private: + char c_; +}; + +namespace boost { +namespace asio { + template <> struct is_match_condition<match_char> + { + enum { value = true }; + }; +} // namespace asio +} // namespace boost + +void test_dynamic_string_read_until_match_condition() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data1, data2; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb1 = boost::asio::dynamic_buffer(data1); + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb2 = boost::asio::dynamic_buffer(data2, 25); + boost::system::error_code ec; + + s.reset(read_data, sizeof(read_data)); + sb1.consume(sb1.size()); + std::size_t length = boost::asio::read_until(s, sb1, match_char('Z')); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, match_char('Z')); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, match_char('Z')); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, match_char('Z'), ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, match_char('Z'), ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, match_char('Z'), ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, match_char('Z'), ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, match_char('Z'), ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, match_char('Z'), ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, match_char('Y'), ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, match_char('Y'), ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, match_char('Y'), ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); +} + +void test_streambuf_read_until_match_condition() +{ +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::streambuf sb1; + boost::asio::streambuf sb2(25); + boost::system::error_code ec; + + s.reset(read_data, sizeof(read_data)); + sb1.consume(sb1.size()); + std::size_t length = boost::asio::read_until(s, sb1, match_char('Z')); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, match_char('Z')); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, match_char('Z')); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, match_char('Z'), ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, match_char('Z'), ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb1.consume(sb1.size()); + length = boost::asio::read_until(s, sb1, match_char('Z'), ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, match_char('Z'), ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, match_char('Z'), ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, match_char('Z'), ec); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, match_char('Y'), ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, match_char('Y'), ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + sb2.consume(sb2.size()); + length = boost::asio::read_until(s, sb2, match_char('Y'), ec); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +} + +void async_read_handler( + const boost::system::error_code& err, boost::system::error_code* err_out, + std::size_t bytes_transferred, std::size_t* bytes_out, bool* called) +{ + *err_out = err; + *bytes_out = bytes_transferred; + *called = true; +} + +void test_dynamic_string_async_read_until_char() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data1, data2; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb1 = boost::asio::dynamic_buffer(data1); + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb2 = boost::asio::dynamic_buffer(data2, 25); + boost::system::error_code ec; + std::size_t length; + bool called; + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, 'Z', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, 'Z', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, 'Z', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, 'Z', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, 'Z', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, 'Z', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, 'Y', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, 'Y', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, 'Y', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + int i = boost::asio::async_read_until(s, sb2, 'Y', + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); +} + +void test_streambuf_async_read_until_char() +{ +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::streambuf sb1; + boost::asio::streambuf sb2(25); + boost::system::error_code ec; + std::size_t length; + bool called; + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, 'Z', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, 'Z', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, 'Z', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, 'Z', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, 'Z', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, 'Z', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, 'Y', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, 'Y', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, 'Y', + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + int i = boost::asio::async_read_until(s, sb2, 'Y', + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +} + +void test_dynamic_string_async_read_until_string() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data1, data2; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb1 = boost::asio::dynamic_buffer(data1); + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb2 = boost::asio::dynamic_buffer(data2, 25); + boost::system::error_code ec; + std::size_t length; + bool called; + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, "XYZ", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, "XYZ", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, "XYZ", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, "XYZ", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, "XYZ", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, "XYZ", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, "WXY", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, "WXY", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, "WXY", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + int i = boost::asio::async_read_until(s, sb2, "WXY", + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); +} + +void test_streambuf_async_read_until_string() +{ +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::streambuf sb1; + boost::asio::streambuf sb2(25); + boost::system::error_code ec; + std::size_t length; + bool called; + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, "XYZ", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, "XYZ", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, "XYZ", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, "XYZ", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, "XYZ", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, "XYZ", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, "WXY", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, "WXY", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, "WXY", + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + int i = boost::asio::async_read_until(s, sb2, "WXY", + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +} + +void test_dynamic_string_async_read_until_match_condition() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data1, data2; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb1 = boost::asio::dynamic_buffer(data1); + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb2 = boost::asio::dynamic_buffer(data2, 25); + boost::system::error_code ec; + std::size_t length; + bool called; + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, match_char('Z'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, match_char('Z'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, match_char('Z'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, match_char('Z'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, match_char('Z'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, match_char('Z'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, match_char('Y'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, match_char('Y'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, match_char('Y'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + int i = boost::asio::async_read_until(s, sb2, match_char('Y'), + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); +} + +void test_streambuf_async_read_until_match_condition() +{ +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::streambuf sb1; + boost::asio::streambuf sb2(25); + boost::system::error_code ec; + std::size_t length; + bool called; + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, match_char('Z'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, match_char('Z'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb1.consume(sb1.size()); + boost::asio::async_read_until(s, sb1, match_char('Z'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 26); + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, match_char('Z'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, match_char('Z'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, match_char('Z'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(ec == boost::asio::error::not_found); + BOOST_ASIO_CHECK(length == 0); + + s.reset(read_data, sizeof(read_data)); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, match_char('Y'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(1); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, match_char('Y'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + s.next_read_length(10); + ec = boost::system::error_code(); + length = 0; + called = false; + sb2.consume(sb2.size()); + boost::asio::async_read_until(s, sb2, match_char('Y'), + bindns::bind(async_read_handler, _1, &ec, + _2, &length, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(!ec); + BOOST_ASIO_CHECK(length == 25); + + s.reset(read_data, sizeof(read_data)); + sb2.consume(sb2.size()); + int i = boost::asio::async_read_until(s, sb2, match_char('Y'), + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +} + +BOOST_ASIO_TEST_SUITE +( + "read_until", + BOOST_ASIO_TEST_CASE(test_dynamic_string_read_until_char) + BOOST_ASIO_TEST_CASE(test_streambuf_read_until_char) + BOOST_ASIO_TEST_CASE(test_dynamic_string_read_until_string) + BOOST_ASIO_TEST_CASE(test_streambuf_read_until_string) + BOOST_ASIO_TEST_CASE(test_dynamic_string_read_until_match_condition) + BOOST_ASIO_TEST_CASE(test_streambuf_read_until_match_condition) + BOOST_ASIO_TEST_CASE(test_dynamic_string_async_read_until_char) + BOOST_ASIO_TEST_CASE(test_streambuf_async_read_until_char) + BOOST_ASIO_TEST_CASE(test_dynamic_string_async_read_until_string) + BOOST_ASIO_TEST_CASE(test_streambuf_async_read_until_string) + BOOST_ASIO_TEST_CASE(test_dynamic_string_async_read_until_match_condition) + BOOST_ASIO_TEST_CASE(test_streambuf_async_read_until_match_condition) +) diff --git a/src/boost/libs/asio/test/redirect_error.cpp b/src/boost/libs/asio/test/redirect_error.cpp new file mode 100644 index 000000000..2cbcfcbcc --- /dev/null +++ b/src/boost/libs/asio/test/redirect_error.cpp @@ -0,0 +1,25 @@ +// +// redirect_error.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/redirect_error.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "redirect_error", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/serial_port.cpp b/src/boost/libs/asio/test/serial_port.cpp new file mode 100644 index 000000000..a75c58338 --- /dev/null +++ b/src/boost/libs/asio/test/serial_port.cpp @@ -0,0 +1,173 @@ +// +// serial_port.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/serial_port.hpp> + +#include "archetypes/async_result.hpp" +#include <boost/asio/io_context.hpp> +#include "unit_test.hpp" + +//------------------------------------------------------------------------------ + +// serial_port_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// serial_port compile and link correctly. Runtime failures are ignored. + +namespace serial_port_compile { + +struct write_some_handler +{ + write_some_handler() {} + void operator()(const boost::system::error_code&, std::size_t) {} +#if defined(BOOST_ASIO_HAS_MOVE) + write_some_handler(write_some_handler&&) {} +private: + write_some_handler(const write_some_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +struct read_some_handler +{ + read_some_handler() {} + void operator()(const boost::system::error_code&, std::size_t) {} +#if defined(BOOST_ASIO_HAS_MOVE) + read_some_handler(read_some_handler&&) {} +private: + read_some_handler(const read_some_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +void test() +{ +#if defined(BOOST_ASIO_HAS_SERIAL_PORT) + using namespace boost::asio; + + try + { + io_context ioc; + const io_context::executor_type ioc_ex = ioc.get_executor(); + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + serial_port::baud_rate serial_port_option; + archetypes::lazy_handler lazy; + boost::system::error_code ec; + + // basic_serial_port constructors. + + serial_port port1(ioc); + serial_port port2(ioc, "null"); + serial_port::native_handle_type native_port1 = port1.native_handle(); +#if defined(BOOST_ASIO_MSVC) && (_MSC_VER < 1910) + // Skip this on older MSVC due to mysterious ambiguous overload errors. +#else + serial_port port3(ioc, native_port1); +#endif + + serial_port port4(ioc_ex); + serial_port port5(ioc_ex, "null"); + serial_port::native_handle_type native_port2 = port1.native_handle(); + serial_port port6(ioc_ex, native_port2); + +#if defined(BOOST_ASIO_HAS_MOVE) + serial_port port7(std::move(port6)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_serial_port operators. + +#if defined(BOOST_ASIO_HAS_MOVE) + port1 = serial_port(ioc); + port1 = std::move(port2); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_io_object functions. + + serial_port::executor_type ex = port1.get_executor(); + (void)ex; + + // basic_serial_port functions. + + serial_port::lowest_layer_type& lowest_layer = port1.lowest_layer(); + (void)lowest_layer; + + const serial_port& port8 = port1; + const serial_port::lowest_layer_type& lowest_layer2 = port8.lowest_layer(); + (void)lowest_layer2; + + port1.open("null"); + port1.open("null", ec); + + serial_port::native_handle_type native_port3 = port1.native_handle(); + port1.assign(native_port3); + serial_port::native_handle_type native_port4 = port1.native_handle(); + port1.assign(native_port4, ec); + + bool is_open = port1.is_open(); + (void)is_open; + + port1.close(); + port1.close(ec); + + serial_port::native_handle_type native_port5 = port1.native_handle(); + (void)native_port5; + + port1.cancel(); + port1.cancel(ec); + + port1.set_option(serial_port_option); + port1.set_option(serial_port_option, ec); + + port1.get_option(serial_port_option); + port1.get_option(serial_port_option, ec); + + port1.send_break(); + port1.send_break(ec); + + port1.write_some(buffer(mutable_char_buffer)); + port1.write_some(buffer(const_char_buffer)); + port1.write_some(buffer(mutable_char_buffer), ec); + port1.write_some(buffer(const_char_buffer), ec); + + port1.async_write_some(buffer(mutable_char_buffer), write_some_handler()); + port1.async_write_some(buffer(const_char_buffer), write_some_handler()); + int i1 = port1.async_write_some(buffer(mutable_char_buffer), lazy); + (void)i1; + int i2 = port1.async_write_some(buffer(const_char_buffer), lazy); + (void)i2; + + port1.read_some(buffer(mutable_char_buffer)); + port1.read_some(buffer(mutable_char_buffer), ec); + + port1.async_read_some(buffer(mutable_char_buffer), read_some_handler()); + int i3 = port1.async_read_some(buffer(mutable_char_buffer), lazy); + (void)i3; + } + catch (std::exception&) + { + } +#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) +} + +} // namespace serial_port_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "serial_port", + BOOST_ASIO_TEST_CASE(serial_port_compile::test) +) diff --git a/src/boost/libs/asio/test/serial_port_base.cpp b/src/boost/libs/asio/test/serial_port_base.cpp new file mode 100644 index 000000000..40015f149 --- /dev/null +++ b/src/boost/libs/asio/test/serial_port_base.cpp @@ -0,0 +1,99 @@ +// +// serial_port_base.cpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/serial_port_base.hpp> + +#include <boost/asio/io_context.hpp> +#include <boost/asio/serial_port.hpp> +#include "unit_test.hpp" + +//------------------------------------------------------------------------------ + +// serial_port_base_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Verify that all options and and their accessors compile. Runtime failures are +// ignored. + +namespace serial_port_base_compile { + +void test() +{ +#if defined(BOOST_ASIO_HAS_SERIAL_PORT) + using namespace boost::asio; + + try + { + io_context ioc; + serial_port port(ioc); + + // baud_rate class. + + serial_port_base::baud_rate baud_rate1(9600); + port.set_option(baud_rate1); + serial_port_base::baud_rate baud_rate2; + port.get_option(baud_rate2); + (void)static_cast<unsigned int>(baud_rate2.value()); + + // flow_control class. + + serial_port_base::flow_control flow_control1( + serial_port_base::flow_control::none); + port.set_option(flow_control1); + serial_port_base::flow_control flow_control2; + port.get_option(flow_control2); + (void)static_cast<serial_port_base::flow_control::type>( + flow_control2.value()); + + // parity class. + + serial_port_base::parity parity1(serial_port_base::parity::none); + port.set_option(parity1); + serial_port_base::parity parity2; + port.get_option(parity2); + (void)static_cast<serial_port_base::parity::type>(parity2.value()); + + // stop_bits class. + + serial_port_base::stop_bits stop_bits1(serial_port_base::stop_bits::one); + port.set_option(stop_bits1); + serial_port_base::stop_bits stop_bits2; + port.get_option(stop_bits2); + (void)static_cast<serial_port_base::stop_bits::type>(stop_bits2.value()); + + // character_size class. + + serial_port_base::character_size character_size1(8); + port.set_option(character_size1); + serial_port_base::character_size character_size2; + port.get_option(character_size2); + (void)static_cast<unsigned int>(character_size2.value()); + } + catch (std::exception&) + { + } +#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) +} + +} // namespace serial_port_base_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "serial_port_base", + BOOST_ASIO_TEST_CASE(serial_port_base_compile::test) +) diff --git a/src/boost/libs/asio/test/signal_set.cpp b/src/boost/libs/asio/test/signal_set.cpp new file mode 100644 index 000000000..97f714f4d --- /dev/null +++ b/src/boost/libs/asio/test/signal_set.cpp @@ -0,0 +1,95 @@ +// +// signal_set.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/signal_set.hpp> + +#include "archetypes/async_result.hpp" +#include <boost/asio/io_context.hpp> +#include "unit_test.hpp" + +//------------------------------------------------------------------------------ + +// signal_set_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// signal_set compile and link correctly. Runtime failures are ignored. + +namespace signal_set_compile { + +void signal_handler(const boost::system::error_code&, int) +{ +} + +void test() +{ + using namespace boost::asio; + + try + { + io_context ioc; + const io_context::executor_type ioc_ex = ioc.get_executor(); + archetypes::lazy_handler lazy; + boost::system::error_code ec; + + // basic_signal_set constructors. + + signal_set set1(ioc); + signal_set set2(ioc, 1); + signal_set set3(ioc, 1, 2); + signal_set set4(ioc, 1, 2, 3); + + signal_set set5(ioc_ex); + signal_set set6(ioc_ex, 1); + signal_set set7(ioc_ex, 1, 2); + signal_set set8(ioc_ex, 1, 2, 3); + + // basic_io_object functions. + + signal_set::executor_type ex = set1.get_executor(); + (void)ex; + + // basic_signal_set functions. + + set1.add(1); + set1.add(1, ec); + + set1.remove(1); + set1.remove(1, ec); + + set1.clear(); + set1.clear(ec); + + set1.cancel(); + set1.cancel(ec); + + set1.async_wait(&signal_handler); + int i = set1.async_wait(lazy); + (void)i; + } + catch (std::exception&) + { + } +} + +} // namespace signal_set_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "signal_set", + BOOST_ASIO_TEST_CASE(signal_set_compile::test) +) diff --git a/src/boost/libs/asio/test/socket_base.cpp b/src/boost/libs/asio/test/socket_base.cpp new file mode 100644 index 000000000..9fbf49193 --- /dev/null +++ b/src/boost/libs/asio/test/socket_base.cpp @@ -0,0 +1,650 @@ +// +// socket_base.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/socket_base.hpp> + +#include <boost/asio/io_context.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/ip/udp.hpp> +#include "unit_test.hpp" + +//------------------------------------------------------------------------------ + +// socket_base_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all nested classes, enums and constants in +// socket_base compile and link correctly. Runtime failures are ignored. + +namespace socket_base_compile { + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_context ioc; + ip::tcp::socket sock(ioc); + char buf[1024]; + + // shutdown_type enumeration. + + sock.shutdown(socket_base::shutdown_receive); + sock.shutdown(socket_base::shutdown_send); + sock.shutdown(socket_base::shutdown_both); + + // message_flags constants. + + sock.receive(buffer(buf), socket_base::message_peek); + sock.receive(buffer(buf), socket_base::message_out_of_band); + sock.send(buffer(buf), socket_base::message_do_not_route); + + // broadcast class. + + socket_base::broadcast broadcast1(true); + sock.set_option(broadcast1); + socket_base::broadcast broadcast2; + sock.get_option(broadcast2); + broadcast1 = true; + (void)static_cast<bool>(broadcast1); + (void)static_cast<bool>(!broadcast1); + (void)static_cast<bool>(broadcast1.value()); + + // debug class. + + socket_base::debug debug1(true); + sock.set_option(debug1); + socket_base::debug debug2; + sock.get_option(debug2); + debug1 = true; + (void)static_cast<bool>(debug1); + (void)static_cast<bool>(!debug1); + (void)static_cast<bool>(debug1.value()); + + // do_not_route class. + + socket_base::do_not_route do_not_route1(true); + sock.set_option(do_not_route1); + socket_base::do_not_route do_not_route2; + sock.get_option(do_not_route2); + do_not_route1 = true; + (void)static_cast<bool>(do_not_route1); + (void)static_cast<bool>(!do_not_route1); + (void)static_cast<bool>(do_not_route1.value()); + + // keep_alive class. + + socket_base::keep_alive keep_alive1(true); + sock.set_option(keep_alive1); + socket_base::keep_alive keep_alive2; + sock.get_option(keep_alive2); + keep_alive1 = true; + (void)static_cast<bool>(keep_alive1); + (void)static_cast<bool>(!keep_alive1); + (void)static_cast<bool>(keep_alive1.value()); + + // send_buffer_size class. + + socket_base::send_buffer_size send_buffer_size1(1024); + sock.set_option(send_buffer_size1); + socket_base::send_buffer_size send_buffer_size2; + sock.get_option(send_buffer_size2); + send_buffer_size1 = 1; + (void)static_cast<int>(send_buffer_size1.value()); + + // send_low_watermark class. + + socket_base::send_low_watermark send_low_watermark1(128); + sock.set_option(send_low_watermark1); + socket_base::send_low_watermark send_low_watermark2; + sock.get_option(send_low_watermark2); + send_low_watermark1 = 1; + (void)static_cast<int>(send_low_watermark1.value()); + + // receive_buffer_size class. + + socket_base::receive_buffer_size receive_buffer_size1(1024); + sock.set_option(receive_buffer_size1); + socket_base::receive_buffer_size receive_buffer_size2; + sock.get_option(receive_buffer_size2); + receive_buffer_size1 = 1; + (void)static_cast<int>(receive_buffer_size1.value()); + + // receive_low_watermark class. + + socket_base::receive_low_watermark receive_low_watermark1(128); + sock.set_option(receive_low_watermark1); + socket_base::receive_low_watermark receive_low_watermark2; + sock.get_option(receive_low_watermark2); + receive_low_watermark1 = 1; + (void)static_cast<int>(receive_low_watermark1.value()); + + // reuse_address class. + + socket_base::reuse_address reuse_address1(true); + sock.set_option(reuse_address1); + socket_base::reuse_address reuse_address2; + sock.get_option(reuse_address2); + reuse_address1 = true; + (void)static_cast<bool>(reuse_address1); + (void)static_cast<bool>(!reuse_address1); + (void)static_cast<bool>(reuse_address1.value()); + + // linger class. + + socket_base::linger linger1(true, 30); + sock.set_option(linger1); + socket_base::linger linger2; + sock.get_option(linger2); + linger1.enabled(true); + (void)static_cast<bool>(linger1.enabled()); + linger1.timeout(1); + (void)static_cast<int>(linger1.timeout()); + + // out_of_band_inline class. + + socket_base::out_of_band_inline out_of_band_inline1(true); + sock.set_option(out_of_band_inline1); + socket_base::out_of_band_inline out_of_band_inline2; + sock.get_option(out_of_band_inline2); + out_of_band_inline1 = true; + (void)static_cast<bool>(out_of_band_inline1); + (void)static_cast<bool>(!out_of_band_inline1); + (void)static_cast<bool>(out_of_band_inline1.value()); + + // enable_connection_aborted class. + + socket_base::enable_connection_aborted enable_connection_aborted1(true); + sock.set_option(enable_connection_aborted1); + socket_base::enable_connection_aborted enable_connection_aborted2; + sock.get_option(enable_connection_aborted2); + enable_connection_aborted1 = true; + (void)static_cast<bool>(enable_connection_aborted1); + (void)static_cast<bool>(!enable_connection_aborted1); + (void)static_cast<bool>(enable_connection_aborted1.value()); + + // bytes_readable class. + + socket_base::bytes_readable bytes_readable; + sock.io_control(bytes_readable); + std::size_t bytes = bytes_readable.get(); + (void)bytes; + } + catch (std::exception&) + { + } +} + +} // namespace socket_base_compile + +//------------------------------------------------------------------------------ + +// socket_base_runtime test +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks the runtime operation of the socket options and I/O +// control commands defined in socket_base. + +namespace socket_base_runtime { + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + io_context ioc; + ip::udp::socket udp_sock(ioc, ip::udp::v4()); + ip::tcp::socket tcp_sock(ioc, ip::tcp::v4()); + ip::tcp::acceptor tcp_acceptor(ioc, ip::tcp::v4()); + boost::system::error_code ec; + + // broadcast class. + + socket_base::broadcast broadcast1(true); + BOOST_ASIO_CHECK(broadcast1.value()); + BOOST_ASIO_CHECK(static_cast<bool>(broadcast1)); + BOOST_ASIO_CHECK(!!broadcast1); + udp_sock.set_option(broadcast1, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + socket_base::broadcast broadcast2; + udp_sock.get_option(broadcast2, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(broadcast2.value()); + BOOST_ASIO_CHECK(static_cast<bool>(broadcast2)); + BOOST_ASIO_CHECK(!!broadcast2); + + socket_base::broadcast broadcast3(false); + BOOST_ASIO_CHECK(!broadcast3.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(broadcast3)); + BOOST_ASIO_CHECK(!broadcast3); + udp_sock.set_option(broadcast3, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + socket_base::broadcast broadcast4; + udp_sock.get_option(broadcast4, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(!broadcast4.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(broadcast4)); + BOOST_ASIO_CHECK(!broadcast4); + + // debug class. + + socket_base::debug debug1(true); + BOOST_ASIO_CHECK(debug1.value()); + BOOST_ASIO_CHECK(static_cast<bool>(debug1)); + BOOST_ASIO_CHECK(!!debug1); + udp_sock.set_option(debug1, ec); +#if defined(__linux__) + // On Linux, only root can set SO_DEBUG. + bool not_root = (ec == boost::asio::error::access_denied); + BOOST_ASIO_CHECK(!ec || not_root); + BOOST_ASIO_WARN_MESSAGE(!ec, "Must be root to set debug socket option"); +#else // defined(__linux__) +# if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Option is not supported under Windows CE. + BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, + ec.value() << ", " << ec.message()); +# else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +# endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) +#endif // defined(__linux__) + + socket_base::debug debug2; + udp_sock.get_option(debug2, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Option is not supported under Windows CE. + BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, + ec.value() << ", " << ec.message()); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +# if defined(__linux__) + BOOST_ASIO_CHECK(debug2.value() || not_root); + BOOST_ASIO_CHECK(static_cast<bool>(debug2) || not_root); + BOOST_ASIO_CHECK(!!debug2 || not_root); +# else // defined(__linux__) + BOOST_ASIO_CHECK(debug2.value()); + BOOST_ASIO_CHECK(static_cast<bool>(debug2)); + BOOST_ASIO_CHECK(!!debug2); +# endif // defined(__linux__) +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + + socket_base::debug debug3(false); + BOOST_ASIO_CHECK(!debug3.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(debug3)); + BOOST_ASIO_CHECK(!debug3); + udp_sock.set_option(debug3, ec); +#if defined(__linux__) + BOOST_ASIO_CHECK(!ec || not_root); +#else // defined(__linux__) +# if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Option is not supported under Windows CE. + BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, + ec.value() << ", " << ec.message()); +# else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +# endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) +#endif // defined(__linux__) + + socket_base::debug debug4; + udp_sock.get_option(debug4, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Option is not supported under Windows CE. + BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, + ec.value() << ", " << ec.message()); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +# if defined(__linux__) + BOOST_ASIO_CHECK(!debug4.value() || not_root); + BOOST_ASIO_CHECK(!static_cast<bool>(debug4) || not_root); + BOOST_ASIO_CHECK(!debug4 || not_root); +# else // defined(__linux__) + BOOST_ASIO_CHECK(!debug4.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(debug4)); + BOOST_ASIO_CHECK(!debug4); +# endif // defined(__linux__) +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + + // do_not_route class. + + socket_base::do_not_route do_not_route1(true); + BOOST_ASIO_CHECK(do_not_route1.value()); + BOOST_ASIO_CHECK(static_cast<bool>(do_not_route1)); + BOOST_ASIO_CHECK(!!do_not_route1); + udp_sock.set_option(do_not_route1, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Option is not supported under Windows CE. + BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, + ec.value() << ", " << ec.message()); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + + socket_base::do_not_route do_not_route2; + udp_sock.get_option(do_not_route2, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Option is not supported under Windows CE. + BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, + ec.value() << ", " << ec.message()); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(do_not_route2.value()); + BOOST_ASIO_CHECK(static_cast<bool>(do_not_route2)); + BOOST_ASIO_CHECK(!!do_not_route2); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + + socket_base::do_not_route do_not_route3(false); + BOOST_ASIO_CHECK(!do_not_route3.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(do_not_route3)); + BOOST_ASIO_CHECK(!do_not_route3); + udp_sock.set_option(do_not_route3, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Option is not supported under Windows CE. + BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, + ec.value() << ", " << ec.message()); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + + socket_base::do_not_route do_not_route4; + udp_sock.get_option(do_not_route4, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Option is not supported under Windows CE. + BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, + ec.value() << ", " << ec.message()); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(!do_not_route4.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(do_not_route4)); + BOOST_ASIO_CHECK(!do_not_route4); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + + // keep_alive class. + + socket_base::keep_alive keep_alive1(true); + BOOST_ASIO_CHECK(keep_alive1.value()); + BOOST_ASIO_CHECK(static_cast<bool>(keep_alive1)); + BOOST_ASIO_CHECK(!!keep_alive1); + tcp_sock.set_option(keep_alive1, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + socket_base::keep_alive keep_alive2; + tcp_sock.get_option(keep_alive2, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(keep_alive2.value()); + BOOST_ASIO_CHECK(static_cast<bool>(keep_alive2)); + BOOST_ASIO_CHECK(!!keep_alive2); + + socket_base::keep_alive keep_alive3(false); + BOOST_ASIO_CHECK(!keep_alive3.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(keep_alive3)); + BOOST_ASIO_CHECK(!keep_alive3); + tcp_sock.set_option(keep_alive3, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + socket_base::keep_alive keep_alive4; + tcp_sock.get_option(keep_alive4, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(!keep_alive4.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(keep_alive4)); + BOOST_ASIO_CHECK(!keep_alive4); + + // send_buffer_size class. + + socket_base::send_buffer_size send_buffer_size1(4096); + BOOST_ASIO_CHECK(send_buffer_size1.value() == 4096); + tcp_sock.set_option(send_buffer_size1, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + socket_base::send_buffer_size send_buffer_size2; + tcp_sock.get_option(send_buffer_size2, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(send_buffer_size2.value() == 4096); + + socket_base::send_buffer_size send_buffer_size3(16384); + BOOST_ASIO_CHECK(send_buffer_size3.value() == 16384); + tcp_sock.set_option(send_buffer_size3, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + socket_base::send_buffer_size send_buffer_size4; + tcp_sock.get_option(send_buffer_size4, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(send_buffer_size4.value() == 16384); + + // send_low_watermark class. + + socket_base::send_low_watermark send_low_watermark1(4096); + BOOST_ASIO_CHECK(send_low_watermark1.value() == 4096); + tcp_sock.set_option(send_low_watermark1, ec); +#if defined(WIN32) || defined(__linux__) || defined(__sun) + BOOST_ASIO_CHECK(!!ec); // Not supported on Windows, Linux or Solaris. +#else + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +#endif + + socket_base::send_low_watermark send_low_watermark2; + tcp_sock.get_option(send_low_watermark2, ec); +#if defined(WIN32) || defined(__sun) + BOOST_ASIO_CHECK(!!ec); // Not supported on Windows or Solaris. +#elif defined(__linux__) + BOOST_ASIO_CHECK(!ec); // Not supported on Linux but can get value. +#else + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(send_low_watermark2.value() == 4096); +#endif + + socket_base::send_low_watermark send_low_watermark3(8192); + BOOST_ASIO_CHECK(send_low_watermark3.value() == 8192); + tcp_sock.set_option(send_low_watermark3, ec); +#if defined(WIN32) || defined(__linux__) || defined(__sun) + BOOST_ASIO_CHECK(!!ec); // Not supported on Windows, Linux or Solaris. +#else + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +#endif + + socket_base::send_low_watermark send_low_watermark4; + tcp_sock.get_option(send_low_watermark4, ec); +#if defined(WIN32) || defined(__sun) + BOOST_ASIO_CHECK(!!ec); // Not supported on Windows or Solaris. +#elif defined(__linux__) + BOOST_ASIO_CHECK(!ec); // Not supported on Linux but can get value. +#else + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(send_low_watermark4.value() == 8192); +#endif + + // receive_buffer_size class. + + socket_base::receive_buffer_size receive_buffer_size1(4096); + BOOST_ASIO_CHECK(receive_buffer_size1.value() == 4096); + tcp_sock.set_option(receive_buffer_size1, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Option is not supported under Windows CE. + BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, + ec.value() << ", " << ec.message()); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + + socket_base::receive_buffer_size receive_buffer_size2; + tcp_sock.get_option(receive_buffer_size2, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK(!ec); // Not supported under Windows CE but can get value. +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(receive_buffer_size2.value() == 4096); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + + socket_base::receive_buffer_size receive_buffer_size3(16384); + BOOST_ASIO_CHECK(receive_buffer_size3.value() == 16384); + tcp_sock.set_option(receive_buffer_size3, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + // Option is not supported under Windows CE. + BOOST_ASIO_CHECK_MESSAGE(ec == boost::asio::error::no_protocol_option, + ec.value() << ", " << ec.message()); +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + + socket_base::receive_buffer_size receive_buffer_size4; + tcp_sock.get_option(receive_buffer_size4, ec); +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK(!ec); // Not supported under Windows CE but can get value. +#else // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(receive_buffer_size4.value() == 16384); +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + + // receive_low_watermark class. + + socket_base::receive_low_watermark receive_low_watermark1(4096); + BOOST_ASIO_CHECK(receive_low_watermark1.value() == 4096); + tcp_sock.set_option(receive_low_watermark1, ec); +#if defined(WIN32) || defined(__sun) + BOOST_ASIO_CHECK(!!ec); // Not supported on Windows or Solaris. +#else + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +#endif + + socket_base::receive_low_watermark receive_low_watermark2; + tcp_sock.get_option(receive_low_watermark2, ec); +#if defined(WIN32) || defined(__sun) + BOOST_ASIO_CHECK(!!ec); // Not supported on Windows or Solaris. +#else + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(receive_low_watermark2.value() == 4096); +#endif + + socket_base::receive_low_watermark receive_low_watermark3(8192); + BOOST_ASIO_CHECK(receive_low_watermark3.value() == 8192); + tcp_sock.set_option(receive_low_watermark3, ec); +#if defined(WIN32) || defined(__sun) + BOOST_ASIO_CHECK(!!ec); // Not supported on Windows or Solaris. +#else + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +#endif + + socket_base::receive_low_watermark receive_low_watermark4; + tcp_sock.get_option(receive_low_watermark4, ec); +#if defined(WIN32) || defined(__sun) + BOOST_ASIO_CHECK(!!ec); // Not supported on Windows or Solaris. +#else + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(receive_low_watermark4.value() == 8192); +#endif + + // reuse_address class. + + socket_base::reuse_address reuse_address1(true); + BOOST_ASIO_CHECK(reuse_address1.value()); + BOOST_ASIO_CHECK(static_cast<bool>(reuse_address1)); + BOOST_ASIO_CHECK(!!reuse_address1); + udp_sock.set_option(reuse_address1, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + socket_base::reuse_address reuse_address2; + udp_sock.get_option(reuse_address2, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(reuse_address2.value()); + BOOST_ASIO_CHECK(static_cast<bool>(reuse_address2)); + BOOST_ASIO_CHECK(!!reuse_address2); + + socket_base::reuse_address reuse_address3(false); + BOOST_ASIO_CHECK(!reuse_address3.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(reuse_address3)); + BOOST_ASIO_CHECK(!reuse_address3); + udp_sock.set_option(reuse_address3, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + socket_base::reuse_address reuse_address4; + udp_sock.get_option(reuse_address4, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(!reuse_address4.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(reuse_address4)); + BOOST_ASIO_CHECK(!reuse_address4); + + // linger class. + + socket_base::linger linger1(true, 60); + BOOST_ASIO_CHECK(linger1.enabled()); + BOOST_ASIO_CHECK(linger1.timeout() == 60); + tcp_sock.set_option(linger1, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + socket_base::linger linger2; + tcp_sock.get_option(linger2, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(linger2.enabled()); + BOOST_ASIO_CHECK(linger2.timeout() == 60); + + socket_base::linger linger3(false, 0); + BOOST_ASIO_CHECK(!linger3.enabled()); + BOOST_ASIO_CHECK(linger3.timeout() == 0); + tcp_sock.set_option(linger3, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + socket_base::linger linger4; + tcp_sock.get_option(linger4, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(!linger4.enabled()); + + // enable_connection_aborted class. + + socket_base::enable_connection_aborted enable_connection_aborted1(true); + BOOST_ASIO_CHECK(enable_connection_aborted1.value()); + BOOST_ASIO_CHECK(static_cast<bool>(enable_connection_aborted1)); + BOOST_ASIO_CHECK(!!enable_connection_aborted1); + tcp_acceptor.set_option(enable_connection_aborted1, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + socket_base::enable_connection_aborted enable_connection_aborted2; + tcp_acceptor.get_option(enable_connection_aborted2, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(enable_connection_aborted2.value()); + BOOST_ASIO_CHECK(static_cast<bool>(enable_connection_aborted2)); + BOOST_ASIO_CHECK(!!enable_connection_aborted2); + + socket_base::enable_connection_aborted enable_connection_aborted3(false); + BOOST_ASIO_CHECK(!enable_connection_aborted3.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(enable_connection_aborted3)); + BOOST_ASIO_CHECK(!enable_connection_aborted3); + tcp_acceptor.set_option(enable_connection_aborted3, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + + socket_base::enable_connection_aborted enable_connection_aborted4; + tcp_acceptor.get_option(enable_connection_aborted4, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); + BOOST_ASIO_CHECK(!enable_connection_aborted4.value()); + BOOST_ASIO_CHECK(!static_cast<bool>(enable_connection_aborted4)); + BOOST_ASIO_CHECK(!enable_connection_aborted4); + + // bytes_readable class. + + socket_base::bytes_readable bytes_readable; + udp_sock.io_control(bytes_readable, ec); + BOOST_ASIO_CHECK_MESSAGE(!ec, ec.value() << ", " << ec.message()); +} + +} // namespace socket_base_runtime + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "socket_base", + BOOST_ASIO_TEST_CASE(socket_base_compile::test) + BOOST_ASIO_TEST_CASE(socket_base_runtime::test) +) diff --git a/src/boost/libs/asio/test/ssl/Jamfile.v2 b/src/boost/libs/asio/test/ssl/Jamfile.v2 new file mode 100644 index 000000000..fd6f550ed --- /dev/null +++ b/src/boost/libs/asio/test/ssl/Jamfile.v2 @@ -0,0 +1,60 @@ +# +# Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +import os ; +import feature ; + +lib ssl ; +lib crypto ; + +lib socket ; # SOLARIS +lib nsl ; # SOLARIS +lib ws2_32 ; # NT +lib mswsock ; # NT +lib ipv6 ; # HPUX +lib network ; # HAIKU + +local USE_SELECT = + <define>BOOST_ASIO_DISABLE_EPOLL + <define>BOOST_ASIO_DISABLE_KQUEUE + <define>BOOST_ASIO_DISABLE_IOCP + ; + +project + : requirements + <library>/boost/date_time//boost_date_time + <library>/boost/system//boost_system + <library>/boost/chrono//boost_chrono + <define>BOOST_ALL_NO_LIB=1 + <threading>multi + <target-os>solaris:<library>socket + <target-os>solaris:<library>nsl + <target-os>windows:<define>_WIN32_WINNT=0x0501 + <target-os>windows,<toolset>gcc:<library>ws2_32 + <target-os>windows,<toolset>gcc:<library>mswsock + <target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS + <target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED + <target-os>hpux:<library>ipv6 + <target-os>haiku:<library>network + ; + +test-suite "asio-ssl" : + [ compile context_base.cpp ] + [ compile context_base.cpp : $(USE_SELECT) : context_base_select ] + [ compile context.cpp ] + [ compile context.cpp : $(USE_SELECT) : context_select ] + [ compile error.cpp ] + [ compile error.cpp : $(USE_SELECT) : error_select ] + [ compile host_name_verification.cpp ] + [ compile host_name_verification.cpp : $(USE_SELECT) : host_name_verification_select ] + [ compile rfc2818_verification.cpp ] + [ compile rfc2818_verification.cpp : $(USE_SELECT) : rfc2818_verification_select ] + [ compile stream_base.cpp ] + [ compile stream_base.cpp : $(USE_SELECT) : stream_base_select ] + [ compile stream.cpp ] + [ compile stream.cpp : $(USE_SELECT) : stream_select ] + ; diff --git a/src/boost/libs/asio/test/ssl/context.cpp b/src/boost/libs/asio/test/ssl/context.cpp new file mode 100644 index 000000000..12b3d838b --- /dev/null +++ b/src/boost/libs/asio/test/ssl/context.cpp @@ -0,0 +1,25 @@ +// +// context.cpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ssl/context.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ssl/context", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ssl/context_base.cpp b/src/boost/libs/asio/test/ssl/context_base.cpp new file mode 100644 index 000000000..a63af9dac --- /dev/null +++ b/src/boost/libs/asio/test/ssl/context_base.cpp @@ -0,0 +1,25 @@ +// +// context_base.cpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ssl/context_base.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ssl/context_base", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ssl/error.cpp b/src/boost/libs/asio/test/ssl/error.cpp new file mode 100644 index 000000000..722abe448 --- /dev/null +++ b/src/boost/libs/asio/test/ssl/error.cpp @@ -0,0 +1,25 @@ +// +// error.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ssl/error.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ssl/error", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ssl/host_name_verification.cpp b/src/boost/libs/asio/test/ssl/host_name_verification.cpp new file mode 100644 index 000000000..783455a95 --- /dev/null +++ b/src/boost/libs/asio/test/ssl/host_name_verification.cpp @@ -0,0 +1,25 @@ +// +// host_name_verification.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ssl/host_name_verification.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ssl/host_name_verification", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ssl/rfc2818_verification.cpp b/src/boost/libs/asio/test/ssl/rfc2818_verification.cpp new file mode 100644 index 000000000..92d002e5b --- /dev/null +++ b/src/boost/libs/asio/test/ssl/rfc2818_verification.cpp @@ -0,0 +1,25 @@ +// +// rfc2818_verification.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ssl/rfc2818_verification.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ssl/rfc2818_verification", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ssl/stream.cpp b/src/boost/libs/asio/test/ssl/stream.cpp new file mode 100644 index 000000000..007dd5f4c --- /dev/null +++ b/src/boost/libs/asio/test/ssl/stream.cpp @@ -0,0 +1,191 @@ +// +// stream.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ssl/stream.hpp> + +#include <boost/asio.hpp> +#include <boost/asio/ssl.hpp> +#include "../archetypes/async_result.hpp" +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +// ssl_stream_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// ssl::stream::socket compile and link correctly. Runtime failures are ignored. + +namespace ssl_stream_compile { + +bool verify_callback(bool, boost::asio::ssl::verify_context&) +{ + return false; +} + +void handshake_handler(const boost::system::error_code&) +{ +} + +void buffered_handshake_handler(const boost::system::error_code&, std::size_t) +{ +} + +void shutdown_handler(const boost::system::error_code&) +{ +} + +void write_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void read_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void test() +{ + using namespace boost::asio; + namespace ip = boost::asio::ip; + + try + { + io_context ioc; + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + boost::asio::ssl::context context(boost::asio::ssl::context::sslv23); + archetypes::lazy_handler lazy; + boost::system::error_code ec; + + // ssl::stream constructors. + + ssl::stream<ip::tcp::socket> stream1(ioc, context); + ip::tcp::socket socket1(ioc, ip::tcp::v4()); + ssl::stream<ip::tcp::socket&> stream2(socket1, context); + + // basic_io_object functions. + + ssl::stream<ip::tcp::socket>::executor_type ex = stream1.get_executor(); + (void)ex; + + // ssl::stream functions. + + SSL* ssl1 = stream1.native_handle(); + (void)ssl1; + + ssl::stream<ip::tcp::socket>::lowest_layer_type& lowest_layer + = stream1.lowest_layer(); + (void)lowest_layer; + + const ssl::stream<ip::tcp::socket>& stream3 = stream1; + const ssl::stream<ip::tcp::socket>::lowest_layer_type& lowest_layer2 + = stream3.lowest_layer(); + (void)lowest_layer2; + + stream1.set_verify_mode(ssl::verify_none); + stream1.set_verify_mode(ssl::verify_none, ec); + + stream1.set_verify_depth(1); + stream1.set_verify_depth(1, ec); + + stream1.set_verify_callback(verify_callback); + stream1.set_verify_callback(verify_callback, ec); + + stream1.handshake(ssl::stream_base::client); + stream1.handshake(ssl::stream_base::server); + stream1.handshake(ssl::stream_base::client, ec); + stream1.handshake(ssl::stream_base::server, ec); + + stream1.handshake(ssl::stream_base::client, buffer(mutable_char_buffer)); + stream1.handshake(ssl::stream_base::server, buffer(mutable_char_buffer)); + stream1.handshake(ssl::stream_base::client, buffer(const_char_buffer)); + stream1.handshake(ssl::stream_base::server, buffer(const_char_buffer)); + stream1.handshake(ssl::stream_base::client, + buffer(mutable_char_buffer), ec); + stream1.handshake(ssl::stream_base::server, + buffer(mutable_char_buffer), ec); + stream1.handshake(ssl::stream_base::client, + buffer(const_char_buffer), ec); + stream1.handshake(ssl::stream_base::server, + buffer(const_char_buffer), ec); + + stream1.async_handshake(ssl::stream_base::client, handshake_handler); + stream1.async_handshake(ssl::stream_base::server, handshake_handler); + int i1 = stream1.async_handshake(ssl::stream_base::client, lazy); + (void)i1; + int i2 = stream1.async_handshake(ssl::stream_base::server, lazy); + (void)i2; + + stream1.async_handshake(ssl::stream_base::client, + buffer(mutable_char_buffer), buffered_handshake_handler); + stream1.async_handshake(ssl::stream_base::server, + buffer(mutable_char_buffer), buffered_handshake_handler); + stream1.async_handshake(ssl::stream_base::client, + buffer(const_char_buffer), buffered_handshake_handler); + stream1.async_handshake(ssl::stream_base::server, + buffer(const_char_buffer), buffered_handshake_handler); + int i3 = stream1.async_handshake(ssl::stream_base::client, + buffer(mutable_char_buffer), lazy); + (void)i3; + int i4 = stream1.async_handshake(ssl::stream_base::server, + buffer(mutable_char_buffer), lazy); + (void)i4; + int i5 = stream1.async_handshake(ssl::stream_base::client, + buffer(const_char_buffer), lazy); + (void)i5; + int i6 = stream1.async_handshake(ssl::stream_base::server, + buffer(const_char_buffer), lazy); + (void)i6; + + stream1.shutdown(); + stream1.shutdown(ec); + + stream1.async_shutdown(shutdown_handler); + int i7 = stream1.async_shutdown(lazy); + (void)i7; + + stream1.write_some(buffer(mutable_char_buffer)); + stream1.write_some(buffer(const_char_buffer)); + stream1.write_some(buffer(mutable_char_buffer), ec); + stream1.write_some(buffer(const_char_buffer), ec); + + stream1.async_write_some(buffer(mutable_char_buffer), write_some_handler); + stream1.async_write_some(buffer(const_char_buffer), write_some_handler); + int i8 = stream1.async_write_some(buffer(mutable_char_buffer), lazy); + (void)i8; + int i9 = stream1.async_write_some(buffer(const_char_buffer), lazy); + (void)i9; + + stream1.read_some(buffer(mutable_char_buffer)); + stream1.read_some(buffer(mutable_char_buffer), ec); + + stream1.async_read_some(buffer(mutable_char_buffer), read_some_handler); + int i10 = stream1.async_read_some(buffer(mutable_char_buffer), lazy); + (void)i10; + } + catch (std::exception&) + { + } +} + +} // namespace ssl_stream_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "ssl/stream", + BOOST_ASIO_TEST_CASE(ssl_stream_compile::test) +) diff --git a/src/boost/libs/asio/test/ssl/stream_base.cpp b/src/boost/libs/asio/test/ssl/stream_base.cpp new file mode 100644 index 000000000..5d02e34ad --- /dev/null +++ b/src/boost/libs/asio/test/ssl/stream_base.cpp @@ -0,0 +1,25 @@ +// +// stream_base.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/ssl/stream_base.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ssl/stream_base", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/steady_timer.cpp b/src/boost/libs/asio/test/steady_timer.cpp new file mode 100644 index 000000000..237f71c89 --- /dev/null +++ b/src/boost/libs/asio/test/steady_timer.cpp @@ -0,0 +1,30 @@ +// +// steady_timer.cpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Prevent link dependency on the Boost.System library. +#if !defined(BOOST_SYSTEM_NO_DEPRECATED) +#define BOOST_SYSTEM_NO_DEPRECATED +#endif // !defined(BOOST_SYSTEM_NO_DEPRECATED) + +// Test that header file is self-contained. +#include <boost/asio/steady_timer.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "steady_timer", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/strand.cpp b/src/boost/libs/asio/test/strand.cpp new file mode 100644 index 000000000..66e97b90b --- /dev/null +++ b/src/boost/libs/asio/test/strand.cpp @@ -0,0 +1,263 @@ +// +// strand.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/strand.hpp> + +#include <sstream> +#include <boost/asio/executor.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/dispatch.hpp> +#include <boost/asio/post.hpp> +#include <boost/asio/detail/thread.hpp> +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +# include <boost/asio/deadline_timer.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +# include <boost/asio/steady_timer.hpp> +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +using namespace boost::asio; + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = std; +#endif + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +typedef deadline_timer timer; +namespace chronons = boost::posix_time; +#elif defined(BOOST_ASIO_HAS_CHRONO) +typedef steady_timer timer; +namespace chronons = boost::asio::chrono; +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +void increment(int* count) +{ + ++(*count); +} + +void increment_without_lock(strand<io_context::executor_type>* s, int* count) +{ + BOOST_ASIO_CHECK(!s->running_in_this_thread()); + + int original_count = *count; + + dispatch(*s, bindns::bind(increment, count)); + + // No other functions are currently executing through the locking dispatcher, + // so the previous call to dispatch should have successfully nested. + BOOST_ASIO_CHECK(*count == original_count + 1); +} + +void increment_with_lock(strand<io_context::executor_type>* s, int* count) +{ + BOOST_ASIO_CHECK(s->running_in_this_thread()); + + int original_count = *count; + + dispatch(*s, bindns::bind(increment, count)); + + // The current function already holds the strand's lock, so the + // previous call to dispatch should have successfully nested. + BOOST_ASIO_CHECK(*count == original_count + 1); +} + +void sleep_increment(io_context* ioc, int* count) +{ + timer t(*ioc, chronons::seconds(2)); + t.wait(); + + ++(*count); +} + +void increment_by_a(int* count, int a) +{ + (*count) += a; +} + +void increment_by_a_b(int* count, int a, int b) +{ + (*count) += a + b; +} + +void increment_by_a_b_c(int* count, int a, int b, int c) +{ + (*count) += a + b + c; +} + +void increment_by_a_b_c_d(int* count, int a, int b, int c, int d) +{ + (*count) += a + b + c + d; +} + +void start_sleep_increments(io_context* ioc, + strand<io_context::executor_type>* s, int* count) +{ + // Give all threads a chance to start. + timer t(*ioc, chronons::seconds(2)); + t.wait(); + + // Start three increments. + post(*s, bindns::bind(sleep_increment, ioc, count)); + post(*s, bindns::bind(sleep_increment, ioc, count)); + post(*s, bindns::bind(sleep_increment, ioc, count)); +} + +void throw_exception() +{ + throw 1; +} + +void io_context_run(io_context* ioc) +{ + ioc->run(); +} + +void strand_test() +{ + io_context ioc; + strand<io_context::executor_type> s = make_strand(ioc); + int count = 0; + + post(ioc, bindns::bind(increment_without_lock, &s, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + post(s, bindns::bind(increment_with_lock, &s, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all work has finished. + BOOST_ASIO_CHECK(count == 1); + + count = 0; + ioc.restart(); + post(ioc, bindns::bind(start_sleep_increments, &ioc, &s, &count)); + boost::asio::detail::thread thread1(bindns::bind(io_context_run, &ioc)); + boost::asio::detail::thread thread2(bindns::bind(io_context_run, &ioc)); + + // Check all events run one after another even though there are two threads. + timer timer1(ioc, chronons::seconds(3)); + timer1.wait(); + BOOST_ASIO_CHECK(count == 0); +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + timer1.expires_at(timer1.expires_at() + chronons::seconds(2)); +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + timer1.expires_at(timer1.expiry() + chronons::seconds(2)); +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + timer1.wait(); + BOOST_ASIO_CHECK(count == 1); +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + timer1.expires_at(timer1.expires_at() + chronons::seconds(2)); +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + timer1.expires_at(timer1.expiry() + chronons::seconds(2)); +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + timer1.wait(); + BOOST_ASIO_CHECK(count == 2); + + thread1.join(); + thread2.join(); + + // The run() calls will not return until all work has finished. + BOOST_ASIO_CHECK(count == 3); + + count = 0; + int exception_count = 0; + ioc.restart(); + post(s, throw_exception); + post(s, bindns::bind(increment, &count)); + post(s, bindns::bind(increment, &count)); + post(s, throw_exception); + post(s, bindns::bind(increment, &count)); + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(count == 0); + BOOST_ASIO_CHECK(exception_count == 0); + + for (;;) + { + try + { + ioc.run(); + break; + } + catch (int) + { + ++exception_count; + } + } + + // The run() calls will not return until all work has finished. + BOOST_ASIO_CHECK(count == 3); + BOOST_ASIO_CHECK(exception_count == 2); + + count = 0; + ioc.restart(); + + // Check for clean shutdown when handlers posted through an orphaned strand + // are abandoned. + { + strand<io_context::executor_type> s2 = make_strand(ioc.get_executor()); + post(s2, bindns::bind(increment, &count)); + post(s2, bindns::bind(increment, &count)); + post(s2, bindns::bind(increment, &count)); + } + + // No handlers can be called until run() is called. + BOOST_ASIO_CHECK(count == 0); +} + +void strand_conversion_test() +{ + io_context ioc; + strand<io_context::executor_type> s1 = make_strand(ioc); + + // Converting constructors. + + strand<executor> s2(s1); + strand<executor> s3 = strand<io_context::executor_type>(s1); + + // Converting assignment. + + s3 = s1; + s3 = strand<io_context::executor_type>(s1); +} + +BOOST_ASIO_TEST_SUITE +( + "strand", + BOOST_ASIO_TEST_CASE(strand_test) + BOOST_ASIO_COMPILE_TEST_CASE(strand_conversion_test) +) diff --git a/src/boost/libs/asio/test/streambuf.cpp b/src/boost/libs/asio/test/streambuf.cpp new file mode 100644 index 000000000..6c17167cb --- /dev/null +++ b/src/boost/libs/asio/test/streambuf.cpp @@ -0,0 +1,62 @@ +// +// streambuf.cpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/streambuf.hpp> + +#include <boost/asio/buffer.hpp> +#include "unit_test.hpp" + +void streambuf_test() +{ + boost::asio::streambuf sb; + + sb.sputn("abcd", 4); + + BOOST_ASIO_CHECK(sb.size() == 4); + + for (int i = 0; i < 100; ++i) + { + sb.consume(3); + + BOOST_ASIO_CHECK(sb.size() == 1); + + char buf[1]; + sb.sgetn(buf, 1); + + BOOST_ASIO_CHECK(sb.size() == 0); + + sb.sputn("ab", 2); + + BOOST_ASIO_CHECK(sb.size() == 2); + + boost::asio::buffer_copy(sb.prepare(10), boost::asio::buffer("cd", 2)); + sb.commit(2); + + BOOST_ASIO_CHECK(sb.size() == 4); + } + + BOOST_ASIO_CHECK(sb.size() == 4); + + sb.consume(4); + + BOOST_ASIO_CHECK(sb.size() == 0); +} + +BOOST_ASIO_TEST_SUITE +( + "streambuf", + BOOST_ASIO_TEST_CASE(streambuf_test) +) diff --git a/src/boost/libs/asio/test/system_context.cpp b/src/boost/libs/asio/test/system_context.cpp new file mode 100644 index 000000000..32d08bf61 --- /dev/null +++ b/src/boost/libs/asio/test/system_context.cpp @@ -0,0 +1,30 @@ +// +// system_context.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Prevent link dependency on the Boost.System library. +#if !defined(BOOST_SYSTEM_NO_DEPRECATED) +#define BOOST_SYSTEM_NO_DEPRECATED +#endif // !defined(BOOST_SYSTEM_NO_DEPRECATED) + +// Test that header file is self-contained. +#include <boost/asio/system_context.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "system_context", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/system_executor.cpp b/src/boost/libs/asio/test/system_executor.cpp new file mode 100644 index 000000000..2f286f438 --- /dev/null +++ b/src/boost/libs/asio/test/system_executor.cpp @@ -0,0 +1,30 @@ +// +// system_executor.cpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Prevent link dependency on the Boost.System library. +#if !defined(BOOST_SYSTEM_NO_DEPRECATED) +#define BOOST_SYSTEM_NO_DEPRECATED +#endif // !defined(BOOST_SYSTEM_NO_DEPRECATED) + +// Test that header file is self-contained. +#include <boost/asio/system_executor.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "system_executor", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/system_timer.cpp b/src/boost/libs/asio/test/system_timer.cpp new file mode 100644 index 000000000..88755bff8 --- /dev/null +++ b/src/boost/libs/asio/test/system_timer.cpp @@ -0,0 +1,399 @@ +// +// system_timer.cpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Prevent link dependency on the Boost.System library. +#if !defined(BOOST_SYSTEM_NO_DEPRECATED) +#define BOOST_SYSTEM_NO_DEPRECATED +#endif // !defined(BOOST_SYSTEM_NO_DEPRECATED) + +// Test that header file is self-contained. +#include <boost/asio/system_timer.hpp> + +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_STD_CHRONO) + +#include <boost/asio/executor_work_guard.hpp> +#include <boost/asio/io_context.hpp> +#include <boost/asio/detail/thread.hpp> + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +void increment(int* count) +{ + ++(*count); +} + +void decrement_to_zero(boost::asio::system_timer* t, int* count) +{ + if (*count > 0) + { + --(*count); + + int before_value = *count; + + t->expires_at(t->expiry() + boost::asio::chrono::seconds(1)); + t->async_wait(bindns::bind(decrement_to_zero, t, count)); + + // Completion cannot nest, so count value should remain unchanged. + BOOST_ASIO_CHECK(*count == before_value); + } +} + +void increment_if_not_cancelled(int* count, + const boost::system::error_code& ec) +{ + if (!ec) + ++(*count); +} + +void cancel_timer(boost::asio::system_timer* t) +{ + std::size_t num_cancelled = t->cancel(); + BOOST_ASIO_CHECK(num_cancelled == 1); +} + +void cancel_one_timer(boost::asio::system_timer* t) +{ + std::size_t num_cancelled = t->cancel_one(); + BOOST_ASIO_CHECK(num_cancelled == 1); +} + +boost::asio::system_timer::time_point now() +{ + return boost::asio::system_timer::clock_type::now(); +} + +void system_timer_test() +{ + using boost::asio::chrono::seconds; + using boost::asio::chrono::microseconds; + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + const boost::asio::io_context::executor_type ioc_ex = ioc.get_executor(); + int count = 0; + + boost::asio::system_timer::time_point start = now(); + + boost::asio::system_timer t1(ioc, seconds(1)); + t1.wait(); + + // The timer must block until after its expiry time. + boost::asio::system_timer::time_point end = now(); + boost::asio::system_timer::time_point expected_end = start + seconds(1); + BOOST_ASIO_CHECK(expected_end < end || expected_end == end); + + start = now(); + + boost::asio::system_timer t2(ioc_ex, seconds(1) + microseconds(500000)); + t2.wait(); + + // The timer must block until after its expiry time. + end = now(); + expected_end = start + seconds(1) + microseconds(500000); + BOOST_ASIO_CHECK(expected_end < end || expected_end == end); + + t2.expires_at(t2.expiry() + seconds(1)); + t2.wait(); + + // The timer must block until after its expiry time. + end = now(); + expected_end += seconds(1); + BOOST_ASIO_CHECK(expected_end < end || expected_end == end); + + start = now(); + + t2.expires_after(seconds(1) + microseconds(200000)); + t2.wait(); + + // The timer must block until after its expiry time. + end = now(); + expected_end = start + seconds(1) + microseconds(200000); + BOOST_ASIO_CHECK(expected_end < end || expected_end == end); + + start = now(); + + boost::asio::system_timer t3(ioc, seconds(5)); + t3.async_wait(bindns::bind(increment, &count)); + + // No completions can be delivered until run() is called. + BOOST_ASIO_CHECK(count == 0); + + ioc.run(); + + // The run() call will not return until all operations have finished, and + // this should not be until after the timer's expiry time. + BOOST_ASIO_CHECK(count == 1); + end = now(); + expected_end = start + seconds(1); + BOOST_ASIO_CHECK(expected_end < end || expected_end == end); + + count = 3; + start = now(); + + boost::asio::system_timer t4(ioc, seconds(1)); + t4.async_wait(bindns::bind(decrement_to_zero, &t4, &count)); + + // No completions can be delivered until run() is called. + BOOST_ASIO_CHECK(count == 3); + + ioc.restart(); + ioc.run(); + + // The run() call will not return until all operations have finished, and + // this should not be until after the timer's final expiry time. + BOOST_ASIO_CHECK(count == 0); + end = now(); + expected_end = start + seconds(3); + BOOST_ASIO_CHECK(expected_end < end || expected_end == end); + + count = 0; + start = now(); + + boost::asio::system_timer t5(ioc, seconds(10)); + t5.async_wait(bindns::bind(increment_if_not_cancelled, &count, _1)); + boost::asio::system_timer t6(ioc, seconds(1)); + t6.async_wait(bindns::bind(cancel_timer, &t5)); + + // No completions can be delivered until run() is called. + BOOST_ASIO_CHECK(count == 0); + + ioc.restart(); + ioc.run(); + + // The timer should have been cancelled, so count should not have changed. + // The total run time should not have been much more than 1 second (and + // certainly far less than 10 seconds). + BOOST_ASIO_CHECK(count == 0); + end = now(); + expected_end = start + seconds(2); + BOOST_ASIO_CHECK(end < expected_end); + + // Wait on the timer again without cancelling it. This time the asynchronous + // wait should run to completion and increment the counter. + t5.async_wait(bindns::bind(increment_if_not_cancelled, &count, _1)); + + ioc.restart(); + ioc.run(); + + // The timer should not have been cancelled, so count should have changed. + // The total time since the timer was created should be more than 10 seconds. + BOOST_ASIO_CHECK(count == 1); + end = now(); + expected_end = start + seconds(10); + BOOST_ASIO_CHECK(expected_end < end || expected_end == end); + + count = 0; + start = now(); + + // Start two waits on a timer, one of which will be cancelled. The one + // which is not cancelled should still run to completion and increment the + // counter. + boost::asio::system_timer t7(ioc, seconds(3)); + t7.async_wait(bindns::bind(increment_if_not_cancelled, &count, _1)); + t7.async_wait(bindns::bind(increment_if_not_cancelled, &count, _1)); + boost::asio::system_timer t8(ioc, seconds(1)); + t8.async_wait(bindns::bind(cancel_one_timer, &t7)); + + ioc.restart(); + ioc.run(); + + // One of the waits should not have been cancelled, so count should have + // changed. The total time since the timer was created should be more than 3 + // seconds. + BOOST_ASIO_CHECK(count == 1); + end = now(); + expected_end = start + seconds(3); + BOOST_ASIO_CHECK(expected_end < end || expected_end == end); +} + +struct timer_handler +{ + timer_handler() {} + void operator()(const boost::system::error_code&) {} +#if defined(BOOST_ASIO_HAS_MOVE) + timer_handler(timer_handler&&) {} +private: + timer_handler(const timer_handler&); +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +void system_timer_cancel_test() +{ + static boost::asio::io_context io_context; + struct timer + { + boost::asio::system_timer t; + timer() : t(io_context) + { + t.expires_at((boost::asio::system_timer::time_point::max)()); + } + } timers[50]; + + timers[2].t.async_wait(timer_handler()); + timers[41].t.async_wait(timer_handler()); + for (int i = 10; i < 20; ++i) + timers[i].t.async_wait(timer_handler()); + + BOOST_ASIO_CHECK(timers[2].t.cancel() == 1); + BOOST_ASIO_CHECK(timers[41].t.cancel() == 1); + for (int i = 10; i < 20; ++i) + BOOST_ASIO_CHECK(timers[i].t.cancel() == 1); +} + +struct custom_allocation_timer_handler +{ + custom_allocation_timer_handler(int* count) : count_(count) {} + void operator()(const boost::system::error_code&) {} + int* count_; +}; + +void* asio_handler_allocate(std::size_t size, + custom_allocation_timer_handler* handler) +{ + ++(*handler->count_); + return ::operator new(size); +} + +void asio_handler_deallocate(void* pointer, std::size_t, + custom_allocation_timer_handler* handler) +{ + --(*handler->count_); + ::operator delete(pointer); +} + +void system_timer_custom_allocation_test() +{ + static boost::asio::io_context io_context; + struct timer + { + boost::asio::system_timer t; + timer() : t(io_context) {} + } timers[100]; + + int allocation_count = 0; + + for (int i = 0; i < 50; ++i) + { + timers[i].t.expires_at((boost::asio::system_timer::time_point::max)()); + timers[i].t.async_wait(custom_allocation_timer_handler(&allocation_count)); + } + + for (int i = 50; i < 100; ++i) + { + timers[i].t.expires_at((boost::asio::system_timer::time_point::min)()); + timers[i].t.async_wait(custom_allocation_timer_handler(&allocation_count)); + } + + for (int i = 0; i < 50; ++i) + timers[i].t.cancel(); + + io_context.run(); + + BOOST_ASIO_CHECK(allocation_count == 0); +} + +void io_context_run(boost::asio::io_context* ioc) +{ + ioc->run(); +} + +void system_timer_thread_test() +{ + boost::asio::io_context ioc; + boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work + = boost::asio::make_work_guard(ioc); + boost::asio::system_timer t1(ioc); + boost::asio::system_timer t2(ioc); + int count = 0; + + boost::asio::detail::thread th(bindns::bind(io_context_run, &ioc)); + + t2.expires_after(boost::asio::chrono::seconds(2)); + t2.wait(); + + t1.expires_after(boost::asio::chrono::seconds(2)); + t1.async_wait(bindns::bind(increment, &count)); + + t2.expires_after(boost::asio::chrono::seconds(4)); + t2.wait(); + + ioc.stop(); + th.join(); + + BOOST_ASIO_CHECK(count == 1); +} + +#if defined(BOOST_ASIO_HAS_MOVE) +boost::asio::system_timer make_timer(boost::asio::io_context& ioc, int* count) +{ + boost::asio::system_timer t(ioc); + t.expires_after(boost::asio::chrono::seconds(1)); + t.async_wait(bindns::bind(increment, count)); + return t; +} +#endif + +void system_timer_move_test() +{ +#if defined(BOOST_ASIO_HAS_MOVE) + boost::asio::io_context io_context1; + boost::asio::io_context io_context2; + int count = 0; + + boost::asio::system_timer t1 = make_timer(io_context1, &count); + boost::asio::system_timer t2 = make_timer(io_context2, &count); + boost::asio::system_timer t3 = std::move(t1); + + t2 = std::move(t1); + + io_context2.run(); + + BOOST_ASIO_CHECK(count == 1); + + io_context1.run(); + + BOOST_ASIO_CHECK(count == 2); +#endif // defined(BOOST_ASIO_HAS_MOVE) +} + +BOOST_ASIO_TEST_SUITE +( + "system_timer", + BOOST_ASIO_TEST_CASE(system_timer_test) + BOOST_ASIO_TEST_CASE(system_timer_cancel_test) + BOOST_ASIO_TEST_CASE(system_timer_custom_allocation_test) + BOOST_ASIO_TEST_CASE(system_timer_thread_test) + BOOST_ASIO_TEST_CASE(system_timer_move_test) +) +#else // defined(BOOST_ASIO_HAS_STD_CHRONO) +BOOST_ASIO_TEST_SUITE +( + "system_timer", + BOOST_ASIO_TEST_CASE(null_test) +) +#endif // defined(BOOST_ASIO_HAS_STD_CHRONO) diff --git a/src/boost/libs/asio/test/this_coro.cpp b/src/boost/libs/asio/test/this_coro.cpp new file mode 100644 index 000000000..9a5c4eb77 --- /dev/null +++ b/src/boost/libs/asio/test/this_coro.cpp @@ -0,0 +1,25 @@ +// +// this_coro.cpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/this_coro.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "this_coro", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/time_traits.cpp b/src/boost/libs/asio/test/time_traits.cpp new file mode 100644 index 000000000..181d6fac1 --- /dev/null +++ b/src/boost/libs/asio/test/time_traits.cpp @@ -0,0 +1,25 @@ +// +// time_traits.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/time_traits.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "time_traits", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ts/buffer.cpp b/src/boost/libs/asio/test/ts/buffer.cpp new file mode 100644 index 000000000..2b2f86a4c --- /dev/null +++ b/src/boost/libs/asio/test/ts/buffer.cpp @@ -0,0 +1,30 @@ +// +// buffer.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Prevent link dependency on the Boost.System library. +#if !defined(BOOST_SYSTEM_NO_DEPRECATED) +#define BOOST_SYSTEM_NO_DEPRECATED +#endif // !defined(BOOST_SYSTEM_NO_DEPRECATED) + +// Test that header file is self-contained. +#include <boost/asio/ts/buffer.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ts/buffer", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ts/executor.cpp b/src/boost/libs/asio/test/ts/executor.cpp new file mode 100644 index 000000000..97faf2b57 --- /dev/null +++ b/src/boost/libs/asio/test/ts/executor.cpp @@ -0,0 +1,30 @@ +// +// executor.cpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Prevent link dependency on the Boost.System library. +#if !defined(BOOST_SYSTEM_NO_DEPRECATED) +#define BOOST_SYSTEM_NO_DEPRECATED +#endif // !defined(BOOST_SYSTEM_NO_DEPRECATED) + +// Test that header file is self-contained. +#include <boost/asio/ts/executor.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ts/executor", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ts/internet.cpp b/src/boost/libs/asio/test/ts/internet.cpp new file mode 100644 index 000000000..d630723bd --- /dev/null +++ b/src/boost/libs/asio/test/ts/internet.cpp @@ -0,0 +1,30 @@ +// +// internet.cpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Prevent link dependency on the Boost.System library. +#if !defined(BOOST_SYSTEM_NO_DEPRECATED) +#define BOOST_SYSTEM_NO_DEPRECATED +#endif // !defined(BOOST_SYSTEM_NO_DEPRECATED) + +// Test that header file is self-contained. +#include <boost/asio/ts/internet.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ts/internet", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ts/io_context.cpp b/src/boost/libs/asio/test/ts/io_context.cpp new file mode 100644 index 000000000..c5fdbc178 --- /dev/null +++ b/src/boost/libs/asio/test/ts/io_context.cpp @@ -0,0 +1,30 @@ +// +// io_context.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Prevent link dependency on the Boost.System library. +#if !defined(BOOST_SYSTEM_NO_DEPRECATED) +#define BOOST_SYSTEM_NO_DEPRECATED +#endif // !defined(BOOST_SYSTEM_NO_DEPRECATED) + +// Test that header file is self-contained. +#include <boost/asio/ts/io_context.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ts/io_context", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ts/net.cpp b/src/boost/libs/asio/test/ts/net.cpp new file mode 100644 index 000000000..12b1d5568 --- /dev/null +++ b/src/boost/libs/asio/test/ts/net.cpp @@ -0,0 +1,30 @@ +// +// net.cpp +// ~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Prevent link dependency on the Boost.System library. +#if !defined(BOOST_SYSTEM_NO_DEPRECATED) +#define BOOST_SYSTEM_NO_DEPRECATED +#endif // !defined(BOOST_SYSTEM_NO_DEPRECATED) + +// Test that header file is self-contained. +#include <boost/asio/ts/net.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ts/net", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ts/netfwd.cpp b/src/boost/libs/asio/test/ts/netfwd.cpp new file mode 100644 index 000000000..796d918b4 --- /dev/null +++ b/src/boost/libs/asio/test/ts/netfwd.cpp @@ -0,0 +1,33 @@ +// +// netfwd.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Prevent link dependency on the Boost.System library. +#if !defined(BOOST_SYSTEM_NO_DEPRECATED) +#define BOOST_SYSTEM_NO_DEPRECATED +#endif // !defined(BOOST_SYSTEM_NO_DEPRECATED) + +// Test that header file is self-contained. +#include <boost/asio/ts/netfwd.hpp> + +// Test that forward declarations don't conflict with full declarations. +#include <boost/asio/ts/net.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ts/netfwd", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ts/socket.cpp b/src/boost/libs/asio/test/ts/socket.cpp new file mode 100644 index 000000000..1722e8e18 --- /dev/null +++ b/src/boost/libs/asio/test/ts/socket.cpp @@ -0,0 +1,30 @@ +// +// socket.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Prevent link dependency on the Boost.System library. +#if !defined(BOOST_SYSTEM_NO_DEPRECATED) +#define BOOST_SYSTEM_NO_DEPRECATED +#endif // !defined(BOOST_SYSTEM_NO_DEPRECATED) + +// Test that header file is self-contained. +#include <boost/asio/ts/socket.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ts/socket", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/ts/timer.cpp b/src/boost/libs/asio/test/ts/timer.cpp new file mode 100644 index 000000000..5e500f1f0 --- /dev/null +++ b/src/boost/libs/asio/test/ts/timer.cpp @@ -0,0 +1,30 @@ +// +// timer.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Prevent link dependency on the Boost.System library. +#if !defined(BOOST_SYSTEM_NO_DEPRECATED) +#define BOOST_SYSTEM_NO_DEPRECATED +#endif // !defined(BOOST_SYSTEM_NO_DEPRECATED) + +// Test that header file is self-contained. +#include <boost/asio/ts/timer.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "ts/timer", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/unit_test.hpp b/src/boost/libs/asio/test/unit_test.hpp new file mode 100644 index 000000000..6d5a78478 --- /dev/null +++ b/src/boost/libs/asio/test/unit_test.hpp @@ -0,0 +1,177 @@ +// +// unit_test.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef UNIT_TEST_HPP +#define UNIT_TEST_HPP + +#include <boost/asio/detail/config.hpp> +#include <iostream> +#include <boost/asio/detail/atomic_count.hpp> + +#if defined(__sun) +# include <stdlib.h> // Needed for lrand48. +#endif // defined(__sun) + +#if defined(__BORLANDC__) + +// Prevent use of intrinsic for strcmp. +# include <cstring> +# undef strcmp + +// Suppress error about condition always being true. +# pragma option -w-ccc + +#endif // defined(__BORLANDC__) + +#if defined(BOOST_ASIO_MSVC) +# pragma warning (disable:4127) +# pragma warning (push) +# pragma warning (disable:4244) +# pragma warning (disable:4702) +#endif // defined(BOOST_ASIO_MSVC) + +#if !defined(BOOST_ASIO_TEST_IOSTREAM) +# define BOOST_ASIO_TEST_IOSTREAM std::cerr +#endif // !defined(BOOST_ASIO_TEST_IOSTREAM) + +namespace boost { +namespace asio { +namespace detail { + +inline const char*& test_name() +{ + static const char* name = 0; + return name; +} + +inline atomic_count& test_errors() +{ + static atomic_count errors(0); + return errors; +} + +inline void begin_test_suite(const char* name) +{ + boost::asio::detail::test_name(); + boost::asio::detail::test_errors(); + BOOST_ASIO_TEST_IOSTREAM << name << " test suite begins" << std::endl; +} + +inline int end_test_suite(const char* name) +{ + BOOST_ASIO_TEST_IOSTREAM << name << " test suite ends" << std::endl; + BOOST_ASIO_TEST_IOSTREAM << "\n*** "; + long errors = boost::asio::detail::test_errors(); + if (errors == 0) + BOOST_ASIO_TEST_IOSTREAM << "No errors detected."; + else if (errors == 1) + BOOST_ASIO_TEST_IOSTREAM << "1 error detected."; + else + BOOST_ASIO_TEST_IOSTREAM << errors << " errors detected." << std::endl; + BOOST_ASIO_TEST_IOSTREAM << std::endl; + return errors == 0 ? 0 : 1; +} + +template <void (*Test)()> +inline void run_test(const char* name) +{ + test_name() = name; + long errors_before = boost::asio::detail::test_errors(); + Test(); + if (test_errors() == errors_before) + BOOST_ASIO_TEST_IOSTREAM << name << " passed" << std::endl; + else + BOOST_ASIO_TEST_IOSTREAM << name << " failed" << std::endl; +} + +template <void (*)()> +inline void compile_test(const char* name) +{ + BOOST_ASIO_TEST_IOSTREAM << name << " passed" << std::endl; +} + +#if defined(BOOST_ASIO_NO_EXCEPTIONS) + +template <typename T> +void throw_exception(const T& t) +{ + BOOST_ASIO_TEST_IOSTREAM << "Exception: " << t.what() << std::endl; + std::abort(); +} + +#endif // defined(BOOST_ASIO_NO_EXCEPTIONS) + +} // namespace detail +} // namespace asio +} // namespace boost + +#define BOOST_ASIO_CHECK(expr) \ + do { if (!(expr)) { \ + BOOST_ASIO_TEST_IOSTREAM << __FILE__ << "(" << __LINE__ << "): " \ + << boost::asio::detail::test_name() << ": " \ + << "check '" << #expr << "' failed" << std::endl; \ + ++boost::asio::detail::test_errors(); \ + } } while (0) + +#define BOOST_ASIO_CHECK_MESSAGE(expr, msg) \ + do { if (!(expr)) { \ + BOOST_ASIO_TEST_IOSTREAM << __FILE__ << "(" << __LINE__ << "): " \ + << boost::asio::detail::test_name() << ": " \ + << msg << std::endl; \ + ++boost::asio::detail::test_errors(); \ + } } while (0) + +#define BOOST_ASIO_WARN_MESSAGE(expr, msg) \ + do { if (!(expr)) { \ + BOOST_ASIO_TEST_IOSTREAM << __FILE__ << "(" << __LINE__ << "): " \ + << boost::asio::detail::test_name() << ": " \ + << msg << std::endl; \ + } } while (0) + +#define BOOST_ASIO_ERROR(msg) \ + do { \ + BOOST_ASIO_TEST_IOSTREAM << __FILE__ << "(" << __LINE__ << "): " \ + << boost::asio::detail::test_name() << ": " \ + << msg << std::endl; \ + ++boost::asio::detail::test_errors(); \ + } while (0) + +#define BOOST_ASIO_TEST_SUITE(name, tests) \ + int main() \ + { \ + boost::asio::detail::begin_test_suite(name); \ + tests \ + return boost::asio::detail::end_test_suite(name); \ + } + +#define BOOST_ASIO_TEST_CASE(test) \ + boost::asio::detail::run_test<&test>(#test); + +#define BOOST_ASIO_COMPILE_TEST_CASE(test) \ + boost::asio::detail::compile_test<&test>(#test); + +inline void null_test() +{ +} + +#if defined(__GNUC__) && defined(_AIX) + +// AIX needs this symbol defined in asio, even if it doesn't do anything. +int test_main(int, char**) +{ +} + +#endif // defined(__GNUC__) && defined(_AIX) + +#if defined(BOOST_ASIO_MSVC) +# pragma warning (pop) +#endif // defined(BOOST_ASIO_MSVC) + +#endif // UNIT_TEST_HPP diff --git a/src/boost/libs/asio/test/use_awaitable.cpp b/src/boost/libs/asio/test/use_awaitable.cpp new file mode 100644 index 000000000..338576a73 --- /dev/null +++ b/src/boost/libs/asio/test/use_awaitable.cpp @@ -0,0 +1,25 @@ +// +// use_awaitable.cpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/use_awaitable.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "use_awaitable", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/use_future.cpp b/src/boost/libs/asio/test/use_future.cpp new file mode 100644 index 000000000..33d3f6187 --- /dev/null +++ b/src/boost/libs/asio/test/use_future.cpp @@ -0,0 +1,670 @@ +// +// use_future.cpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/use_future.hpp> + +#include <string> +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_STD_FUTURE) + +#include "archetypes/async_ops.hpp" + +void use_future_0_test() +{ + using boost::asio::use_future; + using namespace archetypes; + + std::future<void> f; + + f = async_op_0(use_future); + try + { + f.get(); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ec_0(true, use_future); + try + { + f.get(); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ec_0(false, use_future); + try + { + f.get(); + BOOST_ASIO_CHECK(false); + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::operation_aborted); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ex_0(true, use_future); + try + { + f.get(); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ex_0(false, use_future); + try + { + f.get(); + BOOST_ASIO_CHECK(false); + } + catch (std::exception& e) + { + BOOST_ASIO_CHECK(e.what() == std::string("blah")); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } +} + +void use_future_1_test() +{ + using boost::asio::use_future; + using namespace archetypes; + + std::future<int> f; + + f = async_op_1(use_future); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 42); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ec_1(true, use_future); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 42); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ec_1(false, use_future); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(false); + (void)i; + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::operation_aborted); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ex_1(true, use_future); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 42); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ex_1(false, use_future); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(false); + (void)i; + } + catch (std::exception& e) + { + BOOST_ASIO_CHECK(e.what() == std::string("blah")); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } +} + +void use_future_2_test() +{ + using boost::asio::use_future; + using namespace archetypes; + + std::future<std::tuple<int, double>> f; + + f = async_op_2(use_future); + try + { + int i; + double d; + std::tie(i, d) = f.get(); + BOOST_ASIO_CHECK(i == 42); + BOOST_ASIO_CHECK(d == 2.0); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ec_2(true, use_future); + try + { + int i; + double d; + std::tie(i, d) = f.get(); + BOOST_ASIO_CHECK(i == 42); + BOOST_ASIO_CHECK(d == 2.0); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ec_2(false, use_future); + try + { + std::tuple<int, double> t = f.get(); + BOOST_ASIO_CHECK(false); + (void)t; + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::operation_aborted); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ex_2(true, use_future); + try + { + int i; + double d; + std::tie(i, d) = f.get(); + BOOST_ASIO_CHECK(i == 42); + BOOST_ASIO_CHECK(d == 2.0); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ex_2(false, use_future); + try + { + std::tuple<int, double> t = f.get(); + BOOST_ASIO_CHECK(false); + (void)t; + } + catch (std::exception& e) + { + BOOST_ASIO_CHECK(e.what() == std::string("blah")); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } +} + +void use_future_3_test() +{ + using boost::asio::use_future; + using namespace archetypes; + + std::future<std::tuple<int, double, char>> f; + + f = async_op_3(use_future); + try + { + int i; + double d; + char c; + std::tie(i, d, c) = f.get(); + BOOST_ASIO_CHECK(i == 42); + BOOST_ASIO_CHECK(d == 2.0); + BOOST_ASIO_CHECK(c == 'a'); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ec_3(true, use_future); + try + { + int i; + double d; + char c; + std::tie(i, d, c) = f.get(); + BOOST_ASIO_CHECK(i == 42); + BOOST_ASIO_CHECK(d == 2.0); + BOOST_ASIO_CHECK(c == 'a'); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ec_3(false, use_future); + try + { + std::tuple<int, double, char> t = f.get(); + BOOST_ASIO_CHECK(false); + (void)t; + } + catch (boost::system::system_error& e) + { + BOOST_ASIO_CHECK(e.code() == boost::asio::error::operation_aborted); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ex_3(true, use_future); + try + { + int i; + double d; + char c; + std::tie(i, d, c) = f.get(); + BOOST_ASIO_CHECK(i == 42); + BOOST_ASIO_CHECK(d == 2.0); + BOOST_ASIO_CHECK(c == 'a'); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ex_3(false, use_future); + try + { + std::tuple<int, double, char> t = f.get(); + BOOST_ASIO_CHECK(false); + (void)t; + } + catch (std::exception& e) + { + BOOST_ASIO_CHECK(e.what() == std::string("blah")); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } +} + +int package_0() +{ + return 42; +} + +int package_ec_0(boost::system::error_code ec) +{ + return ec ? 0 : 42; +} + +int package_ex_0(std::exception_ptr ex) +{ + return ex ? 0 : 42; +} + +void use_future_package_0_test() +{ + using boost::asio::use_future; + using namespace archetypes; + + std::future<int> f; + + f = async_op_0(use_future(package_0)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 42); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ec_0(true, use_future(&package_ec_0)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 42); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ec_0(false, use_future(package_ec_0)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 0); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ex_0(true, use_future(package_ex_0)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 42); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ex_0(false, use_future(package_ex_0)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 0); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } +} + +int package_1(int i) +{ + return i; +} + +int package_ec_1(boost::system::error_code ec, int i) +{ + return ec ? 0 : i; +} + +int package_ex_1(std::exception_ptr ex, int i) +{ + return ex ? 0 : i; +} + +void use_future_package_1_test() +{ + using boost::asio::use_future; + using namespace archetypes; + + std::future<int> f; + + f = async_op_1(use_future(package_1)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 42); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ec_1(true, use_future(package_ec_1)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 42); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ec_1(false, use_future(package_ec_1)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 0); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ex_1(true, use_future(package_ex_1)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 42); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ex_1(false, use_future(package_ex_1)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 0); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } +} + +int package_2(int i, double) +{ + return i; +} + +int package_ec_2(boost::system::error_code ec, int i, double) +{ + return ec ? 0 : i; +} + +int package_ex_2(std::exception_ptr ex, int i, double) +{ + return ex ? 0 : i; +} + +void use_future_package_2_test() +{ + using boost::asio::use_future; + using namespace archetypes; + + std::future<int> f; + + f = async_op_2(use_future(package_2)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 42); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ec_2(true, use_future(package_ec_2)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 42); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ec_2(false, use_future(package_ec_2)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 0); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ex_2(true, use_future(package_ex_2)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 42); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ex_2(false, use_future(package_ex_2)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 0); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } +} + +int package_3(int i, double, char) +{ + return i; +} + +int package_ec_3(boost::system::error_code ec, int i, double, char) +{ + return ec ? 0 : i; +} + +int package_ex_3(std::exception_ptr ex, int i, double, char) +{ + return ex ? 0 : i; +} + +void use_future_package_3_test() +{ + using boost::asio::use_future; + using namespace archetypes; + + std::future<int> f; + + f = async_op_3(use_future(package_3)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 42); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ec_3(true, use_future(package_ec_3)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 42); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ec_3(false, use_future(package_ec_3)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 0); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ex_3(true, use_future(package_ex_3)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 42); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } + + f = async_op_ex_3(false, use_future(package_ex_3)); + try + { + int i = f.get(); + BOOST_ASIO_CHECK(i == 0); + } + catch (...) + { + BOOST_ASIO_CHECK(false); + } +} + +BOOST_ASIO_TEST_SUITE +( + "use_future", + BOOST_ASIO_TEST_CASE(use_future_0_test) + BOOST_ASIO_TEST_CASE(use_future_1_test) + BOOST_ASIO_TEST_CASE(use_future_2_test) + BOOST_ASIO_TEST_CASE(use_future_3_test) + BOOST_ASIO_TEST_CASE(use_future_package_0_test) + BOOST_ASIO_TEST_CASE(use_future_package_1_test) + BOOST_ASIO_TEST_CASE(use_future_package_2_test) + BOOST_ASIO_TEST_CASE(use_future_package_3_test) +) + +#else // defined(BOOST_ASIO_HAS_STD_FUTURE) + +BOOST_ASIO_TEST_SUITE +( + "use_future", + BOOST_ASIO_TEST_CASE(null_test) +) + +#endif // defined(BOOST_ASIO_HAS_STD_FUTURE) diff --git a/src/boost/libs/asio/test/uses_executor.cpp b/src/boost/libs/asio/test/uses_executor.cpp new file mode 100644 index 000000000..fb4702b87 --- /dev/null +++ b/src/boost/libs/asio/test/uses_executor.cpp @@ -0,0 +1,25 @@ +// +// uses_executor.cpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/uses_executor.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "uses_executor", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/wait_traits.cpp b/src/boost/libs/asio/test/wait_traits.cpp new file mode 100644 index 000000000..50514710f --- /dev/null +++ b/src/boost/libs/asio/test/wait_traits.cpp @@ -0,0 +1,25 @@ +// +// wait_traits.cpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/wait_traits.hpp> + +#include "unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "wait_traits", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/windows/basic_object_handle.cpp b/src/boost/libs/asio/test/windows/basic_object_handle.cpp new file mode 100644 index 000000000..d128873e3 --- /dev/null +++ b/src/boost/libs/asio/test/windows/basic_object_handle.cpp @@ -0,0 +1,25 @@ +// +// basic_object_handle.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/windows/basic_object_handle.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "basic_object_handle", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/windows/basic_overlapped_handle.cpp b/src/boost/libs/asio/test/windows/basic_overlapped_handle.cpp new file mode 100644 index 000000000..bd9623165 --- /dev/null +++ b/src/boost/libs/asio/test/windows/basic_overlapped_handle.cpp @@ -0,0 +1,25 @@ +// +// basic_overlapped_handle.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/windows/basic_overlapped_handle.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "basic_overlapped_handle", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/windows/basic_random_access_handle.cpp b/src/boost/libs/asio/test/windows/basic_random_access_handle.cpp new file mode 100644 index 000000000..925d068ca --- /dev/null +++ b/src/boost/libs/asio/test/windows/basic_random_access_handle.cpp @@ -0,0 +1,25 @@ +// +// basic_random_access_handle.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/windows/basic_random_access_handle.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "basic_random_access_handle", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/windows/basic_stream_handle.cpp b/src/boost/libs/asio/test/windows/basic_stream_handle.cpp new file mode 100644 index 000000000..b15d88d5e --- /dev/null +++ b/src/boost/libs/asio/test/windows/basic_stream_handle.cpp @@ -0,0 +1,25 @@ +// +// basic_stream_handle.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/windows/basic_stream_handle.hpp> + +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "basic_stream_handle", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/windows/object_handle.cpp b/src/boost/libs/asio/test/windows/object_handle.cpp new file mode 100644 index 000000000..66c016646 --- /dev/null +++ b/src/boost/libs/asio/test/windows/object_handle.cpp @@ -0,0 +1,130 @@ +// +// object_handle.cpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/windows/object_handle.hpp> + +#include <boost/asio/io_context.hpp> +#include "../archetypes/async_result.hpp" +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +// windows_object_handle_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// windows::object_handle compile and link correctly. Runtime failures are +// ignored. + +namespace windows_object_handle_compile { + +void wait_handler(const boost::system::error_code&) +{ +} + +void test() +{ +#if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) + using namespace boost::asio; + namespace win = boost::asio::windows; + + try + { + io_context ioc; + const io_context::executor_type ioc_ex = ioc.get_executor(); + archetypes::lazy_handler lazy; + boost::system::error_code ec; + + // basic_object_handle constructors. + + win::object_handle handle1(ioc); + HANDLE native_handle1 = INVALID_HANDLE_VALUE; +#if defined(BOOST_ASIO_MSVC) && (_MSC_VER < 1910) + // Skip this on older MSVC due to mysterious ambiguous overload errors. +#else + win::object_handle handle2(ioc, native_handle1); +#endif + + win::object_handle handle3(ioc_ex); + HANDLE native_handle2 = INVALID_HANDLE_VALUE; + win::object_handle handle4(ioc_ex, native_handle2); + +#if defined(BOOST_ASIO_HAS_MOVE) + win::object_handle handle5(std::move(handle4)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_object_handle operators. + +#if defined(BOOST_ASIO_HAS_MOVE) + handle1 = win::object_handle(ioc); + handle1 = std::move(handle3); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_io_object functions. + + win::object_handle::executor_type ex = handle1.get_executor(); + (void)ex; + + // basic_handle functions. + + win::object_handle::lowest_layer_type& lowest_layer + = handle1.lowest_layer(); + (void)lowest_layer; + + const win::object_handle& handle6 = handle1; + const win::object_handle::lowest_layer_type& lowest_layer3 + = handle6.lowest_layer(); + (void)lowest_layer3; + + HANDLE native_handle4 = INVALID_HANDLE_VALUE; + handle1.assign(native_handle4); + + bool is_open = handle1.is_open(); + (void)is_open; + + handle1.close(); + handle1.close(ec); + + win::object_handle::native_handle_type native_handle3 + = handle1.native_handle(); + (void)native_handle3; + + handle1.cancel(); + handle1.cancel(ec); + + // basic_object_handle functions. + + handle1.wait(); + handle1.wait(ec); + + handle1.async_wait(&wait_handler); + int i1 = handle1.async_wait(lazy); + (void)i1; + } + catch (std::exception&) + { + } +#endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) +} + +} // namespace windows_object_handle_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "windows/object_handle", + BOOST_ASIO_TEST_CASE(windows_object_handle_compile::test) +) diff --git a/src/boost/libs/asio/test/windows/overlapped_handle.cpp b/src/boost/libs/asio/test/windows/overlapped_handle.cpp new file mode 100644 index 000000000..c06d0a8c0 --- /dev/null +++ b/src/boost/libs/asio/test/windows/overlapped_handle.cpp @@ -0,0 +1,26 @@ +// +// overlapped_handle.cpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/windows/overlapped_handle.hpp> + +#include <boost/asio.hpp> +#include "../unit_test.hpp" + +BOOST_ASIO_TEST_SUITE +( + "windows/overlapped_handle", + BOOST_ASIO_TEST_CASE(null_test) +) diff --git a/src/boost/libs/asio/test/windows/overlapped_ptr.cpp b/src/boost/libs/asio/test/windows/overlapped_ptr.cpp new file mode 100644 index 000000000..da20280b9 --- /dev/null +++ b/src/boost/libs/asio/test/windows/overlapped_ptr.cpp @@ -0,0 +1,107 @@ +// +// overlapped_ptr.cpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/windows/overlapped_ptr.hpp> + +#include <boost/asio/executor.hpp> +#include <boost/asio/io_context.hpp> +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +// windows_overlapped_ptr_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// windows::overlapped_ptr compile and link correctly. Runtime failures are +// ignored. + +namespace windows_overlapped_ptr_compile { + +void overlapped_handler_1(const boost::system::error_code&, std::size_t) +{ +} + +struct overlapped_handler_2 +{ + void operator()(const boost::system::error_code&, std::size_t) + { + } +}; + +void test() +{ +#if defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) + using namespace boost::asio; + namespace win = boost::asio::windows; + + try + { + io_context ioc; + boost::asio::executor ex(ioc.get_executor()); + + // basic_overlapped_ptr constructors. + + win::overlapped_ptr ptr1; + + win::overlapped_ptr ptr2(ioc, &overlapped_handler_1); + win::overlapped_ptr ptr3(ioc, overlapped_handler_2()); + + win::overlapped_ptr ptr4(ioc.get_executor(), &overlapped_handler_1); + win::overlapped_ptr ptr5(ioc.get_executor(), overlapped_handler_2()); + win::overlapped_ptr ptr6(ex, &overlapped_handler_1); + win::overlapped_ptr ptr7(ex, overlapped_handler_2()); + + // overlapped_ptr functions. + + ptr1.reset(); + + ptr2.reset(ioc, &overlapped_handler_1); + ptr3.reset(ioc, overlapped_handler_2()); + + ptr2.reset(ioc.get_executor(), &overlapped_handler_1); + ptr3.reset(ioc.get_executor(), overlapped_handler_2()); + ptr2.reset(ex, &overlapped_handler_1); + ptr3.reset(ex, overlapped_handler_2()); + + OVERLAPPED* ov1 = ptr1.get(); + (void)ov1; + + const win::overlapped_ptr& ptr8(ptr1); + const OVERLAPPED* ov2 = ptr4.get(); + (void)ov2; + + OVERLAPPED* ov3 = ptr1.release(); + (void)ov3; + + boost::system::error_code ec; + std::size_t bytes_transferred = 0; + ptr1.complete(ec, bytes_transferred); + } + catch (std::exception&) + { + } +#endif // defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) +} + +} // namespace windows_overlapped_ptr_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "windows/overlapped_ptr", + BOOST_ASIO_TEST_CASE(windows_overlapped_ptr_compile::test) +) diff --git a/src/boost/libs/asio/test/windows/random_access_handle.cpp b/src/boost/libs/asio/test/windows/random_access_handle.cpp new file mode 100644 index 000000000..d2edcb0c4 --- /dev/null +++ b/src/boost/libs/asio/test/windows/random_access_handle.cpp @@ -0,0 +1,155 @@ +// +// random_access_handle.cpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/windows/random_access_handle.hpp> + +#include <boost/asio/io_context.hpp> +#include "../archetypes/async_result.hpp" +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +// windows_random_access_handle_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// windows::random_access_handle compile and link correctly. Runtime failures +// are ignored. + +namespace windows_random_access_handle_compile { + +void write_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void read_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void test() +{ +#if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + using namespace boost::asio; + namespace win = boost::asio::windows; + + try + { + io_context ioc; + const io_context::executor_type ioc_ex = ioc.get_executor(); + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + boost::asio::uint64_t offset = 0; + archetypes::lazy_handler lazy; + boost::system::error_code ec; + + // basic_random_access_handle constructors. + + win::random_access_handle handle1(ioc); + HANDLE native_handle1 = INVALID_HANDLE_VALUE; +#if defined(BOOST_ASIO_MSVC) && (_MSC_VER < 1910) + // Skip this on older MSVC due to mysterious ambiguous overload errors. +#else + win::random_access_handle handle2(ioc, native_handle1); +#endif + + win::random_access_handle handle3(ioc_ex); + HANDLE native_handle2 = INVALID_HANDLE_VALUE; + win::random_access_handle handle4(ioc_ex, native_handle2); + +#if defined(BOOST_ASIO_HAS_MOVE) + win::random_access_handle handle5(std::move(handle4)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_random_access_handle operators. + +#if defined(BOOST_ASIO_HAS_MOVE) + handle1 = win::random_access_handle(ioc); + handle1 = std::move(handle4); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_io_object functions. + + windows::random_access_handle::executor_type ex = handle1.get_executor(); + (void)ex; + + // basic_overlapped_handle functions. + + win::random_access_handle::lowest_layer_type& lowest_layer + = handle1.lowest_layer(); + (void)lowest_layer; + + const win::random_access_handle& handle6 = handle1; + const win::random_access_handle::lowest_layer_type& lowest_layer2 + = handle6.lowest_layer(); + (void)lowest_layer2; + + HANDLE native_handle3 = INVALID_HANDLE_VALUE; + handle1.assign(native_handle3); + + bool is_open = handle1.is_open(); + (void)is_open; + + handle1.close(); + handle1.close(ec); + + win::random_access_handle::native_handle_type native_handle4 + = handle1.native_handle(); + (void)native_handle4; + + handle1.cancel(); + handle1.cancel(ec); + + // basic_random_access_handle functions. + + handle1.write_some_at(offset, buffer(mutable_char_buffer)); + handle1.write_some_at(offset, buffer(const_char_buffer)); + handle1.write_some_at(offset, buffer(mutable_char_buffer), ec); + handle1.write_some_at(offset, buffer(const_char_buffer), ec); + + handle1.async_write_some_at(offset, + buffer(mutable_char_buffer), &write_some_handler); + handle1.async_write_some_at(offset, + buffer(const_char_buffer), &write_some_handler); + int i1 = handle1.async_write_some_at(offset, + buffer(mutable_char_buffer), lazy); + (void)i1; + int i2 = handle1.async_write_some_at(offset, + buffer(const_char_buffer), lazy); + (void)i2; + + handle1.read_some_at(offset, buffer(mutable_char_buffer)); + handle1.read_some_at(offset, buffer(mutable_char_buffer), ec); + + handle1.async_read_some_at(offset, + buffer(mutable_char_buffer), &read_some_handler); + int i3 = handle1.async_read_some_at(offset, + buffer(mutable_char_buffer), lazy); + (void)i3; + } + catch (std::exception&) + { + } +#endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) +} + +} // namespace windows_random_access_handle_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "windows/random_access_handle", + BOOST_ASIO_TEST_CASE(windows_random_access_handle_compile::test) +) diff --git a/src/boost/libs/asio/test/windows/stream_handle.cpp b/src/boost/libs/asio/test/windows/stream_handle.cpp new file mode 100644 index 000000000..a782454c9 --- /dev/null +++ b/src/boost/libs/asio/test/windows/stream_handle.cpp @@ -0,0 +1,148 @@ +// +// stream_handle.cpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/windows/stream_handle.hpp> + +#include <boost/asio/io_context.hpp> +#include "../archetypes/async_result.hpp" +#include "../unit_test.hpp" + +//------------------------------------------------------------------------------ + +// windows_stream_handle_compile test +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// The following test checks that all public member functions on the class +// windows::stream_handle compile and link correctly. Runtime failures are +// ignored. + +namespace windows_stream_handle_compile { + +void write_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void read_some_handler(const boost::system::error_code&, std::size_t) +{ +} + +void test() +{ +#if defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) + using namespace boost::asio; + namespace win = boost::asio::windows; + + try + { + io_context ioc; + const io_context::executor_type ioc_ex = ioc.get_executor(); + char mutable_char_buffer[128] = ""; + const char const_char_buffer[128] = ""; + archetypes::lazy_handler lazy; + boost::system::error_code ec; + + // basic_stream_handle constructors. + + win::stream_handle handle1(ioc); + HANDLE native_handle1 = INVALID_HANDLE_VALUE; +#if defined(BOOST_ASIO_MSVC) && (_MSC_VER < 1910) + // Skip this on older MSVC due to mysterious ambiguous overload errors. +#else + win::stream_handle handle2(ioc, native_handle1); +#endif + + win::stream_handle handle3(ioc_ex); + HANDLE native_handle2 = INVALID_HANDLE_VALUE; + win::stream_handle handle4(ioc_ex, native_handle2); + +#if defined(BOOST_ASIO_HAS_MOVE) + win::stream_handle handle5(std::move(handle4)); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_stream_handle operators. + +#if defined(BOOST_ASIO_HAS_MOVE) + handle1 = win::stream_handle(ioc); + handle1 = std::move(handle4); +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // basic_io_object functions. + + windows::stream_handle::executor_type ex = handle1.get_executor(); + (void)ex; + + // basic_overlapped_handle functions. + + win::stream_handle::lowest_layer_type& lowest_layer + = handle1.lowest_layer(); + (void)lowest_layer; + + const win::stream_handle& handle6 = handle1; + const win::stream_handle::lowest_layer_type& lowest_layer2 + = handle6.lowest_layer(); + (void)lowest_layer2; + + HANDLE native_handle3 = INVALID_HANDLE_VALUE; + handle1.assign(native_handle3); + + bool is_open = handle1.is_open(); + (void)is_open; + + handle1.close(); + handle1.close(ec); + + win::stream_handle::native_handle_type native_handle4 + = handle1.native_handle(); + (void)native_handle4; + + handle1.cancel(); + handle1.cancel(ec); + + // basic_stream_handle functions. + + handle1.write_some(buffer(mutable_char_buffer)); + handle1.write_some(buffer(const_char_buffer)); + handle1.write_some(buffer(mutable_char_buffer), ec); + handle1.write_some(buffer(const_char_buffer), ec); + + handle1.async_write_some(buffer(mutable_char_buffer), &write_some_handler); + handle1.async_write_some(buffer(const_char_buffer), &write_some_handler); + int i1 = handle1.async_write_some(buffer(mutable_char_buffer), lazy); + (void)i1; + int i2 = handle1.async_write_some(buffer(const_char_buffer), lazy); + (void)i2; + + handle1.read_some(buffer(mutable_char_buffer)); + handle1.read_some(buffer(mutable_char_buffer), ec); + + handle1.async_read_some(buffer(mutable_char_buffer), &read_some_handler); + int i3 = handle1.async_read_some(buffer(mutable_char_buffer), lazy); + (void)i3; + } + catch (std::exception&) + { + } +#endif // defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) +} + +} // namespace windows_stream_handle_compile + +//------------------------------------------------------------------------------ + +BOOST_ASIO_TEST_SUITE +( + "windows/stream_handle", + BOOST_ASIO_TEST_CASE(windows_stream_handle_compile::test) +) diff --git a/src/boost/libs/asio/test/write.cpp b/src/boost/libs/asio/test/write.cpp new file mode 100644 index 000000000..85d2470e2 --- /dev/null +++ b/src/boost/libs/asio/test/write.cpp @@ -0,0 +1,4904 @@ +// +// write.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/write.hpp> + +#include <cstring> +#include <vector> +#include "archetypes/async_result.hpp" +#include <boost/asio/io_context.hpp> +#include <boost/asio/post.hpp> +#include <boost/asio/streambuf.hpp> +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) +#include <boost/array.hpp> +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) +# include <array> +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + +using namespace std; // For memcmp, memcpy and memset. + +class test_stream +{ +public: + typedef boost::asio::io_context::executor_type executor_type; + + test_stream(boost::asio::io_context& io_context) + : io_context_(io_context), + length_(max_length), + position_(0), + next_write_length_(max_length) + { + memset(data_, 0, max_length); + } + + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return io_context_.get_executor(); + } + + void reset(size_t length = max_length) + { + BOOST_ASIO_CHECK(length <= max_length); + + memset(data_, 0, max_length); + length_ = length; + position_ = 0; + next_write_length_ = length; + } + + void next_write_length(size_t length) + { + next_write_length_ = length; + } + + template <typename Iterator> + bool check_buffers(Iterator begin, Iterator end, size_t length) + { + if (length != position_) + return false; + + Iterator iter = begin; + size_t checked_length = 0; + for (; iter != end && checked_length < length; ++iter) + { + size_t buffer_length = boost::asio::buffer_size(*iter); + if (buffer_length > length - checked_length) + buffer_length = length - checked_length; + if (memcmp(data_ + checked_length, iter->data(), buffer_length) != 0) + return false; + checked_length += buffer_length; + } + + return true; + } + + template <typename Const_Buffers> + bool check_buffers(const Const_Buffers& buffers, size_t length) + { + return check_buffers(boost::asio::buffer_sequence_begin(buffers), + boost::asio::buffer_sequence_end(buffers), length); + } + + template <typename Const_Buffers> + size_t write_some(const Const_Buffers& buffers) + { + size_t n = boost::asio::buffer_copy( + boost::asio::buffer(data_, length_) + position_, + buffers, next_write_length_); + position_ += n; + return n; + } + + template <typename Const_Buffers> + size_t write_some(const Const_Buffers& buffers, boost::system::error_code& ec) + { + ec = boost::system::error_code(); + return write_some(buffers); + } + + template <typename Const_Buffers, typename Handler> + void async_write_some(const Const_Buffers& buffers, + BOOST_ASIO_MOVE_ARG(Handler) handler) + { + size_t bytes_transferred = write_some(buffers); + boost::asio::post(get_executor(), + boost::asio::detail::bind_handler( + BOOST_ASIO_MOVE_CAST(Handler)(handler), + boost::system::error_code(), bytes_transferred)); + } + +private: + boost::asio::io_context& io_context_; + enum { max_length = 8192 }; + char data_[max_length]; + size_t length_; + size_t position_; + size_t next_write_length_; +}; + +static const char write_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +static char mutable_write_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +void test_2_arg_zero_buffers_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::vector<boost::asio::const_buffer> buffers; + + size_t bytes_transferred = boost::asio::write(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == 0); +} + +void test_2_arg_const_buffer_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + size_t bytes_transferred = boost::asio::write(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +} + +void test_2_arg_mutable_buffer_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::mutable_buffer buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + size_t bytes_transferred = boost::asio::write(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); +} + +void test_2_arg_vector_buffers_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(boost::asio::buffer(write_data, 32)); + buffers.push_back(boost::asio::buffer(write_data, 39) + 32); + buffers.push_back(boost::asio::buffer(write_data) + 39); + + s.reset(); + size_t bytes_transferred = boost::asio::write(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +} + +void test_2_arg_dynamic_string_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb + = boost::asio::dynamic_buffer(data, sizeof(write_data)); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + size_t bytes_transferred = boost::asio::write(s, sb); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, sb); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, sb); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +} + +void test_3_arg_nothrow_zero_buffers_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::vector<boost::asio::const_buffer> buffers; + + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == 0); + BOOST_ASIO_CHECK(!error); +} + +void test_3_arg_nothrow_const_buffer_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_3_arg_nothrow_mutable_buffer_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::mutable_buffer buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_3_arg_nothrow_vector_buffers_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(boost::asio::buffer(write_data, 32)); + buffers.push_back(boost::asio::buffer(write_data, 39) + 32); + buffers.push_back(boost::asio::buffer(write_data) + 39); + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_3_arg_nothrow_dynamic_string_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb + = boost::asio::dynamic_buffer(data, sizeof(write_data)); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write(s, sb, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, sb, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, sb, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); +} + +bool old_style_transfer_all(const boost::system::error_code& ec, + size_t /*bytes_transferred*/) +{ + return !!ec; +} + +struct short_transfer +{ + short_transfer() {} +#if defined(BOOST_ASIO_HAS_MOVE) + short_transfer(short_transfer&&) {} +#else // defined(BOOST_ASIO_HAS_MOVE) + short_transfer(const short_transfer&) {} +#endif // defined(BOOST_ASIO_HAS_MOVE) + size_t operator()(const boost::system::error_code& ec, + size_t /*bytes_transferred*/) + { + return !!ec ? 0 : 3; + } +}; + +void test_3_arg_const_buffer_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + size_t bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +} + +void test_3_arg_mutable_buffer_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::mutable_buffer buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + size_t bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); +} + +void test_3_arg_vector_buffers_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(boost::asio::buffer(write_data, 32)); + buffers.push_back(boost::asio::buffer(write_data, 39) + 32); + buffers.push_back(boost::asio::buffer(write_data) + 39); + + s.reset(); + size_t bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +} + +void test_3_arg_dynamic_string_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb + = boost::asio::dynamic_buffer(data, sizeof(write_data)); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + size_t bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + bytes_transferred = boost::asio::write(s, sb, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, sb, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, sb, old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + bytes_transferred = boost::asio::write(s, sb, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + bytes_transferred = boost::asio::write(s, sb, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + bytes_transferred = boost::asio::write(s, sb, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +} + +void test_4_arg_const_buffer_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_4_arg_mutable_buffer_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::mutable_buffer buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_4_arg_vector_buffers_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(boost::asio::buffer(write_data, 32)); + buffers.push_back(boost::asio::buffer(write_data, 39) + 32); + buffers.push_back(boost::asio::buffer(write_data) + 39); + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, buffers, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_4_arg_dynamic_string_write() +{ + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb + = boost::asio::dynamic_buffer(data, sizeof(write_data)); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + bytes_transferred = boost::asio::write(s, sb, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + bytes_transferred = boost::asio::write(s, sb, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write(s, sb, short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); +} + +void async_write_handler(const boost::system::error_code& e, + size_t bytes_transferred, size_t expected_bytes_transferred, bool* called) +{ + *called = true; + BOOST_ASIO_CHECK(!e); + BOOST_ASIO_CHECK(bytes_transferred == expected_bytes_transferred); +} + +void test_3_arg_const_buffer_async_write() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + bool called = false; + boost::asio::async_write(s, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + int i = boost::asio::async_write(s, buffers, archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +} + +void test_3_arg_mutable_buffer_async_write() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::mutable_buffer buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + bool called = false; + boost::asio::async_write(s, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + int i = boost::asio::async_write(s, buffers, archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); +} + +void test_3_arg_boost_array_buffers_async_write() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) + boost::asio::io_context ioc; + test_stream s(ioc); + boost::array<boost::asio::const_buffer, 2> buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + bool called = false; + boost::asio::async_write(s, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + int i = boost::asio::async_write(s, buffers, archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) +} + +void test_3_arg_std_array_buffers_async_write() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + boost::asio::io_context ioc; + test_stream s(ioc); + std::array<boost::asio::const_buffer, 2> buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + bool called = false; + boost::asio::async_write(s, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + int i = boost::asio::async_write(s, buffers, archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) +} + +void test_3_arg_vector_buffers_async_write() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(boost::asio::buffer(write_data, 32)); + buffers.push_back(boost::asio::buffer(write_data, 39) + 32); + buffers.push_back(boost::asio::buffer(write_data) + 39); + + s.reset(); + bool called = false; + boost::asio::async_write(s, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + int i = boost::asio::async_write(s, buffers, archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +} + +void test_3_arg_dynamic_string_async_write() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb + = boost::asio::dynamic_buffer(data, sizeof(write_data)); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + bool called = false; + boost::asio::async_write(s, sb, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + int i = boost::asio::async_write(s, sb, archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +} + +void test_3_arg_streambuf_async_write() +{ +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::streambuf sb; + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + bool called = false; + boost::asio::async_write(s, sb, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + int i = boost::asio::async_write(s, sb, archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +} + +void test_4_arg_const_buffer_async_write() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + bool called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + int i = boost::asio::async_write(s, buffers, short_transfer(), + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +} + +void test_4_arg_mutable_buffer_async_write() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::mutable_buffer buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + bool called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(mutable_write_data))); + + s.reset(); + int i = boost::asio::async_write(s, buffers, short_transfer(), + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +} + +void test_4_arg_boost_array_buffers_async_write() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) + boost::asio::io_context ioc; + test_stream s(ioc); + boost::array<boost::asio::const_buffer, 2> buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + bool called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + int i = boost::asio::async_write(s, buffers, short_transfer(), + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) +} + +void test_4_arg_std_array_buffers_async_write() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + boost::asio::io_context ioc; + test_stream s(ioc); + std::array<boost::asio::const_buffer, 2> buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + bool called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + int i = boost::asio::async_write(s, buffers, short_transfer(), + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) +} + +void test_4_arg_vector_buffers_async_write() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(boost::asio::buffer(write_data, 32)); + buffers.push_back(boost::asio::buffer(write_data, 39) + 32); + buffers.push_back(boost::asio::buffer(write_data) + 39); + + s.reset(); + bool called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write(s, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + int i = boost::asio::async_write(s, buffers, short_transfer(), + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +} + +void test_4_arg_dynamic_string_async_write() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + std::string data; + boost::asio::dynamic_string_buffer<char, std::string::traits_type, + std::string::allocator_type> sb + = boost::asio::dynamic_buffer(data, sizeof(write_data)); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + bool called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write(s, sb, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write(s, sb, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + data.assign(write_data, sizeof(write_data)); + int i = boost::asio::async_write(s, sb, short_transfer(), + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +} + +void test_4_arg_streambuf_async_write() +{ +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_stream s(ioc); + boost::asio::streambuf sb; + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + bool called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 50)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 1)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, 42)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write(s, sb, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write(s, sb, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write(s, sb, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write(s, sb, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + int i = boost::asio::async_write(s, sb, short_transfer(), + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(buffers, sizeof(write_data))); +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +} + +BOOST_ASIO_TEST_SUITE +( + "write", + BOOST_ASIO_TEST_CASE(test_2_arg_zero_buffers_write) + BOOST_ASIO_TEST_CASE(test_2_arg_const_buffer_write) + BOOST_ASIO_TEST_CASE(test_2_arg_mutable_buffer_write) + BOOST_ASIO_TEST_CASE(test_2_arg_vector_buffers_write) + BOOST_ASIO_TEST_CASE(test_2_arg_dynamic_string_write) + BOOST_ASIO_TEST_CASE(test_3_arg_nothrow_zero_buffers_write) + BOOST_ASIO_TEST_CASE(test_3_arg_nothrow_const_buffer_write) + BOOST_ASIO_TEST_CASE(test_3_arg_nothrow_mutable_buffer_write) + BOOST_ASIO_TEST_CASE(test_3_arg_nothrow_vector_buffers_write) + BOOST_ASIO_TEST_CASE(test_3_arg_nothrow_dynamic_string_write) + BOOST_ASIO_TEST_CASE(test_3_arg_const_buffer_write) + BOOST_ASIO_TEST_CASE(test_3_arg_mutable_buffer_write) + BOOST_ASIO_TEST_CASE(test_3_arg_vector_buffers_write) + BOOST_ASIO_TEST_CASE(test_3_arg_dynamic_string_write) + BOOST_ASIO_TEST_CASE(test_4_arg_const_buffer_write) + BOOST_ASIO_TEST_CASE(test_4_arg_mutable_buffer_write) + BOOST_ASIO_TEST_CASE(test_4_arg_vector_buffers_write) + BOOST_ASIO_TEST_CASE(test_4_arg_dynamic_string_write) + BOOST_ASIO_TEST_CASE(test_3_arg_const_buffer_async_write) + BOOST_ASIO_TEST_CASE(test_3_arg_mutable_buffer_async_write) + BOOST_ASIO_TEST_CASE(test_3_arg_boost_array_buffers_async_write) + BOOST_ASIO_TEST_CASE(test_3_arg_std_array_buffers_async_write) + BOOST_ASIO_TEST_CASE(test_3_arg_vector_buffers_async_write) + BOOST_ASIO_TEST_CASE(test_3_arg_dynamic_string_async_write) + BOOST_ASIO_TEST_CASE(test_3_arg_streambuf_async_write) + BOOST_ASIO_TEST_CASE(test_4_arg_const_buffer_async_write) + BOOST_ASIO_TEST_CASE(test_4_arg_mutable_buffer_async_write) + BOOST_ASIO_TEST_CASE(test_4_arg_boost_array_buffers_async_write) + BOOST_ASIO_TEST_CASE(test_4_arg_std_array_buffers_async_write) + BOOST_ASIO_TEST_CASE(test_4_arg_vector_buffers_async_write) + BOOST_ASIO_TEST_CASE(test_4_arg_dynamic_string_async_write) + BOOST_ASIO_TEST_CASE(test_4_arg_streambuf_async_write) +) diff --git a/src/boost/libs/asio/test/write_at.cpp b/src/boost/libs/asio/test/write_at.cpp new file mode 100644 index 000000000..8730491f7 --- /dev/null +++ b/src/boost/libs/asio/test/write_at.cpp @@ -0,0 +1,7563 @@ +// +// write_at.cpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Disable autolinking for unit tests. +#if !defined(BOOST_ALL_NO_LIB) +#define BOOST_ALL_NO_LIB 1 +#endif // !defined(BOOST_ALL_NO_LIB) + +// Test that header file is self-contained. +#include <boost/asio/write_at.hpp> + +#include <cstring> +#include "archetypes/async_result.hpp" +#include <boost/asio/io_context.hpp> +#include <boost/asio/post.hpp> +#include <boost/asio/streambuf.hpp> +#include "unit_test.hpp" + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <boost/bind/bind.hpp> +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) +# include <functional> +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) +#include <boost/array.hpp> +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) +# include <array> +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + +using namespace std; // For memcmp, memcpy and memset. + +class test_random_access_device +{ +public: + typedef boost::asio::io_context::executor_type executor_type; + + test_random_access_device(boost::asio::io_context& io_context) + : io_context_(io_context), + length_(max_length), + next_write_length_(max_length) + { + memset(data_, 0, max_length); + } + + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return io_context_.get_executor(); + } + + void reset() + { + memset(data_, 0, max_length); + next_write_length_ = max_length; + } + + void next_write_length(size_t length) + { + next_write_length_ = length; + } + + template <typename Iterator> + bool check_buffers(boost::asio::uint64_t offset, + Iterator begin, Iterator end, size_t length) + { + if (offset + length > max_length) + return false; + + Iterator iter = begin; + size_t checked_length = 0; + for (; iter != end && checked_length < length; ++iter) + { + size_t buffer_length = boost::asio::buffer_size(*iter); + if (buffer_length > length - checked_length) + buffer_length = length - checked_length; + if (memcmp(data_ + offset + checked_length, + iter->data(), buffer_length) != 0) + return false; + checked_length += buffer_length; + } + + return true; + } + + template <typename Const_Buffers> + bool check_buffers(boost::asio::uint64_t offset, + const Const_Buffers& buffers, size_t length) + { + return check_buffers(offset, boost::asio::buffer_sequence_begin(buffers), + boost::asio::buffer_sequence_end(buffers), length); + } + + template <typename Const_Buffers> + size_t write_some_at(boost::asio::uint64_t offset, + const Const_Buffers& buffers) + { + return boost::asio::buffer_copy( + boost::asio::buffer(data_, length_) + offset, + buffers, next_write_length_); + } + + template <typename Const_Buffers> + size_t write_some_at(boost::asio::uint64_t offset, + const Const_Buffers& buffers, boost::system::error_code& ec) + { + ec = boost::system::error_code(); + return write_some_at(offset, buffers); + } + + template <typename Const_Buffers, typename Handler> + void async_write_some_at(boost::asio::uint64_t offset, + const Const_Buffers& buffers, BOOST_ASIO_MOVE_ARG(Handler) handler) + { + size_t bytes_transferred = write_some_at(offset, buffers); + boost::asio::post(get_executor(), + boost::asio::detail::bind_handler( + BOOST_ASIO_MOVE_CAST(Handler)(handler), + boost::system::error_code(), bytes_transferred)); + } + +private: + boost::asio::io_context& io_context_; + enum { max_length = 8192 }; + char data_[max_length]; + size_t length_; + size_t next_write_length_; +}; + +static const char write_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +static char mutable_write_data[] + = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +void test_3_arg_const_buffer_write_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); +} + +void test_3_arg_mutable_buffer_write_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::mutable_buffer buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); +} + +void test_3_arg_vector_buffers_write_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(boost::asio::buffer(write_data, 32)); + buffers.push_back(boost::asio::buffer(write_data) + 32); + + s.reset(); + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); +} + +void test_4_arg_nothrow_const_buffer_write_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_4_arg_nothrow_mutable_buffer_write_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::mutable_buffer buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_4_arg_nothrow_vector_buffers_write_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(boost::asio::buffer(write_data, 32)); + buffers.push_back(boost::asio::buffer(write_data) + 32); + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); +} + +bool old_style_transfer_all(const boost::system::error_code& ec, + size_t /*bytes_transferred*/) +{ + return !!ec; +} + +struct short_transfer +{ + short_transfer() {} +#if defined(BOOST_ASIO_HAS_MOVE) + short_transfer(short_transfer&&) {} +#else // defined(BOOST_ASIO_HAS_MOVE) + short_transfer(const short_transfer&) {} +#endif // defined(BOOST_ASIO_HAS_MOVE) + size_t operator()(const boost::system::error_code& ec, + size_t /*bytes_transferred*/) + { + return !!ec ? 0 : 3; + } +}; + +void test_4_arg_const_buffer_write_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); +} + +void test_4_arg_mutable_buffer_write_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::mutable_buffer buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); +} + +void test_4_arg_vector_buffers_write_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(boost::asio::buffer(write_data, 32)); + buffers.push_back(boost::asio::buffer(write_data) + 32); + + s.reset(); + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42)); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1)); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10)); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42)); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 0, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, short_transfer()); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); +} + +void test_5_arg_const_buffer_write_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_5_arg_mutable_buffer_write_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::mutable_buffer buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(mutable_write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + BOOST_ASIO_CHECK(!error); +} + +void test_5_arg_vector_buffers_write_at() +{ + boost::asio::io_context ioc; + test_random_access_device s(ioc); + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(boost::asio::buffer(write_data, 32)); + buffers.push_back(boost::asio::buffer(write_data) + 32); + + s.reset(); + boost::system::error_code error; + size_t bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_all(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 50); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), error); + BOOST_ASIO_CHECK(bytes_transferred == 1); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), error); + BOOST_ASIO_CHECK(bytes_transferred == 10); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), error); + BOOST_ASIO_CHECK(bytes_transferred == 42); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + old_style_transfer_all, error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(1); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 0, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); + + s.reset(); + s.next_write_length(10); + error = boost::system::error_code(); + bytes_transferred = boost::asio::write_at(s, 1234, buffers, + short_transfer(), error); + BOOST_ASIO_CHECK(bytes_transferred == sizeof(write_data)); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + BOOST_ASIO_CHECK(!error); +} + +void async_write_handler(const boost::system::error_code& e, + size_t bytes_transferred, size_t expected_bytes_transferred, bool* called) +{ + *called = true; + BOOST_ASIO_CHECK(!e); + BOOST_ASIO_CHECK(bytes_transferred == expected_bytes_transferred); +} + +void test_4_arg_const_buffer_async_write_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + int i = boost::asio::async_write_at(s, 0, buffers, + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); +} + +void test_4_arg_mutable_buffer_async_write_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::mutable_buffer buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + int i = boost::asio::async_write_at(s, 0, buffers, + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); +} + +void test_4_arg_boost_array_buffers_async_write_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::array<boost::asio::const_buffer, 2> buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + int i = boost::asio::async_write_at(s, 0, buffers, + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) +} + +void test_4_arg_std_array_buffers_async_write_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + boost::asio::io_context ioc; + test_random_access_device s(ioc); + std::array<boost::asio::const_buffer, 2> buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + int i = boost::asio::async_write_at(s, 0, buffers, + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) +} + +void test_4_arg_vector_buffers_async_write_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_random_access_device s(ioc); + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(boost::asio::buffer(write_data, 32)); + buffers.push_back(boost::asio::buffer(write_data) + 32); + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + int i = boost::asio::async_write_at(s, 0, buffers, + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); +} + +void test_4_arg_streambuf_async_write_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::streambuf sb; + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + bool called = false; + boost::asio::async_write_at(s, 0, sb, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 1234, sb, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, sb, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, sb, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, sb, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, sb, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, sb, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + int i = boost::asio::async_write_at(s, 0, sb, + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); +} + +void test_5_arg_const_buffer_async_write_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + int i = boost::asio::async_write_at(s, 0, buffers, short_transfer(), + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); +} + +void test_5_arg_mutable_buffer_async_write_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::mutable_buffer buffers + = boost::asio::buffer(mutable_write_data, sizeof(mutable_write_data)); + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(mutable_write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(mutable_write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(mutable_write_data))); + + s.reset(); + int i = boost::asio::async_write_at(s, 0, buffers, short_transfer(), + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); +} + +void test_5_arg_boost_array_buffers_async_write_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + +#if defined(BOOST_ASIO_HAS_BOOST_ARRAY) + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::array<boost::asio::const_buffer, 2> buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + int i = boost::asio::async_write_at(s, 0, buffers, short_transfer(), + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); +#endif // defined(BOOST_ASIO_HAS_BOOST_ARRAY) +} + +void test_5_arg_std_array_buffers_async_write_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + boost::asio::io_context ioc; + test_random_access_device s(ioc); + std::array<boost::asio::const_buffer, 2> buffers = { { + boost::asio::buffer(write_data, 32), + boost::asio::buffer(write_data) + 32 } }; + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + int i = boost::asio::async_write_at(s, 0, buffers, short_transfer(), + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) +} + +void test_5_arg_vector_buffers_async_write_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_random_access_device s(ioc); + std::vector<boost::asio::const_buffer> buffers; + buffers.push_back(boost::asio::buffer(write_data, 32)); + buffers.push_back(boost::asio::buffer(write_data) + 32); + + s.reset(); + bool called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, buffers, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + int i = boost::asio::async_write_at(s, 0, buffers, short_transfer(), + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); +} + +void test_5_arg_streambuf_async_write_at() +{ +#if defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = boost; +#else // defined(BOOST_ASIO_HAS_BOOST_BIND) + namespace bindns = std; +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + using bindns::placeholders::_1; + using bindns::placeholders::_2; + + boost::asio::io_context ioc; + test_random_access_device s(ioc); + boost::asio::streambuf sb; + boost::asio::const_buffer buffers + = boost::asio::buffer(write_data, sizeof(write_data)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + bool called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_all(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_at_least(1), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_at_least(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 50)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_at_least(42), + bindns::bind(async_write_handler, + _1, _2, 50, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 50)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 1)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_exactly(1), + bindns::bind(async_write_handler, + _1, _2, 1, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 1)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_exactly(10), + bindns::bind(async_write_handler, + _1, _2, 10, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 10)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, sb, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, 42)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, sb, + boost::asio::transfer_exactly(42), + bindns::bind(async_write_handler, + _1, _2, 42, &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, 42)); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 0, sb, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 1234, sb, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, sb, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, sb, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, sb, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, sb, old_style_transfer_all, + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 0, sb, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + called = false; + boost::asio::async_write_at(s, 1234, sb, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 0, sb, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(1); + called = false; + boost::asio::async_write_at(s, 1234, sb, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 0, sb, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + s.next_write_length(10); + called = false; + boost::asio::async_write_at(s, 1234, sb, short_transfer(), + bindns::bind(async_write_handler, + _1, _2, sizeof(write_data), &called)); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(called); + BOOST_ASIO_CHECK(s.check_buffers(1234, buffers, sizeof(write_data))); + + s.reset(); + sb.consume(sb.size()); + sb.sputn(write_data, sizeof(write_data)); + int i = boost::asio::async_write_at(s, 0, sb, short_transfer(), + archetypes::lazy_handler()); + BOOST_ASIO_CHECK(i == 42); + ioc.restart(); + ioc.run(); + BOOST_ASIO_CHECK(s.check_buffers(0, buffers, sizeof(write_data))); +} + +BOOST_ASIO_TEST_SUITE +( + "write_at", + BOOST_ASIO_TEST_CASE(test_3_arg_const_buffer_write_at) + BOOST_ASIO_TEST_CASE(test_3_arg_mutable_buffer_write_at) + BOOST_ASIO_TEST_CASE(test_3_arg_vector_buffers_write_at) + BOOST_ASIO_TEST_CASE(test_4_arg_nothrow_const_buffer_write_at) + BOOST_ASIO_TEST_CASE(test_4_arg_nothrow_mutable_buffer_write_at) + BOOST_ASIO_TEST_CASE(test_4_arg_nothrow_vector_buffers_write_at) + BOOST_ASIO_TEST_CASE(test_4_arg_const_buffer_write_at) + BOOST_ASIO_TEST_CASE(test_4_arg_mutable_buffer_write_at) + BOOST_ASIO_TEST_CASE(test_4_arg_vector_buffers_write_at) + BOOST_ASIO_TEST_CASE(test_5_arg_const_buffer_write_at) + BOOST_ASIO_TEST_CASE(test_5_arg_mutable_buffer_write_at) + BOOST_ASIO_TEST_CASE(test_5_arg_vector_buffers_write_at) + BOOST_ASIO_TEST_CASE(test_4_arg_const_buffer_async_write_at) + BOOST_ASIO_TEST_CASE(test_4_arg_mutable_buffer_async_write_at) + BOOST_ASIO_TEST_CASE(test_4_arg_boost_array_buffers_async_write_at) + BOOST_ASIO_TEST_CASE(test_4_arg_std_array_buffers_async_write_at) + BOOST_ASIO_TEST_CASE(test_4_arg_vector_buffers_async_write_at) + BOOST_ASIO_TEST_CASE(test_4_arg_streambuf_async_write_at) + BOOST_ASIO_TEST_CASE(test_5_arg_const_buffer_async_write_at) + BOOST_ASIO_TEST_CASE(test_5_arg_mutable_buffer_async_write_at) + BOOST_ASIO_TEST_CASE(test_5_arg_boost_array_buffers_async_write_at) + BOOST_ASIO_TEST_CASE(test_5_arg_std_array_buffers_async_write_at) + BOOST_ASIO_TEST_CASE(test_5_arg_vector_buffers_async_write_at) + BOOST_ASIO_TEST_CASE(test_5_arg_streambuf_async_write_at) +) diff --git a/src/boost/libs/asio/tools/handlerviz.pl b/src/boost/libs/asio/tools/handlerviz.pl new file mode 100755 index 000000000..7e8de3df2 --- /dev/null +++ b/src/boost/libs/asio/tools/handlerviz.pl @@ -0,0 +1,299 @@ +#!/usr/bin/perl -w +# +# handlerviz.pl +# ~~~~~~~~~~~~~ +# +# A visualisation tool for post-processing the debug output generated by +# Asio-based programs. Programs write this output to the standard error stream +# when compiled with the define `BOOST_ASIO_ENABLE_HANDLER_TRACKING'. +# +# This tool generates output intended for use with the GraphViz tool `dot'. For +# example, to convert output to a PNG image, use: +# +# perl handlerviz.pl < output.txt | dot -Tpng > output.png +# +# To convert to a PDF file, use: +# +# perl handlerviz.pl < output.txt | dot -Tpdf > output.pdf +# +# Copyright (c) 2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +use strict; + +my %nodes = (); +my @edges = (); +my %anon_nodes = (); +my $anon_id = 0; +my %all_nodes = (); + +#------------------------------------------------------------------------------- +# Parse the debugging output and populate the nodes and edges. + +sub parse_debug_output() +{ + while (my $line = <>) + { + chomp($line); + + if ($line =~ /\@asio\|([^|]*)\|([^|]*)\|(.*)$/) + { + my $timestamp = $1; + my $action = $2; + my $description = $3; + + # Handler creation. + if ($action =~ /^([0-9]+)\*([0-9]+)$/) + { + my $begin = $1; + my $end = $2; + my $label = $description; + $label =~ s/\./\\n/g; + + if ($begin eq "0") + { + $begin = "a" . $anon_id++; + $anon_nodes{$begin} = $timestamp; + $all_nodes{"$timestamp-$begin"} = $begin; + } + + my %edge = ( begin=>$begin, end=>$end, label=>$label ); + push(@edges, \%edge); + } + + # Begin handler invocation. + elsif ($action =~ /^>([0-9]+)$/) + { + my %new_node = ( label=>$description, entry=>$timestamp ); + $new_node{content} = (); + $nodes{$1} = \%new_node; + $all_nodes{"$timestamp-$1"} = $1; + } + + # End handler invocation. + elsif ($action =~ /^<([0-9]+)$/) + { + $nodes{$1}->{exit} = $timestamp; + } + + # Handler threw exception. + elsif ($action =~ /^!([0-9]+)$/) + { + push(@{$nodes{$1}->{content}}, "exception"); + } + + # Handler was destroyed without being invoked. + elsif ($action =~ /^~([0-9]+)$/) + { + my %new_node = ( label=>"$timestamp destroyed" ); + $new_node{content} = (); + $nodes{$1} = \%new_node; + $all_nodes{"$timestamp-$1"} = $1; + } + + # Handler performed some operation. + elsif ($action =~ /^([0-9]+)$/) + { + if ($1 eq "0") + { + my $id = "a" . $anon_id++; + $anon_nodes{$id} = "$timestamp\\l$description"; + $all_nodes{"$timestamp-$id"} = $id; + } + else + { + push(@{$nodes{$1}->{content}}, "$description"); + } + } + } + } +} + +#------------------------------------------------------------------------------- +# Helper function to convert a string to escaped HTML text. + +sub escape($) +{ + my $text = shift; + $text =~ s/&/\&\;/g; + $text =~ s/</\<\;/g; + $text =~ s/>/\>\;/g; + $text =~ s/\t/ /g; + return $text; +} + +#------------------------------------------------------------------------------- +# Templates for dot output. + +my $graph_header = <<"EOF"; +/* Generated by asioviz.pl */ +digraph G +{ +graph [ nodesep="1" ]; +node [ shape="box", fontsize="9" ]; +edge [ arrowtail="dot", fontsize="9" ]; +EOF + +my $graph_footer = <<"EOF"; +} +EOF + +my $node_header = <<"EOF"; +"%name%" +[ +label=<<table border="0" cellspacing="0"> +<tr><td align="left" bgcolor="gray" border="0">%label%</td></tr> +EOF + +my $node_footer = <<"EOF"; +</table>> +] +EOF + +my $node_content = <<"EOF"; +<tr><td align="left" bgcolor="white" border="0"> +<font face="mono" point-size="9">%content%</font> +</td></tr> +EOF + +my $anon_nodes_header = <<"EOF"; +{ +node [ shape="record" ]; +EOF + +my $anon_nodes_footer = <<"EOF"; +} +EOF + +my $anon_node = <<"EOF"; +"%name%" [ label="%label%", color="gray" ]; +EOF + +my $edges_header = <<"EOF"; +{ +edge [ style="dashed", arrowhead="open", weight="100" ]; +EOF + +my $edges_footer = <<"EOF"; +} +EOF + +my $edge = <<"EOF"; +"%begin%" -> "%end%" [ label="%label%" ] +EOF + +my $node_order_header = <<"EOF"; +{ +edge [ style="invis", weight="1" ]; +EOF + +my $node_order_footer = <<"EOF"; +} +EOF + +my $node_order = <<"EOF"; +"%begin%" -> "%end%" +EOF + +#------------------------------------------------------------------------------- +# Generate dot output from the nodes and edges. + +sub print_nodes() +{ + foreach my $name (sort keys %nodes) + { + my $node = $nodes{$name}; + my $entry = $node->{entry}; + my $exit = $node->{exit}; + my $label = escape($node->{label}); + my $header = $node_header; + $header =~ s/%name%/$name/g; + $header =~ s/%label%/$label/g; + print($header); + + my $line = $node_content; + my $content = $entry . " + " . sprintf("%.6f", $exit - $entry) . "s"; + $line =~ s/%content%/$content/g; + print($line); + + foreach my $content (@{$node->{content}}) + { + $content = escape($content); + $content = " " if length($content) == 0; + my $line = $node_content; + $line =~ s/%content%/$content/g; + print($line); + } + + print($node_footer); + } +} + +sub print_anon_nodes() +{ + print($anon_nodes_header); + foreach my $name (sort keys %anon_nodes) + { + my $label = $anon_nodes{$name}; + my $line = $anon_node; + $line =~ s/%name%/$name/g; + $line =~ s/%label%/$label/g; + print($line); + } + print($edges_footer); +} + +sub print_edges() +{ + print($edges_header); + foreach my $e (@edges) + { + my $begin = $e->{begin}; + my $end = $e->{end}; + my $label = $e->{label}; + my $line = $edge; + $line =~ s/%begin%/$begin/g; + $line =~ s/%end%/$end/g; + $line =~ s/%label%/$label/g; + print($line); + } + print($edges_footer); +} + +sub print_node_order() +{ + my $prev = ""; + print($node_order_header); + foreach my $name (sort keys %all_nodes) + { + if ($prev ne "") + { + my $begin = $prev; + my $end = $all_nodes{$name}; + my $line = $node_order; + $line =~ s/%begin%/$begin/g; + $line =~ s/%end%/$end/g; + print($line); + } + $prev = $all_nodes{$name}; + } + print($node_order_footer); +} + +sub generate_dot() +{ + print($graph_header); + print_nodes(); + print_anon_nodes(); + print_edges(); + print_node_order(); + print($graph_footer); +} + +#------------------------------------------------------------------------------- + +parse_debug_output(); +generate_dot(); |