1
2
3
4
5
6 package socktest
7
8 import (
9 "fmt"
10 "sync"
11 )
12
13
14
15 type Switch struct {
16 once sync.Once
17
18 fmu sync.RWMutex
19 fltab map[FilterType]Filter
20
21 smu sync.RWMutex
22 sotab Sockets
23 stats stats
24 }
25
26 func (sw *Switch) init() {
27 sw.fltab = make(map[FilterType]Filter)
28 sw.sotab = make(Sockets)
29 sw.stats = make(stats)
30 }
31
32
33 func (sw *Switch) Stats() []Stat {
34 var st []Stat
35 sw.smu.RLock()
36 for _, s := range sw.stats {
37 ns := *s
38 st = append(st, ns)
39 }
40 sw.smu.RUnlock()
41 return st
42 }
43
44
45 func (sw *Switch) Sockets() Sockets {
46 sw.smu.RLock()
47 tab := make(Sockets, len(sw.sotab))
48 for i, s := range sw.sotab {
49 tab[i] = s
50 }
51 sw.smu.RUnlock()
52 return tab
53 }
54
55
56
57 type Cookie uint64
58
59
60 func (c Cookie) Family() int { return int(c >> 48) }
61
62
63 func (c Cookie) Type() int { return int(c << 16 >> 32) }
64
65
66 func (c Cookie) Protocol() int { return int(c & 0xff) }
67
68 func cookie(family, sotype, proto int) Cookie {
69 return Cookie(family)<<48 | Cookie(sotype)&0xffffffff<<16 | Cookie(proto)&0xff
70 }
71
72
73 type Status struct {
74 Cookie Cookie
75 Err error
76 SocketErr error
77 }
78
79 func (so Status) String() string {
80 return fmt.Sprintf("(%s, %s, %s): syscallerr=%v socketerr=%v", familyString(so.Cookie.Family()), typeString(so.Cookie.Type()), protocolString(so.Cookie.Protocol()), so.Err, so.SocketErr)
81 }
82
83
84 type Stat struct {
85 Family int
86 Type int
87 Protocol int
88
89 Opened uint64
90 Connected uint64
91 Listened uint64
92 Accepted uint64
93 Closed uint64
94
95 OpenFailed uint64
96 ConnectFailed uint64
97 ListenFailed uint64
98 AcceptFailed uint64
99 CloseFailed uint64
100 }
101
102 func (st Stat) String() string {
103 return fmt.Sprintf("(%s, %s, %s): opened=%d connected=%d listened=%d accepted=%d closed=%d openfailed=%d connectfailed=%d listenfailed=%d acceptfailed=%d closefailed=%d", familyString(st.Family), typeString(st.Type), protocolString(st.Protocol), st.Opened, st.Connected, st.Listened, st.Accepted, st.Closed, st.OpenFailed, st.ConnectFailed, st.ListenFailed, st.AcceptFailed, st.CloseFailed)
104 }
105
106 type stats map[Cookie]*Stat
107
108 func (st stats) getLocked(c Cookie) *Stat {
109 s, ok := st[c]
110 if !ok {
111 s = &Stat{Family: c.Family(), Type: c.Type(), Protocol: c.Protocol()}
112 st[c] = s
113 }
114 return s
115 }
116
117
118 type FilterType int
119
120 const (
121 FilterSocket FilterType = iota
122 FilterConnect
123 FilterListen
124 FilterAccept
125 FilterGetsockoptInt
126 FilterClose
127 )
128
129
130
131
132
133
134
135
136
137
138 type Filter func(*Status) (AfterFilter, error)
139
140 func (f Filter) apply(st *Status) (AfterFilter, error) {
141 if f == nil {
142 return nil, nil
143 }
144 return f(st)
145 }
146
147
148
149
150
151
152
153
154 type AfterFilter func(*Status) error
155
156 func (f AfterFilter) apply(st *Status) error {
157 if f == nil {
158 return nil
159 }
160 return f(st)
161 }
162
163
164 func (sw *Switch) Set(t FilterType, f Filter) {
165 sw.once.Do(sw.init)
166 sw.fmu.Lock()
167 sw.fltab[t] = f
168 sw.fmu.Unlock()
169 }
170
View as plain text