github.com/matrixorigin/matrixone@v1.2.0/pkg/util/address/address.go (about) 1 // Copyright 2023 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package address 16 17 import ( 18 "fmt" 19 "net" 20 "strings" 21 "sync" 22 "time" 23 ) 24 25 const ( 26 defaultListenAddressHost = "0.0.0.0" 27 defaultReservedSlots = 20 28 ) 29 30 // Address is used to describe the address of a MO running service, divided into 2 addresses, 31 // ListenAddress and ServiceAddress. 32 // 33 // ListenAddress is used to indicate the address of the service listener, used to accept external 34 // connections. 35 // 36 // ServiceAddress is used to register to the HAKeeper address, other nodes can get this address to 37 // connect to this MO's service 38 // 39 // TODO(fagongzi): refactor all address configurations in MO. 40 type Address struct { 41 // ListenAddress listen address 42 ListenAddress string `toml:"listen-address"` 43 // ServiceAddress service address 44 ServiceAddress string `toml:"service-addresss"` 45 } 46 47 // Adjust adjust address according to the rules: 48 // 1. If ListenAddress is not set, then use defaultListenAddress 49 // 2. if ServiceAddress is not set, then use ListenAddress 50 // 3. if machineHost is set, then replace the host of ServiceAddress with machineHost 51 func (addr *Address) Adjust( 52 machineHost string, 53 defaultListenAddress string) { 54 if addr.ListenAddress == "" { 55 addr.ListenAddress = defaultListenAddress 56 } 57 if addr.ServiceAddress == "" { 58 addr.ServiceAddress = addr.ListenAddress 59 } 60 if machineHost != "" { 61 addr.ServiceAddress = replaceHost(addr.ServiceAddress, machineHost) 62 } 63 } 64 65 func replaceHost( 66 address string, 67 newHost string) string { 68 oldHost := address[:strings.Index(address, ":")] 69 if oldHost == "" { 70 panic("address's host not found: " + address) 71 } 72 return strings.Replace(address, oldHost, newHost, 1) 73 } 74 75 // AddressManager manages all service names and ports. It uses unified 76 // listen address and service address. The port of each service is generated 77 // by port base and the port slot. 78 type AddressManager interface { 79 // Register registers a service by its name and port slot. 80 Register(portSlot int) int 81 // ListenAddress returns the service address of the service. 82 ListenAddress(slot int) string 83 // ServiceAddress returns the service address of the service. 84 ServiceAddress(slot int) string 85 } 86 87 type addressManager struct { 88 portBase int 89 reservedSlots int 90 address Address 91 mu struct { 92 sync.Mutex 93 portAdvanced int 94 services map[int]int // slot => port number 95 } 96 } 97 98 func NewAddressManager(serviceAddress string, portBase int) AddressManager { 99 am := &addressManager{ 100 address: Address{ 101 ListenAddress: defaultListenAddressHost, 102 ServiceAddress: serviceAddress, 103 }, 104 portBase: portBase, 105 reservedSlots: defaultReservedSlots, 106 } 107 am.mu.portAdvanced = 0 108 am.mu.services = make(map[int]int) 109 return am 110 } 111 112 // Register implements the AddressManager interface. 113 func (m *addressManager) Register(portSlot int) int { 114 m.mu.Lock() 115 defer m.mu.Unlock() 116 if m.portBase == 0 { 117 return 0 118 } 119 if _, ok := m.mu.services[portSlot]; ok { 120 return m.mu.services[portSlot] 121 } 122 m.mu.services[portSlot] = m.portAdvanceLocked() 123 return m.mu.services[portSlot] 124 } 125 126 // ListenAddress implements the AddressManager interface. 127 func (m *addressManager) ListenAddress(slot int) string { 128 m.mu.Lock() 129 defer m.mu.Unlock() 130 p, ok := m.mu.services[slot] 131 if !ok { 132 panic(fmt.Sprintf("slot %d has not been registered yet", slot)) 133 } 134 return fmt.Sprintf("%s:%d", m.address.ListenAddress, p) 135 } 136 137 // ServiceAddress implements the AddressManager interface. 138 func (m *addressManager) ServiceAddress(slot int) string { 139 m.mu.Lock() 140 defer m.mu.Unlock() 141 p, ok := m.mu.services[slot] 142 if !ok { 143 panic(fmt.Sprintf("slot %d has not been registered yet", slot)) 144 } 145 return fmt.Sprintf("%s:%d", m.address.ServiceAddress, p) 146 } 147 148 // portAdvanceLocked advances the port and return the first available one. 149 func (m *addressManager) portAdvanceLocked() int { 150 var port int 151 for { 152 port = m.portBase + m.mu.portAdvanced 153 if localPortCheck(port) { 154 break 155 } 156 m.mu.portAdvanced++ 157 if m.mu.portAdvanced > m.reservedSlots { 158 panic(fmt.Sprintf("no ports are available between %d and %d", 159 m.portBase, m.portBase+m.reservedSlots)) 160 } 161 } 162 m.mu.portAdvanced++ 163 return port 164 } 165 166 // localPortCheck checks if the local port is available to use. If the port is not used, return 167 // true; otherwise, return false. 168 func localPortCheck(port int) bool { 169 return !RemoteAddressAvail(fmt.Sprintf(":%d", port), 0) 170 } 171 172 // RemoteAddressAvail checks if remote address can be connected. 173 func RemoteAddressAvail(address string, timeout time.Duration) bool { 174 conn, err := net.DialTimeout("tcp", address, timeout) 175 if err != nil { 176 return false 177 } else { 178 if conn != nil { 179 _ = conn.Close() 180 return true 181 } else { 182 return false 183 } 184 } 185 }