[DEV] add v1.76.0

This commit is contained in:
2021-10-05 21:37:46 +02:00
parent a97e9ae7d4
commit d0115b733d
45133 changed files with 4744437 additions and 1026325 deletions

View File

@@ -1,43 +1,29 @@
#
# Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;
if [ os.name ] = SOLARIS
{
lib socket ;
lib nsl ;
}
else if [ os.name ] = NT
{
lib ws2_32 ;
lib mswsock ;
}
else if [ os.name ] = HPUX
{
lib ipv6 ;
}
else if [ os.name ] = HAIKU
{
lib network ;
}
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
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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
;

View File

@@ -2,7 +2,7 @@
// server.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -1,43 +1,29 @@
#
# Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;
if [ os.name ] = SOLARIS
{
lib socket ;
lib nsl ;
}
else if [ os.name ] = NT
{
lib ws2_32 ;
lib mswsock ;
}
else if [ os.name ] = HPUX
{
lib ipv6 ;
}
else if [ os.name ] = HAIKU
{
lib network ;
}
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
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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
;

View File

@@ -2,7 +2,7 @@
// reference_counted.cpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -13,6 +13,7 @@
#include <memory>
#include <utility>
#include <vector>
#include <ctime>
using boost::asio::ip::tcp;
@@ -60,7 +61,7 @@ private:
auto self(shared_from_this());
boost::asio::async_write(socket_, buffer,
[this, self](boost::system::error_code /*ec*/, std::size_t /*length*/)
[self](boost::system::error_code /*ec*/, std::size_t /*length*/)
{
});
}

View File

@@ -1,30 +1,16 @@
#
# Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;
if [ os.name ] = SOLARIS
{
lib socket ;
lib nsl ;
}
else if [ os.name ] = NT
{
lib ws2_32 ;
lib mswsock ;
}
else if [ os.name ] = HPUX
{
lib ipv6 ;
}
else if [ os.name ] = HAIKU
{
lib network ;
}
lib socket ; # SOLARIS
lib nsl ; # SOLARIS
lib ws2_32 ; # NT
lib mswsock ; # NT
lib ipv6 ; # HPUX
lib network ; # HAIKU
project
: requirements
@@ -32,15 +18,15 @@ project
<library>/boost/thread//boost_thread
<define>BOOST_ALL_NO_LIB=1
<threading>multi
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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 ;

View File

@@ -2,7 +2,7 @@
// chat_client.cpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// chat_message.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// chat_server.cpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -1,30 +1,16 @@
#
# Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;
if [ os.name ] = SOLARIS
{
lib socket ;
lib nsl ;
}
else if [ os.name ] = NT
{
lib ws2_32 ;
lib mswsock ;
}
else if [ os.name ] = HPUX
{
lib ipv6 ;
}
else if [ os.name ] = HAIKU
{
lib network ;
}
lib socket ; # SOLARIS
lib nsl ; # SOLARIS
lib ws2_32 ; # NT
lib mswsock ; # NT
lib ipv6 ; # HPUX
lib network ; # HAIKU
project
: requirements
@@ -32,15 +18,15 @@ project
<library>/boost/thread//boost_thread
<define>BOOST_ALL_NO_LIB=1
<threading>multi
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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 ;

View File

@@ -2,7 +2,7 @@
// async_tcp_echo_server.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// async_udp_echo_server.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// blocking_tcp_echo_client.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// blocking_tcp_echo_server.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// blocking_udp_echo_client.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// blocking_udp_echo_server.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -1,45 +1,31 @@
#
# Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;
if [ os.name ] = SOLARIS
{
lib socket ;
lib nsl ;
}
else if [ os.name ] = NT
{
lib ws2_32 ;
lib mswsock ;
}
else if [ os.name ] = HPUX
{
lib ipv6 ;
}
else if [ os.name ] = HAIKU
{
lib network ;
}
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
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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 ;

View File

@@ -1,5 +1,5 @@
#include <boost/asio/any_io_executor.hpp>
#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>
@@ -10,8 +10,8 @@
#include <typeinfo>
#include <vector>
using boost::asio::any_io_executor;
using boost::asio::defer;
using boost::asio::executor;
using boost::asio::post;
using boost::asio::strand;
using boost::asio::system_executor;
@@ -106,7 +106,7 @@ public:
protected:
// Construct the actor to use the specified executor for all message handlers.
actor(executor e)
actor(any_io_executor e)
: executor_(std::move(e))
{
}
@@ -124,7 +124,7 @@ protected:
template <class Actor, class Message>
void deregister_handler(void (Actor::* mf)(Message, actor_address))
{
const std::type_info& id = typeid(message_handler<Message>);
const std::type_info& id = typeid(Message);
for (auto iter = handlers_.begin(); iter != handlers_.end(); ++iter)
{
if ((*iter)->message_id() == id)
@@ -171,7 +171,7 @@ private:
// 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_;
strand<any_io_executor> executor_;
std::vector<std::shared_ptr<message_handler_base>> handlers_;
};
@@ -221,7 +221,7 @@ using boost::asio::thread_pool;
class member : public actor
{
public:
explicit member(executor e)
explicit member(any_io_executor e)
: actor(std::move(e))
{
register_handler(&member::init_handler);

View File

@@ -1,9 +1,9 @@
#include <boost/asio/post.hpp>
#include <boost/asio/thread_pool.hpp>
#include <boost/asio/execution.hpp>
#include <boost/asio/static_thread_pool.hpp>
#include <iostream>
using boost::asio::post;
using boost::asio::thread_pool;
using boost::asio::static_thread_pool;
namespace execution = boost::asio::execution;
// Traditional active object pattern.
// Member functions do not block.
@@ -11,37 +11,43 @@ using boost::asio::thread_pool;
class bank_account
{
int balance_ = 0;
mutable thread_pool pool_{1};
mutable static_thread_pool pool_{1};
public:
void deposit(int amount)
{
post(pool_, [=]
{
balance_ += amount;
});
execution::execute(
pool_.executor(),
[this, amount]
{
balance_ += amount;
});
}
void withdraw(int amount)
{
post(pool_, [=]
{
if (balance_ >= amount)
balance_ -= amount;
});
execution::execute(
pool_.executor(),
[this, amount]
{
if (balance_ >= amount)
balance_ -= amount;
});
}
void print_balance() const
{
post(pool_, [=]
{
std::cout << "balance = " << balance_ << "\n";
});
execution::execute(
pool_.executor(),
[this]
{
std::cout << "balance = " << balance_ << "\n";
});
}
~bank_account()
{
pool_.join();
pool_.wait();
}
};

View File

@@ -1,11 +1,9 @@
#include <boost/asio/post.hpp>
#include <boost/asio/thread_pool.hpp>
#include <boost/asio/use_future.hpp>
#include <boost/asio/execution.hpp>
#include <boost/asio/static_thread_pool.hpp>
#include <iostream>
using boost::asio::post;
using boost::asio::thread_pool;
using boost::asio::use_future;
using boost::asio::static_thread_pool;
namespace execution = boost::asio::execution;
// Traditional active object pattern.
// Member functions block until operation is finished.
@@ -13,35 +11,43 @@ using boost::asio::use_future;
class bank_account
{
int balance_ = 0;
mutable thread_pool pool_{1};
mutable static_thread_pool pool_{1};
public:
void deposit(int amount)
{
post(pool_,
use_future([=]
execution::execute(
boost::asio::require(pool_.executor(),
execution::blocking.always),
[this, amount]
{
balance_ += amount;
})).get();
});
}
void withdraw(int amount)
{
post(pool_,
use_future([=]
execution::execute(
boost::asio::require(pool_.executor(),
execution::blocking.always),
[this, amount]
{
if (balance_ >= amount)
balance_ -= amount;
})).get();
});
}
int balance() const
{
return post(pool_,
use_future([=]
int result = 0;
execution::execute(
boost::asio::require(pool_.executor(),
execution::blocking.always),
[this, &result]
{
return balance_;
})).get();
result = balance_;
});
return result;
}
};

View File

@@ -1,20 +1,20 @@
#include <boost/asio/dispatch.hpp>
#include <boost/asio/execution_context.hpp>
#include <boost/asio/thread_pool.hpp>
#include <boost/asio/execution.hpp>
#include <boost/asio/static_thread_pool.hpp>
#include <algorithm>
#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;
using boost::asio::static_thread_pool;
namespace execution = boost::asio::execution;
// 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
class fork_join_pool
{
public:
// The constructor starts a thread pool with the specified number of threads.
@@ -22,7 +22,7 @@ public:
// 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)
std::size_t thread_count = std::max(std::thread::hardware_concurrency(), 1u) * 2)
: use_count_(1),
threads_(thread_count)
{
@@ -32,7 +32,9 @@ public:
// 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_, [&]
execution::execute(
threads_.executor(),
[this]
{
std::unique_lock<std::mutex> lock(mutex_);
while (use_count_ > 0)
@@ -44,7 +46,7 @@ public:
catch (...)
{
stop_threads();
threads_.join();
threads_.wait();
throw;
}
}
@@ -53,7 +55,7 @@ public:
~fork_join_pool()
{
stop_threads();
threads_.join();
threads_.wait();
}
private:
@@ -117,7 +119,7 @@ private:
// 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,
void do_execute(std::shared_ptr<function_base> p,
const std::shared_ptr<std::size_t>& work_count)
{
std::unique_lock<std::mutex> lock(mutex_);
@@ -135,16 +137,6 @@ private:
}
}
// 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()
{
@@ -158,7 +150,7 @@ private:
std::queue<std::shared_ptr<function_base>> queue_;
std::size_t use_count_;
std::size_t thread_count_;
thread_pool threads_;
static_thread_pool threads_;
};
// A class that satisfies the Executor requirements. Every function or piece of
@@ -172,45 +164,16 @@ public:
{
}
fork_join_pool& context() const noexcept
fork_join_pool& query(execution::context_t) const noexcept
{
return context_;
}
void on_work_started() const noexcept
template <class Func>
void execute(Func f) const
{
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);
auto p(std::make_shared<function<Func>>(std::move(f), work_count_));
context_.do_execute(p, work_count_);
}
friend bool operator==(const fork_executor& a,
@@ -289,8 +252,8 @@ void fork_join_sort(Iterator begin, Iterator end)
{
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); });
execution::execute(fork, [=]{ fork_join_sort(begin, begin + n / 2); });
execution::execute(fork, [=]{ fork_join_sort(begin + n / 2, end); });
}
std::inplace_merge(begin, begin + n / 2, end);
}

View File

@@ -11,6 +11,7 @@
#include <queue>
#include <thread>
#include <vector>
#include <cctype>
using boost::asio::execution_context;
using boost::asio::executor_binder;
@@ -19,9 +20,10 @@ using boost::asio::post;
using boost::asio::system_executor;
using boost::asio::use_future;
using boost::asio::use_service;
namespace execution = boost::asio::execution;
// An executor that launches a new thread for each function submitted to it.
// This class satisfies the Executor requirements.
// This class satisfies the executor requirements.
class thread_executor
{
private:
@@ -54,40 +56,28 @@ private:
};
public:
execution_context& context() const noexcept
execution_context& query(execution::context_t) const
{
return system_executor().context();
return boost::asio::query(system_executor(), execution::context);
}
void on_work_started() const noexcept
execution::blocking_t query(execution::blocking_t) const
{
// This executor doesn't count work.
return execution::blocking.never;
}
void on_work_finished() const noexcept
thread_executor require(execution::blocking_t::never_t) const
{
// This executor doesn't count work.
return *this;
}
template <class Func, class Alloc>
void dispatch(Func&& f, const Alloc& a) const
template <class Func>
void execute(Func f) 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());
thread_bag& bag = use_service<thread_bag>(query(execution::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
{
@@ -291,7 +281,7 @@ void writer(queue_back<std::string> in)
int main()
{
thread_pool pool;
thread_pool pool(1);
auto f = pipeline(reader, filter, bind_executor(pool, upper), writer);
f.wait();

View File

@@ -8,6 +8,7 @@
using boost::asio::dispatch;
using boost::asio::execution_context;
namespace execution = boost::asio::execution;
class priority_scheduler : public execution_context
{
@@ -21,47 +22,20 @@ public:
{
}
priority_scheduler& context() const noexcept
priority_scheduler& query(execution::context_t) const noexcept
{
return context_;
}
void on_work_started() const noexcept
template <class Func>
void execute(Func f) const
{
// 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)));
auto p(std::make_shared<item<Func>>(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
{
@@ -79,6 +53,12 @@ public:
int priority_;
};
~priority_scheduler() noexcept
{
shutdown();
destroy();
}
executor_type get_executor(int pri = 0) noexcept
{
return executor_type(*const_cast<priority_scheduler*>(this), pri);

View File

@@ -1,45 +1,31 @@
#
# Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;
if [ os.name ] = SOLARIS
{
lib socket ;
lib nsl ;
}
else if [ os.name ] = NT
{
lib ws2_32 ;
lib mswsock ;
}
else if [ os.name ] = HPUX
{
lib ipv6 ;
}
else if [ os.name ] = HAIKU
{
lib network ;
}
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
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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
@@ -47,13 +33,13 @@ exe process_per_connection
/boost/system//boost_system
: <define>BOOST_ALL_NO_LIB=1
<threading>multi
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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
;

View File

@@ -2,7 +2,7 @@
// daemon.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// process_per_connection.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -1,43 +1,29 @@
#
# Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;
if [ os.name ] = SOLARIS
{
lib socket ;
lib nsl ;
}
else if [ os.name ] = NT
{
lib ws2_32 ;
lib mswsock ;
}
else if [ os.name ] = HPUX
{
lib ipv6 ;
}
else if [ os.name ] = HAIKU
{
lib network ;
}
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
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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
;

View File

@@ -2,7 +2,7 @@
// daytime_client.cpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -77,7 +77,8 @@ int main(int argc, char* argv[])
// 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);
auto work = boost::asio::require(io_context.get_executor(),
boost::asio::execution::outstanding_work.tracked);
std::thread thread([&io_context](){ io_context.run(); });
get_daytime(io_context, argv[1]);

View File

@@ -1,30 +1,16 @@
#
# Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;
if [ os.name ] = SOLARIS
{
lib socket ;
lib nsl ;
}
else if [ os.name ] = NT
{
lib ws2_32 ;
lib mswsock ;
}
else if [ os.name ] = HPUX
{
lib ipv6 ;
}
else if [ os.name ] = HAIKU
{
lib network ;
}
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
@@ -33,13 +19,13 @@ exe async_tcp_echo_server
<define>BOOST_ALL_NO_LIB=1
<define>BOOST_ASIO_CUSTOM_HANDLER_TRACKING=\\\"custom_tracking.hpp\\\"
<threading>multi
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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
;

View File

@@ -2,7 +2,7 @@
// async_tcp_echo_server.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -16,6 +16,13 @@
using boost::asio::ip::tcp;
// Define a helper macro to invoke BOOST_ASIO_HANDLER_LOCATION with the current
// file name, line number, and function name. For the function name, you might
// also consider using __PRETTY_FUNCTION__, BOOST_CURRENT_FUNCTION, or a hand-
// crafted name. For C++20 or later, you may also use std::source_location.
#define HANDLER_LOCATION \
BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, __func__))
class session
: public std::enable_shared_from_this<session>
{
@@ -27,16 +34,22 @@ public:
void start()
{
HANDLER_LOCATION;
do_read();
}
private:
void do_read()
{
HANDLER_LOCATION;
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)
{
HANDLER_LOCATION;
if (!ec)
{
do_write(length);
@@ -46,10 +59,14 @@ private:
void do_write(std::size_t length)
{
HANDLER_LOCATION;
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*/)
{
HANDLER_LOCATION;
if (!ec)
{
do_read();
@@ -74,9 +91,13 @@ public:
private:
void do_accept()
{
HANDLER_LOCATION;
acceptor_.async_accept(
[this](boost::system::error_code ec, tcp::socket socket)
{
HANDLER_LOCATION;
if (!ec)
{
std::make_shared<session>(std::move(socket))->start();

View File

@@ -2,7 +2,7 @@
// custom_tracking.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -24,6 +24,9 @@
# define BOOST_ASIO_HANDLER_TRACKING_INIT \
::custom_tracking::init()
# define BOOST_ASIO_HANDLER_LOCATION(args) \
::custom_tracking::location args
# define BOOST_ASIO_HANDLER_CREATION(args) \
::custom_tracking::creation args
@@ -71,6 +74,13 @@ struct custom_tracking
{
}
// Record a source location.
static void location(const char* file_name,
int line, const char* function_name)
{
std::printf("At location %s:%d in %s\n", file_name, line, function_name);
}
// Record the creation of a tracked handler.
static void creation(boost::asio::execution_context& /*ctx*/,
tracked_handler& h, const char* object_type, void* /*object*/,

View File

@@ -1,30 +1,16 @@
#
# Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;
if [ os.name ] = SOLARIS
{
lib socket ;
lib nsl ;
}
else if [ os.name ] = NT
{
lib ws2_32 ;
lib mswsock ;
}
else if [ os.name ] = HPUX
{
lib ipv6 ;
}
else if [ os.name ] = HAIKU
{
lib network ;
}
lib socket ; # SOLARIS
lib nsl ; # SOLARIS
lib ws2_32 ; # NT
lib mswsock ; # NT
lib ipv6 ; # HPUX
lib network ; # HAIKU
exe server
: connection.cpp
@@ -39,13 +25,13 @@ exe server
/boost/thread//boost_thread
: <define>BOOST_ALL_NO_LIB=1
<threading>multi
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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
;

View File

@@ -2,7 +2,7 @@
// connection.cpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// connection.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// connection_manager.cpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// connection_manager.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// header.hpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// main.cpp
// ~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// mime_types.cpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// mime_types.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// reply.cpp
// ~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// reply.hpp
// ~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// request.hpp
// ~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// request_handler.cpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// request_handler.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// request_parser.cpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// request_parser.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// server.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// server.hpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -1,43 +1,29 @@
#
# Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;
if [ os.name ] = SOLARIS
{
lib socket ;
lib nsl ;
}
else if [ os.name ] = NT
{
lib ws2_32 ;
lib mswsock ;
}
else if [ os.name ] = HPUX
{
lib ipv6 ;
}
else if [ os.name ] = HAIKU
{
lib network ;
}
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
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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
;

View File

@@ -2,7 +2,7 @@
// prioritised_handlers.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,7 +15,7 @@
using boost::asio::ip::tcp;
class handler_priority_queue : boost::asio::execution_context
class handler_priority_queue : public boost::asio::execution_context
{
public:
template <typename Function>
@@ -142,7 +142,8 @@ private:
//----------------------------------------------------------------------
void high_priority_handler(const boost::system::error_code& /*ec*/)
void high_priority_handler(const boost::system::error_code& /*ec*/,
tcp::socket /*socket*/)
{
std::cout << "High priority handler\n";
}
@@ -178,8 +179,7 @@ int main()
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));
acceptor.async_accept(pri_queue.wrap(100, high_priority_handler));
tcp::socket client_socket(io_context);
client_socket.connect(acceptor.local_endpoint());

View File

@@ -0,0 +1,31 @@
#
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;

View File

@@ -0,0 +1,91 @@
//
// http_client.cpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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;
}

View File

@@ -1,30 +1,16 @@
#
# Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;
if [ os.name ] = SOLARIS
{
lib socket ;
lib nsl ;
}
else if [ os.name ] = NT
{
lib ws2_32 ;
lib mswsock ;
}
else if [ os.name ] = HPUX
{
lib ipv6 ;
}
else if [ os.name ] = HAIKU
{
lib network ;
}
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
@@ -32,15 +18,15 @@ exe connect_pair
/boost/thread//boost_thread
: <define>BOOST_ALL_NO_LIB=1
<threading>multi
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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
@@ -48,15 +34,15 @@ exe iostream_client
/boost/system//boost_system
: <define>BOOST_ALL_NO_LIB=1
<threading>multi
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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
@@ -64,15 +50,15 @@ exe stream_client
/boost/system//boost_system
: <define>BOOST_ALL_NO_LIB=1
<threading>multi
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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
@@ -80,13 +66,13 @@ exe stream_server
/boost/system//boost_system
: <define>BOOST_ALL_NO_LIB=1
<threading>multi
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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
;

View File

@@ -2,7 +2,7 @@
// connect_pair.cpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// stream_client.cpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// stream_client.cpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// stream_server.cpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -1,45 +1,31 @@
#
# Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;
if [ os.name ] = SOLARIS
{
lib socket ;
lib nsl ;
}
else if [ os.name ] = NT
{
lib ws2_32 ;
lib mswsock ;
}
else if [ os.name ] = HPUX
{
lib ipv6 ;
}
else if [ os.name ] = HAIKU
{
lib network ;
}
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
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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 ;

View File

@@ -2,7 +2,7 @@
// receiver.cpp
// ~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -2,7 +2,7 @@
// sender.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -1,43 +1,29 @@
#
# Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;
if [ os.name ] = SOLARIS
{
lib socket ;
lib nsl ;
}
else if [ os.name ] = NT
{
lib ws2_32 ;
lib mswsock ;
}
else if [ os.name ] = HPUX
{
lib ipv6 ;
}
else if [ os.name ] = HAIKU
{
lib network ;
}
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
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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
;

View File

@@ -2,7 +2,7 @@
// third_party_lib.cpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -0,0 +1,39 @@
#
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;

View File

@@ -0,0 +1,113 @@
//
// composed_1.cpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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();
}

View File

@@ -0,0 +1,131 @@
//
// composed_2.cpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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();
}

View File

@@ -0,0 +1,192 @@
//
// composed_3.cpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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();
}

View File

@@ -0,0 +1,207 @@
//
// composed_4.cpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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();
}

View File

@@ -0,0 +1,243 @@
//
// composed_5.cpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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();
}

View File

@@ -0,0 +1,302 @@
//
// composed_6.cpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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.
typename std::decay<decltype(boost::asio::prefer(
std::declval<tcp::socket::executor_type>(),
boost::asio::execution::outstanding_work.tracked))>::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.
// 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::prefer(socket.get_executor(),
boost::asio::execution::outstanding_work.tracked),
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();
}

View File

@@ -0,0 +1,222 @@
//
// composed_7.cpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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();
}

View File

@@ -0,0 +1,217 @@
//
// composed_8.cpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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();
}

View File

@@ -0,0 +1,30 @@
#
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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
;

View File

@@ -0,0 +1,143 @@
//
// socks4.hpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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

View File

@@ -0,0 +1,94 @@
//
// sync_client.cpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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").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.
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;
}

View File

@@ -1,30 +1,16 @@
#
# Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;
if [ os.name ] = SOLARIS
{
lib socket ;
lib nsl ;
}
else if [ os.name ] = NT
{
lib ws2_32 ;
lib mswsock ;
}
else if [ os.name ] = HPUX
{
lib ipv6 ;
}
else if [ os.name ] = HAIKU
{
lib network ;
}
lib socket ; # SOLARIS
lib nsl ; # SOLARIS
lib ws2_32 ; # NT
lib mswsock ; # NT
lib ipv6 ; # HPUX
lib network ; # HAIKU
exe server
: echo_server.cpp
@@ -33,13 +19,13 @@ exe server
/boost/system//boost_system
: <define>BOOST_ALL_NO_LIB=1
<threading>multi
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<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
;

View File

@@ -2,7 +2,7 @@
// echo_server.cpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -21,10 +21,10 @@ using boost::asio::ip::tcp;
class session : public std::enable_shared_from_this<session>
{
public:
explicit session(tcp::socket socket)
explicit session(boost::asio::io_context& io_context, tcp::socket socket)
: socket_(std::move(socket)),
timer_(socket_.get_io_context()),
strand_(socket_.get_io_context())
timer_(io_context),
strand_(io_context.get_executor())
{
}
@@ -67,7 +67,7 @@ public:
private:
tcp::socket socket_;
boost::asio::steady_timer timer_;
boost::asio::io_context::strand strand_;
boost::asio::strand<boost::asio::io_context::executor_type> strand_;
};
int main(int argc, char* argv[])
@@ -93,7 +93,10 @@ int main(int argc, char* argv[])
boost::system::error_code ec;
tcp::socket socket(io_context);
acceptor.async_accept(socket, yield[ec]);
if (!ec) std::make_shared<session>(std::move(socket))->go();
if (!ec)
{
std::make_shared<session>(io_context, std::move(socket))->go();
}
}
});

View File

@@ -2,7 +2,7 @@
// parallel_grep.cpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -0,0 +1,48 @@
#
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;

View File

@@ -0,0 +1,8 @@
The passphrase for both the CA and server private keys is "test".
-------------------------------------------------------------------------------
Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -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-----

View File

@@ -0,0 +1,165 @@
//
// client.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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;
}

View File

@@ -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-----

View File

@@ -0,0 +1,145 @@
//
// server.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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(boost::asio::ssl::stream<tcp::socket> socket)
: socket_(std::move(socket))
{
}
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>(
boost::asio::ssl::stream<tcp::socket>(
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;
}

View File

@@ -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-----

View File

@@ -0,0 +1,36 @@
#
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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 ;

View File

@@ -0,0 +1,311 @@
//
// async_tcp_client.cpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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;
}

View File

@@ -0,0 +1,192 @@
//
// blocking_tcp_client.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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;
}

View File

@@ -0,0 +1,200 @@
//
// blocking_token_tcp_client.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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 = boost::asio::query(
socket_.get_executor(), boost::asio::execution::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;
}

View File

@@ -0,0 +1,155 @@
//
// blocking_udp_client.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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;
}

View File

@@ -0,0 +1,433 @@
//
// server.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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;
}

View File

@@ -0,0 +1,30 @@
#
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the 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
;

View File

@@ -0,0 +1,106 @@
//
// time_t_timer.cpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the 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;
}