summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/net/dcsctp/public
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/net/dcsctp/public')
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/BUILD.gn103
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/dcsctp_handover_state.cc68
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/dcsctp_handover_state.h135
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/dcsctp_message.h54
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/dcsctp_options.h201
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/dcsctp_socket.h617
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/dcsctp_socket_factory.cc34
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/dcsctp_socket_factory.h32
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/mock_dcsctp_socket.h90
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/mock_dcsctp_socket_factory.h33
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/mock_dcsctp_socket_test.cc27
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/packet_observer.h37
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/text_pcap_packet_observer.cc54
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/text_pcap_packet_observer.h46
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/timeout.h53
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/types.h143
-rw-r--r--third_party/libwebrtc/net/dcsctp/public/types_test.cc50
17 files changed, 1777 insertions, 0 deletions
diff --git a/third_party/libwebrtc/net/dcsctp/public/BUILD.gn b/third_party/libwebrtc/net/dcsctp/public/BUILD.gn
new file mode 100644
index 0000000000..6cb289bf5b
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/BUILD.gn
@@ -0,0 +1,103 @@
+# Copyright (c) 2021 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.
+
+import("../../../webrtc.gni")
+
+rtc_source_set("types") {
+ deps = [
+ "../../../api:array_view",
+ "../../../rtc_base:strong_alias",
+ ]
+ sources = [
+ "dcsctp_message.h",
+ "dcsctp_options.h",
+ "types.h",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
+}
+
+rtc_source_set("socket") {
+ deps = [
+ ":types",
+ "../../../api:array_view",
+ "../../../api/task_queue:task_queue",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:strong_alias",
+ ]
+ sources = [
+ "dcsctp_handover_state.cc",
+ "dcsctp_handover_state.h",
+ "dcsctp_socket.h",
+ "packet_observer.h",
+ "timeout.h",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+}
+
+rtc_source_set("factory") {
+ deps = [
+ ":socket",
+ ":types",
+ "../socket:dcsctp_socket",
+ ]
+ sources = [
+ "dcsctp_socket_factory.cc",
+ "dcsctp_socket_factory.h",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+}
+
+rtc_source_set("mocks") {
+ testonly = true
+ sources = [
+ "mock_dcsctp_socket.h",
+ "mock_dcsctp_socket_factory.h",
+ ]
+ deps = [
+ ":factory",
+ ":socket",
+ "../../../test:test_support",
+ ]
+}
+
+rtc_source_set("utils") {
+ deps = [
+ ":socket",
+ ":types",
+ "../../../api:array_view",
+ "../../../rtc_base:logging",
+ "../../../rtc_base:stringutils",
+ "../socket:dcsctp_socket",
+ ]
+ sources = [
+ "text_pcap_packet_observer.cc",
+ "text_pcap_packet_observer.h",
+ ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+}
+
+if (rtc_include_tests) {
+ rtc_library("dcsctp_public_unittests") {
+ testonly = true
+
+ deps = [
+ ":mocks",
+ ":types",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:gunit_helpers",
+ "../../../test:test_support",
+ ]
+ sources = [
+ "mock_dcsctp_socket_test.cc",
+ "types_test.cc",
+ ]
+ }
+}
diff --git a/third_party/libwebrtc/net/dcsctp/public/dcsctp_handover_state.cc b/third_party/libwebrtc/net/dcsctp/public/dcsctp_handover_state.cc
new file mode 100644
index 0000000000..6a1bd06eba
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/dcsctp_handover_state.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2021 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.
+ */
+#include "net/dcsctp/public/dcsctp_handover_state.h"
+
+#include <string>
+
+#include "absl/strings/string_view.h"
+
+namespace dcsctp {
+namespace {
+constexpr absl::string_view HandoverUnreadinessReasonToString(
+ HandoverUnreadinessReason reason) {
+ switch (reason) {
+ case HandoverUnreadinessReason::kWrongConnectionState:
+ return "WRONG_CONNECTION_STATE";
+ case HandoverUnreadinessReason::kSendQueueNotEmpty:
+ return "SEND_QUEUE_NOT_EMPTY";
+ case HandoverUnreadinessReason::kDataTrackerTsnBlocksPending:
+ return "DATA_TRACKER_TSN_BLOCKS_PENDING";
+ case HandoverUnreadinessReason::kReassemblyQueueDeliveredTSNsGap:
+ return "REASSEMBLY_QUEUE_DELIVERED_TSN_GAP";
+ case HandoverUnreadinessReason::kStreamResetDeferred:
+ return "STREAM_RESET_DEFERRED";
+ case HandoverUnreadinessReason::kOrderedStreamHasUnassembledChunks:
+ return "ORDERED_STREAM_HAS_UNASSEMBLED_CHUNKS";
+ case HandoverUnreadinessReason::kUnorderedStreamHasUnassembledChunks:
+ return "UNORDERED_STREAM_HAS_UNASSEMBLED_CHUNKS";
+ case HandoverUnreadinessReason::kRetransmissionQueueOutstandingData:
+ return "RETRANSMISSION_QUEUE_OUTSTANDING_DATA";
+ case HandoverUnreadinessReason::kRetransmissionQueueFastRecovery:
+ return "RETRANSMISSION_QUEUE_FAST_RECOVERY";
+ case HandoverUnreadinessReason::kRetransmissionQueueNotEmpty:
+ return "RETRANSMISSION_QUEUE_NOT_EMPTY";
+ case HandoverUnreadinessReason::kPendingStreamReset:
+ return "PENDING_STREAM_RESET";
+ case HandoverUnreadinessReason::kPendingStreamResetRequest:
+ return "PENDING_STREAM_RESET_REQUEST";
+ }
+}
+} // namespace
+
+std::string HandoverReadinessStatus::ToString() const {
+ std::string result;
+ for (uint32_t bit = 1;
+ bit <= static_cast<uint32_t>(HandoverUnreadinessReason::kMax);
+ bit *= 2) {
+ auto flag = static_cast<HandoverUnreadinessReason>(bit);
+ if (Contains(flag)) {
+ if (!result.empty()) {
+ result.append(",");
+ }
+ absl::string_view s = HandoverUnreadinessReasonToString(flag);
+ result.append(s.data(), s.size());
+ }
+ }
+ if (result.empty()) {
+ result = "READY";
+ }
+ return result;
+}
+} // namespace dcsctp
diff --git a/third_party/libwebrtc/net/dcsctp/public/dcsctp_handover_state.h b/third_party/libwebrtc/net/dcsctp/public/dcsctp_handover_state.h
new file mode 100644
index 0000000000..253f4da939
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/dcsctp_handover_state.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2021 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 NET_DCSCTP_PUBLIC_DCSCTP_HANDOVER_STATE_H_
+#define NET_DCSCTP_PUBLIC_DCSCTP_HANDOVER_STATE_H_
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "rtc_base/strong_alias.h"
+
+namespace dcsctp {
+
+// Stores state snapshot of a dcSCTP socket. The snapshot can be used to
+// recreate the socket - possibly in another process. This state should be
+// treaded as opaque - the calling client should not inspect or alter it except
+// for serialization. Serialization is not provided by dcSCTP. If needed it has
+// to be implemented in the calling client.
+struct DcSctpSocketHandoverState {
+ enum class SocketState {
+ kClosed,
+ kConnected,
+ };
+ SocketState socket_state = SocketState::kClosed;
+
+ uint32_t my_verification_tag = 0;
+ uint32_t my_initial_tsn = 0;
+ uint32_t peer_verification_tag = 0;
+ uint32_t peer_initial_tsn = 0;
+ uint64_t tie_tag = 0;
+
+ struct Capabilities {
+ bool partial_reliability = false;
+ bool message_interleaving = false;
+ bool reconfig = false;
+ uint16_t negotiated_maximum_incoming_streams = 0;
+ uint16_t negotiated_maximum_outgoing_streams = 0;
+ };
+ Capabilities capabilities;
+
+ struct OutgoingStream {
+ uint32_t id = 0;
+ uint32_t next_ssn = 0;
+ uint32_t next_unordered_mid = 0;
+ uint32_t next_ordered_mid = 0;
+ uint16_t priority = 0;
+ };
+ struct Transmission {
+ uint32_t next_tsn = 0;
+ uint32_t next_reset_req_sn = 0;
+ uint32_t cwnd = 0;
+ uint32_t rwnd = 0;
+ uint32_t ssthresh = 0;
+ uint32_t partial_bytes_acked = 0;
+ std::vector<OutgoingStream> streams;
+ };
+ Transmission tx;
+
+ struct OrderedStream {
+ uint32_t id = 0;
+ uint32_t next_ssn = 0;
+ };
+ struct UnorderedStream {
+ uint32_t id = 0;
+ };
+ struct Receive {
+ bool seen_packet = false;
+ uint32_t last_cumulative_acked_tsn = 0;
+ uint32_t last_assembled_tsn = 0;
+ uint32_t last_completed_deferred_reset_req_sn = 0;
+ uint32_t last_completed_reset_req_sn = 0;
+ std::vector<OrderedStream> ordered_streams;
+ std::vector<UnorderedStream> unordered_streams;
+ };
+ Receive rx;
+};
+
+// A list of possible reasons for a socket to be not ready for handover.
+enum class HandoverUnreadinessReason : uint32_t {
+ kWrongConnectionState = 1,
+ kSendQueueNotEmpty = 2,
+ kPendingStreamResetRequest = 4,
+ kDataTrackerTsnBlocksPending = 8,
+ kPendingStreamReset = 16,
+ kReassemblyQueueDeliveredTSNsGap = 32,
+ kStreamResetDeferred = 64,
+ kOrderedStreamHasUnassembledChunks = 128,
+ kUnorderedStreamHasUnassembledChunks = 256,
+ kRetransmissionQueueOutstandingData = 512,
+ kRetransmissionQueueFastRecovery = 1024,
+ kRetransmissionQueueNotEmpty = 2048,
+ kMax = kRetransmissionQueueNotEmpty,
+};
+
+// Return value of `DcSctpSocketInterface::GetHandoverReadiness`. Set of
+// `HandoverUnreadinessReason` bits. When no bit is set, the socket is in the
+// state in which a snapshot of the state can be made by
+// `GetHandoverStateAndClose()`.
+class HandoverReadinessStatus
+ : public webrtc::StrongAlias<class HandoverReadinessStatusTag, uint32_t> {
+ public:
+ // Constructs an empty `HandoverReadinessStatus` which represents ready state.
+ constexpr HandoverReadinessStatus()
+ : webrtc::StrongAlias<class HandoverReadinessStatusTag, uint32_t>(0) {}
+ // Constructs status object that contains a single reason for not being
+ // handover ready.
+ constexpr explicit HandoverReadinessStatus(HandoverUnreadinessReason reason)
+ : webrtc::StrongAlias<class HandoverReadinessStatusTag, uint32_t>(
+ static_cast<uint32_t>(reason)) {}
+
+ // Convenience methods
+ constexpr bool IsReady() const { return value() == 0; }
+ constexpr bool Contains(HandoverUnreadinessReason reason) const {
+ return value() & static_cast<uint32_t>(reason);
+ }
+ HandoverReadinessStatus& Add(HandoverUnreadinessReason reason) {
+ return Add(HandoverReadinessStatus(reason));
+ }
+ HandoverReadinessStatus& Add(HandoverReadinessStatus status) {
+ value() |= status.value();
+ return *this;
+ }
+ std::string ToString() const;
+};
+
+} // namespace dcsctp
+
+#endif // NET_DCSCTP_PUBLIC_DCSCTP_HANDOVER_STATE_H_
diff --git a/third_party/libwebrtc/net/dcsctp/public/dcsctp_message.h b/third_party/libwebrtc/net/dcsctp/public/dcsctp_message.h
new file mode 100644
index 0000000000..38e6763916
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/dcsctp_message.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2021 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 NET_DCSCTP_PUBLIC_DCSCTP_MESSAGE_H_
+#define NET_DCSCTP_PUBLIC_DCSCTP_MESSAGE_H_
+
+#include <cstdint>
+#include <utility>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/public/types.h"
+
+namespace dcsctp {
+
+// An SCTP message is a group of bytes sent and received as a whole on a
+// specified stream identifier (`stream_id`), and with a payload protocol
+// identifier (`ppid`).
+class DcSctpMessage {
+ public:
+ DcSctpMessage(StreamID stream_id, PPID ppid, std::vector<uint8_t> payload)
+ : stream_id_(stream_id), ppid_(ppid), payload_(std::move(payload)) {}
+
+ DcSctpMessage(DcSctpMessage&& other) = default;
+ DcSctpMessage& operator=(DcSctpMessage&& other) = default;
+ DcSctpMessage(const DcSctpMessage&) = delete;
+ DcSctpMessage& operator=(const DcSctpMessage&) = delete;
+
+ // The stream identifier to which the message is sent.
+ StreamID stream_id() const { return stream_id_; }
+
+ // The payload protocol identifier (ppid) associated with the message.
+ PPID ppid() const { return ppid_; }
+
+ // The payload of the message.
+ rtc::ArrayView<const uint8_t> payload() const { return payload_; }
+
+ // When destructing the message, extracts the payload.
+ std::vector<uint8_t> ReleasePayload() && { return std::move(payload_); }
+
+ private:
+ StreamID stream_id_;
+ PPID ppid_;
+ std::vector<uint8_t> payload_;
+};
+} // namespace dcsctp
+
+#endif // NET_DCSCTP_PUBLIC_DCSCTP_MESSAGE_H_
diff --git a/third_party/libwebrtc/net/dcsctp/public/dcsctp_options.h b/third_party/libwebrtc/net/dcsctp/public/dcsctp_options.h
new file mode 100644
index 0000000000..4511bed4a4
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/dcsctp_options.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2021 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 NET_DCSCTP_PUBLIC_DCSCTP_OPTIONS_H_
+#define NET_DCSCTP_PUBLIC_DCSCTP_OPTIONS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "absl/types/optional.h"
+#include "net/dcsctp/public/types.h"
+
+namespace dcsctp {
+struct DcSctpOptions {
+ // The largest safe SCTP packet. Starting from the minimum guaranteed MTU
+ // value of 1280 for IPv6 (which may not support fragmentation), take off 85
+ // bytes for DTLS/TURN/TCP/IP and ciphertext overhead.
+ //
+ // Additionally, it's possible that TURN adds an additional 4 bytes of
+ // overhead after a channel has been established, so an additional 4 bytes is
+ // subtracted
+ //
+ // 1280 IPV6 MTU
+ // -40 IPV6 header
+ // -8 UDP
+ // -24 GCM Cipher
+ // -13 DTLS record header
+ // -4 TURN ChannelData
+ // = 1191 bytes.
+ static constexpr size_t kMaxSafeMTUSize = 1191;
+
+ // The local port for which the socket is supposed to be bound to. Incoming
+ // packets will be verified that they are sent to this port number and all
+ // outgoing packets will have this port number as source port.
+ int local_port = 5000;
+
+ // The remote port to send packets to. All outgoing packets will have this
+ // port number as destination port.
+ int remote_port = 5000;
+
+ // The announced maximum number of incoming streams. Note that this value is
+ // constant and can't be currently increased in run-time as "Add Incoming
+ // Streams Request" in RFC6525 isn't supported.
+ //
+ // The socket implementation doesn't have any per-stream fixed costs, which is
+ // why the default value is set to be the maximum value.
+ uint16_t announced_maximum_incoming_streams = 65535;
+
+ // The announced maximum number of outgoing streams. Note that this value is
+ // constant and can't be currently increased in run-time as "Add Outgoing
+ // Streams Request" in RFC6525 isn't supported.
+ //
+ // The socket implementation doesn't have any per-stream fixed costs, which is
+ // why the default value is set to be the maximum value.
+ uint16_t announced_maximum_outgoing_streams = 65535;
+
+ // Maximum SCTP packet size. The library will limit the size of generated
+ // packets to be less than or equal to this number. This does not include any
+ // overhead of DTLS, TURN, UDP or IP headers.
+ size_t mtu = kMaxSafeMTUSize;
+
+ // The largest allowed message payload to be sent. Messages will be rejected
+ // if their payload is larger than this value. Note that this doesn't affect
+ // incoming messages, which may larger than this value (but smaller than
+ // `max_receiver_window_buffer_size`).
+ size_t max_message_size = 256 * 1024;
+
+ // The default stream priority, if not overridden by
+ // `SctpSocket::SetStreamPriority`. The default value is selected to be
+ // compatible with https://www.w3.org/TR/webrtc-priority/, section 4.2-4.3.
+ StreamPriority default_stream_priority = StreamPriority(256);
+
+ // Maximum received window buffer size. This should be a bit larger than the
+ // largest sized message you want to be able to receive. This essentially
+ // limits the memory usage on the receive side. Note that memory is allocated
+ // dynamically, and this represents the maximum amount of buffered data. The
+ // actual memory usage of the library will be smaller in normal operation, and
+ // will be larger than this due to other allocations and overhead if the
+ // buffer is fully utilized.
+ size_t max_receiver_window_buffer_size = 5 * 1024 * 1024;
+
+ // Maximum send buffer size. It will not be possible to queue more data than
+ // this before sending it.
+ size_t max_send_buffer_size = 2'000'000;
+
+ // A threshold that, when the amount of data in the send buffer goes below
+ // this value, will trigger `DcSctpCallbacks::OnTotalBufferedAmountLow`.
+ size_t total_buffered_amount_low_threshold = 1'800'000;
+
+ // Max allowed RTT value. When the RTT is measured and it's found to be larger
+ // than this value, it will be discarded and not used for e.g. any RTO
+ // calculation. The default value is an extreme maximum but can be adapted
+ // to better match the environment.
+ DurationMs rtt_max = DurationMs(60'000);
+
+ // Initial RTO value.
+ DurationMs rto_initial = DurationMs(500);
+
+ // Maximum RTO value.
+ DurationMs rto_max = DurationMs(60'000);
+
+ // Minimum RTO value. This must be larger than an expected peer delayed ack
+ // timeout.
+ DurationMs rto_min = DurationMs(400);
+
+ // T1-init timeout.
+ DurationMs t1_init_timeout = DurationMs(1000);
+
+ // T1-cookie timeout.
+ DurationMs t1_cookie_timeout = DurationMs(1000);
+
+ // T2-shutdown timeout.
+ DurationMs t2_shutdown_timeout = DurationMs(1000);
+
+ // For t1-init, t1-cookie, t2-shutdown, t3-rtx, this value - if set - will be
+ // the upper bound on how large the exponentially backed off timeout can
+ // become. The lower the duration, the faster the connection can recover on
+ // transient network issues. Setting this value may require changing
+ // `max_retransmissions` and `max_init_retransmits` to ensure that the
+ // connection is not closed too quickly.
+ absl::optional<DurationMs> max_timer_backoff_duration = absl::nullopt;
+
+ // Hearbeat interval (on idle connections only). Set to zero to disable.
+ DurationMs heartbeat_interval = DurationMs(30000);
+
+ // The maximum time when a SACK will be sent from the arrival of an
+ // unacknowledged packet. Whatever is smallest of RTO/2 and this will be used.
+ DurationMs delayed_ack_max_timeout = DurationMs(200);
+
+ // The minimum limit for the measured RTT variance
+ //
+ // Setting this below the expected delayed ack timeout (+ margin) of the peer
+ // might result in unnecessary retransmissions, as the maximum time it takes
+ // to ACK a DATA chunk is typically RTT + ATO (delayed ack timeout), and when
+ // the SCTP channel is quite idle, and heartbeats dominate the source of RTT
+ // measurement, the RTO would converge with the smoothed RTT (SRTT). The
+ // default ATO is 200ms in usrsctp, and a 20ms (10%) margin would include the
+ // processing time of received packets and the clock granularity when setting
+ // the delayed ack timer on the peer.
+ //
+ // This is described for TCP in
+ // https://datatracker.ietf.org/doc/html/rfc6298#section-4.
+ DurationMs min_rtt_variance = DurationMs(220);
+
+ // The initial congestion window size, in number of MTUs.
+ // See https://tools.ietf.org/html/rfc4960#section-7.2.1 which defaults at ~3
+ // and https://research.google/pubs/pub36640/ which argues for at least ten
+ // segments.
+ size_t cwnd_mtus_initial = 10;
+
+ // The minimum congestion window size, in number of MTUs, upon detection of
+ // packet loss by SACK. Note that if the retransmission timer expires, the
+ // congestion window will be as small as one MTU. See
+ // https://tools.ietf.org/html/rfc4960#section-7.2.3.
+ size_t cwnd_mtus_min = 4;
+
+ // When the congestion window is at or above this number of MTUs, the
+ // congestion control algorithm will avoid filling the congestion window
+ // fully, if that results in fragmenting large messages into quite small
+ // packets. When the congestion window is smaller than this option, it will
+ // aim to fill the congestion window as much as it can, even if it results in
+ // creating small fragmented packets.
+ size_t avoid_fragmentation_cwnd_mtus = 6;
+
+ // The number of packets that may be sent at once. This is limited to avoid
+ // bursts that too quickly fill the send buffer. Typically in a a socket in
+ // its "slow start" phase (when it sends as much as it can), it will send
+ // up to three packets for every SACK received, so the default limit is set
+ // just above that, and then mostly applicable for (but not limited to) fast
+ // retransmission scenarios.
+ int max_burst = 4;
+
+ // Maximum Data Retransmit Attempts (per DATA chunk). Set to absl::nullopt for
+ // no limit.
+ absl::optional<int> max_retransmissions = 10;
+
+ // Max.Init.Retransmits (https://tools.ietf.org/html/rfc4960#section-15). Set
+ // to absl::nullopt for no limit.
+ absl::optional<int> max_init_retransmits = 8;
+
+ // RFC3758 Partial Reliability Extension
+ bool enable_partial_reliability = true;
+
+ // RFC8260 Stream Schedulers and User Message Interleaving
+ bool enable_message_interleaving = false;
+
+ // If RTO should be added to heartbeat_interval
+ bool heartbeat_interval_include_rtt = true;
+
+ // Disables SCTP packet crc32 verification. Useful when running with fuzzers.
+ bool disable_checksum_verification = false;
+};
+} // namespace dcsctp
+
+#endif // NET_DCSCTP_PUBLIC_DCSCTP_OPTIONS_H_
diff --git a/third_party/libwebrtc/net/dcsctp/public/dcsctp_socket.h b/third_party/libwebrtc/net/dcsctp/public/dcsctp_socket.h
new file mode 100644
index 0000000000..2df6a2c009
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/dcsctp_socket.h
@@ -0,0 +1,617 @@
+/*
+ * Copyright (c) 2021 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 NET_DCSCTP_PUBLIC_DCSCTP_SOCKET_H_
+#define NET_DCSCTP_PUBLIC_DCSCTP_SOCKET_H_
+
+#include <cstdint>
+#include <memory>
+#include <utility>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "api/task_queue/task_queue_base.h"
+#include "net/dcsctp/public/dcsctp_handover_state.h"
+#include "net/dcsctp/public/dcsctp_message.h"
+#include "net/dcsctp/public/dcsctp_options.h"
+#include "net/dcsctp/public/packet_observer.h"
+#include "net/dcsctp/public/timeout.h"
+#include "net/dcsctp/public/types.h"
+
+namespace dcsctp {
+
+// The socket/association state
+enum class SocketState {
+ // The socket is closed.
+ kClosed,
+ // The socket has initiated a connection, which is not yet established. Note
+ // that for incoming connections and for reconnections when the socket is
+ // already connected, the socket will not transition to this state.
+ kConnecting,
+ // The socket is connected, and the connection is established.
+ kConnected,
+ // The socket is shutting down, and the connection is not yet closed.
+ kShuttingDown,
+};
+
+// Send options for sending messages
+struct SendOptions {
+ // If the message should be sent with unordered message delivery.
+ IsUnordered unordered = IsUnordered(false);
+
+ // If set, will discard messages that haven't been correctly sent and
+ // received before the lifetime has expired. This is only available if the
+ // peer supports Partial Reliability Extension (RFC3758).
+ absl::optional<DurationMs> lifetime = absl::nullopt;
+
+ // If set, limits the number of retransmissions. This is only available
+ // if the peer supports Partial Reliability Extension (RFC3758).
+ absl::optional<size_t> max_retransmissions = absl::nullopt;
+
+ // If set, will generate lifecycle events for this message. See e.g.
+ // `DcSctpSocketCallbacks::OnLifecycleMessageFullySent`. This value is decided
+ // by the client and the library will provide it to all lifecycle callbacks.
+ LifecycleId lifecycle_id = LifecycleId::NotSet();
+};
+
+enum class ErrorKind {
+ // Indicates that no error has occurred. This will never be the case when
+ // `OnError` or `OnAborted` is called.
+ kNoError,
+ // There have been too many retries or timeouts, and the library has given up.
+ kTooManyRetries,
+ // A command was received that is only possible to execute when the socket is
+ // connected, which it is not.
+ kNotConnected,
+ // Parsing of the command or its parameters failed.
+ kParseFailed,
+ // Commands are received in the wrong sequence, which indicates a
+ // synchronisation mismatch between the peers.
+ kWrongSequence,
+ // The peer has reported an issue using ERROR or ABORT command.
+ kPeerReported,
+ // The peer has performed a protocol violation.
+ kProtocolViolation,
+ // The receive or send buffers have been exhausted.
+ kResourceExhaustion,
+ // The client has performed an invalid operation.
+ kUnsupportedOperation,
+};
+
+inline constexpr absl::string_view ToString(ErrorKind error) {
+ switch (error) {
+ case ErrorKind::kNoError:
+ return "NO_ERROR";
+ case ErrorKind::kTooManyRetries:
+ return "TOO_MANY_RETRIES";
+ case ErrorKind::kNotConnected:
+ return "NOT_CONNECTED";
+ case ErrorKind::kParseFailed:
+ return "PARSE_FAILED";
+ case ErrorKind::kWrongSequence:
+ return "WRONG_SEQUENCE";
+ case ErrorKind::kPeerReported:
+ return "PEER_REPORTED";
+ case ErrorKind::kProtocolViolation:
+ return "PROTOCOL_VIOLATION";
+ case ErrorKind::kResourceExhaustion:
+ return "RESOURCE_EXHAUSTION";
+ case ErrorKind::kUnsupportedOperation:
+ return "UNSUPPORTED_OPERATION";
+ }
+}
+
+enum class SendStatus {
+ // The message was enqueued successfully. As sending the message is done
+ // asynchronously, this is no guarantee that the message has been actually
+ // sent.
+ kSuccess,
+ // The message was rejected as the payload was empty (which is not allowed in
+ // SCTP).
+ kErrorMessageEmpty,
+ // The message was rejected as the payload was larger than what has been set
+ // as `DcSctpOptions.max_message_size`.
+ kErrorMessageTooLarge,
+ // The message could not be enqueued as the socket is out of resources. This
+ // mainly indicates that the send queue is full.
+ kErrorResourceExhaustion,
+ // The message could not be sent as the socket is shutting down.
+ kErrorShuttingDown,
+};
+
+inline constexpr absl::string_view ToString(SendStatus error) {
+ switch (error) {
+ case SendStatus::kSuccess:
+ return "SUCCESS";
+ case SendStatus::kErrorMessageEmpty:
+ return "ERROR_MESSAGE_EMPTY";
+ case SendStatus::kErrorMessageTooLarge:
+ return "ERROR_MESSAGE_TOO_LARGE";
+ case SendStatus::kErrorResourceExhaustion:
+ return "ERROR_RESOURCE_EXHAUSTION";
+ case SendStatus::kErrorShuttingDown:
+ return "ERROR_SHUTTING_DOWN";
+ }
+}
+
+// Return value of ResetStreams.
+enum class ResetStreamsStatus {
+ // If the connection is not yet established, this will be returned.
+ kNotConnected,
+ // Indicates that ResetStreams operation has been successfully initiated.
+ kPerformed,
+ // Indicates that ResetStreams has failed as it's not supported by the peer.
+ kNotSupported,
+};
+
+inline constexpr absl::string_view ToString(ResetStreamsStatus error) {
+ switch (error) {
+ case ResetStreamsStatus::kNotConnected:
+ return "NOT_CONNECTED";
+ case ResetStreamsStatus::kPerformed:
+ return "PERFORMED";
+ case ResetStreamsStatus::kNotSupported:
+ return "NOT_SUPPORTED";
+ }
+}
+
+// Return value of DcSctpSocketCallbacks::SendPacketWithStatus.
+enum class SendPacketStatus {
+ // Indicates that the packet was successfully sent. As sending is unreliable,
+ // there are no guarantees that the packet was actually delivered.
+ kSuccess,
+ // The packet was not sent due to a temporary failure, such as the local send
+ // buffer becoming exhausted. This return value indicates that the socket will
+ // recover and sending that packet can be retried at a later time.
+ kTemporaryFailure,
+ // The packet was not sent due to other reasons.
+ kError,
+};
+
+// Represent known SCTP implementations.
+enum class SctpImplementation {
+ // There is not enough information toto determine any SCTP implementation.
+ kUnknown,
+ // This implementation.
+ kDcsctp,
+ // https://github.com/sctplab/usrsctp.
+ kUsrSctp,
+ // Any other implementation.
+ kOther,
+};
+
+inline constexpr absl::string_view ToString(SctpImplementation implementation) {
+ switch (implementation) {
+ case SctpImplementation::kUnknown:
+ return "unknown";
+ case SctpImplementation::kDcsctp:
+ return "dcsctp";
+ case SctpImplementation::kUsrSctp:
+ return "usrsctp";
+ case SctpImplementation::kOther:
+ return "other";
+ }
+}
+
+// Tracked metrics, which is the return value of GetMetrics. Optional members
+// will be unset when they are not yet known.
+struct Metrics {
+ // Transmission stats and metrics.
+
+ // Number of packets sent.
+ size_t tx_packets_count = 0;
+
+ // Number of messages requested to be sent.
+ size_t tx_messages_count = 0;
+
+ // The current congestion window (cwnd) in bytes, corresponding to spinfo_cwnd
+ // defined in RFC6458.
+ size_t cwnd_bytes = 0;
+
+ // Smoothed round trip time, corresponding to spinfo_srtt defined in RFC6458.
+ int srtt_ms = 0;
+
+ // Number of data items in the retransmission queue that haven’t been
+ // acked/nacked yet and are in-flight. Corresponding to sstat_unackdata
+ // defined in RFC6458. This may be an approximation when there are messages in
+ // the send queue that haven't been fragmented/packetized yet.
+ size_t unack_data_count = 0;
+
+ // Receive stats and metrics.
+
+ // Number of packets received.
+ size_t rx_packets_count = 0;
+
+ // Number of messages received.
+ size_t rx_messages_count = 0;
+
+ // The peer’s last announced receiver window size, corresponding to
+ // sstat_rwnd defined in RFC6458.
+ uint32_t peer_rwnd_bytes = 0;
+
+ // Returns the detected SCTP implementation of the peer. As this is not
+ // explicitly signalled during the connection establishment, heuristics is
+ // used to analyze e.g. the state cookie in the INIT-ACK chunk.
+ SctpImplementation peer_implementation = SctpImplementation::kUnknown;
+
+ // Indicates if RFC8260 User Message Interleaving has been negotiated by both
+ // peers.
+ bool uses_message_interleaving = false;
+
+ // The number of negotiated incoming and outgoing streams, which is configured
+ // locally as `DcSctpOptions::announced_maximum_incoming_streams` and
+ // `DcSctpOptions::announced_maximum_outgoing_streams`, and which will be
+ // signaled by the peer during connection.
+ uint16_t negotiated_maximum_incoming_streams = 0;
+ uint16_t negotiated_maximum_outgoing_streams = 0;
+};
+
+// Callbacks that the DcSctpSocket will call synchronously to the owning
+// client. It is allowed to call back into the library from callbacks that start
+// with "On". It has been explicitly documented when it's not allowed to call
+// back into this library from within a callback.
+//
+// Theses callbacks are only synchronously triggered as a result of the client
+// calling a public method in `DcSctpSocketInterface`.
+class DcSctpSocketCallbacks {
+ public:
+ virtual ~DcSctpSocketCallbacks() = default;
+
+ // Called when the library wants the packet serialized as `data` to be sent.
+ //
+ // TODO(bugs.webrtc.org/12943): This method is deprecated, see
+ // `SendPacketWithStatus`.
+ //
+ // Note that it's NOT ALLOWED to call into this library from within this
+ // callback.
+ virtual void SendPacket(rtc::ArrayView<const uint8_t> data) {}
+
+ // Called when the library wants the packet serialized as `data` to be sent.
+ //
+ // Note that it's NOT ALLOWED to call into this library from within this
+ // callback.
+ virtual SendPacketStatus SendPacketWithStatus(
+ rtc::ArrayView<const uint8_t> data) {
+ SendPacket(data);
+ return SendPacketStatus::kSuccess;
+ }
+
+ // Called when the library wants to create a Timeout. The callback must return
+ // an object that implements that interface.
+ //
+ // Low precision tasks are scheduled more efficiently by using leeway to
+ // reduce Idle Wake Ups and is the preferred precision whenever possible. High
+ // precision timeouts do not have this leeway, but is still limited by OS
+ // timer precision. At the time of writing, kLow's additional leeway may be up
+ // to 17 ms, but please see webrtc::TaskQueueBase::DelayPrecision for
+ // up-to-date information.
+ //
+ // Note that it's NOT ALLOWED to call into this library from within this
+ // callback.
+ virtual std::unique_ptr<Timeout> CreateTimeout(
+ webrtc::TaskQueueBase::DelayPrecision precision) {
+ // TODO(hbos): When dependencies have migrated to this new signature, make
+ // this pure virtual and delete the other version.
+ return CreateTimeout();
+ }
+ // TODO(hbos): When dependencies have migrated to the other signature, delete
+ // this version.
+ virtual std::unique_ptr<Timeout> CreateTimeout() {
+ return CreateTimeout(webrtc::TaskQueueBase::DelayPrecision::kLow);
+ }
+
+ // Returns the current time in milliseconds (from any epoch).
+ //
+ // Note that it's NOT ALLOWED to call into this library from within this
+ // callback.
+ virtual TimeMs TimeMillis() = 0;
+
+ // Called when the library needs a random number uniformly distributed between
+ // `low` (inclusive) and `high` (exclusive). The random numbers used by the
+ // library are not used for cryptographic purposes. There are no requirements
+ // that the random number generator must be secure.
+ //
+ // Note that it's NOT ALLOWED to call into this library from within this
+ // callback.
+ virtual uint32_t GetRandomInt(uint32_t low, uint32_t high) = 0;
+
+ // Triggered when the outgoing message buffer is empty, meaning that there are
+ // no more queued messages, but there can still be packets in-flight or to be
+ // retransmitted. (in contrast to SCTP_SENDER_DRY_EVENT).
+ //
+ // Note that it's NOT ALLOWED to call into this library from within this
+ // callback.
+ ABSL_DEPRECATED("Use OnTotalBufferedAmountLow instead")
+ virtual void NotifyOutgoingMessageBufferEmpty() {}
+
+ // Called when the library has received an SCTP message in full and delivers
+ // it to the upper layer.
+ //
+ // It is allowed to call into this library from within this callback.
+ virtual void OnMessageReceived(DcSctpMessage message) = 0;
+
+ // Triggered when an non-fatal error is reported by either this library or
+ // from the other peer (by sending an ERROR command). These should be logged,
+ // but no other action need to be taken as the association is still viable.
+ //
+ // It is allowed to call into this library from within this callback.
+ virtual void OnError(ErrorKind error, absl::string_view message) = 0;
+
+ // Triggered when the socket has aborted - either as decided by this socket
+ // due to e.g. too many retransmission attempts, or by the peer when
+ // receiving an ABORT command. No other callbacks will be done after this
+ // callback, unless reconnecting.
+ //
+ // It is allowed to call into this library from within this callback.
+ virtual void OnAborted(ErrorKind error, absl::string_view message) = 0;
+
+ // Called when calling `Connect` succeeds, but also for incoming successful
+ // connection attempts.
+ //
+ // It is allowed to call into this library from within this callback.
+ virtual void OnConnected() = 0;
+
+ // Called when the socket is closed in a controlled way. No other
+ // callbacks will be done after this callback, unless reconnecting.
+ //
+ // It is allowed to call into this library from within this callback.
+ virtual void OnClosed() = 0;
+
+ // On connection restarted (by peer). This is just a notification, and the
+ // association is expected to work fine after this call, but there could have
+ // been packet loss as a result of restarting the association.
+ //
+ // It is allowed to call into this library from within this callback.
+ virtual void OnConnectionRestarted() = 0;
+
+ // Indicates that a stream reset request has failed.
+ //
+ // It is allowed to call into this library from within this callback.
+ virtual void OnStreamsResetFailed(
+ rtc::ArrayView<const StreamID> outgoing_streams,
+ absl::string_view reason) = 0;
+
+ // Indicates that a stream reset request has been performed.
+ //
+ // It is allowed to call into this library from within this callback.
+ virtual void OnStreamsResetPerformed(
+ rtc::ArrayView<const StreamID> outgoing_streams) = 0;
+
+ // When a peer has reset some of its outgoing streams, this will be called. An
+ // empty list indicates that all streams have been reset.
+ //
+ // It is allowed to call into this library from within this callback.
+ virtual void OnIncomingStreamsReset(
+ rtc::ArrayView<const StreamID> incoming_streams) = 0;
+
+ // Will be called when the amount of data buffered to be sent falls to or
+ // below the threshold set when calling `SetBufferedAmountLowThreshold`.
+ //
+ // It is allowed to call into this library from within this callback.
+ virtual void OnBufferedAmountLow(StreamID stream_id) {}
+
+ // Will be called when the total amount of data buffered (in the entire send
+ // buffer, for all streams) falls to or below the threshold specified in
+ // `DcSctpOptions::total_buffered_amount_low_threshold`.
+ virtual void OnTotalBufferedAmountLow() {}
+
+ // == Lifecycle Events ==
+ //
+ // If a `lifecycle_id` is provided as `SendOptions`, lifecycle callbacks will
+ // be triggered as the message is processed by the library.
+ //
+ // The possible transitions are shown in the graph below:
+ //
+ // DcSctpSocket::Send ────────────────────────┐
+ // │ │
+ // │ │
+ // v v
+ // OnLifecycleMessageFullySent ───────> OnLifecycleMessageExpired
+ // │ │
+ // │ │
+ // v v
+ // OnLifeCycleMessageDelivered ────────────> OnLifecycleEnd
+
+ // OnLifecycleMessageFullySent will be called when a message has been fully
+ // sent, meaning that the last fragment has been produced from the send queue
+ // and sent on the network. Note that this will trigger at most once per
+ // message even if the message was retransmitted due to packet loss.
+ //
+ // This is a lifecycle event.
+ //
+ // Note that it's NOT ALLOWED to call into this library from within this
+ // callback.
+ virtual void OnLifecycleMessageFullySent(LifecycleId lifecycle_id) {}
+
+ // OnLifecycleMessageExpired will be called when a message has expired. If it
+ // was expired with data remaining in the send queue that had not been sent
+ // ever, `maybe_delivered` will be set to false. If `maybe_delivered` is true,
+ // the message has at least once been sent and may have been correctly
+ // received by the peer, but it has expired before the receiver managed to
+ // acknowledge it. This means that if `maybe_delivered` is true, it's unknown
+ // if the message was lost or was delivered, and if `maybe_delivered` is
+ // false, it's guaranteed to not be delivered.
+ //
+ // It's guaranteed that `OnLifecycleMessageDelivered` is not called if this
+ // callback has triggered.
+ //
+ // This is a lifecycle event.
+ //
+ // Note that it's NOT ALLOWED to call into this library from within this
+ // callback.
+ virtual void OnLifecycleMessageExpired(LifecycleId lifecycle_id,
+ bool maybe_delivered) {}
+
+ // OnLifecycleMessageDelivered will be called when a non-expired message has
+ // been acknowledged by the peer as delivered.
+ //
+ // Note that this will trigger only when the peer moves its cumulative TSN ack
+ // beyond this message, and will not fire for messages acked using
+ // gap-ack-blocks as those are renegable. This means that this may fire a bit
+ // later than the message was actually first "acked" by the peer, as -
+ // according to the protocol - those acks may be unacked later by the client.
+ //
+ // It's guaranteed that `OnLifecycleMessageExpired` is not called if this
+ // callback has triggered.
+ //
+ // This is a lifecycle event.
+ //
+ // Note that it's NOT ALLOWED to call into this library from within this
+ // callback.
+ virtual void OnLifecycleMessageDelivered(LifecycleId lifecycle_id) {}
+
+ // OnLifecycleEnd will be called when a lifecycle event has reached its end.
+ // It will be called when processing of a message is complete, no matter how
+ // it completed. It will be called after all other lifecycle events, if any.
+ //
+ // Note that it's possible that this callback triggers without any other
+ // lifecycle callbacks having been called before in case of errors, such as
+ // attempting to send an empty message or failing to enqueue a message if the
+ // send queue is full.
+ //
+ // NOTE: When the socket is deallocated, there will be no `OnLifecycleEnd`
+ // callbacks sent for messages that were enqueued. But as long as the socket
+ // is alive, `OnLifecycleEnd` callbacks are guaranteed to be sent as messages
+ // are either expired or successfully acknowledged.
+ //
+ // This is a lifecycle event.
+ //
+ // Note that it's NOT ALLOWED to call into this library from within this
+ // callback.
+ virtual void OnLifecycleEnd(LifecycleId lifecycle_id) {}
+};
+
+// The DcSctpSocket implementation implements the following interface.
+// This class is thread-compatible.
+class DcSctpSocketInterface {
+ public:
+ virtual ~DcSctpSocketInterface() = default;
+
+ // To be called when an incoming SCTP packet is to be processed.
+ virtual void ReceivePacket(rtc::ArrayView<const uint8_t> data) = 0;
+
+ // To be called when a timeout has expired. The `timeout_id` is provided
+ // when the timeout was initiated.
+ virtual void HandleTimeout(TimeoutID timeout_id) = 0;
+
+ // Connects the socket. This is an asynchronous operation, and
+ // `DcSctpSocketCallbacks::OnConnected` will be called on success.
+ virtual void Connect() = 0;
+
+ // Puts this socket to the state in which the original socket was when its
+ // `DcSctpSocketHandoverState` was captured by `GetHandoverStateAndClose`.
+ // `RestoreFromState` is allowed only on the closed socket.
+ // `DcSctpSocketCallbacks::OnConnected` will be called if a connected socket
+ // state is restored.
+ // `DcSctpSocketCallbacks::OnError` will be called on error.
+ virtual void RestoreFromState(const DcSctpSocketHandoverState& state) = 0;
+
+ // Gracefully shutdowns the socket and sends all outstanding data. This is an
+ // asynchronous operation and `DcSctpSocketCallbacks::OnClosed` will be called
+ // on success.
+ virtual void Shutdown() = 0;
+
+ // Closes the connection non-gracefully. Will send ABORT if the connection is
+ // not already closed. No callbacks will be made after Close() has returned.
+ virtual void Close() = 0;
+
+ // The socket state.
+ virtual SocketState state() const = 0;
+
+ // The options it was created with.
+ virtual const DcSctpOptions& options() const = 0;
+
+ // Update the options max_message_size.
+ virtual void SetMaxMessageSize(size_t max_message_size) = 0;
+
+ // Sets the priority of an outgoing stream. The initial value, when not set,
+ // is `DcSctpOptions::default_stream_priority`.
+ virtual void SetStreamPriority(StreamID stream_id,
+ StreamPriority priority) = 0;
+
+ // Returns the currently set priority for an outgoing stream. The initial
+ // value, when not set, is `DcSctpOptions::default_stream_priority`.
+ virtual StreamPriority GetStreamPriority(StreamID stream_id) const = 0;
+
+ // Sends the message `message` using the provided send options.
+ // Sending a message is an asynchronous operation, and the `OnError` callback
+ // may be invoked to indicate any errors in sending the message.
+ //
+ // The association does not have to be established before calling this method.
+ // If it's called before there is an established association, the message will
+ // be queued.
+ virtual SendStatus Send(DcSctpMessage message,
+ const SendOptions& send_options) = 0;
+
+ // Resetting streams is an asynchronous operation and the results will
+ // be notified using `DcSctpSocketCallbacks::OnStreamsResetDone()` on success
+ // and `DcSctpSocketCallbacks::OnStreamsResetFailed()` on failure. Note that
+ // only outgoing streams can be reset.
+ //
+ // When it's known that the peer has reset its own outgoing streams,
+ // `DcSctpSocketCallbacks::OnIncomingStreamReset` is called.
+ //
+ // Note that resetting a stream will also remove all queued messages on those
+ // streams, but will ensure that the currently sent message (if any) is fully
+ // sent before closing the stream.
+ //
+ // Resetting streams can only be done on an established association that
+ // supports stream resetting. Calling this method on e.g. a closed association
+ // or streams that don't support resetting will not perform any operation.
+ virtual ResetStreamsStatus ResetStreams(
+ rtc::ArrayView<const StreamID> outgoing_streams) = 0;
+
+ // Returns the number of bytes of data currently queued to be sent on a given
+ // stream.
+ virtual size_t buffered_amount(StreamID stream_id) const = 0;
+
+ // Returns the number of buffered outgoing bytes that is considered "low" for
+ // a given stream. See `SetBufferedAmountLowThreshold`.
+ virtual size_t buffered_amount_low_threshold(StreamID stream_id) const = 0;
+
+ // Used to specify the number of bytes of buffered outgoing data that is
+ // considered "low" for a given stream, which will trigger an
+ // OnBufferedAmountLow event. The default value is zero (0).
+ virtual void SetBufferedAmountLowThreshold(StreamID stream_id,
+ size_t bytes) = 0;
+
+ // Retrieves the latest metrics. If the socket is not fully connected,
+ // `absl::nullopt` will be returned.
+ virtual absl::optional<Metrics> GetMetrics() const = 0;
+
+ // Returns empty bitmask if the socket is in the state in which a snapshot of
+ // the state can be made by `GetHandoverStateAndClose()`. Return value is
+ // invalidated by a call to any non-const method.
+ virtual HandoverReadinessStatus GetHandoverReadiness() const = 0;
+
+ // Collects a snapshot of the socket state that can be used to reconstruct
+ // this socket in another process. On success this socket object is closed
+ // synchronously and no callbacks will be made after the method has returned.
+ // The method fails if the socket is not in a state ready for handover.
+ // nullopt indicates the failure. `DcSctpSocketCallbacks::OnClosed` will be
+ // called on success.
+ virtual absl::optional<DcSctpSocketHandoverState>
+ GetHandoverStateAndClose() = 0;
+
+ // Returns the detected SCTP implementation of the peer. As this is not
+ // explicitly signalled during the connection establishment, heuristics is
+ // used to analyze e.g. the state cookie in the INIT-ACK chunk.
+ //
+ // If this method is called too early (before
+ // `DcSctpSocketCallbacks::OnConnected` has triggered), this will likely
+ // return `SctpImplementation::kUnknown`.
+ ABSL_DEPRECATED("See Metrics::peer_implementation instead")
+ virtual SctpImplementation peer_implementation() const {
+ return SctpImplementation::kUnknown;
+ }
+};
+} // namespace dcsctp
+
+#endif // NET_DCSCTP_PUBLIC_DCSCTP_SOCKET_H_
diff --git a/third_party/libwebrtc/net/dcsctp/public/dcsctp_socket_factory.cc b/third_party/libwebrtc/net/dcsctp/public/dcsctp_socket_factory.cc
new file mode 100644
index 0000000000..ebcb5553e3
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/dcsctp_socket_factory.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#include "net/dcsctp/public/dcsctp_socket_factory.h"
+
+#include <memory>
+#include <utility>
+
+#include "absl/strings/string_view.h"
+#include "net/dcsctp/public/dcsctp_options.h"
+#include "net/dcsctp/public/dcsctp_socket.h"
+#include "net/dcsctp/public/packet_observer.h"
+#include "net/dcsctp/socket/dcsctp_socket.h"
+
+namespace dcsctp {
+
+DcSctpSocketFactory::~DcSctpSocketFactory() = default;
+
+std::unique_ptr<DcSctpSocketInterface> DcSctpSocketFactory::Create(
+ absl::string_view log_prefix,
+ DcSctpSocketCallbacks& callbacks,
+ std::unique_ptr<PacketObserver> packet_observer,
+ const DcSctpOptions& options) {
+ return std::make_unique<DcSctpSocket>(log_prefix, callbacks,
+ std::move(packet_observer), options);
+}
+} // namespace dcsctp
diff --git a/third_party/libwebrtc/net/dcsctp/public/dcsctp_socket_factory.h b/third_party/libwebrtc/net/dcsctp/public/dcsctp_socket_factory.h
new file mode 100644
index 0000000000..ca429d3275
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/dcsctp_socket_factory.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021 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 NET_DCSCTP_PUBLIC_DCSCTP_SOCKET_FACTORY_H_
+#define NET_DCSCTP_PUBLIC_DCSCTP_SOCKET_FACTORY_H_
+
+#include <memory>
+
+#include "absl/strings/string_view.h"
+#include "net/dcsctp/public/dcsctp_options.h"
+#include "net/dcsctp/public/dcsctp_socket.h"
+#include "net/dcsctp/public/packet_observer.h"
+
+namespace dcsctp {
+class DcSctpSocketFactory {
+ public:
+ virtual ~DcSctpSocketFactory();
+ virtual std::unique_ptr<DcSctpSocketInterface> Create(
+ absl::string_view log_prefix,
+ DcSctpSocketCallbacks& callbacks,
+ std::unique_ptr<PacketObserver> packet_observer,
+ const DcSctpOptions& options);
+};
+} // namespace dcsctp
+
+#endif // NET_DCSCTP_PUBLIC_DCSCTP_SOCKET_FACTORY_H_
diff --git a/third_party/libwebrtc/net/dcsctp/public/mock_dcsctp_socket.h b/third_party/libwebrtc/net/dcsctp/public/mock_dcsctp_socket.h
new file mode 100644
index 0000000000..0fd572bd94
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/mock_dcsctp_socket.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2021 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 NET_DCSCTP_PUBLIC_MOCK_DCSCTP_SOCKET_H_
+#define NET_DCSCTP_PUBLIC_MOCK_DCSCTP_SOCKET_H_
+
+#include "net/dcsctp/public/dcsctp_socket.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+
+class MockDcSctpSocket : public DcSctpSocketInterface {
+ public:
+ MOCK_METHOD(void,
+ ReceivePacket,
+ (rtc::ArrayView<const uint8_t> data),
+ (override));
+
+ MOCK_METHOD(void, HandleTimeout, (TimeoutID timeout_id), (override));
+
+ MOCK_METHOD(void, Connect, (), (override));
+
+ MOCK_METHOD(void,
+ RestoreFromState,
+ (const DcSctpSocketHandoverState&),
+ (override));
+
+ MOCK_METHOD(void, Shutdown, (), (override));
+
+ MOCK_METHOD(void, Close, (), (override));
+
+ MOCK_METHOD(SocketState, state, (), (const, override));
+
+ MOCK_METHOD(const DcSctpOptions&, options, (), (const, override));
+
+ MOCK_METHOD(void, SetMaxMessageSize, (size_t max_message_size), (override));
+
+ MOCK_METHOD(void,
+ SetStreamPriority,
+ (StreamID stream_id, StreamPriority priority),
+ (override));
+
+ MOCK_METHOD(StreamPriority,
+ GetStreamPriority,
+ (StreamID stream_id),
+ (const, override));
+
+ MOCK_METHOD(SendStatus,
+ Send,
+ (DcSctpMessage message, const SendOptions& send_options),
+ (override));
+
+ MOCK_METHOD(ResetStreamsStatus,
+ ResetStreams,
+ (rtc::ArrayView<const StreamID> outgoing_streams),
+ (override));
+
+ MOCK_METHOD(size_t, buffered_amount, (StreamID stream_id), (const, override));
+
+ MOCK_METHOD(size_t,
+ buffered_amount_low_threshold,
+ (StreamID stream_id),
+ (const, override));
+
+ MOCK_METHOD(void,
+ SetBufferedAmountLowThreshold,
+ (StreamID stream_id, size_t bytes),
+ (override));
+
+ MOCK_METHOD(absl::optional<Metrics>, GetMetrics, (), (const, override));
+
+ MOCK_METHOD(HandoverReadinessStatus,
+ GetHandoverReadiness,
+ (),
+ (const, override));
+ MOCK_METHOD(absl::optional<DcSctpSocketHandoverState>,
+ GetHandoverStateAndClose,
+ (),
+ (override));
+};
+
+} // namespace dcsctp
+
+#endif // NET_DCSCTP_PUBLIC_MOCK_DCSCTP_SOCKET_H_
diff --git a/third_party/libwebrtc/net/dcsctp/public/mock_dcsctp_socket_factory.h b/third_party/libwebrtc/net/dcsctp/public/mock_dcsctp_socket_factory.h
new file mode 100644
index 0000000000..61f05577f2
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/mock_dcsctp_socket_factory.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2022 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 NET_DCSCTP_PUBLIC_MOCK_DCSCTP_SOCKET_FACTORY_H_
+#define NET_DCSCTP_PUBLIC_MOCK_DCSCTP_SOCKET_FACTORY_H_
+
+#include <memory>
+
+#include "net/dcsctp/public/dcsctp_socket_factory.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+
+class MockDcSctpSocketFactory : public DcSctpSocketFactory {
+ public:
+ MOCK_METHOD(std::unique_ptr<DcSctpSocketInterface>,
+ Create,
+ (absl::string_view log_prefix,
+ DcSctpSocketCallbacks& callbacks,
+ std::unique_ptr<PacketObserver> packet_observer,
+ const DcSctpOptions& options),
+ (override));
+};
+
+} // namespace dcsctp
+
+#endif // NET_DCSCTP_PUBLIC_MOCK_DCSCTP_SOCKET_FACTORY_H_
diff --git a/third_party/libwebrtc/net/dcsctp/public/mock_dcsctp_socket_test.cc b/third_party/libwebrtc/net/dcsctp/public/mock_dcsctp_socket_test.cc
new file mode 100644
index 0000000000..57013e4ce2
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/mock_dcsctp_socket_test.cc
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2021 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.
+ */
+#include "net/dcsctp/public/mock_dcsctp_socket.h"
+
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+
+// This test exists to ensure that all methods are mocked correctly, and to
+// generate compiler errors if they are not.
+TEST(MockDcSctpSocketTest, CanInstantiateAndConnect) {
+ testing::StrictMock<MockDcSctpSocket> socket;
+
+ EXPECT_CALL(socket, Connect);
+
+ socket.Connect();
+}
+
+} // namespace dcsctp
diff --git a/third_party/libwebrtc/net/dcsctp/public/packet_observer.h b/third_party/libwebrtc/net/dcsctp/public/packet_observer.h
new file mode 100644
index 0000000000..fe7567824f
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/packet_observer.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021 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 NET_DCSCTP_PUBLIC_PACKET_OBSERVER_H_
+#define NET_DCSCTP_PUBLIC_PACKET_OBSERVER_H_
+
+#include <stdint.h>
+
+#include "api/array_view.h"
+#include "net/dcsctp/public/types.h"
+
+namespace dcsctp {
+
+// A PacketObserver can be attached to a socket and will be called for
+// all sent and received packets.
+class PacketObserver {
+ public:
+ virtual ~PacketObserver() = default;
+ // Called when a packet is sent, with the current time (in milliseconds) as
+ // `now`, and the packet payload as `payload`.
+ virtual void OnSentPacket(TimeMs now,
+ rtc::ArrayView<const uint8_t> payload) = 0;
+
+ // Called when a packet is received, with the current time (in milliseconds)
+ // as `now`, and the packet payload as `payload`.
+ virtual void OnReceivedPacket(TimeMs now,
+ rtc::ArrayView<const uint8_t> payload) = 0;
+};
+} // namespace dcsctp
+
+#endif // NET_DCSCTP_PUBLIC_PACKET_OBSERVER_H_
diff --git a/third_party/libwebrtc/net/dcsctp/public/text_pcap_packet_observer.cc b/third_party/libwebrtc/net/dcsctp/public/text_pcap_packet_observer.cc
new file mode 100644
index 0000000000..2b13060190
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/text_pcap_packet_observer.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2021 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.
+ */
+#include "net/dcsctp/public/text_pcap_packet_observer.h"
+
+#include "api/array_view.h"
+#include "net/dcsctp/public/types.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+void TextPcapPacketObserver::OnSentPacket(
+ dcsctp::TimeMs now,
+ rtc::ArrayView<const uint8_t> payload) {
+ PrintPacket("O ", name_, now, payload);
+}
+
+void TextPcapPacketObserver::OnReceivedPacket(
+ dcsctp::TimeMs now,
+ rtc::ArrayView<const uint8_t> payload) {
+ PrintPacket("I ", name_, now, payload);
+}
+
+void TextPcapPacketObserver::PrintPacket(
+ absl::string_view prefix,
+ absl::string_view socket_name,
+ dcsctp::TimeMs now,
+ rtc::ArrayView<const uint8_t> payload) {
+ rtc::StringBuilder s;
+ s << "\n" << prefix;
+ int64_t remaining = *now % (24 * 60 * 60 * 1000);
+ int hours = remaining / (60 * 60 * 1000);
+ remaining = remaining % (60 * 60 * 1000);
+ int minutes = remaining / (60 * 1000);
+ remaining = remaining % (60 * 1000);
+ int seconds = remaining / 1000;
+ int ms = remaining % 1000;
+ s.AppendFormat("%02d:%02d:%02d.%03d", hours, minutes, seconds, ms);
+ s << " 0000";
+ for (uint8_t byte : payload) {
+ s.AppendFormat(" %02x", byte);
+ }
+ s << " # SCTP_PACKET " << socket_name;
+ RTC_LOG(LS_VERBOSE) << s.str();
+}
+
+} // namespace dcsctp
diff --git a/third_party/libwebrtc/net/dcsctp/public/text_pcap_packet_observer.h b/third_party/libwebrtc/net/dcsctp/public/text_pcap_packet_observer.h
new file mode 100644
index 0000000000..0685771ccf
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/text_pcap_packet_observer.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2021 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 NET_DCSCTP_PUBLIC_TEXT_PCAP_PACKET_OBSERVER_H_
+#define NET_DCSCTP_PUBLIC_TEXT_PCAP_PACKET_OBSERVER_H_
+
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "api/array_view.h"
+#include "net/dcsctp/public/packet_observer.h"
+#include "net/dcsctp/public/types.h"
+
+namespace dcsctp {
+
+// Print outs all sent and received packets to the logs, at LS_VERBOSE severity.
+class TextPcapPacketObserver : public dcsctp::PacketObserver {
+ public:
+ explicit TextPcapPacketObserver(absl::string_view name) : name_(name) {}
+
+ // Implementation of `dcsctp::PacketObserver`.
+ void OnSentPacket(dcsctp::TimeMs now,
+ rtc::ArrayView<const uint8_t> payload) override;
+
+ void OnReceivedPacket(dcsctp::TimeMs now,
+ rtc::ArrayView<const uint8_t> payload) override;
+
+ // Prints a packet to the log. Exposed to allow it to be used in compatibility
+ // tests suites that don't use PacketObserver.
+ static void PrintPacket(absl::string_view prefix,
+ absl::string_view socket_name,
+ dcsctp::TimeMs now,
+ rtc::ArrayView<const uint8_t> payload);
+
+ private:
+ const std::string name_;
+};
+
+} // namespace dcsctp
+#endif // NET_DCSCTP_PUBLIC_TEXT_PCAP_PACKET_OBSERVER_H_
diff --git a/third_party/libwebrtc/net/dcsctp/public/timeout.h b/third_party/libwebrtc/net/dcsctp/public/timeout.h
new file mode 100644
index 0000000000..64ba351093
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/timeout.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2021 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 NET_DCSCTP_PUBLIC_TIMEOUT_H_
+#define NET_DCSCTP_PUBLIC_TIMEOUT_H_
+
+#include <cstdint>
+
+#include "net/dcsctp/public/types.h"
+
+namespace dcsctp {
+
+// A very simple timeout that can be started and stopped. When started,
+// it will be given a unique `timeout_id` which should be provided to
+// `DcSctpSocket::HandleTimeout` when it expires.
+class Timeout {
+ public:
+ virtual ~Timeout() = default;
+
+ // Called to start time timeout, with the duration in milliseconds as
+ // `duration` and with the timeout identifier as `timeout_id`, which - if
+ // the timeout expires - shall be provided to `DcSctpSocket::HandleTimeout`.
+ //
+ // `Start` and `Stop` will always be called in pairs. In other words will
+ // ´Start` never be called twice, without a call to `Stop` in between.
+ virtual void Start(DurationMs duration, TimeoutID timeout_id) = 0;
+
+ // Called to stop the running timeout.
+ //
+ // `Start` and `Stop` will always be called in pairs. In other words will
+ // ´Start` never be called twice, without a call to `Stop` in between.
+ //
+ // `Stop` will always be called prior to releasing this object.
+ virtual void Stop() = 0;
+
+ // Called to restart an already running timeout, with the `duration` and
+ // `timeout_id` parameters as described in `Start`. This can be overridden by
+ // the implementation to restart it more efficiently.
+ virtual void Restart(DurationMs duration, TimeoutID timeout_id) {
+ Stop();
+ Start(duration, timeout_id);
+ }
+};
+
+} // namespace dcsctp
+
+#endif // NET_DCSCTP_PUBLIC_TIMEOUT_H_
diff --git a/third_party/libwebrtc/net/dcsctp/public/types.h b/third_party/libwebrtc/net/dcsctp/public/types.h
new file mode 100644
index 0000000000..d0725620d8
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/types.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2019 The Chromium Authors. All rights reserved.
+ * Copyright (c) 2021 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 NET_DCSCTP_PUBLIC_TYPES_H_
+#define NET_DCSCTP_PUBLIC_TYPES_H_
+
+#include <cstdint>
+#include <limits>
+
+#include "rtc_base/strong_alias.h"
+
+namespace dcsctp {
+
+// Stream Identifier
+using StreamID = webrtc::StrongAlias<class StreamIDTag, uint16_t>;
+
+// Payload Protocol Identifier (PPID)
+using PPID = webrtc::StrongAlias<class PPIDTag, uint32_t>;
+
+// Timeout Identifier
+using TimeoutID = webrtc::StrongAlias<class TimeoutTag, uint64_t>;
+
+// Indicates if a message is allowed to be received out-of-order compared to
+// other messages on the same stream.
+using IsUnordered = webrtc::StrongAlias<class IsUnorderedTag, bool>;
+
+// Stream priority, where higher values indicate higher priority. The meaning of
+// this value and how it's used depends on the stream scheduler.
+using StreamPriority = webrtc::StrongAlias<class StreamPriorityTag, uint16_t>;
+
+// Duration, as milliseconds. Overflows after 24 days.
+class DurationMs : public webrtc::StrongAlias<class DurationMsTag, int32_t> {
+ public:
+ constexpr explicit DurationMs(const UnderlyingType& v)
+ : webrtc::StrongAlias<class DurationMsTag, int32_t>(v) {}
+
+ // Convenience methods for working with time.
+ constexpr DurationMs& operator+=(DurationMs d) {
+ value_ += d.value_;
+ return *this;
+ }
+ constexpr DurationMs& operator-=(DurationMs d) {
+ value_ -= d.value_;
+ return *this;
+ }
+ template <typename T>
+ constexpr DurationMs& operator*=(T factor) {
+ value_ *= factor;
+ return *this;
+ }
+};
+
+constexpr inline DurationMs operator+(DurationMs lhs, DurationMs rhs) {
+ return lhs += rhs;
+}
+constexpr inline DurationMs operator-(DurationMs lhs, DurationMs rhs) {
+ return lhs -= rhs;
+}
+template <typename T>
+constexpr inline DurationMs operator*(DurationMs lhs, T rhs) {
+ return lhs *= rhs;
+}
+template <typename T>
+constexpr inline DurationMs operator*(T lhs, DurationMs rhs) {
+ return rhs *= lhs;
+}
+constexpr inline int32_t operator/(DurationMs lhs, DurationMs rhs) {
+ return lhs.value() / rhs.value();
+}
+
+// Represents time, in milliseconds since a client-defined epoch.
+class TimeMs : public webrtc::StrongAlias<class TimeMsTag, int64_t> {
+ public:
+ constexpr explicit TimeMs(const UnderlyingType& v)
+ : webrtc::StrongAlias<class TimeMsTag, int64_t>(v) {}
+
+ // Convenience methods for working with time.
+ constexpr TimeMs& operator+=(DurationMs d) {
+ value_ += *d;
+ return *this;
+ }
+ constexpr TimeMs& operator-=(DurationMs d) {
+ value_ -= *d;
+ return *this;
+ }
+
+ static constexpr TimeMs InfiniteFuture() {
+ return TimeMs(std::numeric_limits<int64_t>::max());
+ }
+};
+
+constexpr inline TimeMs operator+(TimeMs lhs, DurationMs rhs) {
+ return lhs += rhs;
+}
+constexpr inline TimeMs operator+(DurationMs lhs, TimeMs rhs) {
+ return rhs += lhs;
+}
+constexpr inline TimeMs operator-(TimeMs lhs, DurationMs rhs) {
+ return lhs -= rhs;
+}
+constexpr inline DurationMs operator-(TimeMs lhs, TimeMs rhs) {
+ return DurationMs(*lhs - *rhs);
+}
+
+// The maximum number of times the socket should attempt to retransmit a
+// message which fails the first time in unreliable mode.
+class MaxRetransmits
+ : public webrtc::StrongAlias<class MaxRetransmitsTag, uint16_t> {
+ public:
+ constexpr explicit MaxRetransmits(const UnderlyingType& v)
+ : webrtc::StrongAlias<class MaxRetransmitsTag, uint16_t>(v) {}
+
+ // There should be no limit - the message should be sent reliably.
+ static constexpr MaxRetransmits NoLimit() {
+ return MaxRetransmits(std::numeric_limits<uint16_t>::max());
+ }
+};
+
+// An identifier that can be set on sent messages, and picked by the sending
+// client. If different from `::NotSet()`, lifecycle events will be generated,
+// and eventually `DcSctpSocketCallbacks::OnLifecycleEnd` will be called to
+// indicate that the lifecycle isn't tracked any longer. The value zero (0) is
+// not a valid lifecycle identifier, and will be interpreted as not having it
+// set.
+class LifecycleId : public webrtc::StrongAlias<class LifecycleIdTag, uint64_t> {
+ public:
+ constexpr explicit LifecycleId(const UnderlyingType& v)
+ : webrtc::StrongAlias<class LifecycleIdTag, uint64_t>(v) {}
+
+ constexpr bool IsSet() const { return value_ != 0; }
+
+ static constexpr LifecycleId NotSet() { return LifecycleId(0); }
+};
+} // namespace dcsctp
+
+#endif // NET_DCSCTP_PUBLIC_TYPES_H_
diff --git a/third_party/libwebrtc/net/dcsctp/public/types_test.cc b/third_party/libwebrtc/net/dcsctp/public/types_test.cc
new file mode 100644
index 0000000000..d3d1240751
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/public/types_test.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2021 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.
+ */
+#include "net/dcsctp/public/types.h"
+
+#include "rtc_base/gunit.h"
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(TypesTest, DurationOperators) {
+ DurationMs d1(10);
+ DurationMs d2(25);
+ EXPECT_EQ(d1 + d2, DurationMs(35));
+ EXPECT_EQ(d2 - d1, DurationMs(15));
+
+ d1 += d2;
+ EXPECT_EQ(d1, DurationMs(35));
+
+ d1 -= DurationMs(5);
+ EXPECT_EQ(d1, DurationMs(30));
+
+ d1 *= 1.5;
+ EXPECT_EQ(d1, DurationMs(45));
+
+ EXPECT_EQ(DurationMs(10) * 2, DurationMs(20));
+}
+
+TEST(TypesTest, TimeOperators) {
+ EXPECT_EQ(TimeMs(250) + DurationMs(100), TimeMs(350));
+ EXPECT_EQ(DurationMs(250) + TimeMs(100), TimeMs(350));
+ EXPECT_EQ(TimeMs(250) - DurationMs(100), TimeMs(150));
+ EXPECT_EQ(TimeMs(250) - TimeMs(100), DurationMs(150));
+
+ TimeMs t1(150);
+ t1 -= DurationMs(50);
+ EXPECT_EQ(t1, TimeMs(100));
+ t1 += DurationMs(200);
+ EXPECT_EQ(t1, TimeMs(300));
+}
+
+} // namespace
+} // namespace dcsctp