|  | @@ -9,50 +9,59 @@ import (
 | 
	
		
			
				|  |  |  	"v2ray.com/core/common/signal"
 | 
	
		
			
				|  |  |  )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// ConnectionRecyler is the interface for recycling connections.
 | 
	
		
			
				|  |  |  type ConnectionRecyler interface {
 | 
	
		
			
				|  |  | -	Put(ConnectionId, net.Conn)
 | 
	
		
			
				|  |  | +	// Put returns a connection back to a connection pool.
 | 
	
		
			
				|  |  | +	Put(ConnectionID, net.Conn)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -type ConnectionId struct {
 | 
	
		
			
				|  |  | +// ConnectionID is the ID of a connection.
 | 
	
		
			
				|  |  | +type ConnectionID struct {
 | 
	
		
			
				|  |  |  	Local      v2net.Address
 | 
	
		
			
				|  |  |  	Remote     v2net.Address
 | 
	
		
			
				|  |  |  	RemotePort v2net.Port
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func NewConnectionId(source v2net.Address, dest v2net.Destination) ConnectionId {
 | 
	
		
			
				|  |  | -	return ConnectionId{
 | 
	
		
			
				|  |  | +// NewConnectionID creates a new ConnectionId.
 | 
	
		
			
				|  |  | +func NewConnectionID(source v2net.Address, dest v2net.Destination) ConnectionID {
 | 
	
		
			
				|  |  | +	return ConnectionID{
 | 
	
		
			
				|  |  |  		Local:      source,
 | 
	
		
			
				|  |  |  		Remote:     dest.Address,
 | 
	
		
			
				|  |  |  		RemotePort: dest.Port,
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// ExpiringConnection is a connection that will expire in certain time.
 | 
	
		
			
				|  |  |  type ExpiringConnection struct {
 | 
	
		
			
				|  |  |  	conn   net.Conn
 | 
	
		
			
				|  |  |  	expire time.Time
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (o *ExpiringConnection) Expired() bool {
 | 
	
		
			
				|  |  | -	return o.expire.Before(time.Now())
 | 
	
		
			
				|  |  | +// Expired returns true if the connection has expired.
 | 
	
		
			
				|  |  | +func (ec *ExpiringConnection) Expired() bool {
 | 
	
		
			
				|  |  | +	return ec.expire.Before(time.Now())
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// Pool is a connection pool.
 | 
	
		
			
				|  |  |  type Pool struct {
 | 
	
		
			
				|  |  |  	sync.Mutex
 | 
	
		
			
				|  |  | -	connsByDest map[ConnectionId][]*ExpiringConnection
 | 
	
		
			
				|  |  | +	connsByDest map[ConnectionID][]*ExpiringConnection
 | 
	
		
			
				|  |  |  	cleanupOnce signal.Once
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// NewConnectionPool creates a new Pool.
 | 
	
		
			
				|  |  |  func NewConnectionPool() *Pool {
 | 
	
		
			
				|  |  |  	return &Pool{
 | 
	
		
			
				|  |  | -		connsByDest: make(map[ConnectionId][]*ExpiringConnection),
 | 
	
		
			
				|  |  | +		connsByDest: make(map[ConnectionID][]*ExpiringConnection),
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (o *Pool) Get(id ConnectionId) net.Conn {
 | 
	
		
			
				|  |  | -	o.Lock()
 | 
	
		
			
				|  |  | -	defer o.Unlock()
 | 
	
		
			
				|  |  | +// 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()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	list, found := o.connsByDest[id]
 | 
	
		
			
				|  |  | +	list, found := p.connsByDest[id]
 | 
	
		
			
				|  |  |  	if !found {
 | 
	
		
			
				|  |  |  		return nil
 | 
	
		
			
				|  |  |  	}
 | 
	
	
		
			
				|  | @@ -72,18 +81,18 @@ func (o *Pool) Get(id ConnectionId) net.Conn {
 | 
	
		
			
				|  |  |  		list[connIdx] = list[listLen-1]
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  	list = list[:listLen-1]
 | 
	
		
			
				|  |  | -	o.connsByDest[id] = list
 | 
	
		
			
				|  |  | +	p.connsByDest[id] = list
 | 
	
		
			
				|  |  |  	return conn.conn
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (o *Pool) Cleanup() {
 | 
	
		
			
				|  |  | -	defer o.cleanupOnce.Reset()
 | 
	
		
			
				|  |  | +func (p *Pool) cleanup() {
 | 
	
		
			
				|  |  | +	defer p.cleanupOnce.Reset()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	for len(o.connsByDest) > 0 {
 | 
	
		
			
				|  |  | +	for len(p.connsByDest) > 0 {
 | 
	
		
			
				|  |  |  		time.Sleep(time.Second * 5)
 | 
	
		
			
				|  |  |  		expiredConns := make([]net.Conn, 0, 16)
 | 
	
		
			
				|  |  | -		o.Lock()
 | 
	
		
			
				|  |  | -		for dest, list := range o.connsByDest {
 | 
	
		
			
				|  |  | +		p.Lock()
 | 
	
		
			
				|  |  | +		for dest, list := range p.connsByDest {
 | 
	
		
			
				|  |  |  			validConns := make([]*ExpiringConnection, 0, len(list))
 | 
	
		
			
				|  |  |  			for _, conn := range list {
 | 
	
		
			
				|  |  |  				if conn.Expired() {
 | 
	
	
		
			
				|  | @@ -93,34 +102,35 @@ func (o *Pool) Cleanup() {
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  |  			if len(validConns) != len(list) {
 | 
	
		
			
				|  |  | -				o.connsByDest[dest] = validConns
 | 
	
		
			
				|  |  | +				p.connsByDest[dest] = validConns
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  | -		o.Unlock()
 | 
	
		
			
				|  |  | +		p.Unlock()
 | 
	
		
			
				|  |  |  		for _, conn := range expiredConns {
 | 
	
		
			
				|  |  |  			conn.Close()
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (o *Pool) Put(id ConnectionId, conn net.Conn) {
 | 
	
		
			
				|  |  | +// Put implements ConnectionRecyler.Put().
 | 
	
		
			
				|  |  | +func (p *Pool) Put(id ConnectionID, conn net.Conn) {
 | 
	
		
			
				|  |  |  	expiringConn := &ExpiringConnection{
 | 
	
		
			
				|  |  |  		conn:   conn,
 | 
	
		
			
				|  |  |  		expire: time.Now().Add(time.Second * 4),
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	o.Lock()
 | 
	
		
			
				|  |  | -	defer o.Unlock()
 | 
	
		
			
				|  |  | +	p.Lock()
 | 
	
		
			
				|  |  | +	defer p.Unlock()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	list, found := o.connsByDest[id]
 | 
	
		
			
				|  |  | +	list, found := p.connsByDest[id]
 | 
	
		
			
				|  |  |  	if !found {
 | 
	
		
			
				|  |  |  		list = []*ExpiringConnection{expiringConn}
 | 
	
		
			
				|  |  |  	} else {
 | 
	
		
			
				|  |  |  		list = append(list, expiringConn)
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	o.connsByDest[id] = list
 | 
	
		
			
				|  |  | +	p.connsByDest[id] = list
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	o.cleanupOnce.Do(func() {
 | 
	
		
			
				|  |  | -		go o.Cleanup()
 | 
	
		
			
				|  |  | +	p.cleanupOnce.Do(func() {
 | 
	
		
			
				|  |  | +		go p.cleanup()
 | 
	
		
			
				|  |  |  	})
 | 
	
		
			
				|  |  |  }
 |