-
-
Notifications
You must be signed in to change notification settings - Fork 41
/
port.go
122 lines (91 loc) · 2.41 KB
/
port.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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package net
import (
"errors"
"fmt"
"sync"
)
// The Portranger interface allows to get an available port from a pool and to put
// it back after use for later re-use.
type Portranger interface {
// Get a new port from the pool. The port is from the range as providied at initialization.
// If no more ports are available a negative port is returned and error is not nil.
Get() (int, error)
// Put a port back in the pool. It will be silently ignored if a port has already been returned back
// to the pool or if the returned port is not in the range.
Put(int)
}
type portrange struct {
// Minimal port number
min int
// Array to store which ports are used. An
// unused port is false.
ports []bool
// Smallest index in the ports array that
// is an unused port.
minUnused int
lock sync.Mutex
}
// NewPortrange returns a new instance of a Portranger implementation. A minimal and
// maximal port number have to be provided for a valid port range. If the provided
// port range is invalid, nil and an error is retuned.
func NewPortrange(min, max int) (Portranger, error) {
if max <= min {
return nil, fmt.Errorf("invalid port range")
}
if min <= 0 {
min = 1
}
if max > 65535 {
max = 65535
}
r := &portrange{
min: min,
minUnused: 0,
}
r.ports = make([]bool, max-min+1)
return r, nil
}
func (r *portrange) Get() (int, error) {
r.lock.Lock()
defer r.lock.Unlock()
if r.minUnused == -1 {
return -1, fmt.Errorf("no more ports available from range [%d,%d]", r.min, r.min+len(r.ports)-1)
}
// Calculate new port and mark as used
var port int = r.min + r.minUnused
r.ports[r.minUnused] = true
// Find next unused index
var minUnused int = -1
for i := range r.ports {
if !r.ports[i] {
minUnused = i
break
}
}
r.minUnused = minUnused
return port, nil
}
func (r *portrange) Put(port int) {
r.lock.Lock()
defer r.lock.Unlock()
// Check if the returned port is in our range
if port < r.min || port > r.min+len(r.ports)-1 {
return
}
// Translate to index
port -= r.min
r.ports[port] = false
// Adjust the smallest index of the ports array that is unused
if port < r.minUnused || r.minUnused == -1 {
r.minUnused = port
}
}
var ErrNoPortrangerProvided = errors.New("no portranger provided")
type dummy struct{}
func NewDummyPortrange() Portranger {
return &dummy{}
}
func (d *dummy) Get() (int, error) {
return 0, ErrNoPortrangerProvided
}
func (d *dummy) Put(port int) {}