1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright 2021 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #include "media/sctp/dcsctp_transport.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <atomic>
14*d9f75844SAndroid Build Coastguard Worker #include <cstdint>
15*d9f75844SAndroid Build Coastguard Worker #include <limits>
16*d9f75844SAndroid Build Coastguard Worker #include <utility>
17*d9f75844SAndroid Build Coastguard Worker #include <vector>
18*d9f75844SAndroid Build Coastguard Worker
19*d9f75844SAndroid Build Coastguard Worker #include "absl/strings/string_view.h"
20*d9f75844SAndroid Build Coastguard Worker #include "absl/types/optional.h"
21*d9f75844SAndroid Build Coastguard Worker #include "api/array_view.h"
22*d9f75844SAndroid Build Coastguard Worker #include "media/base/media_channel.h"
23*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/public/dcsctp_socket_factory.h"
24*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/public/packet_observer.h"
25*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/public/text_pcap_packet_observer.h"
26*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/public/types.h"
27*d9f75844SAndroid Build Coastguard Worker #include "p2p/base/packet_transport_internal.h"
28*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
29*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
30*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/socket.h"
31*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/strings/string_builder.h"
32*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/thread.h"
33*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/trace_event.h"
34*d9f75844SAndroid Build Coastguard Worker #include "system_wrappers/include/clock.h"
35*d9f75844SAndroid Build Coastguard Worker
36*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
37*d9f75844SAndroid Build Coastguard Worker
38*d9f75844SAndroid Build Coastguard Worker namespace {
39*d9f75844SAndroid Build Coastguard Worker using ::dcsctp::SendPacketStatus;
40*d9f75844SAndroid Build Coastguard Worker
41*d9f75844SAndroid Build Coastguard Worker // When there is packet loss for a long time, the SCTP retry timers will use
42*d9f75844SAndroid Build Coastguard Worker // exponential backoff, which can grow to very long durations and when the
43*d9f75844SAndroid Build Coastguard Worker // connection recovers, it may take a long time to reach the new backoff
44*d9f75844SAndroid Build Coastguard Worker // duration. By limiting it to a reasonable limit, the time to recover reduces.
45*d9f75844SAndroid Build Coastguard Worker constexpr dcsctp::DurationMs kMaxTimerBackoffDuration =
46*d9f75844SAndroid Build Coastguard Worker dcsctp::DurationMs(3000);
47*d9f75844SAndroid Build Coastguard Worker
48*d9f75844SAndroid Build Coastguard Worker enum class WebrtcPPID : dcsctp::PPID::UnderlyingType {
49*d9f75844SAndroid Build Coastguard Worker // https://www.rfc-editor.org/rfc/rfc8832.html#section-8.1
50*d9f75844SAndroid Build Coastguard Worker kDCEP = 50,
51*d9f75844SAndroid Build Coastguard Worker // https://www.rfc-editor.org/rfc/rfc8831.html#section-8
52*d9f75844SAndroid Build Coastguard Worker kString = 51,
53*d9f75844SAndroid Build Coastguard Worker kBinaryPartial = 52, // Deprecated
54*d9f75844SAndroid Build Coastguard Worker kBinary = 53,
55*d9f75844SAndroid Build Coastguard Worker kStringPartial = 54, // Deprecated
56*d9f75844SAndroid Build Coastguard Worker kStringEmpty = 56,
57*d9f75844SAndroid Build Coastguard Worker kBinaryEmpty = 57,
58*d9f75844SAndroid Build Coastguard Worker };
59*d9f75844SAndroid Build Coastguard Worker
ToPPID(DataMessageType message_type,size_t size)60*d9f75844SAndroid Build Coastguard Worker WebrtcPPID ToPPID(DataMessageType message_type, size_t size) {
61*d9f75844SAndroid Build Coastguard Worker switch (message_type) {
62*d9f75844SAndroid Build Coastguard Worker case webrtc::DataMessageType::kControl:
63*d9f75844SAndroid Build Coastguard Worker return WebrtcPPID::kDCEP;
64*d9f75844SAndroid Build Coastguard Worker case webrtc::DataMessageType::kText:
65*d9f75844SAndroid Build Coastguard Worker return size > 0 ? WebrtcPPID::kString : WebrtcPPID::kStringEmpty;
66*d9f75844SAndroid Build Coastguard Worker case webrtc::DataMessageType::kBinary:
67*d9f75844SAndroid Build Coastguard Worker return size > 0 ? WebrtcPPID::kBinary : WebrtcPPID::kBinaryEmpty;
68*d9f75844SAndroid Build Coastguard Worker }
69*d9f75844SAndroid Build Coastguard Worker }
70*d9f75844SAndroid Build Coastguard Worker
ToDataMessageType(dcsctp::PPID ppid)71*d9f75844SAndroid Build Coastguard Worker absl::optional<DataMessageType> ToDataMessageType(dcsctp::PPID ppid) {
72*d9f75844SAndroid Build Coastguard Worker switch (static_cast<WebrtcPPID>(ppid.value())) {
73*d9f75844SAndroid Build Coastguard Worker case WebrtcPPID::kDCEP:
74*d9f75844SAndroid Build Coastguard Worker return webrtc::DataMessageType::kControl;
75*d9f75844SAndroid Build Coastguard Worker case WebrtcPPID::kString:
76*d9f75844SAndroid Build Coastguard Worker case WebrtcPPID::kStringPartial:
77*d9f75844SAndroid Build Coastguard Worker case WebrtcPPID::kStringEmpty:
78*d9f75844SAndroid Build Coastguard Worker return webrtc::DataMessageType::kText;
79*d9f75844SAndroid Build Coastguard Worker case WebrtcPPID::kBinary:
80*d9f75844SAndroid Build Coastguard Worker case WebrtcPPID::kBinaryPartial:
81*d9f75844SAndroid Build Coastguard Worker case WebrtcPPID::kBinaryEmpty:
82*d9f75844SAndroid Build Coastguard Worker return webrtc::DataMessageType::kBinary;
83*d9f75844SAndroid Build Coastguard Worker }
84*d9f75844SAndroid Build Coastguard Worker return absl::nullopt;
85*d9f75844SAndroid Build Coastguard Worker }
86*d9f75844SAndroid Build Coastguard Worker
ToErrorCauseCode(dcsctp::ErrorKind error)87*d9f75844SAndroid Build Coastguard Worker absl::optional<cricket::SctpErrorCauseCode> ToErrorCauseCode(
88*d9f75844SAndroid Build Coastguard Worker dcsctp::ErrorKind error) {
89*d9f75844SAndroid Build Coastguard Worker switch (error) {
90*d9f75844SAndroid Build Coastguard Worker case dcsctp::ErrorKind::kParseFailed:
91*d9f75844SAndroid Build Coastguard Worker return cricket::SctpErrorCauseCode::kUnrecognizedParameters;
92*d9f75844SAndroid Build Coastguard Worker case dcsctp::ErrorKind::kPeerReported:
93*d9f75844SAndroid Build Coastguard Worker return cricket::SctpErrorCauseCode::kUserInitiatedAbort;
94*d9f75844SAndroid Build Coastguard Worker case dcsctp::ErrorKind::kWrongSequence:
95*d9f75844SAndroid Build Coastguard Worker case dcsctp::ErrorKind::kProtocolViolation:
96*d9f75844SAndroid Build Coastguard Worker return cricket::SctpErrorCauseCode::kProtocolViolation;
97*d9f75844SAndroid Build Coastguard Worker case dcsctp::ErrorKind::kResourceExhaustion:
98*d9f75844SAndroid Build Coastguard Worker return cricket::SctpErrorCauseCode::kOutOfResource;
99*d9f75844SAndroid Build Coastguard Worker case dcsctp::ErrorKind::kTooManyRetries:
100*d9f75844SAndroid Build Coastguard Worker case dcsctp::ErrorKind::kUnsupportedOperation:
101*d9f75844SAndroid Build Coastguard Worker case dcsctp::ErrorKind::kNoError:
102*d9f75844SAndroid Build Coastguard Worker case dcsctp::ErrorKind::kNotConnected:
103*d9f75844SAndroid Build Coastguard Worker // No SCTP error cause code matches those
104*d9f75844SAndroid Build Coastguard Worker break;
105*d9f75844SAndroid Build Coastguard Worker }
106*d9f75844SAndroid Build Coastguard Worker return absl::nullopt;
107*d9f75844SAndroid Build Coastguard Worker }
108*d9f75844SAndroid Build Coastguard Worker
IsEmptyPPID(dcsctp::PPID ppid)109*d9f75844SAndroid Build Coastguard Worker bool IsEmptyPPID(dcsctp::PPID ppid) {
110*d9f75844SAndroid Build Coastguard Worker WebrtcPPID webrtc_ppid = static_cast<WebrtcPPID>(ppid.value());
111*d9f75844SAndroid Build Coastguard Worker return webrtc_ppid == WebrtcPPID::kStringEmpty ||
112*d9f75844SAndroid Build Coastguard Worker webrtc_ppid == WebrtcPPID::kBinaryEmpty;
113*d9f75844SAndroid Build Coastguard Worker }
114*d9f75844SAndroid Build Coastguard Worker } // namespace
115*d9f75844SAndroid Build Coastguard Worker
DcSctpTransport(rtc::Thread * network_thread,rtc::PacketTransportInternal * transport,Clock * clock)116*d9f75844SAndroid Build Coastguard Worker DcSctpTransport::DcSctpTransport(rtc::Thread* network_thread,
117*d9f75844SAndroid Build Coastguard Worker rtc::PacketTransportInternal* transport,
118*d9f75844SAndroid Build Coastguard Worker Clock* clock)
119*d9f75844SAndroid Build Coastguard Worker : DcSctpTransport(network_thread,
120*d9f75844SAndroid Build Coastguard Worker transport,
121*d9f75844SAndroid Build Coastguard Worker clock,
122*d9f75844SAndroid Build Coastguard Worker std::make_unique<dcsctp::DcSctpSocketFactory>()) {}
123*d9f75844SAndroid Build Coastguard Worker
DcSctpTransport(rtc::Thread * network_thread,rtc::PacketTransportInternal * transport,Clock * clock,std::unique_ptr<dcsctp::DcSctpSocketFactory> socket_factory)124*d9f75844SAndroid Build Coastguard Worker DcSctpTransport::DcSctpTransport(
125*d9f75844SAndroid Build Coastguard Worker rtc::Thread* network_thread,
126*d9f75844SAndroid Build Coastguard Worker rtc::PacketTransportInternal* transport,
127*d9f75844SAndroid Build Coastguard Worker Clock* clock,
128*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<dcsctp::DcSctpSocketFactory> socket_factory)
129*d9f75844SAndroid Build Coastguard Worker : network_thread_(network_thread),
130*d9f75844SAndroid Build Coastguard Worker transport_(transport),
131*d9f75844SAndroid Build Coastguard Worker clock_(clock),
132*d9f75844SAndroid Build Coastguard Worker random_(clock_->TimeInMicroseconds()),
133*d9f75844SAndroid Build Coastguard Worker socket_factory_(std::move(socket_factory)),
134*d9f75844SAndroid Build Coastguard Worker task_queue_timeout_factory_(
135*d9f75844SAndroid Build Coastguard Worker *network_thread,
136*d9f75844SAndroid Build Coastguard Worker [this]() { return TimeMillis(); },
__anon22529c360302(dcsctp::TimeoutID timeout_id) 137*d9f75844SAndroid Build Coastguard Worker [this](dcsctp::TimeoutID timeout_id) {
138*d9f75844SAndroid Build Coastguard Worker socket_->HandleTimeout(timeout_id);
139*d9f75844SAndroid Build Coastguard Worker }) {
140*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
141*d9f75844SAndroid Build Coastguard Worker static std::atomic<int> instance_count = 0;
142*d9f75844SAndroid Build Coastguard Worker rtc::StringBuilder sb;
143*d9f75844SAndroid Build Coastguard Worker sb << debug_name_ << instance_count++;
144*d9f75844SAndroid Build Coastguard Worker debug_name_ = sb.Release();
145*d9f75844SAndroid Build Coastguard Worker ConnectTransportSignals();
146*d9f75844SAndroid Build Coastguard Worker }
147*d9f75844SAndroid Build Coastguard Worker
~DcSctpTransport()148*d9f75844SAndroid Build Coastguard Worker DcSctpTransport::~DcSctpTransport() {
149*d9f75844SAndroid Build Coastguard Worker if (socket_) {
150*d9f75844SAndroid Build Coastguard Worker socket_->Close();
151*d9f75844SAndroid Build Coastguard Worker }
152*d9f75844SAndroid Build Coastguard Worker }
153*d9f75844SAndroid Build Coastguard Worker
SetOnConnectedCallback(std::function<void ()> callback)154*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::SetOnConnectedCallback(std::function<void()> callback) {
155*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
156*d9f75844SAndroid Build Coastguard Worker on_connected_callback_ = std::move(callback);
157*d9f75844SAndroid Build Coastguard Worker }
158*d9f75844SAndroid Build Coastguard Worker
SetDataChannelSink(DataChannelSink * sink)159*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::SetDataChannelSink(DataChannelSink* sink) {
160*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
161*d9f75844SAndroid Build Coastguard Worker data_channel_sink_ = sink;
162*d9f75844SAndroid Build Coastguard Worker if (data_channel_sink_ && ready_to_send_data_) {
163*d9f75844SAndroid Build Coastguard Worker data_channel_sink_->OnReadyToSend();
164*d9f75844SAndroid Build Coastguard Worker }
165*d9f75844SAndroid Build Coastguard Worker }
166*d9f75844SAndroid Build Coastguard Worker
SetDtlsTransport(rtc::PacketTransportInternal * transport)167*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::SetDtlsTransport(
168*d9f75844SAndroid Build Coastguard Worker rtc::PacketTransportInternal* transport) {
169*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
170*d9f75844SAndroid Build Coastguard Worker DisconnectTransportSignals();
171*d9f75844SAndroid Build Coastguard Worker transport_ = transport;
172*d9f75844SAndroid Build Coastguard Worker ConnectTransportSignals();
173*d9f75844SAndroid Build Coastguard Worker MaybeConnectSocket();
174*d9f75844SAndroid Build Coastguard Worker }
175*d9f75844SAndroid Build Coastguard Worker
Start(int local_sctp_port,int remote_sctp_port,int max_message_size)176*d9f75844SAndroid Build Coastguard Worker bool DcSctpTransport::Start(int local_sctp_port,
177*d9f75844SAndroid Build Coastguard Worker int remote_sctp_port,
178*d9f75844SAndroid Build Coastguard Worker int max_message_size) {
179*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
180*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(max_message_size > 0);
181*d9f75844SAndroid Build Coastguard Worker RTC_DLOG(LS_INFO) << debug_name_ << "->Start(local=" << local_sctp_port
182*d9f75844SAndroid Build Coastguard Worker << ", remote=" << remote_sctp_port
183*d9f75844SAndroid Build Coastguard Worker << ", max_message_size=" << max_message_size << ")";
184*d9f75844SAndroid Build Coastguard Worker
185*d9f75844SAndroid Build Coastguard Worker if (!socket_) {
186*d9f75844SAndroid Build Coastguard Worker dcsctp::DcSctpOptions options;
187*d9f75844SAndroid Build Coastguard Worker options.local_port = local_sctp_port;
188*d9f75844SAndroid Build Coastguard Worker options.remote_port = remote_sctp_port;
189*d9f75844SAndroid Build Coastguard Worker options.max_message_size = max_message_size;
190*d9f75844SAndroid Build Coastguard Worker options.max_timer_backoff_duration = kMaxTimerBackoffDuration;
191*d9f75844SAndroid Build Coastguard Worker // Don't close the connection automatically on too many retransmissions.
192*d9f75844SAndroid Build Coastguard Worker options.max_retransmissions = absl::nullopt;
193*d9f75844SAndroid Build Coastguard Worker options.max_init_retransmits = absl::nullopt;
194*d9f75844SAndroid Build Coastguard Worker
195*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<dcsctp::PacketObserver> packet_observer;
196*d9f75844SAndroid Build Coastguard Worker if (RTC_LOG_CHECK_LEVEL(LS_VERBOSE)) {
197*d9f75844SAndroid Build Coastguard Worker packet_observer =
198*d9f75844SAndroid Build Coastguard Worker std::make_unique<dcsctp::TextPcapPacketObserver>(debug_name_);
199*d9f75844SAndroid Build Coastguard Worker }
200*d9f75844SAndroid Build Coastguard Worker
201*d9f75844SAndroid Build Coastguard Worker socket_ = socket_factory_->Create(debug_name_, *this,
202*d9f75844SAndroid Build Coastguard Worker std::move(packet_observer), options);
203*d9f75844SAndroid Build Coastguard Worker } else {
204*d9f75844SAndroid Build Coastguard Worker if (local_sctp_port != socket_->options().local_port ||
205*d9f75844SAndroid Build Coastguard Worker remote_sctp_port != socket_->options().remote_port) {
206*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR)
207*d9f75844SAndroid Build Coastguard Worker << debug_name_ << "->Start(local=" << local_sctp_port
208*d9f75844SAndroid Build Coastguard Worker << ", remote=" << remote_sctp_port
209*d9f75844SAndroid Build Coastguard Worker << "): Can't change ports on already started transport.";
210*d9f75844SAndroid Build Coastguard Worker return false;
211*d9f75844SAndroid Build Coastguard Worker }
212*d9f75844SAndroid Build Coastguard Worker socket_->SetMaxMessageSize(max_message_size);
213*d9f75844SAndroid Build Coastguard Worker }
214*d9f75844SAndroid Build Coastguard Worker
215*d9f75844SAndroid Build Coastguard Worker MaybeConnectSocket();
216*d9f75844SAndroid Build Coastguard Worker
217*d9f75844SAndroid Build Coastguard Worker return true;
218*d9f75844SAndroid Build Coastguard Worker }
219*d9f75844SAndroid Build Coastguard Worker
OpenStream(int sid)220*d9f75844SAndroid Build Coastguard Worker bool DcSctpTransport::OpenStream(int sid) {
221*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
222*d9f75844SAndroid Build Coastguard Worker RTC_DLOG(LS_INFO) << debug_name_ << "->OpenStream(" << sid << ").";
223*d9f75844SAndroid Build Coastguard Worker
224*d9f75844SAndroid Build Coastguard Worker StreamState stream_state;
225*d9f75844SAndroid Build Coastguard Worker stream_states_.insert_or_assign(dcsctp::StreamID(static_cast<uint16_t>(sid)),
226*d9f75844SAndroid Build Coastguard Worker stream_state);
227*d9f75844SAndroid Build Coastguard Worker return true;
228*d9f75844SAndroid Build Coastguard Worker }
229*d9f75844SAndroid Build Coastguard Worker
ResetStream(int sid)230*d9f75844SAndroid Build Coastguard Worker bool DcSctpTransport::ResetStream(int sid) {
231*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
232*d9f75844SAndroid Build Coastguard Worker RTC_DLOG(LS_INFO) << debug_name_ << "->ResetStream(" << sid << ").";
233*d9f75844SAndroid Build Coastguard Worker if (!socket_) {
234*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << debug_name_ << "->ResetStream(sid=" << sid
235*d9f75844SAndroid Build Coastguard Worker << "): Transport is not started.";
236*d9f75844SAndroid Build Coastguard Worker return false;
237*d9f75844SAndroid Build Coastguard Worker }
238*d9f75844SAndroid Build Coastguard Worker
239*d9f75844SAndroid Build Coastguard Worker dcsctp::StreamID streams[1] = {dcsctp::StreamID(static_cast<uint16_t>(sid))};
240*d9f75844SAndroid Build Coastguard Worker
241*d9f75844SAndroid Build Coastguard Worker auto it = stream_states_.find(streams[0]);
242*d9f75844SAndroid Build Coastguard Worker if (it == stream_states_.end()) {
243*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << debug_name_ << "->ResetStream(sid=" << sid
244*d9f75844SAndroid Build Coastguard Worker << "): Stream is not open.";
245*d9f75844SAndroid Build Coastguard Worker return false;
246*d9f75844SAndroid Build Coastguard Worker }
247*d9f75844SAndroid Build Coastguard Worker
248*d9f75844SAndroid Build Coastguard Worker StreamState& stream_state = it->second;
249*d9f75844SAndroid Build Coastguard Worker if (stream_state.closure_initiated || stream_state.incoming_reset_done ||
250*d9f75844SAndroid Build Coastguard Worker stream_state.outgoing_reset_done) {
251*d9f75844SAndroid Build Coastguard Worker // The closing procedure was already initiated by the remote, don't do
252*d9f75844SAndroid Build Coastguard Worker // anything.
253*d9f75844SAndroid Build Coastguard Worker return false;
254*d9f75844SAndroid Build Coastguard Worker }
255*d9f75844SAndroid Build Coastguard Worker stream_state.closure_initiated = true;
256*d9f75844SAndroid Build Coastguard Worker socket_->ResetStreams(streams);
257*d9f75844SAndroid Build Coastguard Worker return true;
258*d9f75844SAndroid Build Coastguard Worker }
259*d9f75844SAndroid Build Coastguard Worker
SendData(int sid,const SendDataParams & params,const rtc::CopyOnWriteBuffer & payload,cricket::SendDataResult * result)260*d9f75844SAndroid Build Coastguard Worker bool DcSctpTransport::SendData(int sid,
261*d9f75844SAndroid Build Coastguard Worker const SendDataParams& params,
262*d9f75844SAndroid Build Coastguard Worker const rtc::CopyOnWriteBuffer& payload,
263*d9f75844SAndroid Build Coastguard Worker cricket::SendDataResult* result) {
264*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
265*d9f75844SAndroid Build Coastguard Worker RTC_DLOG(LS_VERBOSE) << debug_name_ << "->SendData(sid=" << sid
266*d9f75844SAndroid Build Coastguard Worker << ", type=" << static_cast<int>(params.type)
267*d9f75844SAndroid Build Coastguard Worker << ", length=" << payload.size() << ").";
268*d9f75844SAndroid Build Coastguard Worker
269*d9f75844SAndroid Build Coastguard Worker if (!socket_) {
270*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << debug_name_
271*d9f75844SAndroid Build Coastguard Worker << "->SendData(...): Transport is not started.";
272*d9f75844SAndroid Build Coastguard Worker *result = cricket::SDR_ERROR;
273*d9f75844SAndroid Build Coastguard Worker return false;
274*d9f75844SAndroid Build Coastguard Worker }
275*d9f75844SAndroid Build Coastguard Worker
276*d9f75844SAndroid Build Coastguard Worker // It is possible for a message to be sent from the signaling thread at the
277*d9f75844SAndroid Build Coastguard Worker // same time a data-channel is closing, but before the signaling thread is
278*d9f75844SAndroid Build Coastguard Worker // aware of it. So we need to keep track of currently active data channels and
279*d9f75844SAndroid Build Coastguard Worker // skip sending messages for the ones that are not open or closing.
280*d9f75844SAndroid Build Coastguard Worker // The sending errors are not impacting the data channel API contract as
281*d9f75844SAndroid Build Coastguard Worker // it is allowed to discard queued messages when the channel is closing.
282*d9f75844SAndroid Build Coastguard Worker auto stream_state =
283*d9f75844SAndroid Build Coastguard Worker stream_states_.find(dcsctp::StreamID(static_cast<uint16_t>(sid)));
284*d9f75844SAndroid Build Coastguard Worker if (stream_state == stream_states_.end()) {
285*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_VERBOSE) << "Skipping message on non-open stream with sid: "
286*d9f75844SAndroid Build Coastguard Worker << sid;
287*d9f75844SAndroid Build Coastguard Worker *result = cricket::SDR_ERROR;
288*d9f75844SAndroid Build Coastguard Worker return false;
289*d9f75844SAndroid Build Coastguard Worker }
290*d9f75844SAndroid Build Coastguard Worker
291*d9f75844SAndroid Build Coastguard Worker if (stream_state->second.closure_initiated ||
292*d9f75844SAndroid Build Coastguard Worker stream_state->second.incoming_reset_done ||
293*d9f75844SAndroid Build Coastguard Worker stream_state->second.outgoing_reset_done) {
294*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_VERBOSE) << "Skipping message on closing stream with sid: "
295*d9f75844SAndroid Build Coastguard Worker << sid;
296*d9f75844SAndroid Build Coastguard Worker *result = cricket::SDR_ERROR;
297*d9f75844SAndroid Build Coastguard Worker return false;
298*d9f75844SAndroid Build Coastguard Worker }
299*d9f75844SAndroid Build Coastguard Worker
300*d9f75844SAndroid Build Coastguard Worker auto max_message_size = socket_->options().max_message_size;
301*d9f75844SAndroid Build Coastguard Worker if (max_message_size > 0 && payload.size() > max_message_size) {
302*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << debug_name_
303*d9f75844SAndroid Build Coastguard Worker << "->SendData(...): "
304*d9f75844SAndroid Build Coastguard Worker "Trying to send packet bigger "
305*d9f75844SAndroid Build Coastguard Worker "than the max message size: "
306*d9f75844SAndroid Build Coastguard Worker << payload.size() << " vs max of " << max_message_size;
307*d9f75844SAndroid Build Coastguard Worker *result = cricket::SDR_ERROR;
308*d9f75844SAndroid Build Coastguard Worker return false;
309*d9f75844SAndroid Build Coastguard Worker }
310*d9f75844SAndroid Build Coastguard Worker
311*d9f75844SAndroid Build Coastguard Worker std::vector<uint8_t> message_payload(payload.cdata(),
312*d9f75844SAndroid Build Coastguard Worker payload.cdata() + payload.size());
313*d9f75844SAndroid Build Coastguard Worker if (message_payload.empty()) {
314*d9f75844SAndroid Build Coastguard Worker // https://www.rfc-editor.org/rfc/rfc8831.html#section-6.6
315*d9f75844SAndroid Build Coastguard Worker // SCTP does not support the sending of empty user messages. Therefore, if
316*d9f75844SAndroid Build Coastguard Worker // an empty message has to be sent, the appropriate PPID (WebRTC String
317*d9f75844SAndroid Build Coastguard Worker // Empty or WebRTC Binary Empty) is used, and the SCTP user message of one
318*d9f75844SAndroid Build Coastguard Worker // zero byte is sent.
319*d9f75844SAndroid Build Coastguard Worker message_payload.push_back('\0');
320*d9f75844SAndroid Build Coastguard Worker }
321*d9f75844SAndroid Build Coastguard Worker
322*d9f75844SAndroid Build Coastguard Worker dcsctp::DcSctpMessage message(
323*d9f75844SAndroid Build Coastguard Worker dcsctp::StreamID(static_cast<uint16_t>(sid)),
324*d9f75844SAndroid Build Coastguard Worker dcsctp::PPID(static_cast<uint16_t>(ToPPID(params.type, payload.size()))),
325*d9f75844SAndroid Build Coastguard Worker std::move(message_payload));
326*d9f75844SAndroid Build Coastguard Worker
327*d9f75844SAndroid Build Coastguard Worker dcsctp::SendOptions send_options;
328*d9f75844SAndroid Build Coastguard Worker send_options.unordered = dcsctp::IsUnordered(!params.ordered);
329*d9f75844SAndroid Build Coastguard Worker if (params.max_rtx_ms.has_value()) {
330*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(*params.max_rtx_ms >= 0 &&
331*d9f75844SAndroid Build Coastguard Worker *params.max_rtx_ms <= std::numeric_limits<uint16_t>::max());
332*d9f75844SAndroid Build Coastguard Worker send_options.lifetime = dcsctp::DurationMs(*params.max_rtx_ms);
333*d9f75844SAndroid Build Coastguard Worker }
334*d9f75844SAndroid Build Coastguard Worker if (params.max_rtx_count.has_value()) {
335*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(*params.max_rtx_count >= 0 &&
336*d9f75844SAndroid Build Coastguard Worker *params.max_rtx_count <= std::numeric_limits<uint16_t>::max());
337*d9f75844SAndroid Build Coastguard Worker send_options.max_retransmissions = *params.max_rtx_count;
338*d9f75844SAndroid Build Coastguard Worker }
339*d9f75844SAndroid Build Coastguard Worker
340*d9f75844SAndroid Build Coastguard Worker auto error = socket_->Send(std::move(message), send_options);
341*d9f75844SAndroid Build Coastguard Worker switch (error) {
342*d9f75844SAndroid Build Coastguard Worker case dcsctp::SendStatus::kSuccess:
343*d9f75844SAndroid Build Coastguard Worker *result = cricket::SDR_SUCCESS;
344*d9f75844SAndroid Build Coastguard Worker break;
345*d9f75844SAndroid Build Coastguard Worker case dcsctp::SendStatus::kErrorResourceExhaustion:
346*d9f75844SAndroid Build Coastguard Worker *result = cricket::SDR_BLOCK;
347*d9f75844SAndroid Build Coastguard Worker ready_to_send_data_ = false;
348*d9f75844SAndroid Build Coastguard Worker break;
349*d9f75844SAndroid Build Coastguard Worker default:
350*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << debug_name_
351*d9f75844SAndroid Build Coastguard Worker << "->SendData(...): send() failed with error "
352*d9f75844SAndroid Build Coastguard Worker << dcsctp::ToString(error) << ".";
353*d9f75844SAndroid Build Coastguard Worker *result = cricket::SDR_ERROR;
354*d9f75844SAndroid Build Coastguard Worker break;
355*d9f75844SAndroid Build Coastguard Worker }
356*d9f75844SAndroid Build Coastguard Worker
357*d9f75844SAndroid Build Coastguard Worker return *result == cricket::SDR_SUCCESS;
358*d9f75844SAndroid Build Coastguard Worker }
359*d9f75844SAndroid Build Coastguard Worker
ReadyToSendData()360*d9f75844SAndroid Build Coastguard Worker bool DcSctpTransport::ReadyToSendData() {
361*d9f75844SAndroid Build Coastguard Worker return ready_to_send_data_;
362*d9f75844SAndroid Build Coastguard Worker }
363*d9f75844SAndroid Build Coastguard Worker
max_message_size() const364*d9f75844SAndroid Build Coastguard Worker int DcSctpTransport::max_message_size() const {
365*d9f75844SAndroid Build Coastguard Worker if (!socket_) {
366*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << debug_name_
367*d9f75844SAndroid Build Coastguard Worker << "->max_message_size(...): Transport is not started.";
368*d9f75844SAndroid Build Coastguard Worker return 0;
369*d9f75844SAndroid Build Coastguard Worker }
370*d9f75844SAndroid Build Coastguard Worker return socket_->options().max_message_size;
371*d9f75844SAndroid Build Coastguard Worker }
372*d9f75844SAndroid Build Coastguard Worker
max_outbound_streams() const373*d9f75844SAndroid Build Coastguard Worker absl::optional<int> DcSctpTransport::max_outbound_streams() const {
374*d9f75844SAndroid Build Coastguard Worker if (!socket_)
375*d9f75844SAndroid Build Coastguard Worker return absl::nullopt;
376*d9f75844SAndroid Build Coastguard Worker return socket_->options().announced_maximum_outgoing_streams;
377*d9f75844SAndroid Build Coastguard Worker }
378*d9f75844SAndroid Build Coastguard Worker
max_inbound_streams() const379*d9f75844SAndroid Build Coastguard Worker absl::optional<int> DcSctpTransport::max_inbound_streams() const {
380*d9f75844SAndroid Build Coastguard Worker if (!socket_)
381*d9f75844SAndroid Build Coastguard Worker return absl::nullopt;
382*d9f75844SAndroid Build Coastguard Worker return socket_->options().announced_maximum_incoming_streams;
383*d9f75844SAndroid Build Coastguard Worker }
384*d9f75844SAndroid Build Coastguard Worker
set_debug_name_for_testing(const char * debug_name)385*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::set_debug_name_for_testing(const char* debug_name) {
386*d9f75844SAndroid Build Coastguard Worker debug_name_ = debug_name;
387*d9f75844SAndroid Build Coastguard Worker }
388*d9f75844SAndroid Build Coastguard Worker
SendPacketWithStatus(rtc::ArrayView<const uint8_t> data)389*d9f75844SAndroid Build Coastguard Worker SendPacketStatus DcSctpTransport::SendPacketWithStatus(
390*d9f75844SAndroid Build Coastguard Worker rtc::ArrayView<const uint8_t> data) {
391*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
392*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(socket_);
393*d9f75844SAndroid Build Coastguard Worker
394*d9f75844SAndroid Build Coastguard Worker if (data.size() > (socket_->options().mtu)) {
395*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << debug_name_
396*d9f75844SAndroid Build Coastguard Worker << "->SendPacket(...): "
397*d9f75844SAndroid Build Coastguard Worker "SCTP seems to have made a packet that is bigger "
398*d9f75844SAndroid Build Coastguard Worker "than its official MTU: "
399*d9f75844SAndroid Build Coastguard Worker << data.size() << " vs max of " << socket_->options().mtu;
400*d9f75844SAndroid Build Coastguard Worker return SendPacketStatus::kError;
401*d9f75844SAndroid Build Coastguard Worker }
402*d9f75844SAndroid Build Coastguard Worker TRACE_EVENT0("webrtc", "DcSctpTransport::SendPacket");
403*d9f75844SAndroid Build Coastguard Worker
404*d9f75844SAndroid Build Coastguard Worker if (!transport_ || !transport_->writable())
405*d9f75844SAndroid Build Coastguard Worker return SendPacketStatus::kError;
406*d9f75844SAndroid Build Coastguard Worker
407*d9f75844SAndroid Build Coastguard Worker RTC_DLOG(LS_VERBOSE) << debug_name_ << "->SendPacket(length=" << data.size()
408*d9f75844SAndroid Build Coastguard Worker << ")";
409*d9f75844SAndroid Build Coastguard Worker
410*d9f75844SAndroid Build Coastguard Worker auto result =
411*d9f75844SAndroid Build Coastguard Worker transport_->SendPacket(reinterpret_cast<const char*>(data.data()),
412*d9f75844SAndroid Build Coastguard Worker data.size(), rtc::PacketOptions(), 0);
413*d9f75844SAndroid Build Coastguard Worker
414*d9f75844SAndroid Build Coastguard Worker if (result < 0) {
415*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << debug_name_ << "->SendPacket(length=" << data.size()
416*d9f75844SAndroid Build Coastguard Worker << ") failed with error: " << transport_->GetError()
417*d9f75844SAndroid Build Coastguard Worker << ".";
418*d9f75844SAndroid Build Coastguard Worker
419*d9f75844SAndroid Build Coastguard Worker if (rtc::IsBlockingError(transport_->GetError())) {
420*d9f75844SAndroid Build Coastguard Worker return SendPacketStatus::kTemporaryFailure;
421*d9f75844SAndroid Build Coastguard Worker }
422*d9f75844SAndroid Build Coastguard Worker return SendPacketStatus::kError;
423*d9f75844SAndroid Build Coastguard Worker }
424*d9f75844SAndroid Build Coastguard Worker return SendPacketStatus::kSuccess;
425*d9f75844SAndroid Build Coastguard Worker }
426*d9f75844SAndroid Build Coastguard Worker
CreateTimeout(webrtc::TaskQueueBase::DelayPrecision precision)427*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<dcsctp::Timeout> DcSctpTransport::CreateTimeout(
428*d9f75844SAndroid Build Coastguard Worker webrtc::TaskQueueBase::DelayPrecision precision) {
429*d9f75844SAndroid Build Coastguard Worker return task_queue_timeout_factory_.CreateTimeout(precision);
430*d9f75844SAndroid Build Coastguard Worker }
431*d9f75844SAndroid Build Coastguard Worker
TimeMillis()432*d9f75844SAndroid Build Coastguard Worker dcsctp::TimeMs DcSctpTransport::TimeMillis() {
433*d9f75844SAndroid Build Coastguard Worker return dcsctp::TimeMs(clock_->TimeInMilliseconds());
434*d9f75844SAndroid Build Coastguard Worker }
435*d9f75844SAndroid Build Coastguard Worker
GetRandomInt(uint32_t low,uint32_t high)436*d9f75844SAndroid Build Coastguard Worker uint32_t DcSctpTransport::GetRandomInt(uint32_t low, uint32_t high) {
437*d9f75844SAndroid Build Coastguard Worker return random_.Rand(low, high);
438*d9f75844SAndroid Build Coastguard Worker }
439*d9f75844SAndroid Build Coastguard Worker
OnTotalBufferedAmountLow()440*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::OnTotalBufferedAmountLow() {
441*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
442*d9f75844SAndroid Build Coastguard Worker if (!ready_to_send_data_) {
443*d9f75844SAndroid Build Coastguard Worker ready_to_send_data_ = true;
444*d9f75844SAndroid Build Coastguard Worker if (data_channel_sink_) {
445*d9f75844SAndroid Build Coastguard Worker data_channel_sink_->OnReadyToSend();
446*d9f75844SAndroid Build Coastguard Worker }
447*d9f75844SAndroid Build Coastguard Worker }
448*d9f75844SAndroid Build Coastguard Worker }
449*d9f75844SAndroid Build Coastguard Worker
OnMessageReceived(dcsctp::DcSctpMessage message)450*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::OnMessageReceived(dcsctp::DcSctpMessage message) {
451*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
452*d9f75844SAndroid Build Coastguard Worker RTC_DLOG(LS_VERBOSE) << debug_name_ << "->OnMessageReceived(sid="
453*d9f75844SAndroid Build Coastguard Worker << message.stream_id().value()
454*d9f75844SAndroid Build Coastguard Worker << ", ppid=" << message.ppid().value()
455*d9f75844SAndroid Build Coastguard Worker << ", length=" << message.payload().size() << ").";
456*d9f75844SAndroid Build Coastguard Worker cricket::ReceiveDataParams receive_data_params;
457*d9f75844SAndroid Build Coastguard Worker receive_data_params.sid = message.stream_id().value();
458*d9f75844SAndroid Build Coastguard Worker auto type = ToDataMessageType(message.ppid());
459*d9f75844SAndroid Build Coastguard Worker if (!type.has_value()) {
460*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_VERBOSE) << debug_name_
461*d9f75844SAndroid Build Coastguard Worker << "->OnMessageReceived(): Received an unknown PPID "
462*d9f75844SAndroid Build Coastguard Worker << message.ppid().value()
463*d9f75844SAndroid Build Coastguard Worker << " on an SCTP packet. Dropping.";
464*d9f75844SAndroid Build Coastguard Worker }
465*d9f75844SAndroid Build Coastguard Worker receive_data_params.type = *type;
466*d9f75844SAndroid Build Coastguard Worker // No seq_num available from dcSCTP
467*d9f75844SAndroid Build Coastguard Worker receive_data_params.seq_num = 0;
468*d9f75844SAndroid Build Coastguard Worker receive_buffer_.Clear();
469*d9f75844SAndroid Build Coastguard Worker if (!IsEmptyPPID(message.ppid()))
470*d9f75844SAndroid Build Coastguard Worker receive_buffer_.AppendData(message.payload().data(),
471*d9f75844SAndroid Build Coastguard Worker message.payload().size());
472*d9f75844SAndroid Build Coastguard Worker
473*d9f75844SAndroid Build Coastguard Worker if (data_channel_sink_) {
474*d9f75844SAndroid Build Coastguard Worker data_channel_sink_->OnDataReceived(
475*d9f75844SAndroid Build Coastguard Worker receive_data_params.sid, receive_data_params.type, receive_buffer_);
476*d9f75844SAndroid Build Coastguard Worker }
477*d9f75844SAndroid Build Coastguard Worker }
478*d9f75844SAndroid Build Coastguard Worker
OnError(dcsctp::ErrorKind error,absl::string_view message)479*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::OnError(dcsctp::ErrorKind error,
480*d9f75844SAndroid Build Coastguard Worker absl::string_view message) {
481*d9f75844SAndroid Build Coastguard Worker if (error == dcsctp::ErrorKind::kResourceExhaustion) {
482*d9f75844SAndroid Build Coastguard Worker // Indicates that a message failed to be enqueued, because the send buffer
483*d9f75844SAndroid Build Coastguard Worker // is full, which is a very common (and wanted) state for high throughput
484*d9f75844SAndroid Build Coastguard Worker // sending/benchmarks.
485*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_VERBOSE) << debug_name_
486*d9f75844SAndroid Build Coastguard Worker << "->OnError(error=" << dcsctp::ToString(error)
487*d9f75844SAndroid Build Coastguard Worker << ", message=" << message << ").";
488*d9f75844SAndroid Build Coastguard Worker } else {
489*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << debug_name_
490*d9f75844SAndroid Build Coastguard Worker << "->OnError(error=" << dcsctp::ToString(error)
491*d9f75844SAndroid Build Coastguard Worker << ", message=" << message << ").";
492*d9f75844SAndroid Build Coastguard Worker }
493*d9f75844SAndroid Build Coastguard Worker }
494*d9f75844SAndroid Build Coastguard Worker
OnAborted(dcsctp::ErrorKind error,absl::string_view message)495*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::OnAborted(dcsctp::ErrorKind error,
496*d9f75844SAndroid Build Coastguard Worker absl::string_view message) {
497*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
498*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << debug_name_
499*d9f75844SAndroid Build Coastguard Worker << "->OnAborted(error=" << dcsctp::ToString(error)
500*d9f75844SAndroid Build Coastguard Worker << ", message=" << message << ").";
501*d9f75844SAndroid Build Coastguard Worker ready_to_send_data_ = false;
502*d9f75844SAndroid Build Coastguard Worker RTCError rtc_error(RTCErrorType::OPERATION_ERROR_WITH_DATA,
503*d9f75844SAndroid Build Coastguard Worker std::string(message));
504*d9f75844SAndroid Build Coastguard Worker rtc_error.set_error_detail(RTCErrorDetailType::SCTP_FAILURE);
505*d9f75844SAndroid Build Coastguard Worker auto code = ToErrorCauseCode(error);
506*d9f75844SAndroid Build Coastguard Worker if (code.has_value()) {
507*d9f75844SAndroid Build Coastguard Worker rtc_error.set_sctp_cause_code(static_cast<uint16_t>(*code));
508*d9f75844SAndroid Build Coastguard Worker }
509*d9f75844SAndroid Build Coastguard Worker if (data_channel_sink_) {
510*d9f75844SAndroid Build Coastguard Worker data_channel_sink_->OnTransportClosed(rtc_error);
511*d9f75844SAndroid Build Coastguard Worker }
512*d9f75844SAndroid Build Coastguard Worker }
513*d9f75844SAndroid Build Coastguard Worker
OnConnected()514*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::OnConnected() {
515*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
516*d9f75844SAndroid Build Coastguard Worker RTC_DLOG(LS_INFO) << debug_name_ << "->OnConnected().";
517*d9f75844SAndroid Build Coastguard Worker ready_to_send_data_ = true;
518*d9f75844SAndroid Build Coastguard Worker if (data_channel_sink_) {
519*d9f75844SAndroid Build Coastguard Worker data_channel_sink_->OnReadyToSend();
520*d9f75844SAndroid Build Coastguard Worker }
521*d9f75844SAndroid Build Coastguard Worker if (on_connected_callback_) {
522*d9f75844SAndroid Build Coastguard Worker on_connected_callback_();
523*d9f75844SAndroid Build Coastguard Worker }
524*d9f75844SAndroid Build Coastguard Worker }
525*d9f75844SAndroid Build Coastguard Worker
OnClosed()526*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::OnClosed() {
527*d9f75844SAndroid Build Coastguard Worker RTC_DLOG(LS_INFO) << debug_name_ << "->OnClosed().";
528*d9f75844SAndroid Build Coastguard Worker ready_to_send_data_ = false;
529*d9f75844SAndroid Build Coastguard Worker }
530*d9f75844SAndroid Build Coastguard Worker
OnConnectionRestarted()531*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::OnConnectionRestarted() {
532*d9f75844SAndroid Build Coastguard Worker RTC_DLOG(LS_INFO) << debug_name_ << "->OnConnectionRestarted().";
533*d9f75844SAndroid Build Coastguard Worker }
534*d9f75844SAndroid Build Coastguard Worker
OnStreamsResetFailed(rtc::ArrayView<const dcsctp::StreamID> outgoing_streams,absl::string_view reason)535*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::OnStreamsResetFailed(
536*d9f75844SAndroid Build Coastguard Worker rtc::ArrayView<const dcsctp::StreamID> outgoing_streams,
537*d9f75844SAndroid Build Coastguard Worker absl::string_view reason) {
538*d9f75844SAndroid Build Coastguard Worker // TODO(orphis): Need a test to check for correct behavior
539*d9f75844SAndroid Build Coastguard Worker for (auto& stream_id : outgoing_streams) {
540*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING)
541*d9f75844SAndroid Build Coastguard Worker << debug_name_
542*d9f75844SAndroid Build Coastguard Worker << "->OnStreamsResetFailed(...): Outgoing stream reset failed"
543*d9f75844SAndroid Build Coastguard Worker << ", sid=" << stream_id.value() << ", reason: " << reason << ".";
544*d9f75844SAndroid Build Coastguard Worker }
545*d9f75844SAndroid Build Coastguard Worker }
546*d9f75844SAndroid Build Coastguard Worker
OnStreamsResetPerformed(rtc::ArrayView<const dcsctp::StreamID> outgoing_streams)547*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::OnStreamsResetPerformed(
548*d9f75844SAndroid Build Coastguard Worker rtc::ArrayView<const dcsctp::StreamID> outgoing_streams) {
549*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
550*d9f75844SAndroid Build Coastguard Worker for (auto& stream_id : outgoing_streams) {
551*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << debug_name_
552*d9f75844SAndroid Build Coastguard Worker << "->OnStreamsResetPerformed(...): Outgoing stream reset"
553*d9f75844SAndroid Build Coastguard Worker << ", sid=" << stream_id.value();
554*d9f75844SAndroid Build Coastguard Worker
555*d9f75844SAndroid Build Coastguard Worker auto it = stream_states_.find(stream_id);
556*d9f75844SAndroid Build Coastguard Worker if (it == stream_states_.end()) {
557*d9f75844SAndroid Build Coastguard Worker // Ignoring an outgoing stream reset for a closed stream
558*d9f75844SAndroid Build Coastguard Worker return;
559*d9f75844SAndroid Build Coastguard Worker }
560*d9f75844SAndroid Build Coastguard Worker
561*d9f75844SAndroid Build Coastguard Worker StreamState& stream_state = it->second;
562*d9f75844SAndroid Build Coastguard Worker stream_state.outgoing_reset_done = true;
563*d9f75844SAndroid Build Coastguard Worker
564*d9f75844SAndroid Build Coastguard Worker if (stream_state.incoming_reset_done) {
565*d9f75844SAndroid Build Coastguard Worker // When the close was not initiated locally, we can signal the end of the
566*d9f75844SAndroid Build Coastguard Worker // data channel close procedure when the remote ACKs the reset.
567*d9f75844SAndroid Build Coastguard Worker if (data_channel_sink_) {
568*d9f75844SAndroid Build Coastguard Worker data_channel_sink_->OnChannelClosed(stream_id.value());
569*d9f75844SAndroid Build Coastguard Worker }
570*d9f75844SAndroid Build Coastguard Worker stream_states_.erase(stream_id);
571*d9f75844SAndroid Build Coastguard Worker }
572*d9f75844SAndroid Build Coastguard Worker }
573*d9f75844SAndroid Build Coastguard Worker }
574*d9f75844SAndroid Build Coastguard Worker
OnIncomingStreamsReset(rtc::ArrayView<const dcsctp::StreamID> incoming_streams)575*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::OnIncomingStreamsReset(
576*d9f75844SAndroid Build Coastguard Worker rtc::ArrayView<const dcsctp::StreamID> incoming_streams) {
577*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
578*d9f75844SAndroid Build Coastguard Worker for (auto& stream_id : incoming_streams) {
579*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << debug_name_
580*d9f75844SAndroid Build Coastguard Worker << "->OnIncomingStreamsReset(...): Incoming stream reset"
581*d9f75844SAndroid Build Coastguard Worker << ", sid=" << stream_id.value();
582*d9f75844SAndroid Build Coastguard Worker
583*d9f75844SAndroid Build Coastguard Worker auto it = stream_states_.find(stream_id);
584*d9f75844SAndroid Build Coastguard Worker if (it == stream_states_.end())
585*d9f75844SAndroid Build Coastguard Worker return;
586*d9f75844SAndroid Build Coastguard Worker
587*d9f75844SAndroid Build Coastguard Worker StreamState& stream_state = it->second;
588*d9f75844SAndroid Build Coastguard Worker stream_state.incoming_reset_done = true;
589*d9f75844SAndroid Build Coastguard Worker
590*d9f75844SAndroid Build Coastguard Worker if (!stream_state.closure_initiated) {
591*d9f75844SAndroid Build Coastguard Worker // When receiving an incoming stream reset event for a non local close
592*d9f75844SAndroid Build Coastguard Worker // procedure, the transport needs to reset the stream in the other
593*d9f75844SAndroid Build Coastguard Worker // direction too.
594*d9f75844SAndroid Build Coastguard Worker dcsctp::StreamID streams[1] = {stream_id};
595*d9f75844SAndroid Build Coastguard Worker socket_->ResetStreams(streams);
596*d9f75844SAndroid Build Coastguard Worker if (data_channel_sink_) {
597*d9f75844SAndroid Build Coastguard Worker data_channel_sink_->OnChannelClosing(stream_id.value());
598*d9f75844SAndroid Build Coastguard Worker }
599*d9f75844SAndroid Build Coastguard Worker }
600*d9f75844SAndroid Build Coastguard Worker
601*d9f75844SAndroid Build Coastguard Worker if (stream_state.outgoing_reset_done) {
602*d9f75844SAndroid Build Coastguard Worker // The close procedure that was initiated locally is complete when we
603*d9f75844SAndroid Build Coastguard Worker // receive and incoming reset event.
604*d9f75844SAndroid Build Coastguard Worker if (data_channel_sink_) {
605*d9f75844SAndroid Build Coastguard Worker data_channel_sink_->OnChannelClosed(stream_id.value());
606*d9f75844SAndroid Build Coastguard Worker }
607*d9f75844SAndroid Build Coastguard Worker stream_states_.erase(stream_id);
608*d9f75844SAndroid Build Coastguard Worker }
609*d9f75844SAndroid Build Coastguard Worker }
610*d9f75844SAndroid Build Coastguard Worker }
611*d9f75844SAndroid Build Coastguard Worker
ConnectTransportSignals()612*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::ConnectTransportSignals() {
613*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
614*d9f75844SAndroid Build Coastguard Worker if (!transport_) {
615*d9f75844SAndroid Build Coastguard Worker return;
616*d9f75844SAndroid Build Coastguard Worker }
617*d9f75844SAndroid Build Coastguard Worker transport_->SignalWritableState.connect(
618*d9f75844SAndroid Build Coastguard Worker this, &DcSctpTransport::OnTransportWritableState);
619*d9f75844SAndroid Build Coastguard Worker transport_->SignalReadPacket.connect(this,
620*d9f75844SAndroid Build Coastguard Worker &DcSctpTransport::OnTransportReadPacket);
621*d9f75844SAndroid Build Coastguard Worker transport_->SignalClosed.connect(this, &DcSctpTransport::OnTransportClosed);
622*d9f75844SAndroid Build Coastguard Worker }
623*d9f75844SAndroid Build Coastguard Worker
DisconnectTransportSignals()624*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::DisconnectTransportSignals() {
625*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
626*d9f75844SAndroid Build Coastguard Worker if (!transport_) {
627*d9f75844SAndroid Build Coastguard Worker return;
628*d9f75844SAndroid Build Coastguard Worker }
629*d9f75844SAndroid Build Coastguard Worker transport_->SignalWritableState.disconnect(this);
630*d9f75844SAndroid Build Coastguard Worker transport_->SignalReadPacket.disconnect(this);
631*d9f75844SAndroid Build Coastguard Worker transport_->SignalClosed.disconnect(this);
632*d9f75844SAndroid Build Coastguard Worker }
633*d9f75844SAndroid Build Coastguard Worker
OnTransportWritableState(rtc::PacketTransportInternal * transport)634*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::OnTransportWritableState(
635*d9f75844SAndroid Build Coastguard Worker rtc::PacketTransportInternal* transport) {
636*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
637*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(transport_, transport);
638*d9f75844SAndroid Build Coastguard Worker RTC_DLOG(LS_VERBOSE) << debug_name_
639*d9f75844SAndroid Build Coastguard Worker << "->OnTransportWritableState(), writable="
640*d9f75844SAndroid Build Coastguard Worker << transport->writable();
641*d9f75844SAndroid Build Coastguard Worker MaybeConnectSocket();
642*d9f75844SAndroid Build Coastguard Worker }
643*d9f75844SAndroid Build Coastguard Worker
OnTransportReadPacket(rtc::PacketTransportInternal * transport,const char * data,size_t length,const int64_t &,int flags)644*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::OnTransportReadPacket(
645*d9f75844SAndroid Build Coastguard Worker rtc::PacketTransportInternal* transport,
646*d9f75844SAndroid Build Coastguard Worker const char* data,
647*d9f75844SAndroid Build Coastguard Worker size_t length,
648*d9f75844SAndroid Build Coastguard Worker const int64_t& /* packet_time_us */,
649*d9f75844SAndroid Build Coastguard Worker int flags) {
650*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
651*d9f75844SAndroid Build Coastguard Worker if (flags) {
652*d9f75844SAndroid Build Coastguard Worker // We are only interested in SCTP packets.
653*d9f75844SAndroid Build Coastguard Worker return;
654*d9f75844SAndroid Build Coastguard Worker }
655*d9f75844SAndroid Build Coastguard Worker
656*d9f75844SAndroid Build Coastguard Worker RTC_DLOG(LS_VERBOSE) << debug_name_
657*d9f75844SAndroid Build Coastguard Worker << "->OnTransportReadPacket(), length=" << length;
658*d9f75844SAndroid Build Coastguard Worker if (socket_) {
659*d9f75844SAndroid Build Coastguard Worker socket_->ReceivePacket(rtc::ArrayView<const uint8_t>(
660*d9f75844SAndroid Build Coastguard Worker reinterpret_cast<const uint8_t*>(data), length));
661*d9f75844SAndroid Build Coastguard Worker }
662*d9f75844SAndroid Build Coastguard Worker }
663*d9f75844SAndroid Build Coastguard Worker
OnTransportClosed(rtc::PacketTransportInternal * transport)664*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::OnTransportClosed(
665*d9f75844SAndroid Build Coastguard Worker rtc::PacketTransportInternal* transport) {
666*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread_);
667*d9f75844SAndroid Build Coastguard Worker RTC_DLOG(LS_VERBOSE) << debug_name_ << "->OnTransportClosed().";
668*d9f75844SAndroid Build Coastguard Worker if (data_channel_sink_) {
669*d9f75844SAndroid Build Coastguard Worker data_channel_sink_->OnTransportClosed({});
670*d9f75844SAndroid Build Coastguard Worker }
671*d9f75844SAndroid Build Coastguard Worker }
672*d9f75844SAndroid Build Coastguard Worker
MaybeConnectSocket()673*d9f75844SAndroid Build Coastguard Worker void DcSctpTransport::MaybeConnectSocket() {
674*d9f75844SAndroid Build Coastguard Worker if (transport_ && transport_->writable() && socket_ &&
675*d9f75844SAndroid Build Coastguard Worker socket_->state() == dcsctp::SocketState::kClosed) {
676*d9f75844SAndroid Build Coastguard Worker socket_->Connect();
677*d9f75844SAndroid Build Coastguard Worker }
678*d9f75844SAndroid Build Coastguard Worker }
679*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
680