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