5 // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11 #include <boost/asio.hpp>
16 using boost::asio::ip::tcp
;
18 namespace third_party_lib
{
20 // Simulation of a third party library that wants to perform read and write
21 // operations directly on a socket. It needs to be polled to determine whether
22 // it requires a read or write operation, and notified when the socket is ready
23 // for reading or writing.
27 session(tcp::socket
& socket
)
32 // Returns true if the third party library wants to be notified when the
33 // socket is ready for reading.
34 bool want_read() const
36 return state_
== reading
;
39 // Notify that third party library that it should perform its read operation.
40 void do_read(boost::system::error_code
& ec
)
42 if (std::size_t len
= socket_
.read_some(boost::asio::buffer(data_
), ec
))
44 write_buffer_
= boost::asio::buffer(data_
, len
);
49 // Returns true if the third party library wants to be notified when the
50 // socket is ready for writing.
51 bool want_write() const
53 return state_
== writing
;
56 // Notify that third party library that it should perform its write operation.
57 void do_write(boost::system::error_code
& ec
)
59 if (std::size_t len
= socket_
.write_some(
60 boost::asio::buffer(write_buffer_
), ec
))
62 write_buffer_
= write_buffer_
+ len
;
63 state_
= boost::asio::buffer_size(write_buffer_
) > 0 ? writing
: reading
;
69 enum { reading
, writing
} state_
= reading
;
70 std::array
<char, 128> data_
;
71 boost::asio::const_buffer write_buffer_
;
74 } // namespace third_party_lib
76 // The glue between asio's sockets and the third party library.
78 : public std::enable_shared_from_this
<connection
>
81 connection(tcp::socket socket
)
82 : socket_(std::move(socket
))
88 // Put the socket into non-blocking mode.
89 socket_
.non_blocking(true);
97 auto self(shared_from_this());
99 // Start a read operation if the third party library wants one.
100 if (session_impl_
.want_read() && !read_in_progress_
)
102 read_in_progress_
= true;
103 socket_
.async_wait(tcp::socket::wait_read
,
104 [this, self
](boost::system::error_code ec
)
106 read_in_progress_
= false;
108 // Notify third party library that it can perform a read.
110 session_impl_
.do_read(ec
);
112 // The third party library successfully performed a read on the
113 // socket. Start new read or write operations based on what it now
115 if (!ec
|| ec
== boost::asio::error::would_block
)
118 // Otherwise, an error occurred. Closing the socket cancels any
119 // outstanding asynchronous read or write operations. The
120 // connection object will be destroyed automatically once those
121 // outstanding operations complete.
127 // Start a write operation if the third party library wants one.
128 if (session_impl_
.want_write() && !write_in_progress_
)
130 write_in_progress_
= true;
131 socket_
.async_wait(tcp::socket::wait_write
,
132 [this, self
](boost::system::error_code ec
)
134 write_in_progress_
= false;
136 // Notify third party library that it can perform a write.
138 session_impl_
.do_write(ec
);
140 // The third party library successfully performed a write on the
141 // socket. Start new read or write operations based on what it now
143 if (!ec
|| ec
== boost::asio::error::would_block
)
146 // Otherwise, an error occurred. Closing the socket cancels any
147 // outstanding asynchronous read or write operations. The
148 // connection object will be destroyed automatically once those
149 // outstanding operations complete.
158 third_party_lib::session session_impl_
{socket_
};
159 bool read_in_progress_
= false;
160 bool write_in_progress_
= false;
166 server(boost::asio::io_context
& io_context
, unsigned short port
)
167 : acceptor_(io_context
, {tcp::v4(), port
})
175 acceptor_
.async_accept(
176 [this](boost::system::error_code ec
, tcp::socket socket
)
180 std::make_shared
<connection
>(std::move(socket
))->start();
187 tcp::acceptor acceptor_
;
190 int main(int argc
, char* argv
[])
196 std::cerr
<< "Usage: third_party_lib <port>\n";
200 boost::asio::io_context io_context
;
202 server
s(io_context
, std::atoi(argv
[1]));
206 catch (std::exception
& e
)
208 std::cerr
<< "Exception: " << e
.what() << "\n";