github.com/database64128/shadowsocks-go@v1.7.0/ss2022/slidingwindow.go (about) 1 package ss2022 2 3 const ( 4 swBlockBitLog = 6 // 1<<6 == 64 bits 5 swBlockBits = 1 << swBlockBitLog // must be power of 2 6 swRingBlocks = 1 << 7 // must be power of 2 7 swBlockMask = swRingBlocks - 1 8 swBitMask = swBlockBits - 1 9 swSize = (swRingBlocks - 1) * swBlockBits 10 ) 11 12 // Filter maintains a sliding window of uint64 counters. 13 type Filter struct { 14 last uint64 15 ring [swRingBlocks]uint64 16 } 17 18 // Reset resets the filter to its initial state. 19 func (f *Filter) Reset() { 20 f.last = 0 21 f.ring[0] = 0 22 } 23 24 // IsOk checks whether counter can be accepted by the sliding window filter. 25 func (f *Filter) IsOk(counter uint64) bool { 26 switch { 27 case counter > f.last: // ahead of window 28 return true 29 case f.last-counter > swSize: // behind window 30 return false 31 } 32 33 // In window. Check bit. 34 blockIndex := counter >> swBlockBitLog & swBlockMask 35 bitIndex := counter & swBitMask 36 return f.ring[blockIndex]>>bitIndex&1 == 0 37 } 38 39 // MustAdd adds counter to the sliding window without checking if the counter is valid. 40 // Call IsOk beforehand to make sure the counter is valid. 41 func (f *Filter) MustAdd(counter uint64) { 42 blockIndex := counter >> swBlockBitLog 43 44 // Check if counter is ahead of window. 45 if counter > f.last { 46 lastBlockIndex := f.last >> swBlockBitLog 47 diff := int(blockIndex - lastBlockIndex) 48 if diff > swRingBlocks { 49 diff = swRingBlocks 50 } 51 52 for i := 0; i < diff; i++ { 53 lastBlockIndex = (lastBlockIndex + 1) & swBlockMask 54 f.ring[lastBlockIndex] = 0 55 } 56 57 f.last = counter 58 } 59 60 blockIndex &= swBlockMask 61 bitIndex := counter & swBitMask 62 f.ring[blockIndex] |= 1 << bitIndex 63 } 64 65 // Add attempts to add counter to the sliding window and returns 66 // whether the counter is successfully added to the sliding window. 67 func (f *Filter) Add(counter uint64) bool { 68 unmaskedBlockIndex := counter >> swBlockBitLog 69 blockIndex := unmaskedBlockIndex & swBlockMask 70 bitIndex := counter & swBitMask 71 72 switch { 73 case counter > f.last: // ahead of window 74 lastBlockIndex := f.last >> swBlockBitLog 75 diff := int(unmaskedBlockIndex - lastBlockIndex) 76 if diff > swRingBlocks { 77 diff = swRingBlocks 78 } 79 80 for i := 0; i < diff; i++ { 81 lastBlockIndex = (lastBlockIndex + 1) & swBlockMask 82 f.ring[lastBlockIndex] = 0 83 } 84 85 f.last = counter 86 87 case f.last-counter > swSize: // behind window 88 return false 89 90 case f.ring[blockIndex]>>bitIndex&1 == 1: // already seen by window 91 return false 92 } 93 94 f.ring[blockIndex] |= 1 << bitIndex 95 return true 96 }