5 // Copyright (c) 2003-2019 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>
12 #include <boost/array.hpp>
13 #include <boost/bind.hpp>
14 #include <boost/shared_ptr.hpp>
15 #include <boost/enable_shared_from_this.hpp>
18 using boost::asio::ip::tcp
;
20 namespace third_party_lib
{
22 // Simulation of a third party library that wants to perform read and write
23 // operations directly on a socket. It needs to be polled to determine whether
24 // it requires a read or write operation, and notified when the socket is ready
25 // for reading or writing.
29 session(tcp::socket
& socket
)
35 // Returns true if the third party library wants to be notified when the
36 // socket is ready for reading.
37 bool want_read() const
39 return state_
== reading
;
42 // Notify that third party library that it should perform its read operation.
43 void do_read(boost::system::error_code
& ec
)
45 if (std::size_t len
= socket_
.read_some(boost::asio::buffer(data_
), ec
))
47 write_buffer_
= boost::asio::buffer(data_
, len
);
52 // Returns true if the third party library wants to be notified when the
53 // socket is ready for writing.
54 bool want_write() const
56 return state_
== writing
;
59 // Notify that third party library that it should perform its write operation.
60 void do_write(boost::system::error_code
& ec
)
62 if (std::size_t len
= socket_
.write_some(
63 boost::asio::buffer(write_buffer_
), ec
))
65 write_buffer_
= write_buffer_
+ len
;
66 state_
= boost::asio::buffer_size(write_buffer_
) > 0 ? writing
: reading
;
72 enum { reading
, writing
} state_
;
73 boost::array
<char, 128> data_
;
74 boost::asio::const_buffer write_buffer_
;
77 } // namespace third_party_lib
79 // The glue between asio's sockets and the third party library.
81 : public boost::enable_shared_from_this
<connection
>
84 typedef boost::shared_ptr
<connection
> pointer
;
86 static pointer
create(const boost::asio::executor
& ex
)
88 return pointer(new connection(ex
));
98 // Put the socket into non-blocking mode.
99 socket_
.non_blocking(true);
105 connection(const boost::asio::executor
& ex
)
107 session_impl_(socket_
),
108 read_in_progress_(false),
109 write_in_progress_(false)
113 void start_operations()
115 // Start a read operation if the third party library wants one.
116 if (session_impl_
.want_read() && !read_in_progress_
)
118 read_in_progress_
= true;
119 socket_
.async_wait(tcp::socket::wait_read
,
120 boost::bind(&connection::handle_read
,
122 boost::asio::placeholders::error
));
125 // Start a write operation if the third party library wants one.
126 if (session_impl_
.want_write() && !write_in_progress_
)
128 write_in_progress_
= true;
129 socket_
.async_wait(tcp::socket::wait_write
,
130 boost::bind(&connection::handle_write
,
132 boost::asio::placeholders::error
));
136 void handle_read(boost::system::error_code ec
)
138 read_in_progress_
= false;
140 // Notify third party library that it can perform a read.
142 session_impl_
.do_read(ec
);
144 // The third party library successfully performed a read on the socket.
145 // Start new read or write operations based on what it now wants.
146 if (!ec
|| ec
== boost::asio::error::would_block
)
149 // Otherwise, an error occurred. Closing the socket cancels any outstanding
150 // asynchronous read or write operations. The connection object will be
151 // destroyed automatically once those outstanding operations complete.
156 void handle_write(boost::system::error_code ec
)
158 write_in_progress_
= false;
160 // Notify third party library that it can perform a write.
162 session_impl_
.do_write(ec
);
164 // The third party library successfully performed a write on the socket.
165 // Start new read or write operations based on what it now wants.
166 if (!ec
|| ec
== boost::asio::error::would_block
)
169 // Otherwise, an error occurred. Closing the socket cancels any outstanding
170 // asynchronous read or write operations. The connection object will be
171 // destroyed automatically once those outstanding operations complete.
178 third_party_lib::session session_impl_
;
179 bool read_in_progress_
;
180 bool write_in_progress_
;
186 server(boost::asio::io_context
& io_context
, unsigned short port
)
187 : acceptor_(io_context
, tcp::endpoint(tcp::v4(), port
))
195 connection::pointer new_connection
=
196 connection::create(acceptor_
.get_executor());
198 acceptor_
.async_accept(new_connection
->socket(),
199 boost::bind(&server::handle_accept
, this, new_connection
,
200 boost::asio::placeholders::error
));
203 void handle_accept(connection::pointer new_connection
,
204 const boost::system::error_code
& error
)
208 new_connection
->start();
214 tcp::acceptor acceptor_
;
217 int main(int argc
, char* argv
[])
223 std::cerr
<< "Usage: third_party_lib <port>\n";
227 boost::asio::io_context io_context
;
229 using namespace std
; // For atoi.
230 server
s(io_context
, atoi(argv
[1]));
234 catch (std::exception
& e
)
236 std::cerr
<< "Exception: " << e
.what() << "\n";