]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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_SSL_IPP_INCLUDED | |
9 | #define BEAST_WEBSOCKET_IMPL_SSL_IPP_INCLUDED | |
10 | ||
11 | #include <beast/core/async_completion.hpp> | |
12 | #include <beast/core/handler_helpers.hpp> | |
13 | #include <beast/core/handler_concepts.hpp> | |
14 | #include <beast/core/handler_ptr.hpp> | |
15 | ||
16 | namespace beast { | |
17 | namespace websocket { | |
18 | ||
19 | namespace detail { | |
20 | ||
21 | /* | |
22 | ||
23 | See | |
24 | http://stackoverflow.com/questions/32046034/what-is-the-proper-way-to-securely-disconnect-an-asio-ssl-socket/32054476#32054476 | |
25 | ||
26 | Behavior of ssl::stream regarding close_ | |
27 | ||
28 | If the remote host calls async_shutdown then the | |
29 | local host's async_read will complete with eof. | |
30 | ||
31 | If both hosts call async_shutdown then the calls | |
32 | to async_shutdown will complete with eof. | |
33 | ||
34 | */ | |
35 | template<class AsyncStream, class Handler> | |
36 | class teardown_ssl_op | |
37 | { | |
38 | using stream_type = | |
39 | boost::asio::ssl::stream<AsyncStream>; | |
40 | ||
41 | struct data | |
42 | { | |
43 | bool cont; | |
44 | stream_type& stream; | |
45 | int state = 0; | |
46 | ||
47 | data(Handler& handler, stream_type& stream_) | |
48 | : cont(beast_asio_helpers:: | |
49 | is_continuation(handler)) | |
50 | , stream(stream_) | |
51 | { | |
52 | } | |
53 | }; | |
54 | ||
55 | handler_ptr<data, Handler> d_; | |
56 | ||
57 | public: | |
58 | template<class DeducedHandler> | |
59 | explicit | |
60 | teardown_ssl_op( | |
61 | DeducedHandler&& h, stream_type& stream) | |
62 | : d_(std::forward<DeducedHandler>(h), stream) | |
63 | { | |
64 | (*this)(error_code{}, false); | |
65 | } | |
66 | ||
67 | void | |
68 | operator()(error_code ec, bool again = true); | |
69 | ||
70 | friend | |
71 | void* asio_handler_allocate(std::size_t size, | |
72 | teardown_ssl_op* op) | |
73 | { | |
74 | return beast_asio_helpers:: | |
75 | allocate(size, op->d_.handler()); | |
76 | } | |
77 | ||
78 | friend | |
79 | void asio_handler_deallocate(void* p, | |
80 | std::size_t size, teardown_ssl_op* op) | |
81 | { | |
82 | return beast_asio_helpers:: | |
83 | deallocate(p, size, op->d_.handler()); | |
84 | } | |
85 | ||
86 | friend | |
87 | bool asio_handler_is_continuation( | |
88 | teardown_ssl_op* op) | |
89 | { | |
90 | return op->d_->cont; | |
91 | } | |
92 | ||
93 | template<class Function> | |
94 | friend | |
95 | void asio_handler_invoke(Function&& f, | |
96 | teardown_ssl_op* op) | |
97 | { | |
98 | return beast_asio_helpers:: | |
99 | invoke(f, op->d_.handler()); | |
100 | } | |
101 | }; | |
102 | ||
103 | template<class AsyncStream, class Handler> | |
104 | void | |
105 | teardown_ssl_op<AsyncStream, Handler>:: | |
106 | operator()(error_code ec, bool again) | |
107 | { | |
108 | auto& d = *d_; | |
109 | d.cont = d.cont || again; | |
110 | while(!ec && d.state != 99) | |
111 | { | |
112 | switch(d.state) | |
113 | { | |
114 | case 0: | |
115 | d.state = 99; | |
116 | d.stream.async_shutdown(*this); | |
117 | return; | |
118 | } | |
119 | } | |
120 | d_.invoke(ec); | |
121 | } | |
122 | ||
123 | } // detail | |
124 | ||
125 | //------------------------------------------------------------------------------ | |
126 | ||
127 | template<class AsyncStream> | |
128 | void | |
129 | teardown(teardown_tag, | |
130 | boost::asio::ssl::stream<AsyncStream>& stream, | |
131 | error_code& ec) | |
132 | { | |
133 | stream.shutdown(ec); | |
134 | } | |
135 | ||
136 | template<class AsyncStream, class TeardownHandler> | |
137 | void | |
138 | async_teardown(teardown_tag, | |
139 | boost::asio::ssl::stream<AsyncStream>& stream, | |
140 | TeardownHandler&& handler) | |
141 | { | |
142 | static_assert(beast::is_CompletionHandler< | |
143 | TeardownHandler, void(error_code)>::value, | |
144 | "TeardownHandler requirements not met"); | |
145 | detail::teardown_ssl_op<AsyncStream, typename std::decay< | |
146 | TeardownHandler>::type>{std::forward<TeardownHandler>( | |
147 | handler), stream}; | |
148 | } | |
149 | ||
150 | } // websocket | |
151 | } // beast | |
152 | ||
153 | #endif |