xref: /aosp_15_r20/external/webrtc/media/sctp/dcsctp_transport.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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