blob: 271e82e42ecc5a64f4f3e39142f294eb800a6524 [file] [log] [blame]
Victor Boivieb6580cc2021-04-08 09:56:59 +02001/*
2 * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10#ifndef NET_DCSCTP_SOCKET_DCSCTP_SOCKET_H_
11#define NET_DCSCTP_SOCKET_DCSCTP_SOCKET_H_
12
13#include <cstdint>
14#include <memory>
15#include <string>
16#include <utility>
17
18#include "absl/strings/string_view.h"
19#include "api/array_view.h"
20#include "net/dcsctp/packet/chunk/abort_chunk.h"
21#include "net/dcsctp/packet/chunk/chunk.h"
22#include "net/dcsctp/packet/chunk/cookie_ack_chunk.h"
23#include "net/dcsctp/packet/chunk/cookie_echo_chunk.h"
24#include "net/dcsctp/packet/chunk/data_chunk.h"
25#include "net/dcsctp/packet/chunk/data_common.h"
26#include "net/dcsctp/packet/chunk/error_chunk.h"
27#include "net/dcsctp/packet/chunk/forward_tsn_chunk.h"
28#include "net/dcsctp/packet/chunk/forward_tsn_common.h"
29#include "net/dcsctp/packet/chunk/heartbeat_ack_chunk.h"
30#include "net/dcsctp/packet/chunk/heartbeat_request_chunk.h"
31#include "net/dcsctp/packet/chunk/idata_chunk.h"
32#include "net/dcsctp/packet/chunk/iforward_tsn_chunk.h"
33#include "net/dcsctp/packet/chunk/init_ack_chunk.h"
34#include "net/dcsctp/packet/chunk/init_chunk.h"
35#include "net/dcsctp/packet/chunk/reconfig_chunk.h"
36#include "net/dcsctp/packet/chunk/sack_chunk.h"
37#include "net/dcsctp/packet/chunk/shutdown_ack_chunk.h"
38#include "net/dcsctp/packet/chunk/shutdown_chunk.h"
39#include "net/dcsctp/packet/chunk/shutdown_complete_chunk.h"
40#include "net/dcsctp/packet/data.h"
41#include "net/dcsctp/packet/sctp_packet.h"
42#include "net/dcsctp/public/dcsctp_message.h"
43#include "net/dcsctp/public/dcsctp_options.h"
44#include "net/dcsctp/public/dcsctp_socket.h"
45#include "net/dcsctp/public/packet_observer.h"
46#include "net/dcsctp/rx/data_tracker.h"
47#include "net/dcsctp/rx/reassembly_queue.h"
48#include "net/dcsctp/socket/callback_deferrer.h"
49#include "net/dcsctp/socket/state_cookie.h"
50#include "net/dcsctp/socket/transmission_control_block.h"
51#include "net/dcsctp/timer/timer.h"
52#include "net/dcsctp/tx/fcfs_send_queue.h"
53#include "net/dcsctp/tx/retransmission_error_counter.h"
54#include "net/dcsctp/tx/retransmission_queue.h"
55#include "net/dcsctp/tx/retransmission_timeout.h"
56
57namespace dcsctp {
58
59// DcSctpSocket represents a single SCTP socket, to be used over DTLS.
60//
61// Every dcSCTP is completely isolated from any other socket.
62//
63// This class manages all packet and chunk dispatching and mainly handles the
64// connection sequences (connect, close, shutdown, etc) as well as managing
65// the Transmission Control Block (tcb).
66//
67// This class is thread-compatible.
68class DcSctpSocket : public DcSctpSocketInterface {
69 public:
70 // Instantiates a DcSctpSocket, which interacts with the world through the
71 // `callbacks` interface and is configured using `options`.
72 //
73 // For debugging, `log_prefix` will prefix all debug logs, and a
74 // `packet_observer` can be attached to e.g. dump sent and received packets.
75 DcSctpSocket(absl::string_view log_prefix,
76 DcSctpSocketCallbacks& callbacks,
77 std::unique_ptr<PacketObserver> packet_observer,
78 const DcSctpOptions& options);
79
80 DcSctpSocket(const DcSctpSocket&) = delete;
81 DcSctpSocket& operator=(const DcSctpSocket&) = delete;
82
83 // Implementation of `DcSctpSocketInterface`.
84 void ReceivePacket(rtc::ArrayView<const uint8_t> data) override;
85 void HandleTimeout(TimeoutID timeout_id) override;
86 void Connect() override;
87 void Shutdown() override;
88 void Close() override;
89 SendStatus Send(DcSctpMessage message,
90 const SendOptions& send_options) override;
91 ResetStreamsStatus ResetStreams(
92 rtc::ArrayView<const StreamID> outgoing_streams) override;
93 SocketState state() const override;
94 const DcSctpOptions& options() const override { return options_; }
95
96 // Returns this socket's verification tag, or zero if not yet connected.
97 VerificationTag verification_tag() const {
98 return tcb_ != nullptr ? tcb_->my_verification_tag() : VerificationTag(0);
99 }
100
101 private:
102 // Parameter proposals valid during the connect phase.
103 struct ConnectParameters {
104 TSN initial_tsn = TSN(0);
105 VerificationTag verification_tag = VerificationTag(0);
106 };
107
108 // Detailed state (separate from SocketState, which is the public state).
109 enum class State {
110 kClosed,
111 kCookieWait,
112 // TCB valid in these:
113 kCookieEchoed,
114 kEstablished,
115 kShutdownPending,
116 kShutdownSent,
117 kShutdownReceived,
118 kShutdownAckSent,
119 };
120
121 // Returns the log prefix used for debug logging.
122 std::string log_prefix() const;
123
124 bool IsConsistent() const;
125 static constexpr absl::string_view ToString(DcSctpSocket::State state);
126
127 // Changes the socket state, given a `reason` (for debugging/logging).
128 void SetState(State state, absl::string_view reason);
129 // Fills in `connect_params` with random verification tag and initial TSN.
130 void MakeConnectionParameters();
131 // Closes the association. Note that the TCB will not be valid past this call.
132 void InternalClose(ErrorKind error, absl::string_view message);
133 // Closes the association, because of too many retransmission errors.
134 void CloseConnectionBecauseOfTooManyTransmissionErrors();
135 // Timer expiration handlers
136 absl::optional<DurationMs> OnInitTimerExpiry();
137 absl::optional<DurationMs> OnCookieTimerExpiry();
138 absl::optional<DurationMs> OnShutdownTimerExpiry();
139 // Builds the packet from `builder` and sends it (through callbacks).
140 void SendPacket(SctpPacket::Builder& builder);
141 // Sends SHUTDOWN or SHUTDOWN-ACK if the socket is shutting down and if all
142 // outstanding data has been acknowledged.
143 void MaybeSendShutdownOrAck();
144 // If the socket is shutting down, responds SHUTDOWN to any incoming DATA.
145 void MaybeSendShutdownOnPacketReceived(const SctpPacket& packet);
146 // Sends a INIT chunk.
147 void SendInit();
148 // Sends a CookieEcho chunk.
149 void SendCookieEcho();
150 // Sends a SHUTDOWN chunk.
151 void SendShutdown();
152 // Sends a SHUTDOWN-ACK chunk.
153 void SendShutdownAck();
154 // Validates the SCTP packet, as a whole - not the validity of individual
155 // chunks within it, as that's done in the different chunk handlers.
156 bool ValidatePacket(const SctpPacket& packet);
157 // Parses `payload`, which is a serialized packet that is just going to be
158 // sent and prints all chunks.
159 void DebugPrintOutgoing(rtc::ArrayView<const uint8_t> payload);
160 // Called whenever there may be reassembled messages, and delivers those.
161 void DeliverReassembledMessages();
162 // Returns true if there is a TCB, and false otherwise (and reports an error).
163 bool ValidateHasTCB();
164
165 // Returns true if the parsing of a chunk of type `T` succeeded. If it didn't,
166 // it reports an error and returns false.
167 template <class T>
168 bool ValidateParseSuccess(const absl::optional<T>& c) {
169 if (c.has_value()) {
170 return true;
171 }
172
173 ReportFailedToParseChunk(T::kType);
174 return false;
175 }
176
177 // Reports failing to have parsed a chunk with the provided `chunk_type`.
178 void ReportFailedToParseChunk(int chunk_type);
179 // Called when unknown chunks are received. May report an error.
180 bool HandleUnrecognizedChunk(const SctpPacket::ChunkDescriptor& descriptor);
181
182 // Will dispatch more specific chunk handlers.
183 bool Dispatch(const CommonHeader& header,
184 const SctpPacket::ChunkDescriptor& descriptor);
185 // Handles incoming DATA chunks.
186 void HandleData(const CommonHeader& header,
187 const SctpPacket::ChunkDescriptor& descriptor);
188 // Handles incoming I-DATA chunks.
189 void HandleIData(const CommonHeader& header,
190 const SctpPacket::ChunkDescriptor& descriptor);
191 // Common handler for DATA and I-DATA chunks.
192 void HandleDataCommon(AnyDataChunk& chunk);
193 // Handles incoming INIT chunks.
194 void HandleInit(const CommonHeader& header,
195 const SctpPacket::ChunkDescriptor& descriptor);
196 // Handles incoming INIT-ACK chunks.
197 void HandleInitAck(const CommonHeader& header,
198 const SctpPacket::ChunkDescriptor& descriptor);
199 // Handles incoming SACK chunks.
200 void HandleSack(const CommonHeader& header,
201 const SctpPacket::ChunkDescriptor& descriptor);
202 // Handles incoming HEARTBEAT chunks.
203 void HandleHeartbeatRequest(const CommonHeader& header,
204 const SctpPacket::ChunkDescriptor& descriptor);
205 // Handles incoming HEARTBEAT-ACK chunks.
206 void HandleHeartbeatAck(const CommonHeader& header,
207 const SctpPacket::ChunkDescriptor& descriptor);
208 // Handles incoming ABORT chunks.
209 void HandleAbort(const CommonHeader& header,
210 const SctpPacket::ChunkDescriptor& descriptor);
211 // Handles incoming ERROR chunks.
212 void HandleError(const CommonHeader& header,
213 const SctpPacket::ChunkDescriptor& descriptor);
214 // Handles incoming COOKIE-ECHO chunks.
215 void HandleCookieEcho(const CommonHeader& header,
216 const SctpPacket::ChunkDescriptor& descriptor);
217 // Handles receiving COOKIE-ECHO when there already is a TCB. The return value
218 // indicates if the processing should continue.
219 bool HandleCookieEchoWithTCB(const CommonHeader& header,
220 const StateCookie& cookie);
221 // Handles incoming COOKIE-ACK chunks.
222 void HandleCookieAck(const CommonHeader& header,
223 const SctpPacket::ChunkDescriptor& descriptor);
224 // Handles incoming SHUTDOWN chunks.
225 void HandleShutdown(const CommonHeader& header,
226 const SctpPacket::ChunkDescriptor& descriptor);
227 // Handles incoming SHUTDOWN-ACK chunks.
228 void HandleShutdownAck(const CommonHeader& header,
229 const SctpPacket::ChunkDescriptor& descriptor);
230 // Handles incoming FORWARD-TSN chunks.
231 void HandleForwardTsn(const CommonHeader& header,
232 const SctpPacket::ChunkDescriptor& descriptor);
233 // Handles incoming I-FORWARD-TSN chunks.
234 void HandleIForwardTsn(const CommonHeader& header,
235 const SctpPacket::ChunkDescriptor& descriptor);
236 // Handles incoming RE-CONFIG chunks.
237 void HandleReconfig(const CommonHeader& header,
238 const SctpPacket::ChunkDescriptor& descriptor);
239 // Common handled for FORWARD-TSN/I-FORWARD-TSN.
240 void HandleForwardTsnCommon(const AnyForwardTsnChunk& chunk);
241 // Handles incoming SHUTDOWN-COMPLETE chunks
242 void HandleShutdownComplete(const CommonHeader& header,
243 const SctpPacket::ChunkDescriptor& descriptor);
244
245 const std::string log_prefix_;
246 const std::unique_ptr<PacketObserver> packet_observer_;
247 const DcSctpOptions options_;
248
249 // Enqueues callbacks and dispatches them just before returning to the caller.
250 CallbackDeferrer callbacks_;
251
252 TimerManager timer_manager_;
253 const std::unique_ptr<Timer> t1_init_;
254 const std::unique_ptr<Timer> t1_cookie_;
255 const std::unique_ptr<Timer> t2_shutdown_;
256
257 // The actual SendQueue implementation. As data can be sent on a socket before
258 // the connection is established, this component is not in the TCB.
259 FCFSSendQueue send_queue_;
260
261 // Only valid when state == State::kCookieEchoed
262 // A cached Cookie Echo Chunk, to be re-sent on timer expiry.
263 absl::optional<CookieEchoChunk> cookie_echo_chunk_ = absl::nullopt;
264
265 // Contains verification tag and initial TSN between having sent the INIT
266 // until the connection is established (there is no TCB at this point).
267 ConnectParameters connect_params_;
268 // The socket state.
269 State state_ = State::kClosed;
270 // If the connection is established, contains a transmission control block.
271 std::unique_ptr<TransmissionControlBlock> tcb_;
272};
273} // namespace dcsctp
274
275#endif // NET_DCSCTP_SOCKET_DCSCTP_SOCKET_H_