2 // Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
8 #ifndef BEAST_WEBSOCKET_IMPL_CLOSE_IPP
9 #define BEAST_WEBSOCKET_IMPL_CLOSE_IPP
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>
20 //------------------------------------------------------------------------------
22 // send the close message and wait for the response
24 template<class NextLayer>
25 template<class Handler>
26 class stream<NextLayer>::close_op
28 using fb_type = detail::frame_streambuf;
33 stream<NextLayer>& ws;
38 data(Handler& handler, stream<NextLayer>& ws_,
39 close_reason const& cr_)
40 : cont(beast_asio_helpers::
41 is_continuation(handler))
45 ws.template write_close<
46 static_streambuf>(fb, cr);
50 handler_ptr<data, Handler> d_;
53 close_op(close_op&&) = default;
54 close_op(close_op const&) = default;
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)...)
62 (*this)(error_code{}, false);
67 (*this)(error_code{});
71 operator()(error_code ec, std::size_t);
74 operator()(error_code ec, bool again = true);
77 void* asio_handler_allocate(
78 std::size_t size, close_op* op)
80 return beast_asio_helpers::
81 allocate(size, op->d_.handler());
85 void asio_handler_deallocate(
86 void* p, std::size_t size, close_op* op)
88 return beast_asio_helpers::
89 deallocate(p, size, op->d_.handler());
93 bool asio_handler_is_continuation(close_op* op)
98 template<class Function>
100 void asio_handler_invoke(Function&& f, close_op* op)
102 return beast_asio_helpers::
103 invoke(f, op->d_.handler());
107 template<class NextLayer>
108 template<class Handler>
110 stream<NextLayer>::close_op<Handler>::
111 operator()(error_code ec, std::size_t)
119 template<class NextLayer>
120 template<class Handler>
122 stream<NextLayer>::close_op<Handler>::
123 operator()(error_code ec, bool again)
126 d.cont = d.cont || again;
138 d.ws.wr_op_.template emplace<
139 close_op>(std::move(*this));
142 if(d.ws.failed_ || d.ws.wr_close_)
145 d.ws.get_io_service().post(
146 bind_handler(std::move(*this),
147 boost::asio::error::operation_aborted));
155 BOOST_ASSERT(d.ws.wr_block_ == &d);
157 d.ws.wr_close_ = true;
158 boost::asio::async_write(d.ws.stream_,
159 d.fb.data(), std::move(*this));
163 BOOST_ASSERT(! d.ws.wr_block_);
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));
176 BOOST_ASSERT(d.ws.wr_block_ == &d);
177 if(d.ws.failed_ || d.ws.wr_close_)
180 ec = boost::asio::error::operation_aborted;
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();
198 template<class NextLayer>
199 template<class CloseHandler>
200 typename async_completion<
201 CloseHandler, void(error_code)>::result_type
203 async_close(close_reason const& cr, CloseHandler&& handler)
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();
215 template<class NextLayer>
218 close(close_reason const& cr)
220 static_assert(is_SyncStream<next_layer_type>::value,
221 "SyncStream requirements not met");
225 throw system_error{ec};
228 template<class NextLayer>
231 close(close_reason const& cr, error_code& ec)
233 static_assert(is_SyncStream<next_layer_type>::value,
234 "SyncStream requirements not met");
235 BOOST_ASSERT(! wr_close_);
237 detail::frame_streambuf fb;
238 write_close<static_streambuf>(fb, cr);
239 boost::asio::write(stream_, fb.data(), ec);
243 //------------------------------------------------------------------------------