1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
package meshtastic
import (
"encoding/hex"
"fmt"
"hash"
"sync"
"time"
)
// PacketDeduplicator is a structure that prevents processing of duplicate packets.
// It keeps a record of seen packets and the time they were last seen.
type PacketDeduplicator struct {
hasher hash.Hash // hasher is used for generating packet identifiers.
expiresAfter time.Duration // expiresAfter defines the duration after which a seen packet record expires.
sync.RWMutex // RWMutex is used to protect the seen map from concurrent access.
seen map[string]time.Time // seen maps a packet identifier to the last time it was seen.
}
// NewDeduplicator creates a new PacketDeduplicator with a given hasher and expiration duration for packet records.
// It starts a background goroutine to periodically clean up expired packet records.
func NewDeduplicator(hasher hash.Hash, expiresAfter time.Duration) *PacketDeduplicator {
pd := PacketDeduplicator{
seen: make(map[string]time.Time),
hasher: hasher,
expiresAfter: expiresAfter,
}
go func() {
for {
time.Sleep(expiresAfter)
pd.Lock()
for packet, timestamp := range pd.seen {
if time.Since(timestamp) > pd.expiresAfter {
delete(pd.seen, packet)
}
}
pd.Unlock()
}
}()
return &pd
}
// Seen checks whether a packet with the given sender and packetID has been seen before.
// If not, it records the packet as seen and returns false. Otherwise, it returns true.
func (p *PacketDeduplicator) Seen(sender, packetID uint32) bool {
asString := fmt.Sprintf("%d-%d", sender, packetID)
p.RLock()
if _, exists := p.seen[asString]; !exists {
p.RUnlock()
p.Lock()
defer p.Unlock()
p.seen[asString] = time.Now()
return false
}
p.RUnlock()
return true
}
// SeenData checks whether the data has been seen before based on its hashed value.
// If not, it records the data as seen and returns false. Otherwise, it returns true.
func (p *PacketDeduplicator) SeenData(data []byte) bool {
hashed := p.hasher.Sum(data)
asHex := hex.EncodeToString(hashed)
p.RLock()
if _, exists := p.seen[asHex]; !exists {
p.RUnlock()
p.Lock()
defer p.Unlock()
p.seen[asHex] = time.Now()
return false
}
p.RUnlock()
return true
}
|