本站源代码
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

212 lignes
5.6KB

  1. // +build !windows
  2. // Copyright 2019 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. // This code is heavily inspired by the archived gofacebook/gracenet/net.go handler
  6. package graceful
  7. import (
  8. "fmt"
  9. "net"
  10. "os"
  11. "strconv"
  12. "strings"
  13. "sync"
  14. "code.gitea.io/gitea/modules/log"
  15. )
  16. const (
  17. listenFDs = "LISTEN_FDS"
  18. startFD = 3
  19. )
  20. // In order to keep the working directory the same as when we started we record
  21. // it at startup.
  22. var originalWD, _ = os.Getwd()
  23. var (
  24. once = sync.Once{}
  25. mutex = sync.Mutex{}
  26. providedListeners = []net.Listener{}
  27. activeListeners = []net.Listener{}
  28. )
  29. func getProvidedFDs() (savedErr error) {
  30. // Only inherit the provided FDS once but we will save the error so that repeated calls to this function will return the same error
  31. once.Do(func() {
  32. mutex.Lock()
  33. defer mutex.Unlock()
  34. numFDs := os.Getenv(listenFDs)
  35. if numFDs == "" {
  36. return
  37. }
  38. n, err := strconv.Atoi(numFDs)
  39. if err != nil {
  40. savedErr = fmt.Errorf("%s is not a number: %s. Err: %v", listenFDs, numFDs, err)
  41. return
  42. }
  43. for i := startFD; i < n+startFD; i++ {
  44. file := os.NewFile(uintptr(i), fmt.Sprintf("listener_FD%d", i))
  45. l, err := net.FileListener(file)
  46. if err == nil {
  47. // Close the inherited file if it's a listener
  48. if err = file.Close(); err != nil {
  49. savedErr = fmt.Errorf("error closing provided socket fd %d: %s", i, err)
  50. return
  51. }
  52. providedListeners = append(providedListeners, l)
  53. continue
  54. }
  55. // If needed we can handle packetconns here.
  56. savedErr = fmt.Errorf("Error getting provided socket fd %d: %v", i, err)
  57. return
  58. }
  59. })
  60. return savedErr
  61. }
  62. // CloseProvidedListeners closes all unused provided listeners.
  63. func CloseProvidedListeners() error {
  64. mutex.Lock()
  65. defer mutex.Unlock()
  66. var returnableError error
  67. for _, l := range providedListeners {
  68. err := l.Close()
  69. if err != nil {
  70. log.Error("Error in closing unused provided listener: %v", err)
  71. if returnableError != nil {
  72. returnableError = fmt.Errorf("%v & %v", returnableError, err)
  73. } else {
  74. returnableError = err
  75. }
  76. }
  77. }
  78. providedListeners = []net.Listener{}
  79. return returnableError
  80. }
  81. // GetListener obtains a listener for the local network address. The network must be
  82. // a stream-oriented network: "tcp", "tcp4", "tcp6", "unix" or "unixpacket". It
  83. // returns an provided net.Listener for the matching network and address, or
  84. // creates a new one using net.Listen.
  85. func GetListener(network, address string) (net.Listener, error) {
  86. // Add a deferral to say that we've tried to grab a listener
  87. defer InformCleanup()
  88. switch network {
  89. case "tcp", "tcp4", "tcp6":
  90. tcpAddr, err := net.ResolveTCPAddr(network, address)
  91. if err != nil {
  92. return nil, err
  93. }
  94. return GetListenerTCP(network, tcpAddr)
  95. case "unix", "unixpacket":
  96. unixAddr, err := net.ResolveUnixAddr(network, address)
  97. if err != nil {
  98. return nil, err
  99. }
  100. return GetListenerUnix(network, unixAddr)
  101. default:
  102. return nil, net.UnknownNetworkError(network)
  103. }
  104. }
  105. // GetListenerTCP announces on the local network address. The network must be:
  106. // "tcp", "tcp4" or "tcp6". It returns a provided net.Listener for the
  107. // matching network and address, or creates a new one using net.ListenTCP.
  108. func GetListenerTCP(network string, address *net.TCPAddr) (*net.TCPListener, error) {
  109. if err := getProvidedFDs(); err != nil {
  110. return nil, err
  111. }
  112. mutex.Lock()
  113. defer mutex.Unlock()
  114. // look for a provided listener
  115. for i, l := range providedListeners {
  116. if isSameAddr(l.Addr(), address) {
  117. providedListeners = append(providedListeners[:i], providedListeners[i+1:]...)
  118. activeListeners = append(activeListeners, l)
  119. return l.(*net.TCPListener), nil
  120. }
  121. }
  122. // no provided listener for this address -> make a fresh listener
  123. l, err := net.ListenTCP(network, address)
  124. if err != nil {
  125. return nil, err
  126. }
  127. activeListeners = append(activeListeners, l)
  128. return l, nil
  129. }
  130. // GetListenerUnix announces on the local network address. The network must be:
  131. // "unix" or "unixpacket". It returns a provided net.Listener for the
  132. // matching network and address, or creates a new one using net.ListenUnix.
  133. func GetListenerUnix(network string, address *net.UnixAddr) (*net.UnixListener, error) {
  134. if err := getProvidedFDs(); err != nil {
  135. return nil, err
  136. }
  137. mutex.Lock()
  138. defer mutex.Unlock()
  139. // look for a provided listener
  140. for i, l := range providedListeners {
  141. if isSameAddr(l.Addr(), address) {
  142. providedListeners = append(providedListeners[:i], providedListeners[i+1:]...)
  143. activeListeners = append(activeListeners, l)
  144. return l.(*net.UnixListener), nil
  145. }
  146. }
  147. // make a fresh listener
  148. l, err := net.ListenUnix(network, address)
  149. if err != nil {
  150. return nil, err
  151. }
  152. activeListeners = append(activeListeners, l)
  153. return l, nil
  154. }
  155. func isSameAddr(a1, a2 net.Addr) bool {
  156. // If the addresses are not on the same network fail.
  157. if a1.Network() != a2.Network() {
  158. return false
  159. }
  160. // If the two addresses have the same string representation they're equal
  161. a1s := a1.String()
  162. a2s := a2.String()
  163. if a1s == a2s {
  164. return true
  165. }
  166. // This allows for ipv6 vs ipv4 local addresses to compare as equal. This
  167. // scenario is common when listening on localhost.
  168. const ipv6prefix = "[::]"
  169. a1s = strings.TrimPrefix(a1s, ipv6prefix)
  170. a2s = strings.TrimPrefix(a2s, ipv6prefix)
  171. const ipv4prefix = "0.0.0.0"
  172. a1s = strings.TrimPrefix(a1s, ipv4prefix)
  173. a2s = strings.TrimPrefix(a2s, ipv4prefix)
  174. return a1s == a2s
  175. }
  176. func getActiveListeners() []net.Listener {
  177. mutex.Lock()
  178. defer mutex.Unlock()
  179. listeners := make([]net.Listener, len(activeListeners))
  180. copy(listeners, activeListeners)
  181. return listeners
  182. }
上海开阖软件有限公司 沪ICP备12045867号-1