xref: /aosp_15_r20/external/webrtc/net/dcsctp/socket/stream_reset_handler.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/stream_reset_handler.h"
11 
12 #include <cstdint>
13 #include <memory>
14 #include <utility>
15 #include <vector>
16 
17 #include "absl/types/optional.h"
18 #include "api/array_view.h"
19 #include "net/dcsctp/common/internal_types.h"
20 #include "net/dcsctp/common/str_join.h"
21 #include "net/dcsctp/packet/chunk/reconfig_chunk.h"
22 #include "net/dcsctp/packet/parameter/add_incoming_streams_request_parameter.h"
23 #include "net/dcsctp/packet/parameter/add_outgoing_streams_request_parameter.h"
24 #include "net/dcsctp/packet/parameter/incoming_ssn_reset_request_parameter.h"
25 #include "net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.h"
26 #include "net/dcsctp/packet/parameter/parameter.h"
27 #include "net/dcsctp/packet/parameter/reconfiguration_response_parameter.h"
28 #include "net/dcsctp/packet/parameter/ssn_tsn_reset_request_parameter.h"
29 #include "net/dcsctp/packet/sctp_packet.h"
30 #include "net/dcsctp/packet/tlv_trait.h"
31 #include "net/dcsctp/public/dcsctp_socket.h"
32 #include "net/dcsctp/rx/data_tracker.h"
33 #include "net/dcsctp/rx/reassembly_queue.h"
34 #include "net/dcsctp/socket/context.h"
35 #include "net/dcsctp/timer/timer.h"
36 #include "net/dcsctp/tx/retransmission_queue.h"
37 #include "rtc_base/logging.h"
38 
39 namespace dcsctp {
40 namespace {
41 using ResponseResult = ReconfigurationResponseParameter::Result;
42 
DescriptorsAre(const std::vector<ParameterDescriptor> & c,uint16_t e1,uint16_t e2)43 bool DescriptorsAre(const std::vector<ParameterDescriptor>& c,
44                     uint16_t e1,
45                     uint16_t e2) {
46   return (c[0].type == e1 && c[1].type == e2) ||
47          (c[0].type == e2 && c[1].type == e1);
48 }
49 
50 }  // namespace
51 
Validate(const ReConfigChunk & chunk)52 bool StreamResetHandler::Validate(const ReConfigChunk& chunk) {
53   const Parameters& parameters = chunk.parameters();
54 
55   // https://tools.ietf.org/html/rfc6525#section-3.1
56   // "Note that each RE-CONFIG chunk holds at least one parameter
57   // and at most two parameters. Only the following combinations are allowed:"
58   std::vector<ParameterDescriptor> descriptors = parameters.descriptors();
59   if (descriptors.size() == 1) {
60     if ((descriptors[0].type == OutgoingSSNResetRequestParameter::kType) ||
61         (descriptors[0].type == IncomingSSNResetRequestParameter::kType) ||
62         (descriptors[0].type == SSNTSNResetRequestParameter::kType) ||
63         (descriptors[0].type == AddOutgoingStreamsRequestParameter::kType) ||
64         (descriptors[0].type == AddIncomingStreamsRequestParameter::kType) ||
65         (descriptors[0].type == ReconfigurationResponseParameter::kType)) {
66       return true;
67     }
68   } else if (descriptors.size() == 2) {
69     if (DescriptorsAre(descriptors, OutgoingSSNResetRequestParameter::kType,
70                        IncomingSSNResetRequestParameter::kType) ||
71         DescriptorsAre(descriptors, AddOutgoingStreamsRequestParameter::kType,
72                        AddIncomingStreamsRequestParameter::kType) ||
73         DescriptorsAre(descriptors, ReconfigurationResponseParameter::kType,
74                        OutgoingSSNResetRequestParameter::kType) ||
75         DescriptorsAre(descriptors, ReconfigurationResponseParameter::kType,
76                        ReconfigurationResponseParameter::kType)) {
77       return true;
78     }
79   }
80 
81   RTC_LOG(LS_WARNING) << "Invalid set of RE-CONFIG parameters";
82   return false;
83 }
84 
85 absl::optional<std::vector<ReconfigurationResponseParameter>>
Process(const ReConfigChunk & chunk)86 StreamResetHandler::Process(const ReConfigChunk& chunk) {
87   if (!Validate(chunk)) {
88     return absl::nullopt;
89   }
90 
91   std::vector<ReconfigurationResponseParameter> responses;
92 
93   for (const ParameterDescriptor& desc : chunk.parameters().descriptors()) {
94     switch (desc.type) {
95       case OutgoingSSNResetRequestParameter::kType:
96         HandleResetOutgoing(desc, responses);
97         break;
98 
99       case IncomingSSNResetRequestParameter::kType:
100         HandleResetIncoming(desc, responses);
101         break;
102 
103       case ReconfigurationResponseParameter::kType:
104         HandleResponse(desc);
105         break;
106     }
107   }
108 
109   return responses;
110 }
111 
HandleReConfig(ReConfigChunk chunk)112 void StreamResetHandler::HandleReConfig(ReConfigChunk chunk) {
113   absl::optional<std::vector<ReconfigurationResponseParameter>> responses =
114       Process(chunk);
115 
116   if (!responses.has_value()) {
117     ctx_->callbacks().OnError(ErrorKind::kParseFailed,
118                               "Failed to parse RE-CONFIG command");
119     return;
120   }
121 
122   if (!responses->empty()) {
123     SctpPacket::Builder b = ctx_->PacketBuilder();
124     Parameters::Builder params_builder;
125     for (const auto& response : *responses) {
126       params_builder.Add(response);
127     }
128     b.Add(ReConfigChunk(params_builder.Build()));
129     ctx_->Send(b);
130   }
131 }
132 
ValidateReqSeqNbr(ReconfigRequestSN req_seq_nbr,std::vector<ReconfigurationResponseParameter> & responses)133 bool StreamResetHandler::ValidateReqSeqNbr(
134     ReconfigRequestSN req_seq_nbr,
135     std::vector<ReconfigurationResponseParameter>& responses) {
136   if (req_seq_nbr == last_processed_req_seq_nbr_) {
137     // https://www.rfc-editor.org/rfc/rfc6525.html#section-5.2.1 "If the
138     // received RE-CONFIG chunk contains at least one request and based on the
139     // analysis of the Re-configuration Request Sequence Numbers this is the
140     // last received RE-CONFIG chunk (i.e., a retransmission), the same
141     // RE-CONFIG chunk MUST to be sent back in response, as it was earlier."
142     RTC_DLOG(LS_VERBOSE) << log_prefix_ << "req=" << *req_seq_nbr
143                          << " already processed, returning result="
144                          << ToString(last_processed_req_result_);
145     responses.push_back(ReconfigurationResponseParameter(
146         req_seq_nbr, last_processed_req_result_));
147     return false;
148   }
149 
150   if (req_seq_nbr != ReconfigRequestSN(*last_processed_req_seq_nbr_ + 1)) {
151     // Too old, too new, from wrong association etc.
152     // This is expected to happen when handing over a RTCPeerConnection from one
153     // server to another. The client will notice this and may decide to close
154     // old data channels, which may be sent to the wrong (or both) servers
155     // during a handover.
156     RTC_DLOG(LS_VERBOSE) << log_prefix_ << "req=" << *req_seq_nbr
157                          << " bad seq_nbr";
158     responses.push_back(ReconfigurationResponseParameter(
159         req_seq_nbr, ResponseResult::kErrorBadSequenceNumber));
160     return false;
161   }
162 
163   return true;
164 }
165 
HandleResetOutgoing(const ParameterDescriptor & descriptor,std::vector<ReconfigurationResponseParameter> & responses)166 void StreamResetHandler::HandleResetOutgoing(
167     const ParameterDescriptor& descriptor,
168     std::vector<ReconfigurationResponseParameter>& responses) {
169   absl::optional<OutgoingSSNResetRequestParameter> req =
170       OutgoingSSNResetRequestParameter::Parse(descriptor.data);
171   if (!req.has_value()) {
172     ctx_->callbacks().OnError(ErrorKind::kParseFailed,
173                               "Failed to parse Outgoing Reset command");
174     return;
175   }
176 
177   if (ValidateReqSeqNbr(req->request_sequence_number(), responses)) {
178     RTC_DLOG(LS_VERBOSE) << log_prefix_
179                          << "Reset outgoing streams with req_seq_nbr="
180                          << *req->request_sequence_number();
181 
182     last_processed_req_seq_nbr_ = req->request_sequence_number();
183     last_processed_req_result_ = reassembly_queue_->ResetStreams(
184         *req, data_tracker_->last_cumulative_acked_tsn());
185     if (last_processed_req_result_ == ResponseResult::kSuccessPerformed) {
186       ctx_->callbacks().OnIncomingStreamsReset(req->stream_ids());
187     }
188     responses.push_back(ReconfigurationResponseParameter(
189         req->request_sequence_number(), last_processed_req_result_));
190   }
191 }
192 
HandleResetIncoming(const ParameterDescriptor & descriptor,std::vector<ReconfigurationResponseParameter> & responses)193 void StreamResetHandler::HandleResetIncoming(
194     const ParameterDescriptor& descriptor,
195     std::vector<ReconfigurationResponseParameter>& responses) {
196   absl::optional<IncomingSSNResetRequestParameter> req =
197       IncomingSSNResetRequestParameter::Parse(descriptor.data);
198   if (!req.has_value()) {
199     ctx_->callbacks().OnError(ErrorKind::kParseFailed,
200                               "Failed to parse Incoming Reset command");
201     return;
202   }
203   if (ValidateReqSeqNbr(req->request_sequence_number(), responses)) {
204     responses.push_back(ReconfigurationResponseParameter(
205         req->request_sequence_number(), ResponseResult::kSuccessNothingToDo));
206     last_processed_req_seq_nbr_ = req->request_sequence_number();
207   }
208 }
209 
HandleResponse(const ParameterDescriptor & descriptor)210 void StreamResetHandler::HandleResponse(const ParameterDescriptor& descriptor) {
211   absl::optional<ReconfigurationResponseParameter> resp =
212       ReconfigurationResponseParameter::Parse(descriptor.data);
213   if (!resp.has_value()) {
214     ctx_->callbacks().OnError(
215         ErrorKind::kParseFailed,
216         "Failed to parse Reconfiguration Response command");
217     return;
218   }
219 
220   if (current_request_.has_value() && current_request_->has_been_sent() &&
221       resp->response_sequence_number() == current_request_->req_seq_nbr()) {
222     reconfig_timer_->Stop();
223 
224     switch (resp->result()) {
225       case ResponseResult::kSuccessNothingToDo:
226       case ResponseResult::kSuccessPerformed:
227         RTC_DLOG(LS_VERBOSE)
228             << log_prefix_ << "Reset stream success, req_seq_nbr="
229             << *current_request_->req_seq_nbr() << ", streams="
230             << StrJoin(current_request_->streams(), ",",
231                        [](rtc::StringBuilder& sb, StreamID stream_id) {
232                          sb << *stream_id;
233                        });
234         ctx_->callbacks().OnStreamsResetPerformed(current_request_->streams());
235         current_request_ = absl::nullopt;
236         retransmission_queue_->CommitResetStreams();
237         break;
238       case ResponseResult::kInProgress:
239         RTC_DLOG(LS_VERBOSE)
240             << log_prefix_ << "Reset stream still pending, req_seq_nbr="
241             << *current_request_->req_seq_nbr() << ", streams="
242             << StrJoin(current_request_->streams(), ",",
243                        [](rtc::StringBuilder& sb, StreamID stream_id) {
244                          sb << *stream_id;
245                        });
246         // Force this request to be sent again, but with new req_seq_nbr.
247         current_request_->PrepareRetransmission();
248         reconfig_timer_->set_duration(ctx_->current_rto());
249         reconfig_timer_->Start();
250         break;
251       case ResponseResult::kErrorRequestAlreadyInProgress:
252       case ResponseResult::kDenied:
253       case ResponseResult::kErrorWrongSSN:
254       case ResponseResult::kErrorBadSequenceNumber:
255         RTC_DLOG(LS_WARNING)
256             << log_prefix_ << "Reset stream error=" << ToString(resp->result())
257             << ", req_seq_nbr=" << *current_request_->req_seq_nbr()
258             << ", streams="
259             << StrJoin(current_request_->streams(), ",",
260                        [](rtc::StringBuilder& sb, StreamID stream_id) {
261                          sb << *stream_id;
262                        });
263         ctx_->callbacks().OnStreamsResetFailed(current_request_->streams(),
264                                                ToString(resp->result()));
265         current_request_ = absl::nullopt;
266         retransmission_queue_->RollbackResetStreams();
267         break;
268     }
269   }
270 }
271 
MakeStreamResetRequest()272 absl::optional<ReConfigChunk> StreamResetHandler::MakeStreamResetRequest() {
273   // Only send stream resets if there are streams to reset, and no current
274   // ongoing request (there can only be one at a time), and if the stream
275   // can be reset.
276   if (current_request_.has_value() ||
277       !retransmission_queue_->HasStreamsReadyToBeReset()) {
278     return absl::nullopt;
279   }
280 
281   current_request_.emplace(TSN(*retransmission_queue_->next_tsn() - 1),
282                            retransmission_queue_->GetStreamsReadyToBeReset());
283   reconfig_timer_->set_duration(ctx_->current_rto());
284   reconfig_timer_->Start();
285   return MakeReconfigChunk();
286 }
287 
MakeReconfigChunk()288 ReConfigChunk StreamResetHandler::MakeReconfigChunk() {
289   // The req_seq_nbr will be empty if the request has never been sent before,
290   // or if it was sent, but the sender responded "in progress", and then the
291   // req_seq_nbr will be cleared to re-send with a new number. But if the
292   // request is re-sent due to timeout (reconfig-timer expiring), the same
293   // req_seq_nbr will be used.
294   RTC_DCHECK(current_request_.has_value());
295 
296   if (!current_request_->has_been_sent()) {
297     current_request_->PrepareToSend(next_outgoing_req_seq_nbr_);
298     next_outgoing_req_seq_nbr_ =
299         ReconfigRequestSN(*next_outgoing_req_seq_nbr_ + 1);
300   }
301 
302   Parameters::Builder params_builder =
303       Parameters::Builder().Add(OutgoingSSNResetRequestParameter(
304           current_request_->req_seq_nbr(), current_request_->req_seq_nbr(),
305           current_request_->sender_last_assigned_tsn(),
306           current_request_->streams()));
307 
308   return ReConfigChunk(params_builder.Build());
309 }
310 
ResetStreams(rtc::ArrayView<const StreamID> outgoing_streams)311 void StreamResetHandler::ResetStreams(
312     rtc::ArrayView<const StreamID> outgoing_streams) {
313   for (StreamID stream_id : outgoing_streams) {
314     retransmission_queue_->PrepareResetStream(stream_id);
315   }
316 }
317 
OnReconfigTimerExpiry()318 absl::optional<DurationMs> StreamResetHandler::OnReconfigTimerExpiry() {
319   if (current_request_->has_been_sent()) {
320     // There is an outstanding request, which timed out while waiting for a
321     // response.
322     if (!ctx_->IncrementTxErrorCounter("RECONFIG timeout")) {
323       // Timed out. The connection will close after processing the timers.
324       return absl::nullopt;
325     }
326   } else {
327     // There is no outstanding request, but there is a prepared one. This means
328     // that the receiver has previously responded "in progress", which resulted
329     // in retrying the request (but with a new req_seq_nbr) after a while.
330   }
331 
332   ctx_->Send(ctx_->PacketBuilder().Add(MakeReconfigChunk()));
333   return ctx_->current_rto();
334 }
335 
GetHandoverReadiness() const336 HandoverReadinessStatus StreamResetHandler::GetHandoverReadiness() const {
337   HandoverReadinessStatus status;
338   if (retransmission_queue_->HasStreamsReadyToBeReset()) {
339     status.Add(HandoverUnreadinessReason::kPendingStreamReset);
340   }
341   if (current_request_.has_value()) {
342     status.Add(HandoverUnreadinessReason::kPendingStreamResetRequest);
343   }
344   return status;
345 }
346 
AddHandoverState(DcSctpSocketHandoverState & state)347 void StreamResetHandler::AddHandoverState(DcSctpSocketHandoverState& state) {
348   state.rx.last_completed_reset_req_sn = last_processed_req_seq_nbr_.value();
349   state.tx.next_reset_req_sn = next_outgoing_req_seq_nbr_.value();
350 }
351 
352 }  // namespace dcsctp
353