edgediscovery.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package edgediscovery
  2. import (
  3. "fmt"
  4. "net"
  5. "sync"
  6. "github.com/cloudflare/cloudflared/edgediscovery/allregions"
  7. "github.com/rs/zerolog"
  8. )
  9. const (
  10. LogFieldAddress = "address"
  11. LogFieldConnIndex = "connIndex"
  12. )
  13. var errNoAddressesLeft = fmt.Errorf("there are no free edge addresses left")
  14. // Edge finds addresses on the Cloudflare edge and hands them out to connections.
  15. type Edge struct {
  16. regions *allregions.Regions
  17. sync.Mutex
  18. log *zerolog.Logger
  19. }
  20. // ------------------------------------
  21. // Constructors
  22. // ------------------------------------
  23. // ResolveEdge runs the initial discovery of the Cloudflare edge, finding Addrs that can be allocated
  24. // to connections.
  25. func ResolveEdge(log *zerolog.Logger) (*Edge, error) {
  26. regions, err := allregions.ResolveEdge(log)
  27. if err != nil {
  28. return new(Edge), err
  29. }
  30. return &Edge{
  31. log: log,
  32. regions: regions,
  33. }, nil
  34. }
  35. // StaticEdge creates a list of edge addresses from the list of hostnames. Mainly used for testing connectivity.
  36. func StaticEdge(log *zerolog.Logger, hostnames []string) (*Edge, error) {
  37. regions, err := allregions.StaticEdge(hostnames, log)
  38. if err != nil {
  39. return new(Edge), err
  40. }
  41. return &Edge{
  42. log: log,
  43. regions: regions,
  44. }, nil
  45. }
  46. // MockEdge creates a Cloudflare Edge from arbitrary TCP addresses. Used for testing.
  47. func MockEdge(log *zerolog.Logger, addrs []*net.TCPAddr) *Edge {
  48. regions := allregions.NewNoResolve(addrs)
  49. return &Edge{
  50. log: log,
  51. regions: regions,
  52. }
  53. }
  54. // ------------------------------------
  55. // Methods
  56. // ------------------------------------
  57. // GetAddrForRPC gives this connection an edge Addr.
  58. func (ed *Edge) GetAddrForRPC() (*net.TCPAddr, error) {
  59. ed.Lock()
  60. defer ed.Unlock()
  61. addr := ed.regions.GetAnyAddress()
  62. if addr == nil {
  63. return nil, errNoAddressesLeft
  64. }
  65. return addr, nil
  66. }
  67. // GetAddr gives this proxy connection an edge Addr. Prefer Addrs this connection has already used.
  68. func (ed *Edge) GetAddr(connIndex int) (*net.TCPAddr, error) {
  69. log := ed.log.With().Int(LogFieldConnIndex, connIndex).Logger()
  70. ed.Lock()
  71. defer ed.Unlock()
  72. // If this connection has already used an edge addr, return it.
  73. if addr := ed.regions.AddrUsedBy(connIndex); addr != nil {
  74. log.Debug().Msg("edgediscovery - GetAddr: Returning same address back to proxy connection")
  75. return addr, nil
  76. }
  77. // Otherwise, give it an unused one
  78. addr := ed.regions.GetUnusedAddr(nil, connIndex)
  79. if addr == nil {
  80. log.Debug().Msg("edgediscovery - GetAddr: No addresses left to give proxy connection")
  81. return nil, errNoAddressesLeft
  82. }
  83. log.Debug().Str(LogFieldAddress, addr.String()).Msg("edgediscovery - GetAddr: Giving connection its new address")
  84. return addr, nil
  85. }
  86. // GetDifferentAddr gives back the proxy connection's edge Addr and uses a new one.
  87. func (ed *Edge) GetDifferentAddr(connIndex int) (*net.TCPAddr, error) {
  88. log := ed.log.With().Int(LogFieldConnIndex, connIndex).Logger()
  89. ed.Lock()
  90. defer ed.Unlock()
  91. oldAddr := ed.regions.AddrUsedBy(connIndex)
  92. if oldAddr != nil {
  93. ed.regions.GiveBack(oldAddr)
  94. }
  95. addr := ed.regions.GetUnusedAddr(oldAddr, connIndex)
  96. if addr == nil {
  97. log.Debug().Msg("edgediscovery - GetDifferentAddr: No addresses left to give proxy connection")
  98. // note: if oldAddr were not nil, it will become available on the next iteration
  99. return nil, errNoAddressesLeft
  100. }
  101. log.Debug().Str(LogFieldAddress, addr.String()).Msg("edgediscovery - GetDifferentAddr: Giving connection its new address")
  102. return addr, nil
  103. }
  104. // AvailableAddrs returns how many unused addresses there are left.
  105. func (ed *Edge) AvailableAddrs() int {
  106. ed.Lock()
  107. defer ed.Unlock()
  108. return ed.regions.AvailableAddrs()
  109. }
  110. // GiveBack the address so that other connections can use it.
  111. // Returns true if the address is in this edge.
  112. func (ed *Edge) GiveBack(addr *net.TCPAddr) bool {
  113. ed.Lock()
  114. defer ed.Unlock()
  115. ed.log.Debug().Msg("edgediscovery - GiveBack: Address now unused")
  116. return ed.regions.GiveBack(addr)
  117. }