src/examples/cpp03/nonblocking/third_party_lib.cpp | src/examples/cpp11/nonblocking/third_party_lib.cpp |
⋮ | ⋮ |
1 | // | 1 | // |
2 | //·third_party_lib.cpp | 2 | //·third_party_lib.cpp |
3 | //·~~~~~~~~~~~~~~~~~~~ | 3 | //·~~~~~~~~~~~~~~~~~~~ |
4 | // | 4 | // |
5 | //·Copyright·(c)·2003-2022·Christopher·M.·Kohlhoff·(chris·at·kohlhoff·dot·com) | 5 | //·Copyright·(c)·2003-2022·Christopher·M.·Kohlhoff·(chris·at·kohlhoff·dot·com) |
6 | // | 6 | // |
7 | //·Distributed·under·the·Boost·Software·License,·Version·1.0.·(See·accompanying | 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) | 8 | //·file·LICENSE_1_0.txt·or·copy·at·http://www.boost.org/LICENSE_1_0.txt) |
9 | // | 9 | // |
10 | | 10 | |
11 | #include·<asio.hpp> | 11 | #include·<asio.hpp> |
12 | #include·<boost/array.hpp> | 12 | #include·<array> |
13 | #include·<boost/bind/bind.hpp> | |
14 | #include·<boost/shared_ptr.hpp> | |
15 | #include·<boost/enable_shared_from_this.hpp> | |
16 | #include·<iostream> | 13 | #include·<iostream> |
| 14 | #include·<memory> |
17 | | 15 | |
18 | using·asio::ip::tcp; | 16 | using·asio::ip::tcp; |
19 | | 17 | |
20 | namespace·third_party_lib·{ | 18 | namespace·third_party_lib·{ |
21 | | 19 | |
22 | //·Simulation·of·a·third·party·library·that·wants·to·perform·read·and·write | 20 | //·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 | 21 | //·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 | 22 | //·it·requires·a·read·or·write·operation,·and·notified·when·the·socket·is·ready |
25 | //·for·reading·or·writing. | 23 | //·for·reading·or·writing. |
26 | class·session | 24 | class·session |
27 | { | 25 | { |
28 | public: | 26 | public: |
29 | ··session(tcp::socket&·socket) | 27 | ··session(tcp::socket&·socket) |
30 | ····:·socket_(socket), | 28 | ····:·socket_(socket) |
31 | ······state_(reading) | |
32 | ··{ | 29 | ··{ |
33 | ··} | 30 | ··} |
34 | | 31 | |
35 | ··//·Returns·true·if·the·third·party·library·wants·to·be·notified·when·the | 32 | ··//·Returns·true·if·the·third·party·library·wants·to·be·notified·when·the |
36 | ··//·socket·is·ready·for·reading. | 33 | ··//·socket·is·ready·for·reading. |
37 | ··bool·want_read()·const | 34 | ··bool·want_read()·const |
38 | ··{ | 35 | ··{ |
39 | ····return·state_·==·reading; | 36 | ····return·state_·==·reading; |
40 | ··} | 37 | ··} |
41 | | 38 | |
42 | ··//·Notify·that·third·party·library·that·it·should·perform·its·read·operation. | 39 | ··//·Notify·that·third·party·library·that·it·should·perform·its·read·operation. |
43 | ··void·do_read(asio::error_code&·ec) | 40 | ··void·do_read(std::error_code&·ec) |
44 | ··{ | 41 | ··{ |
45 | ····if·(std::size_t·len·=·socket_.read_some(asio::buffer(data_),·ec)) | 42 | ····if·(std::size_t·len·=·socket_.read_some(asio::buffer(data_),·ec)) |
46 | ····{ | 43 | ····{ |
47 | ······write_buffer_·=·asio::buffer(data_,·len); | 44 | ······write_buffer_·=·asio::buffer(data_,·len); |
48 | ······state_·=·writing; | 45 | ······state_·=·writing; |
49 | ····} | 46 | ····} |
50 | ··} | 47 | ··} |
51 | | 48 | |
52 | ··//·Returns·true·if·the·third·party·library·wants·to·be·notified·when·the | 49 | ··//·Returns·true·if·the·third·party·library·wants·to·be·notified·when·the |
53 | ··//·socket·is·ready·for·writing. | 50 | ··//·socket·is·ready·for·writing. |
54 | ··bool·want_write()·const | 51 | ··bool·want_write()·const |
55 | ··{ | 52 | ··{ |
56 | ····return·state_·==·writing; | 53 | ····return·state_·==·writing; |
57 | ··} | 54 | ··} |
58 | | 55 | |
59 | ··//·Notify·that·third·party·library·that·it·should·perform·its·write·operation. | 56 | ··//·Notify·that·third·party·library·that·it·should·perform·its·write·operation. |
60 | ··void·do_write(asio::error_code&·ec) | 57 | ··void·do_write(std::error_code&·ec) |
61 | ··{ | 58 | ··{ |
62 | ····if·(std::size_t·len·=·socket_.write_some( | 59 | ····if·(std::size_t·len·=·socket_.write_some( |
63 | ··········asio::buffer(write_buffer_),·ec)) | 60 | ··········asio::buffer(write_buffer_),·ec)) |
64 | ····{ | 61 | ····{ |
65 | ······write_buffer_·=·write_buffer_·+·len; | 62 | ······write_buffer_·=·write_buffer_·+·len; |
66 | ······state_·=·asio::buffer_size(write_buffer_)·>·0·?·writing·:·reading; | 63 | ······state_·=·asio::buffer_size(write_buffer_)·>·0·?·writing·:·reading; |
67 | ····} | 64 | ····} |
68 | ··} | 65 | ··} |
69 | | 66 | |
70 | private: | 67 | private: |
71 | ··tcp::socket&·socket_; | 68 | ··tcp::socket&·socket_; |
72 | ··enum·{·reading,·writing·}·state_; | 69 | ··enum·{·reading,·writing·}·state_·=·reading; |
73 | ··boost::array<char,·128>·data_; | 70 | ··std::array<char,·128>·data_; |
74 | ··asio::const_buffer·write_buffer_; | 71 | ··asio::const_buffer·write_buffer_; |
75 | }; | 72 | }; |
76 | | 73 | |
77 | }·//·namespace·third_party_lib | 74 | }·//·namespace·third_party_lib |
78 | | 75 | |
79 | //·The·glue·between·asio's·sockets·and·the·third·party·library. | 76 | //·The·glue·between·asio's·sockets·and·the·third·party·library. |
80 | class·connection | 77 | class·connection |
81 | ··:·public·boost::enable_shared_from_this<connection> | 78 | ··:·public·std::enable_shared_from_this<connection> |
82 | { | 79 | { |
83 | public: | 80 | public: |
84 | ··typedef·boost::shared_ptr<connection>·pointer; | 81 | ··connection(tcp::socket·socket) |
85 | | 82 | ····:·socket_(std::move(socket)) |
86 | ··static·pointer·create(const·asio::any_io_executor&·ex) | |
87 | ··{ | |
88 | ····return·pointer(new·connection(ex)); | |
89 | ··} | |
90 | | |
91 | ··tcp::socket&·socket() | |
92 | ··{ | 83 | ··{ |
93 | ····return·socket_; | |
94 | ··} | 84 | ··} |
95 | | 85 | |
96 | ··void·start() | 86 | ··void·start() |
97 | ··{ | 87 | ··{ |
98 | ····//·Put·the·socket·into·non-blocking·mode. | 88 | ····//·Put·the·socket·into·non-blocking·mode. |
99 | ····socket_.non_blocking(true); | 89 | ····socket_.non_blocking(true); |
100 | | 90 | |
101 | ····start_operations(); | 91 | ····do_operations(); |
102 | ··} | 92 | ··} |
103 | | 93 | |
104 | private: | 94 | private: |
105 | ··connection(const·asio::any_io_executor&·ex) | 95 | ··void·do_operations() |
106 | ····:·socket_(ex), | |
107 | ······session_impl_(socket_), | |
108 | ······read_in_progress_(false), | |
109 | ······write_in_progress_(false) | |
110 | ··{ | 96 | ··{ |
111 | ··} | 97 | ····auto·self(shared_from_this()); |
112 | | 98 | |
113 | ··void·start_operations() | |
114 | ··{ | |
115 | ····//·Start·a·read·operation·if·the·third·party·library·wants·one. | 99 | ····//·Start·a·read·operation·if·the·third·party·library·wants·one. |
116 | ····if·(session_impl_.want_read()·&&·!read_in_progress_) | 100 | ····if·(session_impl_.want_read()·&&·!read_in_progress_) |
117 | ····{ | 101 | ····{ |
118 | ······read_in_progress_·=·true; | 102 | ······read_in_progress_·=·true; |
119 | ······socket_.async_wait(tcp::socket::wait_read, | 103 | ······socket_.async_wait(tcp::socket::wait_read, |
120 | ··········boost::bind(&connection::handle_read, | 104 | ··········[this,·self](std::error_code·ec) |
121 | ············shared_from_this(), | 105 | ··········{ |
122 | ············asio::placeholders::error)); | 106 | ············read_in_progress_·=·false; |
| 107 | |
| 108 | ············//·Notify·third·party·library·that·it·can·perform·a·read. |
| 109 | ············if·(!ec) |
| 110 | ··············session_impl_.do_read(ec); |
| 111 | |
| 112 | ············//·The·third·party·library·successfully·performed·a·read·on·the |
| 113 | ············//·socket.·Start·new·read·or·write·operations·based·on·what·it·now |
| 114 | ············//·wants. |
| 115 | ············if·(!ec·||·ec·==·asio::error::would_block) |
| 116 | ··············do_operations(); |
| 117 | |
| 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. |
| 122 | ············else |
| 123 | ··············socket_.close(); |
| 124 | ··········}); |
123 | ····} | 125 | ····} |
124 | | 126 | |
125 | ····//·Start·a·write·operation·if·the·third·party·library·wants·one. | 127 | ····//·Start·a·write·operation·if·the·third·party·library·wants·one. |
126 | ····if·(session_impl_.want_write()·&&·!write_in_progress_) | 128 | ····if·(session_impl_.want_write()·&&·!write_in_progress_) |
127 | ····{ | 129 | ····{ |
128 | ······write_in_progress_·=·true; | 130 | ······write_in_progress_·=·true; |
129 | ······socket_.async_wait(tcp::socket::wait_write, | 131 | ······socket_.async_wait(tcp::socket::wait_write, |
130 | ··········boost::bind(&connection::handle_write, | 132 | ··········[this,·self](std::error_code·ec) |
131 | ············shared_from_this(), | 133 | ··········{ |
132 | ············asio::placeholders::error)); | 134 | ············write_in_progress_·=·false; |
| 135 | |
| 136 | ············//·Notify·third·party·library·that·it·can·perform·a·write. |
| 137 | ············if·(!ec) |
| 138 | ··············session_impl_.do_write(ec); |
| 139 | |
| 140 | ············//·The·third·party·library·successfully·performed·a·write·on·the |
| 141 | ············//·socket.·Start·new·read·or·write·operations·based·on·what·it·now |
| 142 | ············//·wants. |
| 143 | ············if·(!ec·||·ec·==·asio::error::would_block) |
| 144 | ··············do_operations(); |
| 145 | |
| 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. |
| 150 | ············else |
| 151 | ··············socket_.close(); |
| 152 | ··········}); |
133 | ····} | 153 | ····} |
134 | ··} | 154 | ··} |
135 | | 155 | |
136 | ··void·handle_read(asio::error_code·ec) | |
137 | ··{ | |
138 | ····read_in_progress_·=·false; | |
139 | | |
140 | ····//·Notify·third·party·library·that·it·can·perform·a·read. | |
141 | ····if·(!ec) | |
142 | ······session_impl_.do_read(ec); | |
143 | | |
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·==·asio::error::would_block) | |
147 | ······start_operations(); | |
148 | | |
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. | |
152 | ····else | |
153 | ······socket_.close(); | |
154 | ··} | |
155 | | |
156 | ··void·handle_write(asio::error_code·ec) | |
157 | ··{ | |
158 | ····write_in_progress_·=·false; | |
159 | | |
160 | ····//·Notify·third·party·library·that·it·can·perform·a·write. | |
161 | ····if·(!ec) | |
162 | ······session_impl_.do_write(ec); | |
163 | | |
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·==·asio::error::would_block) | |
167 | ······start_operations(); | |
168 | | |
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. | |
172 | ····else | |
173 | ······socket_.close(); | |
174 | ··} | |
175 | | |
176 | private: | 156 | private: |
177 | ··tcp::socket·socket_; | 157 | ··tcp::socket·socket_; |
178 | ··third_party_lib::session·session_impl_; | 158 | ··third_party_lib::session·session_impl_{socket_}; |
179 | ··bool·read_in_progress_; | 159 | ··bool·read_in_progress_·=·false; |
180 | ··bool·write_in_progress_; | 160 | ··bool·write_in_progress_·=·false; |
181 | }; | 161 | }; |
182 | | 162 | |
183 | class·server | 163 | class·server |
184 | { | 164 | { |
185 | public: | 165 | public: |
186 | ··server(asio::io_context&·io_context,·unsigned·short·port) | 166 | ··server(asio::io_context&·io_context,·unsigned·short·port) |
187 | ····:·acceptor_(io_context,·tcp::endpoint(tcp::v4(),·port)) | 167 | ····:·acceptor_(io_context,·{tcp::v4(),·port}) |
188 | ··{ | 168 | ··{ |
189 | ····start_accept(); | 169 | ····do_accept(); |
190 | ··} | 170 | ··} |
191 | | 171 | |
192 | private: | 172 | private: |
193 | ··void·start_accept() | 173 | ··void·do_accept() |
194 | ··{ | 174 | ··{ |
195 | ····connection::pointer·new_connection·= | 175 | ····acceptor_.async_accept( |
196 | ······connection::create(acceptor_.get_executor()); | 176 | ········[this](std::error_code·ec,·tcp::socket·socket) |
197 | | 177 | ········{ |
198 | ····acceptor_.async_accept(new_connection->socket(), | 178 | ··········if·(!ec) |
199 | ········boost::bind(&server::handle_accept,·this,·new_connection, | 179 | ··········{ |
200 | ··········asio::placeholders::error)); | 180 | ············std::make_shared<connection>(std::move(socket))->start(); |
201 | ··} | 181 | ··········} |
202 | | |
203 | ··void·handle_accept(connection::pointer·new_connection, | |
204 | ······const·asio::error_code&·error) | |
205 | ··{ | |
206 | ····if·(!error) | |
207 | ····{ | |
208 | ······new_connection->start(); | |
209 | ····} | |
210 | | 182 | |
211 | ····start_accept(); | 183 | ··········do_accept(); |
| 184 | ········}); |
212 | ··} | 185 | ··} |
213 | | 186 | |
214 | ··tcp::acceptor·acceptor_; | 187 | ··tcp::acceptor·acceptor_; |
215 | }; | 188 | }; |
216 | | 189 | |
217 | int·main(int·argc,·char*·argv[]) | 190 | int·main(int·argc,·char*·argv[]) |
218 | { | 191 | { |
219 | ··try | 192 | ··try |
220 | ··{ | 193 | ··{ |
221 | ····if·(argc·!=·2) | 194 | ····if·(argc·!=·2) |
222 | ····{ | 195 | ····{ |
223 | ······std::cerr·<<·"Usage:·third_party_lib·<port>\n"; | 196 | ······std::cerr·<<·"Usage:·third_party_lib·<port>\n"; |
224 | ······return·1; | 197 | ······return·1; |
225 | ····} | 198 | ····} |
226 | | 199 | |
227 | ····asio::io_context·io_context; | 200 | ····asio::io_context·io_context; |
228 | | 201 | |
229 | ····using·namespace·std;·//·For·atoi. | 202 | ····server·s(io_context,·std::atoi(argv[1])); |
230 | ····server·s(io_context,·atoi(argv[1])); | |
231 | | 203 | |
232 | ····io_context.run(); | 204 | ····io_context.run(); |
233 | ··} | 205 | ··} |
234 | ··catch·(std::exception&·e) | 206 | ··catch·(std::exception&·e) |
235 | ··{ | 207 | ··{ |
236 | ····std::cerr·<<·"Exception:·"·<<·e.what()·<<·"\n"; | 208 | ····std::cerr·<<·"Exception:·"·<<·e.what()·<<·"\n"; |
237 | ··} | 209 | ··} |
238 | | 210 | |
239 | ··return·0; | 211 | ··return·0; |
240 | } | 212 | } |