1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
6 #include <seastar/core/shared_future.hh>
7 #include <seastar/core/sleep.hh>
9 #include "io_handler.h"
11 namespace crimson::net
{
13 class ProtocolV2 final
: public HandshakeListener
{
14 using AuthConnectionMetaRef
= seastar::lw_shared_ptr
<AuthConnectionMeta
>;
17 ProtocolV2(SocketConnection
&,
22 ProtocolV2(const ProtocolV2
&) = delete;
23 ProtocolV2(ProtocolV2
&&) = delete;
24 ProtocolV2
&operator=(const ProtocolV2
&) = delete;
25 ProtocolV2
&operator=(ProtocolV2
&&) = delete;
28 * as HandshakeListener
31 seastar::future
<> notify_out(
32 crosscore_t::seq_t cc_seq
) final
;
34 seastar::future
<> notify_out_fault(
35 crosscore_t::seq_t cc_seq
,
38 io_handler_state
) final
;
40 seastar::future
<> notify_mark_down(
41 crosscore_t::seq_t cc_seq
) final
;
44 * as ProtocolV2 to be called by SocketConnection
47 void start_connect(const entity_addr_t
& peer_addr
,
48 const entity_name_t
& peer_name
);
50 void start_accept(SocketFRef
&& socket
,
51 const entity_addr_t
& peer_addr
);
53 seastar::future
<> close_clean_yielded();
55 #ifdef UNIT_TESTS_BUILT
56 bool is_ready() const {
57 return state
== state_t::READY
;
60 bool is_standby() const {
61 return state
== state_t::STANDBY
;
64 bool is_closed_clean() const {
68 bool is_closed() const {
69 return state
== state_t::CLOSING
;
74 using io_state_t
= IOHandler::io_state_t
;
76 seastar::future
<> wait_switch_io_shard() {
77 if (pr_switch_io_shard
.has_value()) {
78 return pr_switch_io_shard
->get_shared_future();
80 return seastar::now();
84 seastar::future
<> wait_exit_io() {
85 if (pr_exit_io
.has_value()) {
86 return pr_exit_io
->get_shared_future();
88 assert(!need_exit_io
);
89 return seastar::now();
106 static const char *get_state_name(state_t state
) {
107 const char *const statenames
[] = {"NONE",
117 return statenames
[static_cast<int>(state
)];
120 void trigger_state_phase1(state_t new_state
);
122 void trigger_state_phase2(state_t new_state
, io_state_t new_io_state
);
124 void trigger_state(state_t new_state
, io_state_t new_io_state
) {
125 ceph_assert_always(!pr_switch_io_shard
.has_value());
126 trigger_state_phase1(new_state
);
127 trigger_state_phase2(new_state
, new_io_state
);
130 template <typename Func
, typename T
>
131 void gated_execute(const char *what
, T
&who
, Func
&&func
) {
132 gate
.dispatch_in_background(what
, who
, [this, &who
, &func
] {
133 if (!execution_done
.available()) {
134 // discard the unready future
135 gate
.dispatch_in_background(
136 "gated_execute_abandon",
138 [fut
=std::move(execution_done
)]() mutable {
139 return std::move(fut
);
143 seastar::promise
<> pr
;
144 execution_done
= pr
.get_future();
145 return seastar::futurize_invoke(std::forward
<Func
>(func
)
146 ).finally([pr
=std::move(pr
)]() mutable {
152 void fault(state_t expected_state
,
154 std::exception_ptr eptr
);
156 void reset_session(bool is_full
);
157 seastar::future
<std::tuple
<entity_type_t
, entity_addr_t
>>
158 banner_exchange(bool is_connect
);
160 enum class next_step_t
{
163 none
, // protocol should have been aborted or failed
166 // CONNECTING (client)
167 seastar::future
<> handle_auth_reply();
168 inline seastar::future
<> client_auth() {
169 std::vector
<uint32_t> empty
;
170 return client_auth(empty
);
172 seastar::future
<> client_auth(std::vector
<uint32_t> &allowed_methods
);
174 seastar::future
<next_step_t
> process_wait();
175 seastar::future
<next_step_t
> client_connect();
176 seastar::future
<next_step_t
> client_reconnect();
177 void execute_connecting();
179 // ACCEPTING (server)
180 seastar::future
<> _auth_bad_method(int r
);
181 seastar::future
<> _handle_auth_request(bufferlist
& auth_payload
, bool more
);
182 seastar::future
<> server_auth();
184 bool validate_peer_name(const entity_name_t
& peer_name
) const;
185 seastar::future
<next_step_t
> send_wait();
186 seastar::future
<next_step_t
> reuse_connection(ProtocolV2
* existing_proto
,
188 bool reconnect
=false,
192 seastar::future
<next_step_t
> handle_existing_connection(SocketConnectionRef existing_conn
);
193 seastar::future
<next_step_t
> server_connect();
195 seastar::future
<next_step_t
> read_reconnect();
196 seastar::future
<next_step_t
> send_retry(uint64_t connect_seq
);
197 seastar::future
<next_step_t
> send_retry_global(uint64_t global_seq
);
198 seastar::future
<next_step_t
> send_reset(bool full
);
199 seastar::future
<next_step_t
> server_reconnect();
201 void execute_accepting();
203 // CONNECTING/ACCEPTING
204 seastar::future
<> finish_auth();
207 void execute_establishing(SocketConnectionRef existing_conn
);
209 // ESTABLISHING/REPLACING (server)
210 seastar::future
<> send_server_ident();
212 // REPLACING (server)
213 void trigger_replacing(bool reconnect
,
215 FrameAssemblerV2::mover_t
&&mover
,
216 AuthConnectionMetaRef
&& new_auth_meta
,
217 uint64_t new_peer_global_seq
,
219 uint64_t new_client_cookie
,
220 entity_name_t new_peer_name
,
221 uint64_t new_conn_features
,
222 uint64_t new_peer_supported_features
,
224 uint64_t new_connect_seq
,
225 uint64_t new_msg_seq
);
228 void execute_ready();
231 void execute_standby();
234 void execute_wait(bool max_backoff
);
237 void execute_server_wait();
241 void do_close(bool is_dispatch_reset
,
242 std::optional
<std::function
<void()>> f_accept_new
=std::nullopt
);
245 SocketConnection
&conn
;
247 SocketMessenger
&messenger
;
249 IOHandler
&io_handler
;
251 // asynchronously populated from io_handler
252 io_handler_state io_states
;
254 crosscore_t crosscore
;
256 bool has_socket
= false;
258 // the socket exists and it is not shutdown
259 bool is_socket_valid
= false;
261 FrameAssemblerV2Ref frame_assembler
;
263 bool need_notify_out
= false;
265 std::optional
<seastar::shared_promise
<>> pr_switch_io_shard
;
267 bool need_exit_io
= false;
269 std::optional
<seastar::shared_promise
<>> pr_exit_io
;
271 AuthConnectionMetaRef auth_meta
;
273 crimson::common::Gated gate
;
275 seastar::shared_promise
<> pr_closed_clean
;
277 #ifdef UNIT_TESTS_BUILT
278 bool closed_clean
= false;
281 state_t state
= state_t::NONE
;
283 uint64_t peer_supported_features
= 0;
285 uint64_t client_cookie
= 0;
286 uint64_t server_cookie
= 0;
287 uint64_t global_seq
= 0;
288 uint64_t peer_global_seq
= 0;
289 uint64_t connect_seq
= 0;
291 seastar::future
<> execution_done
= seastar::now();
294 double last_dur_
= 0.0;
295 const SocketConnection
& conn
;
296 std::optional
<seastar::abort_source
> as
;
298 Timer(SocketConnection
& conn
) : conn(conn
) {}
299 double last_dur() const { return last_dur_
; }
300 seastar::future
<> backoff(double seconds
);
309 Timer protocol_timer
;
312 struct create_handlers_ret
{
313 std::unique_ptr
<ConnectionHandler
> io_handler
;
314 std::unique_ptr
<ProtocolV2
> protocol
;
316 inline create_handlers_ret
create_handlers(ChainedDispatchers
&dispatchers
, SocketConnection
&conn
) {
317 std::unique_ptr
<ConnectionHandler
> io_handler
= std::make_unique
<IOHandler
>(dispatchers
, conn
);
318 IOHandler
&io_handler_concrete
= static_cast<IOHandler
&>(*io_handler
);
319 auto protocol
= std::make_unique
<ProtocolV2
>(conn
, io_handler_concrete
);
320 io_handler_concrete
.set_handshake_listener(*protocol
);
321 return {std::move(io_handler
), std::move(protocol
)};
324 } // namespace crimson::net
326 #if FMT_VERSION >= 90000
327 template <> struct fmt::formatter
<crimson::net::ProtocolV2
> : fmt::ostream_formatter
{};