]> git.proxmox.com Git - ceph.git/blob - ceph/src/Beast/include/beast/websocket/impl/close.ipp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / Beast / include / beast / websocket / impl / close.ipp
1 //
2 // Copyright (c) 2013-2017 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
8 #ifndef BEAST_WEBSOCKET_IMPL_CLOSE_IPP
9 #define BEAST_WEBSOCKET_IMPL_CLOSE_IPP
10
11 #include <beast/core/handler_helpers.hpp>
12 #include <beast/core/handler_ptr.hpp>
13 #include <beast/core/static_streambuf.hpp>
14 #include <beast/core/stream_concepts.hpp>
15 #include <memory>
16
17 namespace beast {
18 namespace websocket {
19
20 //------------------------------------------------------------------------------
21
22 // send the close message and wait for the response
23 //
24 template<class NextLayer>
25 template<class Handler>
26 class stream<NextLayer>::close_op
27 {
28 using fb_type = detail::frame_streambuf;
29
30 struct data : op
31 {
32 bool cont;
33 stream<NextLayer>& ws;
34 close_reason cr;
35 fb_type fb;
36 int state = 0;
37
38 data(Handler& handler, stream<NextLayer>& ws_,
39 close_reason const& cr_)
40 : cont(beast_asio_helpers::
41 is_continuation(handler))
42 , ws(ws_)
43 , cr(cr_)
44 {
45 ws.template write_close<
46 static_streambuf>(fb, cr);
47 }
48 };
49
50 handler_ptr<data, Handler> d_;
51
52 public:
53 close_op(close_op&&) = default;
54 close_op(close_op const&) = default;
55
56 template<class DeducedHandler, class... Args>
57 close_op(DeducedHandler&& h,
58 stream<NextLayer>& ws, Args&&... args)
59 : d_(std::forward<DeducedHandler>(h),
60 ws, std::forward<Args>(args)...)
61 {
62 (*this)(error_code{}, false);
63 }
64
65 void operator()()
66 {
67 (*this)(error_code{});
68 }
69
70 void
71 operator()(error_code ec, std::size_t);
72
73 void
74 operator()(error_code ec, bool again = true);
75
76 friend
77 void* asio_handler_allocate(
78 std::size_t size, close_op* op)
79 {
80 return beast_asio_helpers::
81 allocate(size, op->d_.handler());
82 }
83
84 friend
85 void asio_handler_deallocate(
86 void* p, std::size_t size, close_op* op)
87 {
88 return beast_asio_helpers::
89 deallocate(p, size, op->d_.handler());
90 }
91
92 friend
93 bool asio_handler_is_continuation(close_op* op)
94 {
95 return op->d_->cont;
96 }
97
98 template<class Function>
99 friend
100 void asio_handler_invoke(Function&& f, close_op* op)
101 {
102 return beast_asio_helpers::
103 invoke(f, op->d_.handler());
104 }
105 };
106
107 template<class NextLayer>
108 template<class Handler>
109 void
110 stream<NextLayer>::close_op<Handler>::
111 operator()(error_code ec, std::size_t)
112 {
113 auto& d = *d_;
114 if(ec)
115 d.ws.failed_ = true;
116 (*this)(ec);
117 }
118
119 template<class NextLayer>
120 template<class Handler>
121 void
122 stream<NextLayer>::close_op<Handler>::
123 operator()(error_code ec, bool again)
124 {
125 auto& d = *d_;
126 d.cont = d.cont || again;
127 if(ec)
128 goto upcall;
129 for(;;)
130 {
131 switch(d.state)
132 {
133 case 0:
134 if(d.ws.wr_block_)
135 {
136 // suspend
137 d.state = 2;
138 d.ws.wr_op_.template emplace<
139 close_op>(std::move(*this));
140 return;
141 }
142 if(d.ws.failed_ || d.ws.wr_close_)
143 {
144 // call handler
145 d.ws.get_io_service().post(
146 bind_handler(std::move(*this),
147 boost::asio::error::operation_aborted));
148 return;
149 }
150 d.ws.wr_block_ = &d;
151 // [[fallthrough]]
152
153 case 1:
154 // send close frame
155 BOOST_ASSERT(d.ws.wr_block_ == &d);
156 d.state = 99;
157 d.ws.wr_close_ = true;
158 boost::asio::async_write(d.ws.stream_,
159 d.fb.data(), std::move(*this));
160 return;
161
162 case 2:
163 BOOST_ASSERT(! d.ws.wr_block_);
164 d.ws.wr_block_ = &d;
165 d.state = 3;
166 // The current context is safe but might not be
167 // the same as the one for this operation (since
168 // we are being called from a write operation).
169 // Call post to make sure we are invoked the same
170 // way as the final handler for this operation.
171 d.ws.get_io_service().post(
172 bind_handler(std::move(*this), ec));
173 return;
174
175 case 3:
176 BOOST_ASSERT(d.ws.wr_block_ == &d);
177 if(d.ws.failed_ || d.ws.wr_close_)
178 {
179 // call handler
180 ec = boost::asio::error::operation_aborted;
181 goto upcall;
182 }
183 d.state = 1;
184 break;
185
186 case 99:
187 goto upcall;
188 }
189 }
190 upcall:
191 if(d.ws.wr_block_ == &d)
192 d.ws.wr_block_ = nullptr;
193 d.ws.rd_op_.maybe_invoke() ||
194 d.ws.ping_op_.maybe_invoke();
195 d_.invoke(ec);
196 }
197
198 template<class NextLayer>
199 template<class CloseHandler>
200 typename async_completion<
201 CloseHandler, void(error_code)>::result_type
202 stream<NextLayer>::
203 async_close(close_reason const& cr, CloseHandler&& handler)
204 {
205 static_assert(is_AsyncStream<next_layer_type>::value,
206 "AsyncStream requirements not met");
207 beast::async_completion<
208 CloseHandler, void(error_code)
209 > completion{handler};
210 close_op<decltype(completion.handler)>{
211 completion.handler, *this, cr};
212 return completion.result.get();
213 }
214
215 template<class NextLayer>
216 void
217 stream<NextLayer>::
218 close(close_reason const& cr)
219 {
220 static_assert(is_SyncStream<next_layer_type>::value,
221 "SyncStream requirements not met");
222 error_code ec;
223 close(cr, ec);
224 if(ec)
225 throw system_error{ec};
226 }
227
228 template<class NextLayer>
229 void
230 stream<NextLayer>::
231 close(close_reason const& cr, error_code& ec)
232 {
233 static_assert(is_SyncStream<next_layer_type>::value,
234 "SyncStream requirements not met");
235 BOOST_ASSERT(! wr_close_);
236 wr_close_ = true;
237 detail::frame_streambuf fb;
238 write_close<static_streambuf>(fb, cr);
239 boost::asio::write(stream_, fb.data(), ec);
240 failed_ = ec != 0;
241 }
242
243 //------------------------------------------------------------------------------
244
245 } // websocket
246 } // beast
247
248 #endif