pool.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. package internal
  2. import (
  3. "net"
  4. "sync"
  5. "time"
  6. v2net "v2ray.com/core/common/net"
  7. "v2ray.com/core/common/signal"
  8. )
  9. type ConnectionRecyler interface {
  10. Put(ConnectionId, net.Conn)
  11. }
  12. type ConnectionId struct {
  13. Local v2net.Address
  14. Remote v2net.Address
  15. RemotePort v2net.Port
  16. }
  17. func NewConnectionId(source v2net.Address, dest v2net.Destination) ConnectionId {
  18. return ConnectionId{
  19. Local: source,
  20. Remote: dest.Address,
  21. RemotePort: dest.Port,
  22. }
  23. }
  24. type ExpiringConnection struct {
  25. conn net.Conn
  26. expire time.Time
  27. }
  28. func (o *ExpiringConnection) Expired() bool {
  29. return o.expire.Before(time.Now())
  30. }
  31. type Pool struct {
  32. sync.Mutex
  33. connsByDest map[ConnectionId][]*ExpiringConnection
  34. cleanupOnce signal.Once
  35. }
  36. func NewConnectionPool() *Pool {
  37. return &Pool{
  38. connsByDest: make(map[ConnectionId][]*ExpiringConnection),
  39. }
  40. }
  41. func (o *Pool) Get(id ConnectionId) net.Conn {
  42. o.Lock()
  43. defer o.Unlock()
  44. list, found := o.connsByDest[id]
  45. if !found {
  46. return nil
  47. }
  48. connIdx := -1
  49. for idx, conn := range list {
  50. if !conn.Expired() {
  51. connIdx = idx
  52. break
  53. }
  54. }
  55. if connIdx == -1 {
  56. return nil
  57. }
  58. listLen := len(list)
  59. conn := list[connIdx]
  60. if connIdx != listLen-1 {
  61. list[connIdx] = list[listLen-1]
  62. }
  63. list = list[:listLen-1]
  64. o.connsByDest[id] = list
  65. return conn.conn
  66. }
  67. func (o *Pool) Cleanup() {
  68. defer o.cleanupOnce.Reset()
  69. for len(o.connsByDest) > 0 {
  70. time.Sleep(time.Second * 5)
  71. expiredConns := make([]net.Conn, 0, 16)
  72. o.Lock()
  73. for dest, list := range o.connsByDest {
  74. validConns := make([]*ExpiringConnection, 0, len(list))
  75. for _, conn := range list {
  76. if conn.Expired() {
  77. expiredConns = append(expiredConns, conn.conn)
  78. } else {
  79. validConns = append(validConns, conn)
  80. }
  81. }
  82. if len(validConns) != len(list) {
  83. o.connsByDest[dest] = validConns
  84. }
  85. }
  86. o.Unlock()
  87. for _, conn := range expiredConns {
  88. conn.Close()
  89. }
  90. }
  91. }
  92. func (o *Pool) Put(id ConnectionId, conn net.Conn) {
  93. expiringConn := &ExpiringConnection{
  94. conn: conn,
  95. expire: time.Now().Add(time.Second * 4),
  96. }
  97. o.Lock()
  98. defer o.Unlock()
  99. list, found := o.connsByDest[id]
  100. if !found {
  101. list = []*ExpiringConnection{expiringConn}
  102. } else {
  103. list = append(list, expiringConn)
  104. }
  105. o.connsByDest[id] = list
  106. o.cleanupOnce.Do(func() {
  107. go o.Cleanup()
  108. })
  109. }