@@ -39,27 +39,60 @@ func filter(ss []procnet.NetworkDetail, filterFunc func(detail procnet.NetworkDe
39
39
}
40
40
41
41
func portAllocate (protocol string , ip string , count uint64 ) (uint64 , uint64 , error ) {
42
- netprocData , err := procnet .ReadStatsFileData (protocol )
42
+ usedPort , err := getUsedPorts (ip , protocol )
43
+
43
44
if err != nil {
44
45
return 0 , 0 , err
45
46
}
46
- netprocItems := procnet .Parse (netprocData )
47
+
48
+ start := uint64 (allocateStart )
49
+ if count > uint64 (allocateEnd - allocateStart + 1 ) {
50
+ return 0 , 0 , fmt .Errorf ("can not allocate %d ports" , count )
51
+ }
52
+ for start < allocateEnd {
53
+ needReturn := true
54
+ for i := start ; i < start + count ; i ++ {
55
+ if _ , ok := usedPort [i ]; ok {
56
+ needReturn = false
57
+ break
58
+ }
59
+ }
60
+ if needReturn {
61
+ return start , start + count - 1 , nil
62
+ }
63
+ start += count
64
+ }
65
+ return 0 , 0 , fmt .Errorf ("there is not enough %d free ports" , count )
66
+ }
67
+
68
+ func getUsedPorts (ip string , protocol string ) (map [uint64 ]bool , error ) {
69
+ netprocItems := []procnet.NetworkDetail {}
70
+
71
+ if protocol == "tcp" || protocol == "udp" {
72
+ netprocData , err := procnet .ReadStatsFileData (protocol )
73
+ if err != nil {
74
+ return nil , err
75
+ }
76
+ netprocItems = append (netprocItems , procnet .Parse (netprocData )... )
77
+ }
78
+
47
79
// In some circumstances, when we bind address like "0.0.0.0:80", we will get the formation of ":::80" in /proc/net/tcp6.
48
80
// So we need some trick to process this situation.
49
81
if protocol == "tcp" {
50
82
tempTCPV6Data , err := procnet .ReadStatsFileData ("tcp6" )
51
83
if err != nil {
52
- return 0 , 0 , err
84
+ return nil , err
53
85
}
54
86
netprocItems = append (netprocItems , procnet .Parse (tempTCPV6Data )... )
55
87
}
56
88
if protocol == "udp" {
57
89
tempUDPV6Data , err := procnet .ReadStatsFileData ("udp6" )
58
90
if err != nil {
59
- return 0 , 0 , err
91
+ return nil , err
60
92
}
61
93
netprocItems = append (netprocItems , procnet .Parse (tempUDPV6Data )... )
62
94
}
95
+
63
96
if ip != "" {
64
97
netprocItems = filter (netprocItems , func (s procnet.NetworkDetail ) bool {
65
98
// In some circumstances, when we bind address like "0.0.0.0:80", we will get the formation of ":::80" in /proc/net/tcp6.
@@ -75,30 +108,13 @@ func portAllocate(protocol string, ip string, count uint64) (uint64, uint64, err
75
108
76
109
ipTableItems , err := iptable .ReadIPTables ("nat" )
77
110
if err != nil {
78
- return 0 , 0 , err
111
+ return nil , err
79
112
}
80
113
destinationPorts := iptable .ParseIPTableRules (ipTableItems )
81
114
82
115
for _ , port := range destinationPorts {
83
116
usedPort [port ] = true
84
117
}
85
118
86
- start := uint64 (allocateStart )
87
- if count > uint64 (allocateEnd - allocateStart + 1 ) {
88
- return 0 , 0 , fmt .Errorf ("can not allocate %d ports" , count )
89
- }
90
- for start < allocateEnd {
91
- needReturn := true
92
- for i := start ; i < start + count ; i ++ {
93
- if _ , ok := usedPort [i ]; ok {
94
- needReturn = false
95
- break
96
- }
97
- }
98
- if needReturn {
99
- return start , start + count - 1 , nil
100
- }
101
- start += count
102
- }
103
- return 0 , 0 , fmt .Errorf ("there is not enough %d free ports" , count )
119
+ return usedPort , nil
104
120
}
0 commit comments