xref: /aosp_15_r20/external/webrtc/net/dcsctp/socket/transmission_control_block.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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