Skip to content

Commit

Permalink
Add latest seqnum notify to replaydetector
Browse files Browse the repository at this point in the history
Updates the replay detector interface and implementations to support
indicating whether the accepted packet resulted in an update of the
latest sequence number.

Note: this is not a breaking change as the accept() callback was
previously returning zero values and is now returning one, which can be
ignored if desired. It may cause linter failures in some consumers if
using a strict policy.

Signed-off-by: Daniel Mangum <[email protected]>
  • Loading branch information
hasheddan committed Aug 2, 2023
1 parent 571eb96 commit d490a2c
Showing 1 changed file with 24 additions and 11 deletions.
35 changes: 24 additions & 11 deletions replaydetector/replaydetector.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@ package replaydetector
type ReplayDetector interface {
// Check returns true if given sequence number is not replayed.
// Call accept() to mark the packet is received properly.
Check(seq uint64) (accept func(), ok bool)
// The return value of accept() indicates whether the accepted packet is
// has the latest observed sequence number.
Check(seq uint64) (accept func() bool, ok bool)
}

// nop is a no-op func that is returned in the case that Check() fails.
func nop() bool {
return false
}

type slidingWindowDetector struct {
Expand All @@ -30,30 +37,33 @@ func New(windowSize uint, maxSeq uint64) ReplayDetector {
}
}

func (d *slidingWindowDetector) Check(seq uint64) (accept func(), ok bool) {
func (d *slidingWindowDetector) Check(seq uint64) (accept func() bool, ok bool) {
if seq > d.maxSeq {
// Exceeded upper limit.
return func() {}, false
return nop, false
}

if seq <= d.latestSeq {
if d.latestSeq >= uint64(d.windowSize)+seq {
return func() {}, false
return nop, false
}
if d.mask.Bit(uint(d.latestSeq-seq)) != 0 {
// The sequence number is duplicated.
return func() {}, false
return nop, false
}
}

return func() {
return func() bool {
latest := seq == 0
if seq > d.latestSeq {
// Update the head of the window.
d.mask.Lsh(uint(seq - d.latestSeq))
d.latestSeq = seq
latest = true
}
diff := (d.latestSeq - seq) % d.maxSeq
d.mask.SetBit(uint(diff))
return latest
}, true
}

Expand All @@ -75,10 +85,10 @@ type wrappedSlidingWindowDetector struct {
init bool
}

func (d *wrappedSlidingWindowDetector) Check(seq uint64) (accept func(), ok bool) {
func (d *wrappedSlidingWindowDetector) Check(seq uint64) (accept func() bool, ok bool) {
if seq > d.maxSeq {
// Exceeded upper limit.
return func() {}, false
return nop, false
}
if !d.init {
if seq != 0 {
Expand All @@ -99,21 +109,24 @@ func (d *wrappedSlidingWindowDetector) Check(seq uint64) (accept func(), ok bool

if diff >= int64(d.windowSize) {
// Too old.
return func() {}, false
return nop, false
}
if diff >= 0 {
if d.mask.Bit(uint(diff)) != 0 {
// The sequence number is duplicated.
return func() {}, false
return nop, false
}
}

return func() {
return func() bool {
latest := false
if diff < 0 {
// Update the head of the window.
d.mask.Lsh(uint(-diff))
d.latestSeq = seq
latest = true
}
d.mask.SetBit(uint(d.latestSeq - seq))
return latest
}, true
}

0 comments on commit d490a2c

Please sign in to comment.