2019-10-11 20:11:18 +08:00
|
|
|
package nat
|
|
|
|
|
|
|
|
import (
|
2023-02-17 16:31:15 +08:00
|
|
|
"net"
|
2019-10-11 20:11:18 +08:00
|
|
|
"sync"
|
2020-02-17 17:34:19 +08:00
|
|
|
|
|
|
|
C "github.com/Dreamacro/clash/constant"
|
2019-10-11 20:11:18 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
type Table struct {
|
|
|
|
mapping sync.Map
|
|
|
|
}
|
|
|
|
|
2023-02-17 16:31:15 +08:00
|
|
|
type Entry struct {
|
|
|
|
PacketConn C.PacketConn
|
|
|
|
LocalUDPConnMap sync.Map
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Table) Set(key string, e C.PacketConn) {
|
|
|
|
t.mapping.Store(key, &Entry{
|
|
|
|
PacketConn: e,
|
|
|
|
LocalUDPConnMap: sync.Map{},
|
|
|
|
})
|
2019-10-11 20:11:18 +08:00
|
|
|
}
|
|
|
|
|
2020-02-17 17:34:19 +08:00
|
|
|
func (t *Table) Get(key string) C.PacketConn {
|
2023-02-17 16:31:15 +08:00
|
|
|
entry, exist := t.getEntry(key)
|
2019-10-11 20:11:18 +08:00
|
|
|
if !exist {
|
2020-01-31 14:43:54 +08:00
|
|
|
return nil
|
2019-10-11 20:11:18 +08:00
|
|
|
}
|
2023-02-17 16:31:15 +08:00
|
|
|
return entry.PacketConn
|
2019-10-11 20:11:18 +08:00
|
|
|
}
|
|
|
|
|
2020-10-28 21:26:50 +08:00
|
|
|
func (t *Table) GetOrCreateLock(key string) (*sync.Cond, bool) {
|
|
|
|
item, loaded := t.mapping.LoadOrStore(key, sync.NewCond(&sync.Mutex{}))
|
|
|
|
return item.(*sync.Cond), loaded
|
2019-10-11 20:11:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Table) Delete(key string) {
|
|
|
|
t.mapping.Delete(key)
|
|
|
|
}
|
|
|
|
|
2023-02-17 16:31:15 +08:00
|
|
|
func (t *Table) GetLocalConn(lAddr, rAddr string) *net.UDPConn {
|
|
|
|
entry, exist := t.getEntry(lAddr)
|
|
|
|
if !exist {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
item, exist := entry.LocalUDPConnMap.Load(rAddr)
|
|
|
|
if !exist {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return item.(*net.UDPConn)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Table) AddLocalConn(lAddr, rAddr string, conn *net.UDPConn) bool {
|
|
|
|
entry, exist := t.getEntry(lAddr)
|
|
|
|
if !exist {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
entry.LocalUDPConnMap.Store(rAddr, conn)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Table) RangeLocalConn(lAddr string, f func(key, value any) bool) {
|
|
|
|
entry, exist := t.getEntry(lAddr)
|
|
|
|
if !exist {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
entry.LocalUDPConnMap.Range(f)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Table) GetOrCreateLockForLocalConn(lAddr, key string) (*sync.Cond, bool) {
|
|
|
|
entry, loaded := t.getEntry(lAddr)
|
|
|
|
if !loaded {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
item, loaded := entry.LocalUDPConnMap.LoadOrStore(key, sync.NewCond(&sync.Mutex{}))
|
|
|
|
return item.(*sync.Cond), loaded
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Table) DeleteLocalConnMap(lAddr, key string) {
|
|
|
|
entry, loaded := t.getEntry(lAddr)
|
|
|
|
if !loaded {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
entry.LocalUDPConnMap.Delete(key)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Table) getEntry(key string) (*Entry, bool) {
|
|
|
|
item, ok := t.mapping.Load(key)
|
|
|
|
// This should not happen usually since this function called after PacketConn created
|
|
|
|
if !ok {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
entry, ok := item.(*Entry)
|
|
|
|
return entry, ok
|
|
|
|
}
|
|
|
|
|
2019-10-11 20:11:18 +08:00
|
|
|
// New return *Cache
|
|
|
|
func New() *Table {
|
|
|
|
return &Table{}
|
|
|
|
}
|