-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathinput_frag.go
104 lines (92 loc) · 2.4 KB
/
input_frag.go
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
* Copyright (c) 2018 by Farsight Security, Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package nmsg
// NMSG Fragment Cache.
import (
"bytes"
"container/list"
"sort"
"time"
)
type fragCacheEntry struct {
lastUsed time.Time
id uint32
frags fragList
}
// fragList implements sort.Interface to support sorting fragments on
// their "Current" field prior to reassembly.
type fragList []*NmsgFragment
func (fl fragList) Len() int { return len(fl) }
func (fl fragList) Less(i, j int) bool { return fl[i].GetCurrent() < fl[j].GetCurrent() }
func (fl fragList) Swap(i, j int) { fl[i], fl[j] = fl[j], fl[i] }
type fragCache struct {
expiry time.Duration
idmap map[uint32]*list.Element
lru *list.List
}
func newFragmentCache(expiry time.Duration) *fragCache {
return &fragCache{
expiry: expiry,
idmap: make(map[uint32]*list.Element),
lru: list.New(),
}
}
// Expire too-old entries from the fragment cache, returning the number
// of incomplete containers and fragments dropped.
func (fc *fragCache) Expire() (containers, frags int) {
for fc.lru.Len() > 0 {
lruent := fc.lru.Front()
ent := lruent.Value.(*fragCacheEntry)
if time.Since(ent.lastUsed) <= fc.expiry {
break
}
containers++
frags += len(ent.frags)
fc.lru.Remove(lruent)
delete(fc.idmap, ent.id)
}
return
}
// Inserts a fragment into the cache. If the fragment completes a fragmented
// container, Insert returns the reassembled container body. Otherwise, returns
// nil.
func (fc *fragCache) Insert(f *NmsgFragment) []byte {
id := f.GetId()
lruent, ok := fc.idmap[id]
if !ok {
fc.idmap[id] = fc.lru.PushBack(
&fragCacheEntry{
lastUsed: time.Now(),
id: id,
frags: fragList{f},
})
return nil
}
ent := lruent.Value.(*fragCacheEntry)
for i := range ent.frags {
if ent.frags[i].GetCurrent() == f.GetCurrent() {
/* duplicate fragment */
return nil
}
}
ent.frags = append(ent.frags, f)
if ent.frags.Len() <= int(f.GetLast()) {
ent.lastUsed = time.Now()
fc.lru.MoveToBack(lruent)
return nil
}
fc.lru.Remove(lruent)
delete(fc.idmap, id)
/* sort and reassemble fragments */
sort.Sort(ent.frags)
var b bytes.Buffer
for i := range ent.frags {
b.Write(ent.frags[i].GetFragment())
}
return b.Bytes()
}