@@ -33,6 +33,7 @@ func (t *Tunnel) handleUDP(l *cio.Logger, rwc io.ReadWriteCloser, hostPort strin
33
33
},
34
34
udpConns : conns ,
35
35
maxMTU : settings .EnvInt ("UDP_MAX_SIZE" , 9012 ),
36
+ maxConns : settings .EnvInt ("UDP_MAX_CONNS" , 100 ),
36
37
}
37
38
h .Debugf ("UDP max size: %d bytes" , h .maxMTU )
38
39
for {
@@ -48,7 +49,8 @@ type udpHandler struct {
48
49
hostPort string
49
50
* udpChannel
50
51
* udpConns
51
- maxMTU int
52
+ maxMTU int
53
+ maxConns int
52
54
}
53
55
54
56
func (h * udpHandler ) handleWrite (p * udpPacket ) error {
@@ -67,12 +69,13 @@ func (h *udpHandler) handleWrite(p *udpPacket) error {
67
69
//TODO++ dont use go-routines, switch to pollable
68
70
// array of listeners where all listeners are
69
71
// sweeped periodically, removing the idle ones
70
- const maxConns = 100
71
72
if ! exists {
72
- if h .udpConns .len () <= maxConns {
73
+ if h .udpConns .len () <= h . maxConns {
73
74
go h .handleRead (p , conn )
74
75
} else {
75
- h .Debugf ("exceeded max udp connections (%d)" , maxConns )
76
+ //write only
77
+ h .udpConns .setCleanUpTimer (conn .id )
78
+ h .Debugf ("exceeded max udp connections (%d)" , h .maxConns )
76
79
}
77
80
}
78
81
_ , err = conn .Write (p .Payload )
@@ -84,7 +87,14 @@ func (h *udpHandler) handleWrite(p *udpPacket) error {
84
87
85
88
func (h * udpHandler ) handleRead (p * udpPacket , conn * udpConn ) {
86
89
//ensure connection is cleaned up
87
- defer h .udpConns .remove (conn .id )
90
+ defer func () {
91
+ h .udpConns .remove (conn .id )
92
+ conn .Close ()
93
+ }()
94
+ if h .udpConns .len () > h .maxConns {
95
+ h .Debugf ("exceeded max udp connections (%d)" , h .maxConns )
96
+ return
97
+ }
88
98
buff := make ([]byte , h .maxMTU )
89
99
for {
90
100
//response must arrive within 15 seconds
@@ -154,9 +164,37 @@ func (cs *udpConns) closeAll() {
154
164
cs .Unlock ()
155
165
}
156
166
167
+ func (cs * udpConns ) setCleanUpTimer (id string ) {
168
+ cs .Lock ()
169
+ defer cs .Unlock ()
170
+ conn , ok := cs .m [id ]
171
+ if ok {
172
+ conn .writeTimer = time .AfterFunc (settings .EnvDuration ("UDP_DEADLINE" , 15 * time .Second ), func () {
173
+ cs .remove (conn .id )
174
+ conn .Close ()
175
+ })
176
+ }
177
+ }
178
+
157
179
type udpConn struct {
158
180
id string
159
181
net.Conn
182
+ writeTimer * time.Timer
183
+ }
184
+
185
+ func (w * udpConn ) Write (b []byte ) (int , error ) {
186
+ if w .writeTimer != nil {
187
+ w .writeTimer .Stop ()
188
+ w .writeTimer .Reset (settings .EnvDuration ("UDP_DEADLINE" , 15 * time .Second ))
189
+ }
190
+ return w .Conn .Write (b )
191
+ }
192
+
193
+ func (w * udpConn ) Close () error {
194
+ if w .writeTimer != nil {
195
+ w .writeTimer .Stop ()
196
+ }
197
+ return w .Conn .Close ()
160
198
}
161
199
162
200
func (t * Tunnel ) handleSocksUDP (l * cio.Logger , rwc io.ReadWriteCloser ) error {
0 commit comments