1*d9f75844SAndroid Build Coastguard Worker /* 2*d9f75844SAndroid Build Coastguard Worker * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. 3*d9f75844SAndroid Build Coastguard Worker * 4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license 5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source 6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found 7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may 8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree. 9*d9f75844SAndroid Build Coastguard Worker */ 10*d9f75844SAndroid Build Coastguard Worker #ifndef NET_DCSCTP_COMMON_SEQUENCE_NUMBERS_H_ 11*d9f75844SAndroid Build Coastguard Worker #define NET_DCSCTP_COMMON_SEQUENCE_NUMBERS_H_ 12*d9f75844SAndroid Build Coastguard Worker 13*d9f75844SAndroid Build Coastguard Worker #include <cstdint> 14*d9f75844SAndroid Build Coastguard Worker #include <limits> 15*d9f75844SAndroid Build Coastguard Worker #include <utility> 16*d9f75844SAndroid Build Coastguard Worker 17*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/common/internal_types.h" 18*d9f75844SAndroid Build Coastguard Worker 19*d9f75844SAndroid Build Coastguard Worker namespace dcsctp { 20*d9f75844SAndroid Build Coastguard Worker 21*d9f75844SAndroid Build Coastguard Worker // UnwrappedSequenceNumber handles wrapping sequence numbers and unwraps them to 22*d9f75844SAndroid Build Coastguard Worker // an int64_t value space, to allow wrapped sequence numbers to be easily 23*d9f75844SAndroid Build Coastguard Worker // compared for ordering. 24*d9f75844SAndroid Build Coastguard Worker // 25*d9f75844SAndroid Build Coastguard Worker // Sequence numbers are expected to be monotonically increasing, but they do not 26*d9f75844SAndroid Build Coastguard Worker // need to be unwrapped in order, as long as the difference to the previous one 27*d9f75844SAndroid Build Coastguard Worker // is not larger than half the range of the wrapped sequence number. 28*d9f75844SAndroid Build Coastguard Worker // 29*d9f75844SAndroid Build Coastguard Worker // The WrappedType must be a webrtc::StrongAlias type. 30*d9f75844SAndroid Build Coastguard Worker template <typename WrappedType> 31*d9f75844SAndroid Build Coastguard Worker class UnwrappedSequenceNumber { 32*d9f75844SAndroid Build Coastguard Worker public: 33*d9f75844SAndroid Build Coastguard Worker static_assert( 34*d9f75844SAndroid Build Coastguard Worker !std::numeric_limits<typename WrappedType::UnderlyingType>::is_signed, 35*d9f75844SAndroid Build Coastguard Worker "The wrapped type must be unsigned"); 36*d9f75844SAndroid Build Coastguard Worker static_assert( 37*d9f75844SAndroid Build Coastguard Worker std::numeric_limits<typename WrappedType::UnderlyingType>::max() < 38*d9f75844SAndroid Build Coastguard Worker std::numeric_limits<int64_t>::max(), 39*d9f75844SAndroid Build Coastguard Worker "The wrapped type must be less than the int64_t value space"); 40*d9f75844SAndroid Build Coastguard Worker 41*d9f75844SAndroid Build Coastguard Worker // The unwrapper is a sort of factory and converts wrapped sequence numbers to 42*d9f75844SAndroid Build Coastguard Worker // unwrapped ones. 43*d9f75844SAndroid Build Coastguard Worker class Unwrapper { 44*d9f75844SAndroid Build Coastguard Worker public: Unwrapper()45*d9f75844SAndroid Build Coastguard Worker Unwrapper() : largest_(kValueLimit) {} 46*d9f75844SAndroid Build Coastguard Worker Unwrapper(const Unwrapper&) = default; 47*d9f75844SAndroid Build Coastguard Worker Unwrapper& operator=(const Unwrapper&) = default; 48*d9f75844SAndroid Build Coastguard Worker 49*d9f75844SAndroid Build Coastguard Worker // Given a wrapped `value`, and with knowledge of its current last seen 50*d9f75844SAndroid Build Coastguard Worker // largest number, will return a value that can be compared using normal 51*d9f75844SAndroid Build Coastguard Worker // operators, such as less-than, greater-than etc. 52*d9f75844SAndroid Build Coastguard Worker // 53*d9f75844SAndroid Build Coastguard Worker // This will also update the Unwrapper's state, to track the last seen 54*d9f75844SAndroid Build Coastguard Worker // largest value. Unwrap(WrappedType value)55*d9f75844SAndroid Build Coastguard Worker UnwrappedSequenceNumber<WrappedType> Unwrap(WrappedType value) { 56*d9f75844SAndroid Build Coastguard Worker WrappedType wrapped_largest = 57*d9f75844SAndroid Build Coastguard Worker static_cast<WrappedType>(largest_ % kValueLimit); 58*d9f75844SAndroid Build Coastguard Worker int64_t result = largest_ + Delta(value, wrapped_largest); 59*d9f75844SAndroid Build Coastguard Worker if (largest_ < result) { 60*d9f75844SAndroid Build Coastguard Worker largest_ = result; 61*d9f75844SAndroid Build Coastguard Worker } 62*d9f75844SAndroid Build Coastguard Worker return UnwrappedSequenceNumber<WrappedType>(result); 63*d9f75844SAndroid Build Coastguard Worker } 64*d9f75844SAndroid Build Coastguard Worker 65*d9f75844SAndroid Build Coastguard Worker // Similar to `Unwrap`, but will not update the Unwrappers's internal state. PeekUnwrap(WrappedType value)66*d9f75844SAndroid Build Coastguard Worker UnwrappedSequenceNumber<WrappedType> PeekUnwrap(WrappedType value) const { 67*d9f75844SAndroid Build Coastguard Worker WrappedType uint32_largest = 68*d9f75844SAndroid Build Coastguard Worker static_cast<WrappedType>(largest_ % kValueLimit); 69*d9f75844SAndroid Build Coastguard Worker int64_t result = largest_ + Delta(value, uint32_largest); 70*d9f75844SAndroid Build Coastguard Worker return UnwrappedSequenceNumber<WrappedType>(result); 71*d9f75844SAndroid Build Coastguard Worker } 72*d9f75844SAndroid Build Coastguard Worker 73*d9f75844SAndroid Build Coastguard Worker // Resets the Unwrapper to its pristine state. Used when a sequence number 74*d9f75844SAndroid Build Coastguard Worker // is to be reset to zero. Reset()75*d9f75844SAndroid Build Coastguard Worker void Reset() { largest_ = kValueLimit; } 76*d9f75844SAndroid Build Coastguard Worker 77*d9f75844SAndroid Build Coastguard Worker private: Delta(WrappedType value,WrappedType prev_value)78*d9f75844SAndroid Build Coastguard Worker static int64_t Delta(WrappedType value, WrappedType prev_value) { 79*d9f75844SAndroid Build Coastguard Worker static constexpr typename WrappedType::UnderlyingType kBreakpoint = 80*d9f75844SAndroid Build Coastguard Worker kValueLimit / 2; 81*d9f75844SAndroid Build Coastguard Worker typename WrappedType::UnderlyingType diff = *value - *prev_value; 82*d9f75844SAndroid Build Coastguard Worker diff %= kValueLimit; 83*d9f75844SAndroid Build Coastguard Worker if (diff < kBreakpoint) { 84*d9f75844SAndroid Build Coastguard Worker return static_cast<int64_t>(diff); 85*d9f75844SAndroid Build Coastguard Worker } 86*d9f75844SAndroid Build Coastguard Worker return static_cast<int64_t>(diff) - kValueLimit; 87*d9f75844SAndroid Build Coastguard Worker } 88*d9f75844SAndroid Build Coastguard Worker 89*d9f75844SAndroid Build Coastguard Worker int64_t largest_; 90*d9f75844SAndroid Build Coastguard Worker }; 91*d9f75844SAndroid Build Coastguard Worker 92*d9f75844SAndroid Build Coastguard Worker // Returns the wrapped value this type represents. Wrap()93*d9f75844SAndroid Build Coastguard Worker WrappedType Wrap() const { 94*d9f75844SAndroid Build Coastguard Worker return static_cast<WrappedType>(value_ % kValueLimit); 95*d9f75844SAndroid Build Coastguard Worker } 96*d9f75844SAndroid Build Coastguard Worker 97*d9f75844SAndroid Build Coastguard Worker template <typename H> AbslHashValue(H state,const UnwrappedSequenceNumber<WrappedType> & hash)98*d9f75844SAndroid Build Coastguard Worker friend H AbslHashValue(H state, 99*d9f75844SAndroid Build Coastguard Worker const UnwrappedSequenceNumber<WrappedType>& hash) { 100*d9f75844SAndroid Build Coastguard Worker return H::combine(std::move(state), hash.value_); 101*d9f75844SAndroid Build Coastguard Worker } 102*d9f75844SAndroid Build Coastguard Worker 103*d9f75844SAndroid Build Coastguard Worker bool operator==(const UnwrappedSequenceNumber<WrappedType>& other) const { 104*d9f75844SAndroid Build Coastguard Worker return value_ == other.value_; 105*d9f75844SAndroid Build Coastguard Worker } 106*d9f75844SAndroid Build Coastguard Worker bool operator!=(const UnwrappedSequenceNumber<WrappedType>& other) const { 107*d9f75844SAndroid Build Coastguard Worker return value_ != other.value_; 108*d9f75844SAndroid Build Coastguard Worker } 109*d9f75844SAndroid Build Coastguard Worker bool operator<(const UnwrappedSequenceNumber<WrappedType>& other) const { 110*d9f75844SAndroid Build Coastguard Worker return value_ < other.value_; 111*d9f75844SAndroid Build Coastguard Worker } 112*d9f75844SAndroid Build Coastguard Worker bool operator>(const UnwrappedSequenceNumber<WrappedType>& other) const { 113*d9f75844SAndroid Build Coastguard Worker return value_ > other.value_; 114*d9f75844SAndroid Build Coastguard Worker } 115*d9f75844SAndroid Build Coastguard Worker bool operator>=(const UnwrappedSequenceNumber<WrappedType>& other) const { 116*d9f75844SAndroid Build Coastguard Worker return value_ >= other.value_; 117*d9f75844SAndroid Build Coastguard Worker } 118*d9f75844SAndroid Build Coastguard Worker bool operator<=(const UnwrappedSequenceNumber<WrappedType>& other) const { 119*d9f75844SAndroid Build Coastguard Worker return value_ <= other.value_; 120*d9f75844SAndroid Build Coastguard Worker } 121*d9f75844SAndroid Build Coastguard Worker 122*d9f75844SAndroid Build Coastguard Worker // Increments the value. Increment()123*d9f75844SAndroid Build Coastguard Worker void Increment() { ++value_; } 124*d9f75844SAndroid Build Coastguard Worker 125*d9f75844SAndroid Build Coastguard Worker // Returns the next value relative to this sequence number. next_value()126*d9f75844SAndroid Build Coastguard Worker UnwrappedSequenceNumber<WrappedType> next_value() const { 127*d9f75844SAndroid Build Coastguard Worker return UnwrappedSequenceNumber<WrappedType>(value_ + 1); 128*d9f75844SAndroid Build Coastguard Worker } 129*d9f75844SAndroid Build Coastguard Worker 130*d9f75844SAndroid Build Coastguard Worker // Returns a new sequence number based on `value`, and adding `delta` (which 131*d9f75844SAndroid Build Coastguard Worker // may be negative). AddTo(UnwrappedSequenceNumber<WrappedType> value,int delta)132*d9f75844SAndroid Build Coastguard Worker static UnwrappedSequenceNumber<WrappedType> AddTo( 133*d9f75844SAndroid Build Coastguard Worker UnwrappedSequenceNumber<WrappedType> value, 134*d9f75844SAndroid Build Coastguard Worker int delta) { 135*d9f75844SAndroid Build Coastguard Worker return UnwrappedSequenceNumber<WrappedType>(value.value_ + delta); 136*d9f75844SAndroid Build Coastguard Worker } 137*d9f75844SAndroid Build Coastguard Worker 138*d9f75844SAndroid Build Coastguard Worker // Returns the absolute difference between `lhs` and `rhs`. Difference(UnwrappedSequenceNumber<WrappedType> lhs,UnwrappedSequenceNumber<WrappedType> rhs)139*d9f75844SAndroid Build Coastguard Worker static typename WrappedType::UnderlyingType Difference( 140*d9f75844SAndroid Build Coastguard Worker UnwrappedSequenceNumber<WrappedType> lhs, 141*d9f75844SAndroid Build Coastguard Worker UnwrappedSequenceNumber<WrappedType> rhs) { 142*d9f75844SAndroid Build Coastguard Worker return (lhs.value_ > rhs.value_) ? (lhs.value_ - rhs.value_) 143*d9f75844SAndroid Build Coastguard Worker : (rhs.value_ - lhs.value_); 144*d9f75844SAndroid Build Coastguard Worker } 145*d9f75844SAndroid Build Coastguard Worker 146*d9f75844SAndroid Build Coastguard Worker private: UnwrappedSequenceNumber(int64_t value)147*d9f75844SAndroid Build Coastguard Worker explicit UnwrappedSequenceNumber(int64_t value) : value_(value) {} 148*d9f75844SAndroid Build Coastguard Worker static constexpr int64_t kValueLimit = 149*d9f75844SAndroid Build Coastguard Worker static_cast<int64_t>(1) 150*d9f75844SAndroid Build Coastguard Worker << std::numeric_limits<typename WrappedType::UnderlyingType>::digits; 151*d9f75844SAndroid Build Coastguard Worker 152*d9f75844SAndroid Build Coastguard Worker int64_t value_; 153*d9f75844SAndroid Build Coastguard Worker }; 154*d9f75844SAndroid Build Coastguard Worker 155*d9f75844SAndroid Build Coastguard Worker // Unwrapped Transmission Sequence Numbers (TSN) 156*d9f75844SAndroid Build Coastguard Worker using UnwrappedTSN = UnwrappedSequenceNumber<TSN>; 157*d9f75844SAndroid Build Coastguard Worker 158*d9f75844SAndroid Build Coastguard Worker // Unwrapped Stream Sequence Numbers (SSN) 159*d9f75844SAndroid Build Coastguard Worker using UnwrappedSSN = UnwrappedSequenceNumber<SSN>; 160*d9f75844SAndroid Build Coastguard Worker 161*d9f75844SAndroid Build Coastguard Worker // Unwrapped Message Identifier (MID) 162*d9f75844SAndroid Build Coastguard Worker using UnwrappedMID = UnwrappedSequenceNumber<MID>; 163*d9f75844SAndroid Build Coastguard Worker 164*d9f75844SAndroid Build Coastguard Worker } // namespace dcsctp 165*d9f75844SAndroid Build Coastguard Worker 166*d9f75844SAndroid Build Coastguard Worker #endif // NET_DCSCTP_COMMON_SEQUENCE_NUMBERS_H_ 167