]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/beast/websocket/impl/ping.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / beast / websocket / impl / ping.hpp
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_WEBSOCKET_IMPL_PING_HPP
11 #define BOOST_BEAST_WEBSOCKET_IMPL_PING_HPP
12
13 #include <boost/beast/core/async_base.hpp>
14 #include <boost/beast/core/bind_handler.hpp>
15 #include <boost/beast/core/stream_traits.hpp>
16 #include <boost/beast/core/detail/bind_continuation.hpp>
17 #include <boost/beast/websocket/detail/frame.hpp>
18 #include <boost/beast/websocket/impl/stream_impl.hpp>
19 #include <boost/asio/coroutine.hpp>
20 #include <boost/asio/post.hpp>
21 #include <boost/throw_exception.hpp>
22 #include <memory>
23
24 namespace boost {
25 namespace beast {
26 namespace websocket {
27
28 /*
29 This composed operation handles sending ping and pong frames.
30 It only sends the frames it does not make attempts to read
31 any frame data.
32 */
33 template<class NextLayer, bool deflateSupported>
34 template<class Handler>
35 class stream<NextLayer, deflateSupported>::ping_op
36 : public beast::stable_async_base<
37 Handler, beast::executor_type<stream>>
38 , public asio::coroutine
39 {
40 boost::weak_ptr<impl_type> wp_;
41 detail::frame_buffer& fb_;
42
43 public:
44 static constexpr int id = 3; // for soft_mutex
45
46 template<class Handler_>
47 ping_op(
48 Handler_&& h,
49 boost::shared_ptr<impl_type> const& sp,
50 detail::opcode op,
51 ping_data const& payload)
52 : stable_async_base<Handler,
53 beast::executor_type<stream>>(
54 std::forward<Handler_>(h),
55 sp->stream().get_executor())
56 , wp_(sp)
57 , fb_(beast::allocate_stable<
58 detail::frame_buffer>(*this))
59 {
60 // Serialize the ping or pong frame
61 sp->template write_ping<
62 flat_static_buffer_base>(fb_, op, payload);
63 (*this)({}, 0, false);
64 }
65
66 void operator()(
67 error_code ec = {},
68 std::size_t bytes_transferred = 0,
69 bool cont = true)
70 {
71 boost::ignore_unused(bytes_transferred);
72 auto sp = wp_.lock();
73 if(! sp)
74 {
75 ec = net::error::operation_aborted;
76 return this->complete(cont, ec);
77 }
78 auto& impl = *sp;
79 BOOST_ASIO_CORO_REENTER(*this)
80 {
81 // Acquire the write lock
82 if(! impl.wr_block.try_lock(this))
83 {
84 BOOST_ASIO_CORO_YIELD
85 impl.op_ping.emplace(std::move(*this));
86 impl.wr_block.lock(this);
87 BOOST_ASIO_CORO_YIELD
88 net::post(std::move(*this));
89 BOOST_ASSERT(impl.wr_block.is_locked(this));
90 }
91 if(impl.check_stop_now(ec))
92 goto upcall;
93
94 // Send ping frame
95 BOOST_ASIO_CORO_YIELD
96 net::async_write(impl.stream(), fb_.data(),
97 beast::detail::bind_continuation(std::move(*this)));
98 if(impl.check_stop_now(ec))
99 goto upcall;
100
101 upcall:
102 impl.wr_block.unlock(this);
103 impl.op_close.maybe_invoke()
104 || impl.op_idle_ping.maybe_invoke()
105 || impl.op_rd.maybe_invoke()
106 || impl.op_wr.maybe_invoke();
107 this->complete(cont, ec);
108 }
109 }
110 };
111
112 //------------------------------------------------------------------------------
113
114 // sends the idle ping
115 template<class NextLayer, bool deflateSupported>
116 template<class Executor>
117 class stream<NextLayer, deflateSupported>::idle_ping_op
118 : public asio::coroutine
119 , public boost::empty_value<Executor>
120 {
121 boost::weak_ptr<impl_type> wp_;
122 std::unique_ptr<detail::frame_buffer> fb_;
123
124 public:
125 static constexpr int id = 4; // for soft_mutex
126
127 using executor_type = Executor;
128
129 executor_type
130 get_executor() const noexcept
131 {
132 return this->get();
133 }
134
135 idle_ping_op(
136 boost::shared_ptr<impl_type> const& sp,
137 Executor const& ex)
138 : boost::empty_value<Executor>(
139 boost::empty_init_t{}, ex)
140 , wp_(sp)
141 , fb_(new detail::frame_buffer)
142 {
143 if(! sp->idle_pinging)
144 {
145 // Create the ping frame
146 ping_data payload; // empty for now
147 sp->template write_ping<
148 flat_static_buffer_base>(*fb_,
149 detail::opcode::ping, payload);
150
151 sp->idle_pinging = true;
152 (*this)({}, 0);
153 }
154 else
155 {
156 // if we are already in the middle of sending
157 // an idle ping, don't bother sending another.
158 }
159 }
160
161 void operator()(
162 error_code ec = {},
163 std::size_t bytes_transferred = 0)
164 {
165 boost::ignore_unused(bytes_transferred);
166 auto sp = wp_.lock();
167 if(! sp)
168 return;
169 auto& impl = *sp;
170 BOOST_ASIO_CORO_REENTER(*this)
171 {
172 // Acquire the write lock
173 if(! impl.wr_block.try_lock(this))
174 {
175 BOOST_ASIO_CORO_YIELD
176 impl.op_idle_ping.emplace(std::move(*this));
177 impl.wr_block.lock(this);
178 BOOST_ASIO_CORO_YIELD
179 net::post(
180 this->get_executor(), std::move(*this));
181 BOOST_ASSERT(impl.wr_block.is_locked(this));
182 }
183 if(impl.check_stop_now(ec))
184 goto upcall;
185
186 // Send ping frame
187 BOOST_ASIO_CORO_YIELD
188 net::async_write(impl.stream(), fb_->data(),
189 //beast::detail::bind_continuation(std::move(*this)));
190 std::move(*this));
191 if(impl.check_stop_now(ec))
192 goto upcall;
193
194 upcall:
195 BOOST_ASSERT(sp->idle_pinging);
196 sp->idle_pinging = false;
197 impl.wr_block.unlock(this);
198 impl.op_close.maybe_invoke()
199 || impl.op_ping.maybe_invoke()
200 || impl.op_rd.maybe_invoke()
201 || impl.op_wr.maybe_invoke();
202 }
203 }
204 };
205
206 template<class NextLayer, bool deflateSupported>
207 struct stream<NextLayer, deflateSupported>::
208 run_ping_op
209 {
210 template<class WriteHandler>
211 void
212 operator()(
213 WriteHandler&& h,
214 boost::shared_ptr<impl_type> const& sp,
215 detail::opcode op,
216 ping_data const& p)
217 {
218 // If you get an error on the following line it means
219 // that your handler does not meet the documented type
220 // requirements for the handler.
221
222 static_assert(
223 beast::detail::is_invocable<WriteHandler,
224 void(error_code)>::value,
225 "WriteHandler type requirements not met");
226
227 ping_op<
228 typename std::decay<WriteHandler>::type>(
229 std::forward<WriteHandler>(h),
230 sp,
231 op,
232 p);
233 }
234 };
235
236 //------------------------------------------------------------------------------
237
238 template<class NextLayer, bool deflateSupported>
239 void
240 stream<NextLayer, deflateSupported>::
241 ping(ping_data const& payload)
242 {
243 error_code ec;
244 ping(payload, ec);
245 if(ec)
246 BOOST_THROW_EXCEPTION(system_error{ec});
247 }
248
249 template<class NextLayer, bool deflateSupported>
250 void
251 stream<NextLayer, deflateSupported>::
252 ping(ping_data const& payload, error_code& ec)
253 {
254 if(impl_->check_stop_now(ec))
255 return;
256 detail::frame_buffer fb;
257 impl_->template write_ping<flat_static_buffer_base>(
258 fb, detail::opcode::ping, payload);
259 net::write(impl_->stream(), fb.data(), ec);
260 if(impl_->check_stop_now(ec))
261 return;
262 }
263
264 template<class NextLayer, bool deflateSupported>
265 void
266 stream<NextLayer, deflateSupported>::
267 pong(ping_data const& payload)
268 {
269 error_code ec;
270 pong(payload, ec);
271 if(ec)
272 BOOST_THROW_EXCEPTION(system_error{ec});
273 }
274
275 template<class NextLayer, bool deflateSupported>
276 void
277 stream<NextLayer, deflateSupported>::
278 pong(ping_data const& payload, error_code& ec)
279 {
280 if(impl_->check_stop_now(ec))
281 return;
282 detail::frame_buffer fb;
283 impl_->template write_ping<flat_static_buffer_base>(
284 fb, detail::opcode::pong, payload);
285 net::write(impl_->stream(), fb.data(), ec);
286 if(impl_->check_stop_now(ec))
287 return;
288 }
289
290 template<class NextLayer, bool deflateSupported>
291 template<class WriteHandler>
292 BOOST_BEAST_ASYNC_RESULT1(WriteHandler)
293 stream<NextLayer, deflateSupported>::
294 async_ping(ping_data const& payload, WriteHandler&& handler)
295 {
296 static_assert(is_async_stream<next_layer_type>::value,
297 "AsyncStream type requirements not met");
298 return net::async_initiate<
299 WriteHandler,
300 void(error_code)>(
301 run_ping_op{},
302 handler,
303 impl_,
304 detail::opcode::ping,
305 payload);
306 }
307
308 template<class NextLayer, bool deflateSupported>
309 template<class WriteHandler>
310 BOOST_BEAST_ASYNC_RESULT1(WriteHandler)
311 stream<NextLayer, deflateSupported>::
312 async_pong(ping_data const& payload, WriteHandler&& handler)
313 {
314 static_assert(is_async_stream<next_layer_type>::value,
315 "AsyncStream type requirements not met");
316 return net::async_initiate<
317 WriteHandler,
318 void(error_code)>(
319 run_ping_op{},
320 handler,
321 impl_,
322 detail::opcode::pong,
323 payload);
324 }
325
326 } // websocket
327 } // beast
328 } // boost
329
330 #endif