@@ -6,10 +6,12 @@ package ice
6
6
import (
7
7
"fmt"
8
8
"net"
9
+ "time"
9
10
10
11
"github.com/pion/logging"
11
12
"github.com/pion/transport/v2"
12
13
"github.com/pion/transport/v2/stdnet"
14
+ tudp "github.com/pion/transport/v2/udp"
13
15
)
14
16
15
17
// MultiUDPMuxDefault implements both UDPMux and AllConnsGetter,
@@ -18,20 +20,93 @@ import (
18
20
type MultiUDPMuxDefault struct {
19
21
muxes []UDPMux
20
22
localAddrToMux map [string ]UDPMux
23
+
24
+ enablePortBalance bool
25
+ // Manage port balance for mux that listen on multiple ports for same IP,
26
+ // for each IP, only return one addr (one port) for each GetListenAddresses call to
27
+ // avoid duplicate ip candidates be gathered for a single ice agent.
28
+ multiPortsAddresses []* multiPortsAddress
29
+ }
30
+
31
+ type addrMux struct {
32
+ addr net.Addr
33
+ mux UDPMux
34
+ }
35
+
36
+ // each multiPortsAddress represents muxes listen on different ports of a same IP
37
+ type multiPortsAddress struct {
38
+ addresseMuxes []* addrMux
39
+ }
40
+
41
+ func (mpa * multiPortsAddress ) next () net.Addr {
42
+ leastAddr , leastConns := mpa .addresseMuxes [0 ].addr , mpa .addresseMuxes [0 ].mux .ConnCount ()
43
+ for i := 1 ; i < len (mpa .addresseMuxes ); i ++ {
44
+ am := mpa .addresseMuxes [i ]
45
+ if count := am .mux .ConnCount (); count < leastConns {
46
+ leastConns = count
47
+ leastAddr = am .addr
48
+ }
49
+ }
50
+ return leastAddr
51
+ }
52
+
53
+ // MultiUDPMuxOption provide options for NewMultiUDPMuxDefault
54
+ type MultiUDPMuxOption func (* multipleUDPMuxDefaultParams )
55
+
56
+ // MultiUDPMuxOptionWithPortBalance enable traffic balance on ports that belongs to same IP address,
57
+ // that means the MultiUDPMuxDefault will return a single port that has least connection for each IP address
58
+ // in GetListenAddresses return.
59
+ func MultiUDPMuxOptionWithPortBalance () MultiUDPMuxOption {
60
+ return func (params * multipleUDPMuxDefaultParams ) {
61
+ params .portBalance = true
62
+ }
63
+ }
64
+
65
+ type multipleUDPMuxDefaultParams struct {
66
+ portBalance bool
21
67
}
22
68
23
69
// NewMultiUDPMuxDefault creates an instance of MultiUDPMuxDefault that
24
70
// uses the provided UDPMux instances.
25
71
func NewMultiUDPMuxDefault (muxes ... UDPMux ) * MultiUDPMuxDefault {
72
+ return NewMultiUDPMuxDefaultWithOptions (muxes )
73
+ }
74
+
75
+ // NewMultiUDPMuxDefaultWithOptions creates an instance of MultiUDPMuxDefault that
76
+ // uses the provided UDPMux instances and options.
77
+ func NewMultiUDPMuxDefaultWithOptions (muxes []UDPMux , opts ... MultiUDPMuxOption ) * MultiUDPMuxDefault {
78
+ var params multipleUDPMuxDefaultParams
79
+ for _ , opt := range opts {
80
+ opt (& params )
81
+ }
82
+
26
83
addrToMux := make (map [string ]UDPMux )
84
+ ipToAddrs := make (map [string ]* multiPortsAddress )
27
85
for _ , mux := range muxes {
28
86
for _ , addr := range mux .GetListenAddresses () {
29
87
addrToMux [addr .String ()] = mux
88
+
89
+ udpAddr , _ := addr .(* net.UDPAddr )
90
+ ip := udpAddr .IP .String ()
91
+ if mpa , ok := ipToAddrs [ip ]; ok {
92
+ mpa .addresseMuxes = append (mpa .addresseMuxes , & addrMux {addr , mux })
93
+ } else {
94
+ ipToAddrs [ip ] = & multiPortsAddress {
95
+ addresseMuxes : []* addrMux {{addr , mux }},
96
+ }
97
+ }
30
98
}
31
99
}
100
+
101
+ multiPortsAddresses := make ([]* multiPortsAddress , 0 , len (ipToAddrs ))
102
+ for _ , mpa := range ipToAddrs {
103
+ multiPortsAddresses = append (multiPortsAddresses , mpa )
104
+ }
32
105
return & MultiUDPMuxDefault {
33
- muxes : muxes ,
34
- localAddrToMux : addrToMux ,
106
+ muxes : muxes ,
107
+ localAddrToMux : addrToMux ,
108
+ multiPortsAddresses : multiPortsAddresses ,
109
+ enablePortBalance : params .portBalance ,
35
110
}
36
111
}
37
112
@@ -45,6 +120,15 @@ func (m *MultiUDPMuxDefault) GetConn(ufrag string, addr net.Addr) (net.PacketCon
45
120
return mux .GetConn (ufrag , addr )
46
121
}
47
122
123
+ // ConnCount return count of working connections created by the mux.
124
+ func (m * MultiUDPMuxDefault ) ConnCount () int {
125
+ var count int
126
+ for _ , mux := range m .muxes {
127
+ count += mux .ConnCount ()
128
+ }
129
+ return count
130
+ }
131
+
48
132
// RemoveConnByUfrag stops and removes the muxed packet connection
49
133
// from all underlying UDPMux instances.
50
134
func (m * MultiUDPMuxDefault ) RemoveConnByUfrag (ufrag string ) {
@@ -64,8 +148,18 @@ func (m *MultiUDPMuxDefault) Close() error {
64
148
return err
65
149
}
66
150
67
- // GetListenAddresses returns the list of addresses that this mux is listening on
151
+ // GetListenAddresses returns the list of addresses that this mux is listening on,
152
+ // if port balance enabled and there are multiple mux listen on different ports of a same IP addr,
153
+ // will return the mux who has least connections of that IP addr.
68
154
func (m * MultiUDPMuxDefault ) GetListenAddresses () []net.Addr {
155
+ if m .enablePortBalance {
156
+ addrs := make ([]net.Addr , 0 , len (m .multiPortsAddresses ))
157
+ for _ , mpa := range m .multiPortsAddresses {
158
+ addrs = append (addrs , mpa .next ())
159
+ }
160
+ return addrs
161
+ }
162
+
69
163
addrs := make ([]net.Addr , 0 , len (m .localAddrToMux ))
70
164
for _ , mux := range m .muxes {
71
165
addrs = append (addrs , mux .GetListenAddresses ()... )
@@ -76,6 +170,12 @@ func (m *MultiUDPMuxDefault) GetListenAddresses() []net.Addr {
76
170
// NewMultiUDPMuxFromPort creates an instance of MultiUDPMuxDefault that
77
171
// listen all interfaces on the provided port.
78
172
func NewMultiUDPMuxFromPort (port int , opts ... UDPMuxFromPortOption ) (* MultiUDPMuxDefault , error ) {
173
+ return NewMultiUDPMuxFromPorts ([]int {port }, opts ... )
174
+ }
175
+
176
+ // NewMultiUDPMuxFromPorts creates an instance of MultiUDPMuxDefault that
177
+ // listen all interfaces and balance traffic on the provided ports.
178
+ func NewMultiUDPMuxFromPorts (ports []int , opts ... UDPMuxFromPortOption ) (* MultiUDPMuxDefault , error ) {
79
179
params := multiUDPMuxFromPortParam {
80
180
networks : []NetworkType {NetworkTypeUDP4 , NetworkTypeUDP6 },
81
181
}
@@ -95,20 +195,29 @@ func NewMultiUDPMuxFromPort(port int, opts ...UDPMuxFromPortOption) (*MultiUDPMu
95
195
return nil , err
96
196
}
97
197
98
- conns := make ([]net.PacketConn , 0 , len (ips ))
198
+ conns := make ([]net.PacketConn , 0 , len (ports ) * len ( ips ))
99
199
for _ , ip := range ips {
100
- conn , listenErr := params .net .ListenUDP ("udp" , & net.UDPAddr {IP : ip , Port : port })
101
- if listenErr != nil {
102
- err = listenErr
103
- break
104
- }
105
- if params .readBufferSize > 0 {
106
- _ = conn .SetReadBuffer (params .readBufferSize )
200
+ for _ , port := range ports {
201
+ conn , listenErr := params .net .ListenUDP ("udp" , & net.UDPAddr {IP : ip , Port : port })
202
+ if listenErr != nil {
203
+ err = listenErr
204
+ break
205
+ }
206
+ if params .readBufferSize > 0 {
207
+ _ = conn .SetReadBuffer (params .readBufferSize )
208
+ }
209
+ if params .writeBufferSize > 0 {
210
+ _ = conn .SetWriteBuffer (params .writeBufferSize )
211
+ }
212
+ if params .batchWriteSize > 0 {
213
+ conns = append (conns , tudp .NewBatchConn (conn , params .batchWriteSize , params .batchWriteInterval ))
214
+ } else {
215
+ conns = append (conns , conn )
216
+ }
107
217
}
108
- if params . writeBufferSize > 0 {
109
- _ = conn . SetWriteBuffer ( params . writeBufferSize )
218
+ if err != nil {
219
+ break
110
220
}
111
- conns = append (conns , conn )
112
221
}
113
222
114
223
if err != nil {
@@ -128,7 +237,7 @@ func NewMultiUDPMuxFromPort(port int, opts ...UDPMuxFromPortOption) (*MultiUDPMu
128
237
muxes = append (muxes , mux )
129
238
}
130
239
131
- return NewMultiUDPMuxDefault (muxes ... ), nil
240
+ return NewMultiUDPMuxDefaultWithOptions (muxes , MultiUDPMuxOptionWithPortBalance () ), nil
132
241
}
133
242
134
243
// UDPMuxFromPortOption provide options for NewMultiUDPMuxFromPort
@@ -137,14 +246,16 @@ type UDPMuxFromPortOption interface {
137
246
}
138
247
139
248
type multiUDPMuxFromPortParam struct {
140
- ifFilter func (string ) bool
141
- ipFilter func (ip net.IP ) bool
142
- networks []NetworkType
143
- readBufferSize int
144
- writeBufferSize int
145
- logger logging.LeveledLogger
146
- includeLoopback bool
147
- net transport.Net
249
+ ifFilter func (string ) bool
250
+ ipFilter func (ip net.IP ) bool
251
+ networks []NetworkType
252
+ readBufferSize int
253
+ writeBufferSize int
254
+ logger logging.LeveledLogger
255
+ includeLoopback bool
256
+ net transport.Net
257
+ batchWriteSize int
258
+ batchWriteInterval time.Duration
148
259
}
149
260
150
261
type udpMuxFromPortOption struct {
@@ -226,3 +337,13 @@ func UDPMuxFromPortWithNet(n transport.Net) UDPMuxFromPortOption {
226
337
},
227
338
}
228
339
}
340
+
341
+ // UDPMuxFromPortWithBatchWrite enable batch write for UDPMux
342
+ func UDPMuxFromPortWithBatchWrite (batchWriteSize int , batchWriteInterval time.Duration ) UDPMuxFromPortOption {
343
+ return & udpMuxFromPortOption {
344
+ f : func (p * multiUDPMuxFromPortParam ) {
345
+ p .batchWriteSize = batchWriteSize
346
+ p .batchWriteInterval = batchWriteInterval
347
+ },
348
+ }
349
+ }
0 commit comments