123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- package allregions
- import "time"
- const (
- timeoutDuration = 10 * time.Minute
- )
- // Region contains cloudflared edge addresses. The edge is partitioned into several regions for
- // redundancy purposes.
- type Region struct {
- primaryIsActive bool
- active AddrSet
- primary AddrSet
- secondary AddrSet
- primaryTimeout time.Time
- timeoutDuration time.Duration
- }
- // NewRegion creates a region with the given addresses, which are all unused.
- func NewRegion(addrs []*EdgeAddr, overrideIPVersion ConfigIPVersion) Region {
- // The zero value of UsedBy is Unused(), so we can just initialize the map's values with their
- // zero values.
- connForv4 := make(AddrSet)
- connForv6 := make(AddrSet)
- systemPreference := V6
- for i, addr := range addrs {
- if i == 0 {
- // First family of IPs returned is system preference of IP
- systemPreference = addr.IPVersion
- }
- switch addr.IPVersion {
- case V4:
- connForv4[addr] = Unused()
- case V6:
- connForv6[addr] = Unused()
- }
- }
- // Process as system preference
- var primary AddrSet
- var secondary AddrSet
- switch systemPreference {
- case V4:
- primary = connForv4
- secondary = connForv6
- case V6:
- primary = connForv6
- secondary = connForv4
- }
- // Override with provided preference
- switch overrideIPVersion {
- case IPv4Only:
- primary = connForv4
- secondary = make(AddrSet) // empty
- case IPv6Only:
- primary = connForv6
- secondary = make(AddrSet) // empty
- case Auto:
- // no change
- default:
- // no change
- }
- return Region{
- primaryIsActive: true,
- active: primary,
- primary: primary,
- secondary: secondary,
- timeoutDuration: timeoutDuration,
- }
- }
- // AddrUsedBy finds the address used by the given connection in this region.
- // Returns nil if the connection isn't using any IP.
- func (r *Region) AddrUsedBy(connID int) *EdgeAddr {
- edgeAddr := r.primary.AddrUsedBy(connID)
- if edgeAddr == nil {
- edgeAddr = r.secondary.AddrUsedBy(connID)
- }
- return edgeAddr
- }
- // AvailableAddrs counts how many unused addresses this region contains.
- func (r Region) AvailableAddrs() int {
- return r.active.AvailableAddrs()
- }
- // AssignAnyAddress returns a random unused address in this region now
- // assigned to the connID excluding the provided EdgeAddr.
- // Returns nil if all addresses are in use for the region.
- func (r Region) AssignAnyAddress(connID int, excluding *EdgeAddr) *EdgeAddr {
- if addr := r.active.GetUnusedIP(excluding); addr != nil {
- r.active.Use(addr, connID)
- return addr
- }
- return nil
- }
- // GetAnyAddress returns an arbitrary address from the region.
- func (r Region) GetAnyAddress() *EdgeAddr {
- return r.active.GetAnyAddress()
- }
- // GiveBack the address, ensuring it is no longer assigned to an IP.
- // Returns true if the address is in this region.
- func (r *Region) GiveBack(addr *EdgeAddr, hasConnectivityError bool) (ok bool) {
- if ok = r.primary.GiveBack(addr); !ok {
- // Attempt to give back the address in the secondary set
- if ok = r.secondary.GiveBack(addr); !ok {
- // Address is not in this region
- return
- }
- }
- // No connectivity error: no worry
- if !hasConnectivityError {
- return
- }
- // If using primary and returned address is IPv6 and secondary is available
- if r.primaryIsActive && addr.IPVersion == V6 && len(r.secondary) > 0 {
- r.active = r.secondary
- r.primaryIsActive = false
- r.primaryTimeout = time.Now().Add(r.timeoutDuration)
- return
- }
- // Do nothing for IPv4 or if secondary is empty
- if r.primaryIsActive {
- return
- }
- // Immediately return to primary pool, regardless of current primary timeout
- if addr.IPVersion == V4 {
- activatePrimary(r)
- return
- }
- // Timeout exceeded and can be reset to primary pool
- if r.primaryTimeout.Before(time.Now()) {
- activatePrimary(r)
- return
- }
- return
- }
- // activatePrimary sets the primary set to the active set and resets the timeout.
- func activatePrimary(r *Region) {
- r.active = r.primary
- r.primaryIsActive = true
- r.primaryTimeout = time.Now() // reset timeout
- }
|