summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/net/dcsctp/common
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
commit0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch)
treea31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /third_party/libwebrtc/net/dcsctp/common
parentInitial commit. (diff)
downloadfirefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz
firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/net/dcsctp/common')
-rw-r--r--third_party/libwebrtc/net/dcsctp/common/BUILD.gn67
-rw-r--r--third_party/libwebrtc/net/dcsctp/common/handover_testing.cc22
-rw-r--r--third_party/libwebrtc/net/dcsctp/common/handover_testing.h29
-rw-r--r--third_party/libwebrtc/net/dcsctp/common/internal_types.h44
-rw-r--r--third_party/libwebrtc/net/dcsctp/common/math.h36
-rw-r--r--third_party/libwebrtc/net/dcsctp/common/math_test.cc116
-rw-r--r--third_party/libwebrtc/net/dcsctp/common/sequence_numbers.h156
-rw-r--r--third_party/libwebrtc/net/dcsctp/common/sequence_numbers_test.cc202
-rw-r--r--third_party/libwebrtc/net/dcsctp/common/str_join.h56
-rw-r--r--third_party/libwebrtc/net/dcsctp/common/str_join_test.cc45
10 files changed, 773 insertions, 0 deletions
diff --git a/third_party/libwebrtc/net/dcsctp/common/BUILD.gn b/third_party/libwebrtc/net/dcsctp/common/BUILD.gn
new file mode 100644
index 0000000000..78fa0d307e
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/common/BUILD.gn
@@ -0,0 +1,67 @@
+# 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("internal_types") {
+ deps = [
+ "../../../rtc_base:strong_alias",
+ "../public:types",
+ ]
+ sources = [ "internal_types.h" ]
+}
+
+rtc_source_set("math") {
+ deps = []
+ sources = [ "math.h" ]
+}
+
+rtc_source_set("sequence_numbers") {
+ deps = [
+ ":internal_types",
+ "../../../rtc_base:rtc_numerics",
+ ]
+ sources = [ "sequence_numbers.h" ]
+}
+
+rtc_source_set("str_join") {
+ deps = [ "../../../rtc_base:stringutils" ]
+ sources = [ "str_join.h" ]
+ absl_deps = [ "//third_party/abseil-cpp/absl/strings" ]
+}
+
+if (rtc_include_tests) {
+ rtc_library("dcsctp_common_unittests") {
+ testonly = true
+
+ defines = []
+ deps = [
+ ":math",
+ ":sequence_numbers",
+ ":str_join",
+ "../../../api:array_view",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:gunit_helpers",
+ "../../../test:test_support",
+ ]
+ sources = [
+ "math_test.cc",
+ "sequence_numbers_test.cc",
+ "str_join_test.cc",
+ ]
+ }
+}
+
+rtc_library("handover_testing") {
+ deps = [ "../public:socket" ]
+ testonly = true
+ sources = [
+ "handover_testing.cc",
+ "handover_testing.h",
+ ]
+}
diff --git a/third_party/libwebrtc/net/dcsctp/common/handover_testing.cc b/third_party/libwebrtc/net/dcsctp/common/handover_testing.cc
new file mode 100644
index 0000000000..1081766ea5
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/common/handover_testing.cc
@@ -0,0 +1,22 @@
+/*
+ * 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/common/handover_testing.h"
+
+namespace dcsctp {
+namespace {
+// Default transformer function does nothing - dcSCTP does not implement
+// state serialization that could be tested by setting
+// `g_handover_state_transformer_for_test`.
+void NoTransformation(DcSctpSocketHandoverState*) {}
+} // namespace
+
+void (*g_handover_state_transformer_for_test)(DcSctpSocketHandoverState*) =
+ NoTransformation;
+} // namespace dcsctp
diff --git a/third_party/libwebrtc/net/dcsctp/common/handover_testing.h b/third_party/libwebrtc/net/dcsctp/common/handover_testing.h
new file mode 100644
index 0000000000..396016afec
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/common/handover_testing.h
@@ -0,0 +1,29 @@
+/*
+ * 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_COMMON_HANDOVER_TESTING_H_
+#define NET_DCSCTP_COMMON_HANDOVER_TESTING_H_
+
+#include "net/dcsctp/public/dcsctp_handover_state.h"
+
+namespace dcsctp {
+// This global function is to facilitate testing of the socket handover state
+// (`DcSctpSocketHandoverState`) serialization. dcSCTP library users have to
+// implement state serialization if it's needed. To test the serialization one
+// can set a custom `g_handover_state_transformer_for_test` at startup, link to
+// the dcSCTP tests and run the resulting binary. Custom function can serialize
+// and deserialize the passed state. All dcSCTP handover tests call
+// `g_handover_state_transformer_for_test`. If some part of the state is
+// serialized incorrectly or is forgotten, high chance that it will fail the
+// tests.
+extern void (*g_handover_state_transformer_for_test)(
+ DcSctpSocketHandoverState*);
+} // namespace dcsctp
+
+#endif // NET_DCSCTP_COMMON_HANDOVER_TESTING_H_
diff --git a/third_party/libwebrtc/net/dcsctp/common/internal_types.h b/third_party/libwebrtc/net/dcsctp/common/internal_types.h
new file mode 100644
index 0000000000..2354b92cc4
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/common/internal_types.h
@@ -0,0 +1,44 @@
+/*
+ * 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_COMMON_INTERNAL_TYPES_H_
+#define NET_DCSCTP_COMMON_INTERNAL_TYPES_H_
+
+#include <functional>
+#include <utility>
+
+#include "net/dcsctp/public/types.h"
+#include "rtc_base/strong_alias.h"
+
+namespace dcsctp {
+
+// Stream Sequence Number (SSN)
+using SSN = webrtc::StrongAlias<class SSNTag, uint16_t>;
+
+// Message Identifier (MID)
+using MID = webrtc::StrongAlias<class MIDTag, uint32_t>;
+
+// Fragment Sequence Number (FSN)
+using FSN = webrtc::StrongAlias<class FSNTag, uint32_t>;
+
+// Transmission Sequence Number (TSN)
+using TSN = webrtc::StrongAlias<class TSNTag, uint32_t>;
+
+// Reconfiguration Request Sequence Number
+using ReconfigRequestSN =
+ webrtc::StrongAlias<class ReconfigRequestSNTag, uint32_t>;
+
+// Verification Tag, used for packet validation.
+using VerificationTag = webrtc::StrongAlias<class VerificationTagTag, uint32_t>;
+
+// Tie Tag, used as a nonce when connecting.
+using TieTag = webrtc::StrongAlias<class TieTagTag, uint64_t>;
+
+} // namespace dcsctp
+#endif // NET_DCSCTP_COMMON_INTERNAL_TYPES_H_
diff --git a/third_party/libwebrtc/net/dcsctp/common/math.h b/third_party/libwebrtc/net/dcsctp/common/math.h
new file mode 100644
index 0000000000..12f690ed57
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/common/math.h
@@ -0,0 +1,36 @@
+/*
+ * 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_COMMON_MATH_H_
+#define NET_DCSCTP_COMMON_MATH_H_
+
+namespace dcsctp {
+
+// Rounds up `val` to the nearest value that is divisible by four. Frequently
+// used to e.g. pad chunks or parameters to an even 32-bit offset.
+template <typename IntType>
+IntType RoundUpTo4(IntType val) {
+ return (val + 3) & ~3;
+}
+
+// Similarly, rounds down `val` to the nearest value that is divisible by four.
+template <typename IntType>
+IntType RoundDownTo4(IntType val) {
+ return val & ~3;
+}
+
+// Returns true if `val` is divisible by four.
+template <typename IntType>
+bool IsDivisibleBy4(IntType val) {
+ return (val & 3) == 0;
+}
+
+} // namespace dcsctp
+
+#endif // NET_DCSCTP_COMMON_MATH_H_
diff --git a/third_party/libwebrtc/net/dcsctp/common/math_test.cc b/third_party/libwebrtc/net/dcsctp/common/math_test.cc
new file mode 100644
index 0000000000..f95dfbdb55
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/common/math_test.cc
@@ -0,0 +1,116 @@
+/*
+ * 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/common/math.h"
+
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(MathUtilTest, CanRoundUpTo4) {
+ // Signed numbers
+ EXPECT_EQ(RoundUpTo4(static_cast<int>(-5)), -4);
+ EXPECT_EQ(RoundUpTo4(static_cast<int>(-4)), -4);
+ EXPECT_EQ(RoundUpTo4(static_cast<int>(-3)), 0);
+ EXPECT_EQ(RoundUpTo4(static_cast<int>(-2)), 0);
+ EXPECT_EQ(RoundUpTo4(static_cast<int>(-1)), 0);
+ EXPECT_EQ(RoundUpTo4(static_cast<int>(0)), 0);
+ EXPECT_EQ(RoundUpTo4(static_cast<int>(1)), 4);
+ EXPECT_EQ(RoundUpTo4(static_cast<int>(2)), 4);
+ EXPECT_EQ(RoundUpTo4(static_cast<int>(3)), 4);
+ EXPECT_EQ(RoundUpTo4(static_cast<int>(4)), 4);
+ EXPECT_EQ(RoundUpTo4(static_cast<int>(5)), 8);
+ EXPECT_EQ(RoundUpTo4(static_cast<int>(6)), 8);
+ EXPECT_EQ(RoundUpTo4(static_cast<int>(7)), 8);
+ EXPECT_EQ(RoundUpTo4(static_cast<int>(8)), 8);
+ EXPECT_EQ(RoundUpTo4(static_cast<int64_t>(10000000000)), 10000000000);
+ EXPECT_EQ(RoundUpTo4(static_cast<int64_t>(10000000001)), 10000000004);
+
+ // Unsigned numbers
+ EXPECT_EQ(RoundUpTo4(static_cast<unsigned int>(0)), 0u);
+ EXPECT_EQ(RoundUpTo4(static_cast<unsigned int>(1)), 4u);
+ EXPECT_EQ(RoundUpTo4(static_cast<unsigned int>(2)), 4u);
+ EXPECT_EQ(RoundUpTo4(static_cast<unsigned int>(3)), 4u);
+ EXPECT_EQ(RoundUpTo4(static_cast<unsigned int>(4)), 4u);
+ EXPECT_EQ(RoundUpTo4(static_cast<unsigned int>(5)), 8u);
+ EXPECT_EQ(RoundUpTo4(static_cast<unsigned int>(6)), 8u);
+ EXPECT_EQ(RoundUpTo4(static_cast<unsigned int>(7)), 8u);
+ EXPECT_EQ(RoundUpTo4(static_cast<unsigned int>(8)), 8u);
+ EXPECT_EQ(RoundUpTo4(static_cast<uint64_t>(10000000000)), 10000000000u);
+ EXPECT_EQ(RoundUpTo4(static_cast<uint64_t>(10000000001)), 10000000004u);
+}
+
+TEST(MathUtilTest, CanRoundDownTo4) {
+ // Signed numbers
+ EXPECT_EQ(RoundDownTo4(static_cast<int>(-5)), -8);
+ EXPECT_EQ(RoundDownTo4(static_cast<int>(-4)), -4);
+ EXPECT_EQ(RoundDownTo4(static_cast<int>(-3)), -4);
+ EXPECT_EQ(RoundDownTo4(static_cast<int>(-2)), -4);
+ EXPECT_EQ(RoundDownTo4(static_cast<int>(-1)), -4);
+ EXPECT_EQ(RoundDownTo4(static_cast<int>(0)), 0);
+ EXPECT_EQ(RoundDownTo4(static_cast<int>(1)), 0);
+ EXPECT_EQ(RoundDownTo4(static_cast<int>(2)), 0);
+ EXPECT_EQ(RoundDownTo4(static_cast<int>(3)), 0);
+ EXPECT_EQ(RoundDownTo4(static_cast<int>(4)), 4);
+ EXPECT_EQ(RoundDownTo4(static_cast<int>(5)), 4);
+ EXPECT_EQ(RoundDownTo4(static_cast<int>(6)), 4);
+ EXPECT_EQ(RoundDownTo4(static_cast<int>(7)), 4);
+ EXPECT_EQ(RoundDownTo4(static_cast<int>(8)), 8);
+ EXPECT_EQ(RoundDownTo4(static_cast<int64_t>(10000000000)), 10000000000);
+ EXPECT_EQ(RoundDownTo4(static_cast<int64_t>(10000000001)), 10000000000);
+
+ // Unsigned numbers
+ EXPECT_EQ(RoundDownTo4(static_cast<unsigned int>(0)), 0u);
+ EXPECT_EQ(RoundDownTo4(static_cast<unsigned int>(1)), 0u);
+ EXPECT_EQ(RoundDownTo4(static_cast<unsigned int>(2)), 0u);
+ EXPECT_EQ(RoundDownTo4(static_cast<unsigned int>(3)), 0u);
+ EXPECT_EQ(RoundDownTo4(static_cast<unsigned int>(4)), 4u);
+ EXPECT_EQ(RoundDownTo4(static_cast<unsigned int>(5)), 4u);
+ EXPECT_EQ(RoundDownTo4(static_cast<unsigned int>(6)), 4u);
+ EXPECT_EQ(RoundDownTo4(static_cast<unsigned int>(7)), 4u);
+ EXPECT_EQ(RoundDownTo4(static_cast<unsigned int>(8)), 8u);
+ EXPECT_EQ(RoundDownTo4(static_cast<uint64_t>(10000000000)), 10000000000u);
+ EXPECT_EQ(RoundDownTo4(static_cast<uint64_t>(10000000001)), 10000000000u);
+}
+
+TEST(MathUtilTest, IsDivisibleBy4) {
+ // Signed numbers
+ EXPECT_EQ(IsDivisibleBy4(static_cast<int>(-4)), true);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<int>(-3)), false);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<int>(-2)), false);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<int>(-1)), false);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<int>(0)), true);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<int>(1)), false);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<int>(2)), false);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<int>(3)), false);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<int>(4)), true);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<int>(5)), false);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<int>(6)), false);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<int>(7)), false);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<int>(8)), true);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<int64_t>(10000000000)), true);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<int64_t>(10000000001)), false);
+
+ // Unsigned numbers
+ EXPECT_EQ(IsDivisibleBy4(static_cast<unsigned int>(0)), true);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<unsigned int>(1)), false);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<unsigned int>(2)), false);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<unsigned int>(3)), false);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<unsigned int>(4)), true);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<unsigned int>(5)), false);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<unsigned int>(6)), false);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<unsigned int>(7)), false);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<unsigned int>(8)), true);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<uint64_t>(10000000000)), true);
+ EXPECT_EQ(IsDivisibleBy4(static_cast<uint64_t>(10000000001)), false);
+}
+
+} // namespace
+} // namespace dcsctp
diff --git a/third_party/libwebrtc/net/dcsctp/common/sequence_numbers.h b/third_party/libwebrtc/net/dcsctp/common/sequence_numbers.h
new file mode 100644
index 0000000000..d324fb223a
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/common/sequence_numbers.h
@@ -0,0 +1,156 @@
+/*
+ * 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_COMMON_SEQUENCE_NUMBERS_H_
+#define NET_DCSCTP_COMMON_SEQUENCE_NUMBERS_H_
+
+#include <cstdint>
+#include <limits>
+#include <utility>
+
+#include "net/dcsctp/common/internal_types.h"
+#include "rtc_base/numerics/sequence_number_unwrapper.h"
+
+namespace dcsctp {
+
+// UnwrappedSequenceNumber handles wrapping sequence numbers and unwraps them to
+// an int64_t value space, to allow wrapped sequence numbers to be easily
+// compared for ordering.
+//
+// Sequence numbers are expected to be monotonically increasing, but they do not
+// need to be unwrapped in order, as long as the difference to the previous one
+// is not larger than half the range of the wrapped sequence number.
+//
+// The WrappedType must be a webrtc::StrongAlias type.
+template <typename WrappedType>
+class UnwrappedSequenceNumber {
+ public:
+ static_assert(
+ !std::numeric_limits<typename WrappedType::UnderlyingType>::is_signed,
+ "The wrapped type must be unsigned");
+ static_assert(
+ std::numeric_limits<typename WrappedType::UnderlyingType>::max() <
+ std::numeric_limits<int64_t>::max(),
+ "The wrapped type must be less than the int64_t value space");
+
+ // The unwrapper is a sort of factory and converts wrapped sequence numbers to
+ // unwrapped ones.
+ class Unwrapper {
+ public:
+ Unwrapper() = default;
+ Unwrapper(const Unwrapper&) = default;
+ Unwrapper& operator=(const Unwrapper&) = default;
+
+ // Given a wrapped `value`, and with knowledge of its current last seen
+ // largest number, will return a value that can be compared using normal
+ // operators, such as less-than, greater-than etc.
+ //
+ // This will also update the Unwrapper's state, to track the last seen
+ // largest value.
+ UnwrappedSequenceNumber<WrappedType> Unwrap(WrappedType value) {
+ return UnwrappedSequenceNumber<WrappedType>(unwrapper_.Unwrap(*value));
+ }
+
+ // Similar to `Unwrap`, but will not update the Unwrappers's internal state.
+ UnwrappedSequenceNumber<WrappedType> PeekUnwrap(WrappedType value) const {
+ return UnwrappedSequenceNumber<WrappedType>(
+ unwrapper_.PeekUnwrap(*value));
+ }
+
+ // Resets the Unwrapper to its pristine state. Used when a sequence number
+ // is to be reset to zero.
+ void Reset() { unwrapper_.Reset(); }
+
+ private:
+ webrtc::SeqNumUnwrapper<typename WrappedType::UnderlyingType> unwrapper_;
+ };
+
+ // Returns the wrapped value this type represents.
+ WrappedType Wrap() const {
+ return static_cast<WrappedType>(value_ % kValueLimit);
+ }
+
+ template <typename H>
+ friend H AbslHashValue(H state,
+ const UnwrappedSequenceNumber<WrappedType>& hash) {
+ return H::combine(std::move(state), hash.value_);
+ }
+
+ bool operator==(const UnwrappedSequenceNumber<WrappedType>& other) const {
+ return value_ == other.value_;
+ }
+ bool operator!=(const UnwrappedSequenceNumber<WrappedType>& other) const {
+ return value_ != other.value_;
+ }
+ bool operator<(const UnwrappedSequenceNumber<WrappedType>& other) const {
+ return value_ < other.value_;
+ }
+ bool operator>(const UnwrappedSequenceNumber<WrappedType>& other) const {
+ return value_ > other.value_;
+ }
+ bool operator>=(const UnwrappedSequenceNumber<WrappedType>& other) const {
+ return value_ >= other.value_;
+ }
+ bool operator<=(const UnwrappedSequenceNumber<WrappedType>& other) const {
+ return value_ <= other.value_;
+ }
+
+ // Const accessors for underlying value.
+ constexpr const int64_t* operator->() const { return &value_; }
+ constexpr const int64_t& operator*() const& { return value_; }
+ constexpr const int64_t&& operator*() const&& { return std::move(value_); }
+ constexpr const int64_t& value() const& { return value_; }
+ constexpr const int64_t&& value() const&& { return std::move(value_); }
+ constexpr explicit operator const int64_t&() const& { return value_; }
+
+ // Increments the value.
+ void Increment() { ++value_; }
+
+ // Returns the next value relative to this sequence number.
+ UnwrappedSequenceNumber<WrappedType> next_value() const {
+ return UnwrappedSequenceNumber<WrappedType>(value_ + 1);
+ }
+
+ // Returns a new sequence number based on `value`, and adding `delta` (which
+ // may be negative).
+ static UnwrappedSequenceNumber<WrappedType> AddTo(
+ UnwrappedSequenceNumber<WrappedType> value,
+ int delta) {
+ return UnwrappedSequenceNumber<WrappedType>(value.value_ + delta);
+ }
+
+ // Returns the absolute difference between `lhs` and `rhs`.
+ static typename WrappedType::UnderlyingType Difference(
+ UnwrappedSequenceNumber<WrappedType> lhs,
+ UnwrappedSequenceNumber<WrappedType> rhs) {
+ return (lhs.value_ > rhs.value_) ? (lhs.value_ - rhs.value_)
+ : (rhs.value_ - lhs.value_);
+ }
+
+ private:
+ explicit UnwrappedSequenceNumber(int64_t value) : value_(value) {}
+ static constexpr int64_t kValueLimit =
+ static_cast<int64_t>(1)
+ << std::numeric_limits<typename WrappedType::UnderlyingType>::digits;
+
+ int64_t value_;
+};
+
+// Unwrapped Transmission Sequence Numbers (TSN)
+using UnwrappedTSN = UnwrappedSequenceNumber<TSN>;
+
+// Unwrapped Stream Sequence Numbers (SSN)
+using UnwrappedSSN = UnwrappedSequenceNumber<SSN>;
+
+// Unwrapped Message Identifier (MID)
+using UnwrappedMID = UnwrappedSequenceNumber<MID>;
+
+} // namespace dcsctp
+
+#endif // NET_DCSCTP_COMMON_SEQUENCE_NUMBERS_H_
diff --git a/third_party/libwebrtc/net/dcsctp/common/sequence_numbers_test.cc b/third_party/libwebrtc/net/dcsctp/common/sequence_numbers_test.cc
new file mode 100644
index 0000000000..c4842f089e
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/common/sequence_numbers_test.cc
@@ -0,0 +1,202 @@
+/*
+ * 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/common/sequence_numbers.h"
+
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+
+using Wrapped = webrtc::StrongAlias<class WrappedTag, uint16_t>;
+using TestSequence = UnwrappedSequenceNumber<Wrapped>;
+
+TEST(SequenceNumbersTest, SimpleUnwrapping) {
+ TestSequence::Unwrapper unwrapper;
+
+ TestSequence s0 = unwrapper.Unwrap(Wrapped(0));
+ TestSequence s1 = unwrapper.Unwrap(Wrapped(1));
+ TestSequence s2 = unwrapper.Unwrap(Wrapped(2));
+ TestSequence s3 = unwrapper.Unwrap(Wrapped(3));
+
+ EXPECT_LT(s0, s1);
+ EXPECT_LT(s0, s2);
+ EXPECT_LT(s0, s3);
+ EXPECT_LT(s1, s2);
+ EXPECT_LT(s1, s3);
+ EXPECT_LT(s2, s3);
+
+ EXPECT_EQ(TestSequence::Difference(s1, s0), 1);
+ EXPECT_EQ(TestSequence::Difference(s2, s0), 2);
+ EXPECT_EQ(TestSequence::Difference(s3, s0), 3);
+
+ EXPECT_GT(s1, s0);
+ EXPECT_GT(s2, s0);
+ EXPECT_GT(s3, s0);
+ EXPECT_GT(s2, s1);
+ EXPECT_GT(s3, s1);
+ EXPECT_GT(s3, s2);
+
+ s0.Increment();
+ EXPECT_EQ(s0, s1);
+ s1.Increment();
+ EXPECT_EQ(s1, s2);
+ s2.Increment();
+ EXPECT_EQ(s2, s3);
+
+ EXPECT_EQ(TestSequence::AddTo(s0, 2), s3);
+}
+
+TEST(SequenceNumbersTest, MidValueUnwrapping) {
+ TestSequence::Unwrapper unwrapper;
+
+ TestSequence s0 = unwrapper.Unwrap(Wrapped(0x7FFE));
+ TestSequence s1 = unwrapper.Unwrap(Wrapped(0x7FFF));
+ TestSequence s2 = unwrapper.Unwrap(Wrapped(0x8000));
+ TestSequence s3 = unwrapper.Unwrap(Wrapped(0x8001));
+
+ EXPECT_LT(s0, s1);
+ EXPECT_LT(s0, s2);
+ EXPECT_LT(s0, s3);
+ EXPECT_LT(s1, s2);
+ EXPECT_LT(s1, s3);
+ EXPECT_LT(s2, s3);
+
+ EXPECT_EQ(TestSequence::Difference(s1, s0), 1);
+ EXPECT_EQ(TestSequence::Difference(s2, s0), 2);
+ EXPECT_EQ(TestSequence::Difference(s3, s0), 3);
+
+ EXPECT_GT(s1, s0);
+ EXPECT_GT(s2, s0);
+ EXPECT_GT(s3, s0);
+ EXPECT_GT(s2, s1);
+ EXPECT_GT(s3, s1);
+ EXPECT_GT(s3, s2);
+
+ s0.Increment();
+ EXPECT_EQ(s0, s1);
+ s1.Increment();
+ EXPECT_EQ(s1, s2);
+ s2.Increment();
+ EXPECT_EQ(s2, s3);
+
+ EXPECT_EQ(TestSequence::AddTo(s0, 2), s3);
+}
+
+TEST(SequenceNumbersTest, WrappedUnwrapping) {
+ TestSequence::Unwrapper unwrapper;
+
+ TestSequence s0 = unwrapper.Unwrap(Wrapped(0xFFFE));
+ TestSequence s1 = unwrapper.Unwrap(Wrapped(0xFFFF));
+ TestSequence s2 = unwrapper.Unwrap(Wrapped(0x0000));
+ TestSequence s3 = unwrapper.Unwrap(Wrapped(0x0001));
+
+ EXPECT_LT(s0, s1);
+ EXPECT_LT(s0, s2);
+ EXPECT_LT(s0, s3);
+ EXPECT_LT(s1, s2);
+ EXPECT_LT(s1, s3);
+ EXPECT_LT(s2, s3);
+
+ EXPECT_EQ(TestSequence::Difference(s1, s0), 1);
+ EXPECT_EQ(TestSequence::Difference(s2, s0), 2);
+ EXPECT_EQ(TestSequence::Difference(s3, s0), 3);
+
+ EXPECT_GT(s1, s0);
+ EXPECT_GT(s2, s0);
+ EXPECT_GT(s3, s0);
+ EXPECT_GT(s2, s1);
+ EXPECT_GT(s3, s1);
+ EXPECT_GT(s3, s2);
+
+ s0.Increment();
+ EXPECT_EQ(s0, s1);
+ s1.Increment();
+ EXPECT_EQ(s1, s2);
+ s2.Increment();
+ EXPECT_EQ(s2, s3);
+
+ EXPECT_EQ(TestSequence::AddTo(s0, 2), s3);
+}
+
+TEST(SequenceNumbersTest, WrapAroundAFewTimes) {
+ TestSequence::Unwrapper unwrapper;
+
+ TestSequence s0 = unwrapper.Unwrap(Wrapped(0));
+ TestSequence prev = s0;
+
+ for (uint32_t i = 1; i < 65536 * 3; i++) {
+ uint16_t wrapped = static_cast<uint16_t>(i);
+ TestSequence si = unwrapper.Unwrap(Wrapped(wrapped));
+
+ EXPECT_LT(s0, si);
+ EXPECT_LT(prev, si);
+ prev = si;
+ }
+}
+
+TEST(SequenceNumbersTest, IncrementIsSameAsWrapped) {
+ TestSequence::Unwrapper unwrapper;
+
+ TestSequence s0 = unwrapper.Unwrap(Wrapped(0));
+
+ for (uint32_t i = 1; i < 65536 * 2; i++) {
+ uint16_t wrapped = static_cast<uint16_t>(i);
+ TestSequence si = unwrapper.Unwrap(Wrapped(wrapped));
+
+ s0.Increment();
+ EXPECT_EQ(s0, si);
+ }
+}
+
+TEST(SequenceNumbersTest, UnwrappingLargerNumberIsAlwaysLarger) {
+ TestSequence::Unwrapper unwrapper;
+
+ for (uint32_t i = 1; i < 65536 * 2; i++) {
+ uint16_t wrapped = static_cast<uint16_t>(i);
+ TestSequence si = unwrapper.Unwrap(Wrapped(wrapped));
+
+ EXPECT_GT(unwrapper.Unwrap(Wrapped(wrapped + 1)), si);
+ EXPECT_GT(unwrapper.Unwrap(Wrapped(wrapped + 5)), si);
+ EXPECT_GT(unwrapper.Unwrap(Wrapped(wrapped + 10)), si);
+ EXPECT_GT(unwrapper.Unwrap(Wrapped(wrapped + 100)), si);
+ }
+}
+
+TEST(SequenceNumbersTest, UnwrappingSmallerNumberIsAlwaysSmaller) {
+ TestSequence::Unwrapper unwrapper;
+
+ for (uint32_t i = 1; i < 65536 * 2; i++) {
+ uint16_t wrapped = static_cast<uint16_t>(i);
+ TestSequence si = unwrapper.Unwrap(Wrapped(wrapped));
+
+ EXPECT_LT(unwrapper.Unwrap(Wrapped(wrapped - 1)), si);
+ EXPECT_LT(unwrapper.Unwrap(Wrapped(wrapped - 5)), si);
+ EXPECT_LT(unwrapper.Unwrap(Wrapped(wrapped - 10)), si);
+ EXPECT_LT(unwrapper.Unwrap(Wrapped(wrapped - 100)), si);
+ }
+}
+
+TEST(SequenceNumbersTest, DifferenceIsAbsolute) {
+ TestSequence::Unwrapper unwrapper;
+
+ TestSequence this_value = unwrapper.Unwrap(Wrapped(10));
+ TestSequence other_value = TestSequence::AddTo(this_value, 100);
+
+ EXPECT_EQ(TestSequence::Difference(this_value, other_value), 100);
+ EXPECT_EQ(TestSequence::Difference(other_value, this_value), 100);
+
+ TestSequence minus_value = TestSequence::AddTo(this_value, -100);
+
+ EXPECT_EQ(TestSequence::Difference(this_value, minus_value), 100);
+ EXPECT_EQ(TestSequence::Difference(minus_value, this_value), 100);
+}
+
+} // namespace
+} // namespace dcsctp
diff --git a/third_party/libwebrtc/net/dcsctp/common/str_join.h b/third_party/libwebrtc/net/dcsctp/common/str_join.h
new file mode 100644
index 0000000000..04517827b7
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/common/str_join.h
@@ -0,0 +1,56 @@
+/*
+ * 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_COMMON_STR_JOIN_H_
+#define NET_DCSCTP_COMMON_STR_JOIN_H_
+
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace dcsctp {
+
+template <typename Range>
+std::string StrJoin(const Range& seq, absl::string_view delimiter) {
+ rtc::StringBuilder sb;
+ int idx = 0;
+
+ for (const typename Range::value_type& elem : seq) {
+ if (idx > 0) {
+ sb << delimiter;
+ }
+ sb << elem;
+
+ ++idx;
+ }
+ return sb.Release();
+}
+
+template <typename Range, typename Functor>
+std::string StrJoin(const Range& seq,
+ absl::string_view delimiter,
+ const Functor& fn) {
+ rtc::StringBuilder sb;
+ int idx = 0;
+
+ for (const typename Range::value_type& elem : seq) {
+ if (idx > 0) {
+ sb << delimiter;
+ }
+ fn(sb, elem);
+
+ ++idx;
+ }
+ return sb.Release();
+}
+
+} // namespace dcsctp
+
+#endif // NET_DCSCTP_COMMON_STR_JOIN_H_
diff --git a/third_party/libwebrtc/net/dcsctp/common/str_join_test.cc b/third_party/libwebrtc/net/dcsctp/common/str_join_test.cc
new file mode 100644
index 0000000000..dbfd92c1cf
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/common/str_join_test.cc
@@ -0,0 +1,45 @@
+/*
+ * 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/common/str_join.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "test/gmock.h"
+
+namespace dcsctp {
+namespace {
+
+TEST(StrJoinTest, CanJoinStringsFromVector) {
+ std::vector<std::string> strings = {"Hello", "World"};
+ std::string s = StrJoin(strings, " ");
+ EXPECT_EQ(s, "Hello World");
+}
+
+TEST(StrJoinTest, CanJoinNumbersFromArray) {
+ std::array<int, 3> numbers = {1, 2, 3};
+ std::string s = StrJoin(numbers, ",");
+ EXPECT_EQ(s, "1,2,3");
+}
+
+TEST(StrJoinTest, CanFormatElementsWhileJoining) {
+ std::vector<std::pair<std::string, std::string>> pairs = {
+ {"hello", "world"}, {"foo", "bar"}, {"fum", "gazonk"}};
+ std::string s = StrJoin(pairs, ",",
+ [&](rtc::StringBuilder& sb,
+ const std::pair<std::string, std::string>& p) {
+ sb << p.first << "=" << p.second;
+ });
+ EXPECT_EQ(s, "hello=world,foo=bar,fum=gazonk");
+}
+
+} // namespace
+} // namespace dcsctp