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