summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/asio/src/examples/cpp11/nonblocking/third_party_lib.cpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/asio/src/examples/cpp11/nonblocking/third_party_lib.cpp')
-rw-r--r--3rdparty/asio/src/examples/cpp11/nonblocking/third_party_lib.cpp212
1 files changed, 212 insertions, 0 deletions
diff --git a/3rdparty/asio/src/examples/cpp11/nonblocking/third_party_lib.cpp b/3rdparty/asio/src/examples/cpp11/nonblocking/third_party_lib.cpp
new file mode 100644
index 00000000000..5ce61536198
--- /dev/null
+++ b/3rdparty/asio/src/examples/cpp11/nonblocking/third_party_lib.cpp
@@ -0,0 +1,212 @@
+//
+// third_party_lib.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 <asio.hpp>
+#include <array>
+#include <iostream>
+#include <memory>
+
+using asio::ip::tcp;
+
+namespace third_party_lib {
+
+// Simulation of a third party library that wants to perform read and write
+// operations directly on a socket. It needs to be polled to determine whether
+// it requires a read or write operation, and notified when the socket is ready
+// for reading or writing.
+class session
+{
+public:
+ session(tcp::socket& socket)
+ : socket_(socket)
+ {
+ }
+
+ // Returns true if the third party library wants to be notified when the
+ // socket is ready for reading.
+ bool want_read() const
+ {
+ return state_ == reading;
+ }
+
+ // Notify that third party library that it should perform its read operation.
+ void do_read(std::error_code& ec)
+ {
+ if (std::size_t len = socket_.read_some(asio::buffer(data_), ec))
+ {
+ write_buffer_ = asio::buffer(data_, len);
+ state_ = writing;
+ }
+ }
+
+ // Returns true if the third party library wants to be notified when the
+ // socket is ready for writing.
+ bool want_write() const
+ {
+ return state_ == writing;
+ }
+
+ // Notify that third party library that it should perform its write operation.
+ void do_write(std::error_code& ec)
+ {
+ if (std::size_t len = socket_.write_some(
+ asio::buffer(write_buffer_), ec))
+ {
+ write_buffer_ = write_buffer_ + len;
+ state_ = asio::buffer_size(write_buffer_) > 0 ? writing : reading;
+ }
+ }
+
+private:
+ tcp::socket& socket_;
+ enum { reading, writing } state_ = reading;
+ std::array<char, 128> data_;
+ asio::const_buffer write_buffer_;
+};
+
+} // namespace third_party_lib
+
+// The glue between asio's sockets and the third party library.
+class connection
+ : public std::enable_shared_from_this<connection>
+{
+public:
+ connection(tcp::socket socket)
+ : socket_(std::move(socket))
+ {
+ }
+
+ void start()
+ {
+ // Put the socket into non-blocking mode.
+ socket_.non_blocking(true);
+
+ do_operations();
+ }
+
+private:
+ void do_operations()
+ {
+ auto self(shared_from_this());
+
+ // Start a read operation if the third party library wants one.
+ if (session_impl_.want_read() && !read_in_progress_)
+ {
+ read_in_progress_ = true;
+ socket_.async_wait(tcp::socket::wait_read,
+ [this, self](std::error_code ec)
+ {
+ read_in_progress_ = false;
+
+ // Notify third party library that it can perform a read.
+ if (!ec)
+ session_impl_.do_read(ec);
+
+ // The third party library successfully performed a read on the
+ // socket. Start new read or write operations based on what it now
+ // wants.
+ if (!ec || ec == asio::error::would_block)
+ do_operations();
+
+ // Otherwise, an error occurred. Closing the socket cancels any
+ // outstanding asynchronous read or write operations. The
+ // connection object will be destroyed automatically once those
+ // outstanding operations complete.
+ else
+ socket_.close();
+ });
+ }
+
+ // Start a write operation if the third party library wants one.
+ if (session_impl_.want_write() && !write_in_progress_)
+ {
+ write_in_progress_ = true;
+ socket_.async_wait(tcp::socket::wait_write,
+ [this, self](std::error_code ec)
+ {
+ write_in_progress_ = false;
+
+ // Notify third party library that it can perform a write.
+ if (!ec)
+ session_impl_.do_write(ec);
+
+ // The third party library successfully performed a write on the
+ // socket. Start new read or write operations based on what it now
+ // wants.
+ if (!ec || ec == asio::error::would_block)
+ do_operations();
+
+ // Otherwise, an error occurred. Closing the socket cancels any
+ // outstanding asynchronous read or write operations. The
+ // connection object will be destroyed automatically once those
+ // outstanding operations complete.
+ else
+ socket_.close();
+ });
+ }
+ }
+
+private:
+ tcp::socket socket_;
+ third_party_lib::session session_impl_{socket_};
+ bool read_in_progress_ = false;
+ bool write_in_progress_ = false;
+};
+
+class server
+{
+public:
+ server(asio::io_context& io_context, unsigned short port)
+ : acceptor_(io_context, {tcp::v4(), port})
+ {
+ do_accept();
+ }
+
+private:
+ void do_accept()
+ {
+ acceptor_.async_accept(
+ [this](std::error_code ec, tcp::socket socket)
+ {
+ if (!ec)
+ {
+ std::make_shared<connection>(std::move(socket))->start();
+ }
+
+ do_accept();
+ });
+ }
+
+ tcp::acceptor acceptor_;
+};
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 2)
+ {
+ std::cerr << "Usage: third_party_lib <port>\n";
+ return 1;
+ }
+
+ asio::io_context io_context;
+
+ server s(io_context, std::atoi(argv[1]));
+
+ io_context.run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}