]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #pragma once | |
5 | ||
9f95a23c | 6 | #include <seastar/core/gate.hh> |
11fdf7f2 | 7 | #include <seastar/core/reactor.hh> |
9f95a23c | 8 | #include <seastar/core/sharded.hh> |
11fdf7f2 TL |
9 | |
10 | #include "include/buffer.h" | |
11 | ||
9f95a23c TL |
12 | #include "crimson/common/log.h" |
13 | #include "Errors.h" | |
f67539c2 | 14 | #include "Fwd.h" |
9f95a23c TL |
15 | |
16 | #ifdef UNIT_TESTS_BUILT | |
17 | #include "Interceptor.h" | |
18 | #endif | |
19 | ||
20 | namespace crimson::net { | |
21 | ||
22 | class Socket; | |
23 | using SocketRef = std::unique_ptr<Socket>; | |
aee94f69 | 24 | using SocketFRef = seastar::foreign_ptr<SocketRef>; |
11fdf7f2 | 25 | |
aee94f69 | 26 | class Socket { |
9f95a23c TL |
27 | struct construct_tag {}; |
28 | ||
aee94f69 | 29 | public: |
f67539c2 TL |
30 | // if acceptor side, peer is using a different port (ephemeral_port) |
31 | // if connector side, I'm using a different port (ephemeral_port) | |
32 | enum class side_t { | |
33 | acceptor, | |
34 | connector | |
35 | }; | |
aee94f69 | 36 | Socket(seastar::connected_socket &&, side_t, uint16_t e_port, construct_tag); |
f67539c2 | 37 | |
aee94f69 | 38 | ~Socket(); |
9f95a23c | 39 | |
11fdf7f2 TL |
40 | Socket(Socket&& o) = delete; |
41 | ||
aee94f69 TL |
42 | seastar::shard_id get_shard_id() const { |
43 | return sid; | |
9f95a23c TL |
44 | } |
45 | ||
aee94f69 TL |
46 | side_t get_side() const { |
47 | return side; | |
11fdf7f2 | 48 | } |
aee94f69 TL |
49 | |
50 | uint16_t get_ephemeral_port() const { | |
51 | return ephemeral_port; | |
11fdf7f2 | 52 | } |
aee94f69 TL |
53 | |
54 | seastar::socket_address get_local_address() const { | |
55 | return socket.local_address(); | |
11fdf7f2 TL |
56 | } |
57 | ||
1e59de90 | 58 | bool is_shutdown() const { |
aee94f69 | 59 | assert(seastar::this_shard_id() == sid); |
1e59de90 TL |
60 | return socket_is_shutdown; |
61 | } | |
62 | ||
aee94f69 TL |
63 | // learn my ephemeral_port as connector. |
64 | // unfortunately, there's no way to identify which port I'm using as | |
65 | // connector with current seastar interface. | |
66 | void learn_ephemeral_port_as_connector(uint16_t port) { | |
67 | assert(side == side_t::connector && | |
68 | (ephemeral_port == 0 || ephemeral_port == port)); | |
69 | ephemeral_port = port; | |
70 | } | |
71 | ||
72 | /// read the requested number of bytes into a bufferlist | |
73 | seastar::future<bufferlist> read(size_t bytes); | |
74 | ||
75 | seastar::future<bufferptr> read_exactly(size_t bytes); | |
76 | ||
77 | seastar::future<> write(bufferlist); | |
78 | ||
79 | seastar::future<> flush(); | |
80 | ||
81 | seastar::future<> write_flush(bufferlist); | |
82 | ||
9f95a23c TL |
83 | // preemptively disable further reads or writes, can only be shutdown once. |
84 | void shutdown(); | |
85 | ||
11fdf7f2 | 86 | /// Socket can only be closed once. |
9f95a23c TL |
87 | seastar::future<> close(); |
88 | ||
aee94f69 TL |
89 | static seastar::future<SocketRef> |
90 | connect(const entity_addr_t& peer_addr); | |
1e59de90 | 91 | |
aee94f69 TL |
92 | /* |
93 | * test interfaces | |
94 | */ | |
1e59de90 TL |
95 | |
96 | // shutdown for tests | |
97 | void force_shutdown() { | |
aee94f69 | 98 | assert(seastar::this_shard_id() == sid); |
1e59de90 TL |
99 | socket.shutdown_input(); |
100 | socket.shutdown_output(); | |
101 | } | |
102 | ||
9f95a23c TL |
103 | // shutdown input_stream only, for tests |
104 | void force_shutdown_in() { | |
aee94f69 | 105 | assert(seastar::this_shard_id() == sid); |
9f95a23c TL |
106 | socket.shutdown_input(); |
107 | } | |
108 | ||
109 | // shutdown output_stream only, for tests | |
110 | void force_shutdown_out() { | |
aee94f69 | 111 | assert(seastar::this_shard_id() == sid); |
9f95a23c TL |
112 | socket.shutdown_output(); |
113 | } | |
114 | ||
aee94f69 | 115 | private: |
f67539c2 TL |
116 | const seastar::shard_id sid; |
117 | seastar::connected_socket socket; | |
118 | seastar::input_stream<char> in; | |
119 | seastar::output_stream<char> out; | |
1e59de90 | 120 | bool socket_is_shutdown; |
f67539c2 TL |
121 | side_t side; |
122 | uint16_t ephemeral_port; | |
123 | ||
124 | #ifndef NDEBUG | |
125 | bool closed = false; | |
126 | #endif | |
127 | ||
128 | /// buffer state for read() | |
129 | struct { | |
130 | bufferlist buffer; | |
131 | size_t remaining; | |
132 | } r; | |
133 | ||
9f95a23c | 134 | #ifdef UNIT_TESTS_BUILT |
aee94f69 | 135 | public: |
f67539c2 TL |
136 | void set_trap(bp_type_t type, bp_action_t action, socket_blocker* blocker_); |
137 | ||
aee94f69 TL |
138 | private: |
139 | seastar::future<> try_trap_pre(bp_action_t& trap); | |
140 | ||
141 | seastar::future<> try_trap_post(bp_action_t& trap); | |
142 | ||
9f95a23c TL |
143 | bp_action_t next_trap_read = bp_action_t::CONTINUE; |
144 | bp_action_t next_trap_write = bp_action_t::CONTINUE; | |
145 | socket_blocker* blocker = nullptr; | |
9f95a23c | 146 | |
9f95a23c | 147 | #endif |
aee94f69 | 148 | friend class ShardedServerSocket; |
9f95a23c TL |
149 | }; |
150 | ||
20effc67 TL |
151 | using listen_ertr = crimson::errorator< |
152 | crimson::ct_error::address_in_use, // The address is already bound | |
153 | crimson::ct_error::address_not_available // https://techoverflow.net/2021/08/06/how-i-fixed-python-oserror-errno-99-cannot-assign-requested-address/ | |
154 | >; | |
155 | ||
aee94f69 TL |
156 | class ShardedServerSocket |
157 | : public seastar::peering_sharded_service<ShardedServerSocket> { | |
158 | struct construct_tag {}; | |
9f95a23c | 159 | |
aee94f69 TL |
160 | public: |
161 | ShardedServerSocket( | |
162 | seastar::shard_id sid, | |
163 | bool dispatch_only_on_primary_sid, | |
164 | construct_tag); | |
9f95a23c | 165 | |
aee94f69 | 166 | ~ShardedServerSocket(); |
9f95a23c | 167 | |
aee94f69 TL |
168 | ShardedServerSocket(ShardedServerSocket&&) = delete; |
169 | ShardedServerSocket(const ShardedServerSocket&) = delete; | |
170 | ShardedServerSocket& operator=(ShardedServerSocket&&) = delete; | |
171 | ShardedServerSocket& operator=(const ShardedServerSocket&) = delete; | |
9f95a23c | 172 | |
aee94f69 TL |
173 | bool is_fixed_shard_dispatching() const { |
174 | return dispatch_only_on_primary_sid; | |
9f95a23c TL |
175 | } |
176 | ||
aee94f69 | 177 | listen_ertr::future<> listen(entity_addr_t addr); |
9f95a23c | 178 | |
aee94f69 TL |
179 | using accept_func_t = |
180 | std::function<seastar::future<>(SocketRef, entity_addr_t)>; | |
181 | seastar::future<> accept(accept_func_t &&_fn_accept); | |
9f95a23c | 182 | |
aee94f69 | 183 | seastar::future<> shutdown_destroy(); |
9f95a23c | 184 | |
aee94f69 TL |
185 | static seastar::future<ShardedServerSocket*> create( |
186 | bool dispatch_only_on_this_shard); | |
9f95a23c | 187 | |
aee94f69 TL |
188 | private: |
189 | const seastar::shard_id primary_sid; | |
190 | /// XXX: Remove once all infrastructure uses multi-core messenger | |
191 | const bool dispatch_only_on_primary_sid; | |
192 | entity_addr_t listen_addr; | |
193 | std::optional<seastar::server_socket> listener; | |
194 | seastar::gate shutdown_gate; | |
195 | accept_func_t fn_accept; | |
196 | ||
197 | using sharded_service_t = seastar::sharded<ShardedServerSocket>; | |
198 | std::unique_ptr<sharded_service_t> service; | |
11fdf7f2 TL |
199 | }; |
200 | ||
9f95a23c | 201 | } // namespace crimson::net |