1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-10-14 15:03:39 -04:00
v2fly/transport/internet/internal/pool.go

137 lines
2.8 KiB
Go
Raw Normal View History

2016-11-24 17:16:05 -05:00
package internal
import (
"net"
"sync"
"time"
2016-12-21 09:37:16 -05:00
2016-11-24 17:16:05 -05:00
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/signal"
)
2017-01-01 16:12:44 -05:00
// ConnectionRecyler is the interface for recycling connections.
2016-11-27 02:47:24 -05:00
type ConnectionRecyler interface {
2017-01-01 16:12:44 -05:00
// Put returns a connection back to a connection pool.
Put(ConnectionID, net.Conn)
2016-11-27 02:47:24 -05:00
}
2017-01-01 16:12:44 -05:00
// ConnectionID is the ID of a connection.
type ConnectionID struct {
2016-11-24 17:16:05 -05:00
Local v2net.Address
Remote v2net.Address
RemotePort v2net.Port
}
2017-01-01 16:12:44 -05:00
// NewConnectionID creates a new ConnectionId.
func NewConnectionID(source v2net.Address, dest v2net.Destination) ConnectionID {
return ConnectionID{
2016-11-24 17:16:05 -05:00
Local: source,
Remote: dest.Address,
RemotePort: dest.Port,
}
}
2017-01-01 16:12:44 -05:00
// ExpiringConnection is a connection that will expire in certain time.
2016-11-24 17:16:05 -05:00
type ExpiringConnection struct {
conn net.Conn
expire time.Time
}
2017-01-01 16:12:44 -05:00
// Expired returns true if the connection has expired.
func (ec *ExpiringConnection) Expired() bool {
return ec.expire.Before(time.Now())
2016-11-24 17:16:05 -05:00
}
2017-01-01 16:12:44 -05:00
// Pool is a connection pool.
2016-11-24 17:16:05 -05:00
type Pool struct {
sync.Mutex
2017-01-01 16:12:44 -05:00
connsByDest map[ConnectionID][]*ExpiringConnection
2016-11-24 17:16:05 -05:00
cleanupOnce signal.Once
}
2017-01-01 16:12:44 -05:00
// NewConnectionPool creates a new Pool.
2016-11-24 17:16:05 -05:00
func NewConnectionPool() *Pool {
return &Pool{
2017-01-01 16:12:44 -05:00
connsByDest: make(map[ConnectionID][]*ExpiringConnection),
2016-11-24 17:16:05 -05:00
}
}
2017-01-01 16:12:44 -05:00
// Get returns a connection with matching connection ID. Nil if not found.
func (p *Pool) Get(id ConnectionID) net.Conn {
p.Lock()
defer p.Unlock()
2016-11-24 17:16:05 -05:00
2017-01-01 16:12:44 -05:00
list, found := p.connsByDest[id]
2016-11-24 17:16:05 -05:00
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]
2017-01-01 16:12:44 -05:00
p.connsByDest[id] = list
2016-11-24 17:16:05 -05:00
return conn.conn
}
2017-01-01 16:12:44 -05:00
func (p *Pool) cleanup() {
defer p.cleanupOnce.Reset()
2016-11-24 17:16:05 -05:00
2017-01-01 16:12:44 -05:00
for len(p.connsByDest) > 0 {
2016-11-24 17:16:05 -05:00
time.Sleep(time.Second * 5)
expiredConns := make([]net.Conn, 0, 16)
2017-01-01 16:12:44 -05:00
p.Lock()
for dest, list := range p.connsByDest {
2016-11-24 17:16:05 -05:00
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) {
2017-01-01 16:12:44 -05:00
p.connsByDest[dest] = validConns
2016-11-24 17:16:05 -05:00
}
}
2017-01-01 16:12:44 -05:00
p.Unlock()
2016-11-24 17:16:05 -05:00
for _, conn := range expiredConns {
conn.Close()
}
}
}
2017-01-01 16:12:44 -05:00
// Put implements ConnectionRecyler.Put().
func (p *Pool) Put(id ConnectionID, conn net.Conn) {
2016-11-24 17:16:05 -05:00
expiringConn := &ExpiringConnection{
conn: conn,
expire: time.Now().Add(time.Second * 4),
}
2017-01-01 16:12:44 -05:00
p.Lock()
defer p.Unlock()
2016-11-24 17:16:05 -05:00
2017-01-01 16:12:44 -05:00
list, found := p.connsByDest[id]
2016-11-24 17:16:05 -05:00
if !found {
list = []*ExpiringConnection{expiringConn}
} else {
list = append(list, expiringConn)
}
2017-01-01 16:12:44 -05:00
p.connsByDest[id] = list
2016-11-24 17:16:05 -05:00
2017-01-01 16:12:44 -05:00
p.cleanupOnce.Do(func() {
go p.cleanup()
2016-11-24 17:16:05 -05:00
})
}