1 /*
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 #include "net/dcsctp/socket/transmission_control_block.h"
11
12 #include <algorithm>
13 #include <cstdint>
14 #include <memory>
15 #include <string>
16 #include <utility>
17 #include <vector>
18
19 #include "absl/types/optional.h"
20 #include "net/dcsctp/packet/chunk/data_chunk.h"
21 #include "net/dcsctp/packet/chunk/forward_tsn_chunk.h"
22 #include "net/dcsctp/packet/chunk/idata_chunk.h"
23 #include "net/dcsctp/packet/chunk/iforward_tsn_chunk.h"
24 #include "net/dcsctp/packet/chunk/reconfig_chunk.h"
25 #include "net/dcsctp/packet/chunk/sack_chunk.h"
26 #include "net/dcsctp/packet/sctp_packet.h"
27 #include "net/dcsctp/public/dcsctp_options.h"
28 #include "net/dcsctp/rx/data_tracker.h"
29 #include "net/dcsctp/rx/reassembly_queue.h"
30 #include "net/dcsctp/socket/capabilities.h"
31 #include "net/dcsctp/socket/stream_reset_handler.h"
32 #include "net/dcsctp/timer/timer.h"
33 #include "net/dcsctp/tx/retransmission_queue.h"
34 #include "net/dcsctp/tx/retransmission_timeout.h"
35 #include "rtc_base/logging.h"
36 #include "rtc_base/strings/string_builder.h"
37
38 namespace dcsctp {
39
TransmissionControlBlock(TimerManager & timer_manager,absl::string_view log_prefix,const DcSctpOptions & options,const Capabilities & capabilities,DcSctpSocketCallbacks & callbacks,SendQueue & send_queue,VerificationTag my_verification_tag,TSN my_initial_tsn,VerificationTag peer_verification_tag,TSN peer_initial_tsn,size_t a_rwnd,TieTag tie_tag,PacketSender & packet_sender,std::function<bool ()> is_connection_established)40 TransmissionControlBlock::TransmissionControlBlock(
41 TimerManager& timer_manager,
42 absl::string_view log_prefix,
43 const DcSctpOptions& options,
44 const Capabilities& capabilities,
45 DcSctpSocketCallbacks& callbacks,
46 SendQueue& send_queue,
47 VerificationTag my_verification_tag,
48 TSN my_initial_tsn,
49 VerificationTag peer_verification_tag,
50 TSN peer_initial_tsn,
51 size_t a_rwnd,
52 TieTag tie_tag,
53 PacketSender& packet_sender,
54 std::function<bool()> is_connection_established)
55 : log_prefix_(log_prefix),
56 options_(options),
57 timer_manager_(timer_manager),
58 capabilities_(capabilities),
59 callbacks_(callbacks),
60 t3_rtx_(timer_manager_.CreateTimer(
61 "t3-rtx",
62 absl::bind_front(&TransmissionControlBlock::OnRtxTimerExpiry, this),
63 TimerOptions(options.rto_initial,
64 TimerBackoffAlgorithm::kExponential,
65 /*max_restarts=*/absl::nullopt,
66 options.max_timer_backoff_duration))),
67 delayed_ack_timer_(timer_manager_.CreateTimer(
68 "delayed-ack",
69 absl::bind_front(&TransmissionControlBlock::OnDelayedAckTimerExpiry,
70 this),
71 TimerOptions(options.delayed_ack_max_timeout,
72 TimerBackoffAlgorithm::kExponential,
73 /*max_restarts=*/0,
74 /*max_backoff_duration=*/absl::nullopt,
75 webrtc::TaskQueueBase::DelayPrecision::kHigh))),
76 my_verification_tag_(my_verification_tag),
77 my_initial_tsn_(my_initial_tsn),
78 peer_verification_tag_(peer_verification_tag),
79 peer_initial_tsn_(peer_initial_tsn),
80 tie_tag_(tie_tag),
81 is_connection_established_(std::move(is_connection_established)),
82 packet_sender_(packet_sender),
83 rto_(options),
84 tx_error_counter_(log_prefix, options),
85 data_tracker_(log_prefix, delayed_ack_timer_.get(), peer_initial_tsn),
86 reassembly_queue_(log_prefix,
87 peer_initial_tsn,
88 options.max_receiver_window_buffer_size,
89 capabilities.message_interleaving),
90 retransmission_queue_(
91 log_prefix,
92 &callbacks_,
93 my_initial_tsn,
94 a_rwnd,
95 send_queue,
96 absl::bind_front(&TransmissionControlBlock::ObserveRTT, this),
97 [this]() { tx_error_counter_.Clear(); },
98 *t3_rtx_,
99 options,
100 capabilities.partial_reliability,
101 capabilities.message_interleaving),
102 stream_reset_handler_(log_prefix,
103 this,
104 &timer_manager,
105 &data_tracker_,
106 &reassembly_queue_,
107 &retransmission_queue_),
108 heartbeat_handler_(log_prefix, options, this, &timer_manager_) {
109 send_queue.EnableMessageInterleaving(capabilities.message_interleaving);
110 }
111
ObserveRTT(DurationMs rtt)112 void TransmissionControlBlock::ObserveRTT(DurationMs rtt) {
113 DurationMs prev_rto = rto_.rto();
114 rto_.ObserveRTT(rtt);
115 RTC_DLOG(LS_VERBOSE) << log_prefix_ << "new rtt=" << *rtt
116 << ", srtt=" << *rto_.srtt() << ", rto=" << *rto_.rto()
117 << " (" << *prev_rto << ")";
118 t3_rtx_->set_duration(rto_.rto());
119
120 DurationMs delayed_ack_tmo =
121 std::min(rto_.rto() * 0.5, options_.delayed_ack_max_timeout);
122 delayed_ack_timer_->set_duration(delayed_ack_tmo);
123 }
124
OnRtxTimerExpiry()125 absl::optional<DurationMs> TransmissionControlBlock::OnRtxTimerExpiry() {
126 TimeMs now = callbacks_.TimeMillis();
127 RTC_DLOG(LS_INFO) << log_prefix_ << "Timer " << t3_rtx_->name()
128 << " has expired";
129 if (cookie_echo_chunk_.has_value()) {
130 // In the COOKIE_ECHO state, let the T1-COOKIE timer trigger
131 // retransmissions, to avoid having two timers doing that.
132 RTC_DLOG(LS_VERBOSE) << "Not retransmitting as T1-cookie is active.";
133 } else {
134 if (IncrementTxErrorCounter("t3-rtx expired")) {
135 retransmission_queue_.HandleT3RtxTimerExpiry();
136 SendBufferedPackets(now);
137 }
138 }
139 return absl::nullopt;
140 }
141
OnDelayedAckTimerExpiry()142 absl::optional<DurationMs> TransmissionControlBlock::OnDelayedAckTimerExpiry() {
143 data_tracker_.HandleDelayedAckTimerExpiry();
144 MaybeSendSack();
145 return absl::nullopt;
146 }
147
MaybeSendSack()148 void TransmissionControlBlock::MaybeSendSack() {
149 if (data_tracker_.ShouldSendAck(/*also_if_delayed=*/false)) {
150 SctpPacket::Builder builder = PacketBuilder();
151 builder.Add(
152 data_tracker_.CreateSelectiveAck(reassembly_queue_.remaining_bytes()));
153 Send(builder);
154 }
155 }
156
MaybeSendForwardTsn(SctpPacket::Builder & builder,TimeMs now)157 void TransmissionControlBlock::MaybeSendForwardTsn(SctpPacket::Builder& builder,
158 TimeMs now) {
159 if (now >= limit_forward_tsn_until_ &&
160 retransmission_queue_.ShouldSendForwardTsn(now)) {
161 if (capabilities_.message_interleaving) {
162 builder.Add(retransmission_queue_.CreateIForwardTsn());
163 } else {
164 builder.Add(retransmission_queue_.CreateForwardTsn());
165 }
166 packet_sender_.Send(builder);
167 // https://datatracker.ietf.org/doc/html/rfc3758
168 // "IMPLEMENTATION NOTE: An implementation may wish to limit the number of
169 // duplicate FORWARD TSN chunks it sends by ... waiting a full RTT before
170 // sending a duplicate FORWARD TSN."
171 // "Any delay applied to the sending of FORWARD TSN chunk SHOULD NOT exceed
172 // 200ms and MUST NOT exceed 500ms".
173 limit_forward_tsn_until_ = now + std::min(DurationMs(200), rto_.srtt());
174 }
175 }
176
MaybeSendFastRetransmit()177 void TransmissionControlBlock::MaybeSendFastRetransmit() {
178 if (!retransmission_queue_.has_data_to_be_fast_retransmitted()) {
179 return;
180 }
181
182 // https://datatracker.ietf.org/doc/html/rfc4960#section-7.2.4
183 // "Determine how many of the earliest (i.e., lowest TSN) DATA chunks marked
184 // for retransmission will fit into a single packet, subject to constraint of
185 // the path MTU of the destination transport address to which the packet is
186 // being sent. Call this value K. Retransmit those K DATA chunks in a single
187 // packet. When a Fast Retransmit is being performed, the sender SHOULD
188 // ignore the value of cwnd and SHOULD NOT delay retransmission for this
189 // single packet."
190
191 SctpPacket::Builder builder(peer_verification_tag_, options_);
192 auto chunks = retransmission_queue_.GetChunksForFastRetransmit(
193 builder.bytes_remaining());
194 for (auto& [tsn, data] : chunks) {
195 if (capabilities_.message_interleaving) {
196 builder.Add(IDataChunk(tsn, std::move(data), false));
197 } else {
198 builder.Add(DataChunk(tsn, std::move(data), false));
199 }
200 }
201 packet_sender_.Send(builder);
202 }
203
SendBufferedPackets(SctpPacket::Builder & builder,TimeMs now)204 void TransmissionControlBlock::SendBufferedPackets(SctpPacket::Builder& builder,
205 TimeMs now) {
206 for (int packet_idx = 0;
207 packet_idx < options_.max_burst && retransmission_queue_.can_send_data();
208 ++packet_idx) {
209 // Only add control chunks to the first packet that is sent, if sending
210 // multiple packets in one go (as allowed by the congestion window).
211 if (packet_idx == 0) {
212 if (cookie_echo_chunk_.has_value()) {
213 // https://tools.ietf.org/html/rfc4960#section-5.1
214 // "The COOKIE ECHO chunk can be bundled with any pending outbound DATA
215 // chunks, but it MUST be the first chunk in the packet..."
216 RTC_DCHECK(builder.empty());
217 builder.Add(*cookie_echo_chunk_);
218 }
219
220 // https://tools.ietf.org/html/rfc4960#section-6
221 // "Before an endpoint transmits a DATA chunk, if any received DATA
222 // chunks have not been acknowledged (e.g., due to delayed ack), the
223 // sender should create a SACK and bundle it with the outbound DATA chunk,
224 // as long as the size of the final SCTP packet does not exceed the
225 // current MTU."
226 if (data_tracker_.ShouldSendAck(/*also_if_delayed=*/true)) {
227 builder.Add(data_tracker_.CreateSelectiveAck(
228 reassembly_queue_.remaining_bytes()));
229 }
230 MaybeSendForwardTsn(builder, now);
231 absl::optional<ReConfigChunk> reconfig =
232 stream_reset_handler_.MakeStreamResetRequest();
233 if (reconfig.has_value()) {
234 builder.Add(*reconfig);
235 }
236 }
237
238 auto chunks =
239 retransmission_queue_.GetChunksToSend(now, builder.bytes_remaining());
240 for (auto& [tsn, data] : chunks) {
241 if (capabilities_.message_interleaving) {
242 builder.Add(IDataChunk(tsn, std::move(data), false));
243 } else {
244 builder.Add(DataChunk(tsn, std::move(data), false));
245 }
246 }
247
248 if (!packet_sender_.Send(builder)) {
249 break;
250 }
251
252 if (cookie_echo_chunk_.has_value()) {
253 // https://tools.ietf.org/html/rfc4960#section-5.1
254 // "... until the COOKIE ACK is returned the sender MUST NOT send any
255 // other packets to the peer."
256 break;
257 }
258 }
259 }
260
ToString() const261 std::string TransmissionControlBlock::ToString() const {
262 rtc::StringBuilder sb;
263
264 sb.AppendFormat(
265 "verification_tag=%08x, last_cumulative_ack=%u, capabilities=",
266 *peer_verification_tag_, *data_tracker_.last_cumulative_acked_tsn());
267
268 if (capabilities_.partial_reliability) {
269 sb << "PR,";
270 }
271 if (capabilities_.message_interleaving) {
272 sb << "IL,";
273 }
274 if (capabilities_.reconfig) {
275 sb << "Reconfig,";
276 }
277 sb << " max_in=" << capabilities_.negotiated_maximum_incoming_streams;
278 sb << " max_out=" << capabilities_.negotiated_maximum_outgoing_streams;
279
280 return sb.Release();
281 }
282
GetHandoverReadiness() const283 HandoverReadinessStatus TransmissionControlBlock::GetHandoverReadiness() const {
284 HandoverReadinessStatus status;
285 status.Add(data_tracker_.GetHandoverReadiness());
286 status.Add(stream_reset_handler_.GetHandoverReadiness());
287 status.Add(reassembly_queue_.GetHandoverReadiness());
288 status.Add(retransmission_queue_.GetHandoverReadiness());
289 return status;
290 }
291
AddHandoverState(DcSctpSocketHandoverState & state)292 void TransmissionControlBlock::AddHandoverState(
293 DcSctpSocketHandoverState& state) {
294 state.capabilities.partial_reliability = capabilities_.partial_reliability;
295 state.capabilities.message_interleaving = capabilities_.message_interleaving;
296 state.capabilities.reconfig = capabilities_.reconfig;
297 state.capabilities.negotiated_maximum_incoming_streams =
298 capabilities_.negotiated_maximum_incoming_streams;
299 state.capabilities.negotiated_maximum_outgoing_streams =
300 capabilities_.negotiated_maximum_outgoing_streams;
301
302 state.my_verification_tag = my_verification_tag().value();
303 state.peer_verification_tag = peer_verification_tag().value();
304 state.my_initial_tsn = my_initial_tsn().value();
305 state.peer_initial_tsn = peer_initial_tsn().value();
306 state.tie_tag = tie_tag().value();
307
308 data_tracker_.AddHandoverState(state);
309 stream_reset_handler_.AddHandoverState(state);
310 reassembly_queue_.AddHandoverState(state);
311 retransmission_queue_.AddHandoverState(state);
312 }
313
RestoreFromState(const DcSctpSocketHandoverState & state)314 void TransmissionControlBlock::RestoreFromState(
315 const DcSctpSocketHandoverState& state) {
316 data_tracker_.RestoreFromState(state);
317 retransmission_queue_.RestoreFromState(state);
318 reassembly_queue_.RestoreFromState(state);
319 }
320 } // namespace dcsctp
321