diff options
Diffstat (limited to 'third_party/libwebrtc/net/dcsctp/common')
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 |