ports.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. package ports
  2. import (
  3. "errors"
  4. "net"
  5. "strconv"
  6. "sync"
  7. "time"
  8. )
  9. const (
  10. MinPort = 1
  11. MaxPort = 65535
  12. MaxPortReservedDuration = time.Duration(24) * time.Hour
  13. CleanReservedPortsInterval = time.Hour
  14. )
  15. var (
  16. ErrPortAlreadyUsed = errors.New("port already used")
  17. ErrPortNotAllowed = errors.New("port not allowed")
  18. ErrPortUnAvailable = errors.New("port unavailable")
  19. ErrNoAvailablePort = errors.New("no available port")
  20. )
  21. type PortCtx struct {
  22. ProxyName string
  23. Port int
  24. Closed bool
  25. UpdateTime time.Time
  26. }
  27. type Manager struct {
  28. reservedPorts map[string]*PortCtx
  29. usedPorts map[int]*PortCtx
  30. freePorts map[int]struct{}
  31. bindAddr string
  32. netType string
  33. mu sync.Mutex
  34. }
  35. func NewManager(netType string, bindAddr string, allowPorts map[int]struct{}) *Manager {
  36. pm := &Manager{
  37. reservedPorts: make(map[string]*PortCtx),
  38. usedPorts: make(map[int]*PortCtx),
  39. freePorts: make(map[int]struct{}),
  40. bindAddr: bindAddr,
  41. netType: netType,
  42. }
  43. if len(allowPorts) > 0 {
  44. for port := range allowPorts {
  45. pm.freePorts[port] = struct{}{}
  46. }
  47. } else {
  48. for i := MinPort; i <= MaxPort; i++ {
  49. pm.freePorts[i] = struct{}{}
  50. }
  51. }
  52. go pm.cleanReservedPortsWorker()
  53. return pm
  54. }
  55. func (pm *Manager) Acquire(name string, port int) (realPort int, err error) {
  56. portCtx := &PortCtx{
  57. ProxyName: name,
  58. Closed: false,
  59. UpdateTime: time.Now(),
  60. }
  61. var ok bool
  62. pm.mu.Lock()
  63. defer func() {
  64. if err == nil {
  65. portCtx.Port = realPort
  66. }
  67. pm.mu.Unlock()
  68. }()
  69. // check reserved ports first
  70. if port == 0 {
  71. if ctx, ok := pm.reservedPorts[name]; ok {
  72. if pm.isPortAvailable(ctx.Port) {
  73. realPort = ctx.Port
  74. pm.usedPorts[realPort] = portCtx
  75. pm.reservedPorts[name] = portCtx
  76. delete(pm.freePorts, realPort)
  77. return
  78. }
  79. }
  80. }
  81. if port == 0 {
  82. // get random port
  83. count := 0
  84. maxTryTimes := 5
  85. for k := range pm.freePorts {
  86. count++
  87. if count > maxTryTimes {
  88. break
  89. }
  90. if pm.isPortAvailable(k) {
  91. realPort = k
  92. pm.usedPorts[realPort] = portCtx
  93. pm.reservedPorts[name] = portCtx
  94. delete(pm.freePorts, realPort)
  95. break
  96. }
  97. }
  98. if realPort == 0 {
  99. err = ErrNoAvailablePort
  100. }
  101. } else {
  102. // specified port
  103. if _, ok = pm.freePorts[port]; ok {
  104. if pm.isPortAvailable(port) {
  105. realPort = port
  106. pm.usedPorts[realPort] = portCtx
  107. pm.reservedPorts[name] = portCtx
  108. delete(pm.freePorts, realPort)
  109. } else {
  110. err = ErrPortUnAvailable
  111. }
  112. } else {
  113. if _, ok = pm.usedPorts[port]; ok {
  114. err = ErrPortAlreadyUsed
  115. } else {
  116. err = ErrPortNotAllowed
  117. }
  118. }
  119. }
  120. return
  121. }
  122. func (pm *Manager) isPortAvailable(port int) bool {
  123. if pm.netType == "udp" {
  124. addr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(pm.bindAddr, strconv.Itoa(port)))
  125. if err != nil {
  126. return false
  127. }
  128. l, err := net.ListenUDP("udp", addr)
  129. if err != nil {
  130. return false
  131. }
  132. l.Close()
  133. return true
  134. }
  135. l, err := net.Listen(pm.netType, net.JoinHostPort(pm.bindAddr, strconv.Itoa(port)))
  136. if err != nil {
  137. return false
  138. }
  139. l.Close()
  140. return true
  141. }
  142. func (pm *Manager) Release(port int) {
  143. pm.mu.Lock()
  144. defer pm.mu.Unlock()
  145. if ctx, ok := pm.usedPorts[port]; ok {
  146. pm.freePorts[port] = struct{}{}
  147. delete(pm.usedPorts, port)
  148. ctx.Closed = true
  149. ctx.UpdateTime = time.Now()
  150. }
  151. }
  152. // Release reserved port if it isn't used in last 24 hours.
  153. func (pm *Manager) cleanReservedPortsWorker() {
  154. for {
  155. time.Sleep(CleanReservedPortsInterval)
  156. pm.mu.Lock()
  157. for name, ctx := range pm.reservedPorts {
  158. if ctx.Closed && time.Since(ctx.UpdateTime) > MaxPortReservedDuration {
  159. delete(pm.reservedPorts, name)
  160. }
  161. }
  162. pm.mu.Unlock()
  163. }
  164. }