Add utility class for unwrapping 16 bit sequence numbers
Unwrap uint16_t to int64_t, based on delta and last sequence number. This can make application logic, putting packets in maps etc, much simpler. BUG= Review URL: https://codereview.webrtc.org/1209623002 Cr-Commit-Position: refs/heads/master@{#9887}
This commit is contained in:
@ -765,6 +765,46 @@ inline uint32_t LatestTimestamp(uint32_t timestamp1, uint32_t timestamp2) {
|
||||
return IsNewerTimestamp(timestamp1, timestamp2) ? timestamp1 : timestamp2;
|
||||
}
|
||||
|
||||
// Utility class to unwrap a sequence number to a larger type, for easier
|
||||
// handling large ranges. Note that sequence numbers will never be unwrapped
|
||||
// to a negative value.
|
||||
class SequenceNumberUnwrapper {
|
||||
public:
|
||||
SequenceNumberUnwrapper() : last_seq_(-1) {}
|
||||
|
||||
// Get the unwrapped sequence, but don't update the internal state.
|
||||
int64_t UnwrapWithoutUpdate(uint16_t sequence_number) {
|
||||
if (last_seq_ == -1)
|
||||
return sequence_number;
|
||||
|
||||
uint16_t cropped_last = static_cast<uint16_t>(last_seq_);
|
||||
int64_t delta = sequence_number - cropped_last;
|
||||
if (IsNewerSequenceNumber(sequence_number, cropped_last)) {
|
||||
if (delta < 0)
|
||||
delta += (1 << 16); // Wrap forwards.
|
||||
} else if (delta > 0 && (last_seq_ + delta - (1 << 16)) >= 0) {
|
||||
// If sequence_number is older but delta is positive, this is a backwards
|
||||
// wrap-around. However, don't wrap backwards past 0 (unwrapped).
|
||||
delta -= (1 << 16);
|
||||
}
|
||||
|
||||
return last_seq_ + delta;
|
||||
}
|
||||
|
||||
// Only update the internal state to the specified last (unwrapped) sequence.
|
||||
void UpdateLast(int64_t last_sequence) { last_seq_ = last_sequence; }
|
||||
|
||||
// Unwrap the sequence number and update the internal state.
|
||||
int64_t Unwrap(uint16_t sequence_number) {
|
||||
int64_t unwrapped = UnwrapWithoutUpdate(sequence_number);
|
||||
UpdateLast(unwrapped);
|
||||
return unwrapped;
|
||||
}
|
||||
|
||||
private:
|
||||
int64_t last_seq_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULE_COMMON_TYPES_H
|
||||
|
@ -122,4 +122,63 @@ TEST(ClampToInt16, TestCases) {
|
||||
EXPECT_EQ(-0x8000, ClampToInt16(-0x7FFFFFFF));
|
||||
}
|
||||
|
||||
TEST(SequenceNumberUnwrapper, Limits) {
|
||||
SequenceNumberUnwrapper unwrapper;
|
||||
|
||||
EXPECT_EQ(0, unwrapper.Unwrap(0));
|
||||
EXPECT_EQ(0x8000, unwrapper.Unwrap(0x8000));
|
||||
// Delta is exactly 0x8000 but current is lower than input, wrap backwards.
|
||||
EXPECT_EQ(0x0, unwrapper.Unwrap(0x0000));
|
||||
|
||||
EXPECT_EQ(0x8000, unwrapper.Unwrap(0x8000));
|
||||
EXPECT_EQ(0xFFFF, unwrapper.Unwrap(0xFFFF));
|
||||
EXPECT_EQ(0x10000, unwrapper.Unwrap(0x0000));
|
||||
EXPECT_EQ(0xFFFF, unwrapper.Unwrap(0xFFFF));
|
||||
EXPECT_EQ(0x8000, unwrapper.Unwrap(0x8000));
|
||||
EXPECT_EQ(0, unwrapper.Unwrap(0));
|
||||
|
||||
// Don't allow negative values.
|
||||
EXPECT_EQ(0xFFFF, unwrapper.Unwrap(0xFFFF));
|
||||
}
|
||||
|
||||
TEST(SequenceNumberUnwrapper, ForwardWraps) {
|
||||
int64_t seq = 0;
|
||||
SequenceNumberUnwrapper unwrapper;
|
||||
|
||||
const int kMaxIncrease = 0x8000 - 1;
|
||||
const int kNumWraps = 4;
|
||||
for (int i = 0; i < kNumWraps * 2; ++i) {
|
||||
int64_t unwrapped = unwrapper.Unwrap(static_cast<uint16_t>(seq & 0xFFFF));
|
||||
EXPECT_EQ(seq, unwrapped);
|
||||
seq += kMaxIncrease;
|
||||
}
|
||||
|
||||
unwrapper.UpdateLast(0);
|
||||
for (int seq = 0; seq < kNumWraps * 0xFFFF; ++seq) {
|
||||
int64_t unwrapped = unwrapper.Unwrap(static_cast<uint16_t>(seq & 0xFFFF));
|
||||
EXPECT_EQ(seq, unwrapped);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SequenceNumberUnwrapper, BackwardWraps) {
|
||||
SequenceNumberUnwrapper unwrapper;
|
||||
|
||||
const int kMaxDecrease = 0x8000 - 1;
|
||||
const int kNumWraps = 4;
|
||||
int64_t seq = kNumWraps * 2 * kMaxDecrease;
|
||||
unwrapper.UpdateLast(seq);
|
||||
for (int i = kNumWraps * 2; i >= 0; --i) {
|
||||
int64_t unwrapped = unwrapper.Unwrap(static_cast<uint16_t>(seq & 0xFFFF));
|
||||
EXPECT_EQ(seq, unwrapped);
|
||||
seq -= kMaxDecrease;
|
||||
}
|
||||
|
||||
seq = kNumWraps * 0xFFFF;
|
||||
unwrapper.UpdateLast(seq);
|
||||
for (; seq >= 0; --seq) {
|
||||
int64_t unwrapped = unwrapper.Unwrap(static_cast<uint16_t>(seq & 0xFFFF));
|
||||
EXPECT_EQ(seq, unwrapped);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
Reference in New Issue
Block a user