github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/util/net/net.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); 2 // you may not use this file except in compliance with the License. 3 // You may obtain a copy of the License at 4 // 5 // https://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, 9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 // See the License for the specific language governing permissions and 11 // limitations under the License. 12 // 13 // Original source: github.com/micro/go-micro/v3/util/net/net.go 14 15 package net 16 17 import ( 18 "errors" 19 "fmt" 20 "net" 21 "strconv" 22 "strings" 23 ) 24 25 // HostPort format addr and port suitable for dial 26 func HostPort(addr string, port interface{}) string { 27 host := addr 28 if strings.Count(addr, ":") > 0 { 29 host = fmt.Sprintf("[%s]", addr) 30 } 31 // when port is blank or 0, host is a queue name 32 if v, ok := port.(string); ok && v == "" { 33 return host 34 } else if v, ok := port.(int); ok && v == 0 && net.ParseIP(host) == nil { 35 return host 36 } 37 38 return fmt.Sprintf("%s:%v", host, port) 39 } 40 41 // Listen takes addr:portmin-portmax and binds to the first available port 42 // Example: Listen("localhost:5000-6000", fn) 43 func Listen(addr string, fn func(string) (net.Listener, error)) (net.Listener, error) { 44 45 if strings.Count(addr, ":") == 1 && strings.Count(addr, "-") == 0 { 46 return fn(addr) 47 } 48 49 // host:port || host:min-max 50 host, ports, err := net.SplitHostPort(addr) 51 if err != nil { 52 return nil, err 53 } 54 55 // try to extract port range 56 prange := strings.Split(ports, "-") 57 58 // single port 59 if len(prange) < 2 { 60 return fn(addr) 61 } 62 63 // we have a port range 64 65 // extract min port 66 min, err := strconv.Atoi(prange[0]) 67 if err != nil { 68 return nil, errors.New("unable to extract port range") 69 } 70 71 // extract max port 72 max, err := strconv.Atoi(prange[1]) 73 if err != nil { 74 return nil, errors.New("unable to extract port range") 75 } 76 77 // range the ports 78 for port := min; port <= max; port++ { 79 // try bind to host:port 80 ln, err := fn(HostPort(host, port)) 81 if err == nil { 82 return ln, nil 83 } 84 85 // hit max port 86 if port == max { 87 return nil, err 88 } 89 } 90 91 // why are we here? 92 return nil, fmt.Errorf("unable to bind to %s", addr) 93 }