]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | // |
2 | // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) | |
3 | // | |
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | // Official repository: https://github.com/boostorg/beast | |
8 | // | |
9 | ||
10 | #ifndef BOOST_BEAST_DETAIL_IMPL_READ_HPP | |
11 | #define BOOST_BEAST_DETAIL_IMPL_READ_HPP | |
12 | ||
13 | #include <boost/beast/core/bind_handler.hpp> | |
14 | #include <boost/beast/core/async_base.hpp> | |
15 | #include <boost/beast/core/flat_static_buffer.hpp> | |
16 | #include <boost/beast/core/read_size.hpp> | |
17 | #include <boost/asio/basic_stream_socket.hpp> | |
18 | #include <boost/asio/coroutine.hpp> | |
19 | #include <boost/throw_exception.hpp> | |
20 | ||
21 | namespace boost { | |
22 | namespace beast { | |
23 | namespace detail { | |
24 | ||
25 | // The number of bytes in the stack buffer when using non-blocking. | |
26 | static std::size_t constexpr default_max_stack_buffer = 16384; | |
27 | ||
28 | //------------------------------------------------------------------------------ | |
29 | ||
30 | struct dynamic_read_ops | |
31 | { | |
32 | ||
33 | // read into a dynamic buffer until the | |
34 | // condition is met or an error occurs | |
35 | template< | |
36 | class Stream, | |
37 | class DynamicBuffer, | |
38 | class Condition, | |
39 | class Handler> | |
40 | class read_op | |
41 | : public asio::coroutine | |
42 | , public async_base< | |
43 | Handler, beast::executor_type<Stream>> | |
44 | { | |
45 | Stream& s_; | |
46 | DynamicBuffer& b_; | |
47 | Condition cond_; | |
48 | error_code ec_; | |
49 | std::size_t total_ = 0; | |
50 | ||
51 | public: | |
52 | read_op(read_op&&) = default; | |
53 | ||
54 | template<class Handler_, class Condition_> | |
55 | read_op( | |
56 | Handler_&& h, | |
57 | Stream& s, | |
58 | DynamicBuffer& b, | |
59 | Condition_&& cond) | |
60 | : async_base<Handler, | |
61 | beast::executor_type<Stream>>( | |
62 | std::forward<Handler_>(h), | |
63 | s.get_executor()) | |
64 | , s_(s) | |
65 | , b_(b) | |
66 | , cond_(std::forward<Condition_>(cond)) | |
67 | { | |
68 | (*this)({}, 0, false); | |
69 | } | |
70 | ||
71 | void | |
72 | operator()( | |
73 | error_code ec, | |
74 | std::size_t bytes_transferred, | |
75 | bool cont = true) | |
76 | { | |
77 | std::size_t max_prepare; | |
78 | BOOST_ASIO_CORO_REENTER(*this) | |
79 | { | |
80 | for(;;) | |
81 | { | |
82 | max_prepare = beast::read_size(b_, cond_(ec, total_, b_)); | |
83 | if(max_prepare == 0) | |
84 | break; | |
85 | BOOST_ASIO_CORO_YIELD | |
86 | s_.async_read_some( | |
87 | b_.prepare(max_prepare), std::move(*this)); | |
88 | b_.commit(bytes_transferred); | |
89 | total_ += bytes_transferred; | |
90 | } | |
91 | if(! cont) | |
92 | { | |
93 | // run this handler "as-if" using net::post | |
94 | // to reduce template instantiations | |
95 | ec_ = ec; | |
96 | BOOST_ASIO_CORO_YIELD | |
97 | s_.async_read_some( | |
98 | b_.prepare(0), std::move(*this)); | |
99 | ec = ec_; | |
100 | } | |
101 | this->complete_now(ec, total_); | |
102 | } | |
103 | } | |
104 | }; | |
105 | ||
106 | //------------------------------------------------------------------------------ | |
107 | ||
108 | struct run_read_op | |
109 | { | |
110 | template< | |
111 | class AsyncReadStream, | |
112 | class DynamicBuffer, | |
113 | class Condition, | |
114 | class ReadHandler> | |
115 | void | |
116 | operator()( | |
117 | ReadHandler&& h, | |
118 | AsyncReadStream* s, | |
119 | DynamicBuffer* b, | |
120 | Condition&& c) | |
121 | { | |
122 | // If you get an error on the following line it means | |
123 | // that your handler does not meet the documented type | |
124 | // requirements for the handler. | |
125 | ||
126 | static_assert( | |
127 | beast::detail::is_invocable<ReadHandler, | |
128 | void(error_code, std::size_t)>::value, | |
129 | "ReadHandler type requirements not met"); | |
130 | ||
131 | read_op< | |
132 | AsyncReadStream, | |
133 | DynamicBuffer, | |
134 | typename std::decay<Condition>::type, | |
135 | typename std::decay<ReadHandler>::type>( | |
136 | std::forward<ReadHandler>(h), | |
137 | *s, | |
138 | *b, | |
139 | std::forward<Condition>(c)); | |
140 | } | |
141 | ||
142 | }; | |
143 | ||
144 | }; | |
145 | ||
146 | //------------------------------------------------------------------------------ | |
147 | ||
148 | template< | |
149 | class SyncReadStream, | |
150 | class DynamicBuffer, | |
151 | class CompletionCondition, | |
152 | class> | |
153 | std::size_t | |
154 | read( | |
155 | SyncReadStream& stream, | |
156 | DynamicBuffer& buffer, | |
157 | CompletionCondition cond) | |
158 | { | |
159 | static_assert(is_sync_read_stream<SyncReadStream>::value, | |
160 | "SyncReadStream type requirements not met"); | |
161 | static_assert( | |
162 | net::is_dynamic_buffer<DynamicBuffer>::value, | |
163 | "DynamicBuffer type requirements not met"); | |
164 | static_assert( | |
165 | detail::is_invocable<CompletionCondition, | |
166 | void(error_code&, std::size_t, DynamicBuffer&)>::value, | |
167 | "CompletionCondition type requirements not met"); | |
168 | error_code ec; | |
169 | auto const bytes_transferred = detail::read( | |
170 | stream, buffer, std::move(cond), ec); | |
171 | if(ec) | |
172 | BOOST_THROW_EXCEPTION(system_error{ec}); | |
173 | return bytes_transferred; | |
174 | } | |
175 | ||
176 | template< | |
177 | class SyncReadStream, | |
178 | class DynamicBuffer, | |
179 | class CompletionCondition, | |
180 | class> | |
181 | std::size_t | |
182 | read( | |
183 | SyncReadStream& stream, | |
184 | DynamicBuffer& buffer, | |
185 | CompletionCondition cond, | |
186 | error_code& ec) | |
187 | { | |
188 | static_assert(is_sync_read_stream<SyncReadStream>::value, | |
189 | "SyncReadStream type requirements not met"); | |
190 | static_assert( | |
191 | net::is_dynamic_buffer<DynamicBuffer>::value, | |
192 | "DynamicBuffer type requirements not met"); | |
193 | static_assert( | |
194 | detail::is_invocable<CompletionCondition, | |
195 | void(error_code&, std::size_t, DynamicBuffer&)>::value, | |
196 | "CompletionCondition type requirements not met"); | |
197 | ec = {}; | |
198 | std::size_t total = 0; | |
199 | std::size_t max_prepare; | |
200 | for(;;) | |
201 | { | |
202 | max_prepare = beast::read_size(buffer, cond(ec, total, buffer)); | |
203 | if(max_prepare == 0) | |
204 | break; | |
205 | std::size_t const bytes_transferred = | |
206 | stream.read_some(buffer.prepare(max_prepare), ec); | |
207 | buffer.commit(bytes_transferred); | |
208 | total += bytes_transferred; | |
209 | } | |
210 | return total; | |
211 | } | |
212 | ||
213 | template< | |
214 | class AsyncReadStream, | |
215 | class DynamicBuffer, | |
216 | class CompletionCondition, | |
20effc67 | 217 | BOOST_BEAST_ASYNC_TPARAM2 ReadHandler, |
92f5a8d4 TL |
218 | class> |
219 | BOOST_BEAST_ASYNC_RESULT2(ReadHandler) | |
220 | async_read( | |
221 | AsyncReadStream& stream, | |
222 | DynamicBuffer& buffer, | |
223 | CompletionCondition&& cond, | |
224 | ReadHandler&& handler) | |
225 | { | |
226 | static_assert(is_async_read_stream<AsyncReadStream>::value, | |
227 | "AsyncReadStream type requirements not met"); | |
228 | static_assert( | |
229 | net::is_dynamic_buffer<DynamicBuffer>::value, | |
230 | "DynamicBuffer type requirements not met"); | |
231 | static_assert( | |
232 | detail::is_invocable<CompletionCondition, | |
233 | void(error_code&, std::size_t, DynamicBuffer&)>::value, | |
234 | "CompletionCondition type requirements not met"); | |
235 | return net::async_initiate< | |
236 | ReadHandler, | |
237 | void(error_code, std::size_t)>( | |
238 | typename dynamic_read_ops::run_read_op{}, | |
239 | handler, | |
240 | &stream, | |
241 | &buffer, | |
242 | std::forward<CompletionCondition>(cond)); | |
243 | } | |
244 | ||
245 | } // detail | |
246 | } // beast | |
247 | } // boost | |
248 | ||
249 | #endif |