sing/common/conntrack/tracker.go
2022-08-17 21:07:38 +08:00

98 lines
1.9 KiB
Go

package conntrack
import (
"io"
"net"
"sync"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/bufio"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/x/list"
)
type Tracker struct {
access sync.Mutex
connections list.List[io.Closer]
}
func (m *Tracker) Track(conn io.Closer) *Registration {
m.access.Lock()
element := m.connections.PushBack(conn)
m.access.Unlock()
return &Registration{m, element}
}
func (m *Tracker) TrackConn(conn net.Conn) net.Conn {
registration := m.Track(conn)
return &trackConn{conn, registration}
}
func (m *Tracker) TrackPacketConn(conn net.PacketConn) N.NetPacketConn {
registration := m.Track(conn)
return &trackPacketConn{bufio.NewPacketConn(conn), registration}
}
func (m *Tracker) Reset() {
m.access.Lock()
defer m.access.Unlock()
for element := m.connections.Front(); element != nil; element = element.Next() {
common.Close(element.Value)
}
m.connections = list.List[io.Closer]{}
}
type Registration struct {
manager *Tracker
element *list.Element[io.Closer]
}
func (t *Registration) Leave() {
t.manager.access.Lock()
defer t.manager.access.Unlock()
t.manager.connections.Remove(t.element)
}
type trackConn struct {
net.Conn
registration *Registration
}
func (t *trackConn) Close() error {
t.registration.Leave()
return t.Conn.Close()
}
func (t *trackConn) WriteTo(w io.Writer) (n int64, err error) {
return bufio.Copy(w, t.Conn)
}
func (t *trackConn) ReadFrom(r io.Reader) (n int64, err error) {
return bufio.Copy(t.Conn, r)
}
func (t *trackConn) Upstream() any {
return t.Conn
}
func (t *trackConn) ReaderReplaceable() bool {
return true
}
func (t *trackConn) WriterReplaceable() bool {
return true
}
type trackPacketConn struct {
N.NetPacketConn
registration *Registration
}
func (t *trackPacketConn) Close() error {
t.registration.Leave()
return t.NetPacketConn.Close()
}
func (t *trackPacketConn) Upstream() any {
return t.NetPacketConn
}