-
Notifications
You must be signed in to change notification settings - Fork 199
/
ports.go
88 lines (70 loc) · 2 KB
/
ports.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package libp2p
import (
"fmt"
"net"
"strconv"
"strings"
"github.com/ElrondNetwork/elrond-go-core/core/random"
"github.com/ElrondNetwork/elrond-go/p2p"
)
func getPort(port string, handler func(int) error) (int, error) {
val, err := strconv.Atoi(port)
if err == nil {
if val < 0 {
return 0, fmt.Errorf("%w, %d does not represent a positive value for port", p2p.ErrInvalidPortValue, val)
}
return val, nil
}
ports := strings.Split(port, "-")
if len(ports) != 2 {
return 0, fmt.Errorf("%w, provided port string `%s` is not in the correct format, expected `start-end`", p2p.ErrInvalidPortsRangeString, port)
}
startPort, err := strconv.Atoi(ports[0])
if err != nil {
return 0, p2p.ErrInvalidStartingPortValue
}
endPort, err := strconv.Atoi(ports[1])
if err != nil {
return 0, p2p.ErrInvalidEndingPortValue
}
if startPort < minRangePortValue {
return 0, fmt.Errorf("%w, provided starting port should be >= %d", p2p.ErrInvalidValue, minRangePortValue)
}
if endPort < startPort {
return 0, p2p.ErrEndPortIsSmallerThanStartPort
}
return choosePort(startPort, endPort, handler)
}
func choosePort(startPort int, endPort int, handler func(int) error) (int, error) {
log.Debug("generating random free port",
"range", fmt.Sprintf("%d-%d", startPort, endPort),
)
ports := make([]int, 0, endPort-startPort+1)
for i := startPort; i <= endPort; i++ {
ports = append(ports, i)
}
ports = random.FisherYatesShuffle(ports, &random.ConcurrentSafeIntRandomizer{})
for _, p := range ports {
err := handler(p)
if err != nil {
log.Trace("opening port error",
"port", p, "error", err)
continue
}
log.Debug("free port chosen", "port", p)
return p, nil
}
return 0, fmt.Errorf("%w, range %d-%d", p2p.ErrNoFreePortInRange, startPort, endPort)
}
func checkFreePort(port int) error {
addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("localhost:%d", port))
if err != nil {
return err
}
l, err := net.ListenTCP("tcp", addr)
if err != nil {
return err
}
_ = l.Close()
return nil
}