webrtc_m130/media/sctp/sctp_transport_internal.h
Jonas Oreland 575d323671 Fix dcsctp handling of dtls restart
dtls_transport will when detecting a new fingerprint
(e.g by usage of pranswer) signal DtlsTransportState::kNew.
When this happen, the dtls crypto state is lost, and
sctp should reconnect, srtp does this automatically
in current code base.

The existing behavior in dcsctp is that it will detect
peer sending an init, and reconnect. But any messages sent
between the dtls restart and the message arriving from the
peer will be lost.

This patch changes so that this case is gracefully handled by
a) letting dcsctp_transport listen to dtls state
this is big part of patch and involves changing the type of
the underlying dtransport from rtc::PacketTransportInternal to cricket::DtlsTransportInternal. If requested, I can put this
into a separate patch...

b) if a dtls restart happens, delete and restart socket.

Testcase that fails before patch and works after is attached.
Bonus: And include-what-you-use on patch

Bug: b/375327137
Change-Id: Ib78488ae75fd8aeb50d121adf464a33dabbf95e2
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/367202
Commit-Queue: Jonas Oreland <jonaso@webrtc.org>
Reviewed-by: Victor Boivie <boivie@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Auto-Submit: Jonas Oreland <jonaso@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#43546}
2024-12-12 02:47:01 -08:00

157 lines
6.7 KiB
C++

/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef MEDIA_SCTP_SCTP_TRANSPORT_INTERNAL_H_
#define MEDIA_SCTP_SCTP_TRANSPORT_INTERNAL_H_
// TODO(deadbeef): Move SCTP code out of media/, and make it not depend on
// anything in media/.
#include <memory>
#include <string>
#include <vector>
#include "api/priority.h"
#include "api/rtc_error.h"
#include "api/transport/data_channel_transport_interface.h"
#include "media/base/media_channel.h"
#include "p2p/base/packet_transport_internal.h"
#include "p2p/dtls/dtls_transport_internal.h"
#include "rtc_base/copy_on_write_buffer.h"
#include "rtc_base/thread.h"
namespace cricket {
// Constants that are important to API users
// The size of the SCTP association send buffer. 256kB, the usrsctp default.
constexpr int kSctpSendBufferSize = 256 * 1024;
// The number of outgoing streams that we'll negotiate. Since stream IDs (SIDs)
// are 0-based, the highest usable SID is 1023.
//
// It's recommended to use the maximum of 65535 in:
// https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-6.2
// However, we use 1024 in order to save memory. usrsctp allocates 104 bytes
// for each pair of incoming/outgoing streams (on a 64-bit system), so 65535
// streams would waste ~6MB.
//
// Note: "max" and "min" here are inclusive.
constexpr uint16_t kMaxSctpStreams = 1024;
constexpr uint16_t kMaxSctpSid = kMaxSctpStreams - 1;
constexpr uint16_t kMinSctpSid = 0;
// The maximum number of streams that can be negotiated according to spec.
constexpr uint16_t kSpecMaxSctpSid = 65535;
// This is the default SCTP port to use. It is passed along the wire and the
// connectee and connector must be using the same port. It is not related to the
// ports at the IP level. (Corresponds to: sockaddr_conn.sconn_port in
// usrsctp.h)
const int kSctpDefaultPort = 5000;
// Error cause codes defined at
// https://www.iana.org/assignments/sctp-parameters/sctp-parameters.xhtml#sctp-parameters-24
enum class SctpErrorCauseCode : uint16_t {
kInvalidStreamIdentifier = 1,
kMissingMandatoryParameter = 2,
kStaleCookieError = 3,
kOutOfResource = 4,
kUnresolvableAddress = 5,
kUnrecognizedChunkType = 6,
kInvalidMandatoryParameter = 7,
kUnrecognizedParameters = 8,
kNoUserData = 9,
kCookieReceivedWhileShuttingDown = 10,
kRestartWithNewAddresses = 11,
kUserInitiatedAbort = 12,
kProtocolViolation = 13,
};
// Abstract SctpTransport interface for use internally (by PeerConnection etc.).
// Exists to allow mock/fake SctpTransports to be created.
class SctpTransportInternal {
public:
virtual ~SctpTransportInternal() {}
virtual void SetOnConnectedCallback(std::function<void()> callback) = 0;
virtual void SetDataChannelSink(webrtc::DataChannelSink* sink) = 0;
// Changes what underlying DTLS transport is uses. Used when switching which
// bundled transport the SctpTransport uses.
virtual void SetDtlsTransport(cricket::DtlsTransportInternal* transport) = 0;
// When Start is called, connects as soon as possible; this can be called
// before DTLS completes, in which case the connection will begin when DTLS
// completes. This method can be called multiple times, though not if either
// of the ports are changed.
//
// `local_sctp_port` and `remote_sctp_port` are passed along the wire and the
// listener and connector must be using the same port. They are not related
// to the ports at the IP level. If set to -1, we default to
// kSctpDefaultPort.
// `max_message_size_` sets the max message size on the connection.
// It must be smaller than or equal to kSctpSendBufferSize.
// It can be changed by a secons Start() call.
//
// TODO(deadbeef): Support calling Start with different local/remote ports
// and create a new association? Not clear if this is something we need to
// support though. See: https://github.com/w3c/webrtc-pc/issues/979
virtual bool Start(int local_sctp_port,
int remote_sctp_port,
int max_message_size) = 0;
// NOTE: Initially there was a "Stop" method here, but it was never used, so
// it was removed.
// Informs SctpTransport that `sid` will start being used. Returns false if
// it is impossible to use `sid`, or if it's already in use.
// Until calling this, can't send data using `sid`.
// TODO(deadbeef): Actually implement the "returns false if `sid` can't be
// used" part. See:
// https://bugs.chromium.org/p/chromium/issues/detail?id=619849
virtual bool OpenStream(int sid, webrtc::PriorityValue priority) = 0;
// The inverse of OpenStream. Begins the closing procedure, which will
// eventually result in SignalClosingProcedureComplete on the side that
// initiates it, and both SignalClosingProcedureStartedRemotely and
// SignalClosingProcedureComplete on the other side.
virtual bool ResetStream(int sid) = 0;
// Send data down this channel.
// Returns RTCError::OK() if successful an error otherwise. Notably
// RTCErrorType::RESOURCE_EXHAUSTED for blocked operations.
virtual webrtc::RTCError SendData(int sid,
const webrtc::SendDataParams& params,
const rtc::CopyOnWriteBuffer& payload) = 0;
// Indicates when the SCTP socket is created and not blocked by congestion
// control. This changes to false when SDR_BLOCK is returned from SendData,
// and
// changes to true when SignalReadyToSendData is fired. The underlying DTLS/
// ICE channels may be unwritable while ReadyToSendData is true, because data
// can still be queued in usrsctp.
virtual bool ReadyToSendData() = 0;
// Returns the current max message size, set with Start().
virtual int max_message_size() const = 0;
// Returns the current negotiated max # of outbound streams.
// Will return std::nullopt if negotiation is incomplete.
virtual std::optional<int> max_outbound_streams() const = 0;
// Returns the current negotiated max # of inbound streams.
virtual std::optional<int> max_inbound_streams() const = 0;
// Returns the amount of buffered data in the send queue for a stream.
virtual size_t buffered_amount(int sid) const = 0;
virtual size_t buffered_amount_low_threshold(int sid) const = 0;
virtual void SetBufferedAmountLowThreshold(int sid, size_t bytes) = 0;
// Helper for debugging.
virtual void set_debug_name_for_testing(const char* debug_name) = 0;
};
} // namespace cricket
#endif // MEDIA_SCTP_SCTP_TRANSPORT_INTERNAL_H_