| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- package internal
- import (
- "net"
- "sync"
- "time"
- v2net "v2ray.com/core/common/net"
- "v2ray.com/core/common/signal"
- )
- type ConnectionRecyler interface {
- Put(ConnectionId, net.Conn)
- }
- type ConnectionId struct {
- Local v2net.Address
- Remote v2net.Address
- RemotePort v2net.Port
- }
- func NewConnectionId(source v2net.Address, dest v2net.Destination) ConnectionId {
- return ConnectionId{
- Local: source,
- Remote: dest.Address,
- RemotePort: dest.Port,
- }
- }
- type ExpiringConnection struct {
- conn net.Conn
- expire time.Time
- }
- func (o *ExpiringConnection) Expired() bool {
- return o.expire.Before(time.Now())
- }
- type Pool struct {
- sync.Mutex
- connsByDest map[ConnectionId][]*ExpiringConnection
- cleanupOnce signal.Once
- }
- func NewConnectionPool() *Pool {
- return &Pool{
- connsByDest: make(map[ConnectionId][]*ExpiringConnection),
- }
- }
- func (o *Pool) Get(id ConnectionId) net.Conn {
- o.Lock()
- defer o.Unlock()
- list, found := o.connsByDest[id]
- if !found {
- return nil
- }
- connIdx := -1
- for idx, conn := range list {
- if !conn.Expired() {
- connIdx = idx
- break
- }
- }
- if connIdx == -1 {
- return nil
- }
- listLen := len(list)
- conn := list[connIdx]
- if connIdx != listLen-1 {
- list[connIdx] = list[listLen-1]
- }
- list = list[:listLen-1]
- o.connsByDest[id] = list
- return conn.conn
- }
- func (o *Pool) Cleanup() {
- defer o.cleanupOnce.Reset()
- for len(o.connsByDest) > 0 {
- time.Sleep(time.Second * 5)
- expiredConns := make([]net.Conn, 0, 16)
- o.Lock()
- for dest, list := range o.connsByDest {
- validConns := make([]*ExpiringConnection, 0, len(list))
- for _, conn := range list {
- if conn.Expired() {
- expiredConns = append(expiredConns, conn.conn)
- } else {
- validConns = append(validConns, conn)
- }
- }
- if len(validConns) != len(list) {
- o.connsByDest[dest] = validConns
- }
- }
- o.Unlock()
- for _, conn := range expiredConns {
- conn.Close()
- }
- }
- }
- func (o *Pool) Put(id ConnectionId, conn net.Conn) {
- expiringConn := &ExpiringConnection{
- conn: conn,
- expire: time.Now().Add(time.Second * 4),
- }
- o.Lock()
- defer o.Unlock()
- list, found := o.connsByDest[id]
- if !found {
- list = []*ExpiringConnection{expiringConn}
- } else {
- list = append(list, expiringConn)
- }
- o.connsByDest[id] = list
- o.cleanupOnce.Do(func() {
- go o.Cleanup()
- })
- }
|