@@ -25,6 +25,8 @@ import (
25
25
"golang.org/x/net/context"
26
26
)
27
27
28
+ const usepool = true
29
+
28
30
type dot struct {
29
31
ctx context.Context
30
32
done context.CancelFunc
@@ -37,6 +39,7 @@ type dot struct {
37
39
c * dns.Client
38
40
c3 * dns.Client // with ech
39
41
rd * protect.RDial
42
+ pool * core.MultConnPool [uintptr ]
40
43
proxies ipn.Proxies // may be nil
41
44
relay ipn.Proxy // may be nil
42
45
est core.P2QuantileEstimator
@@ -93,6 +96,7 @@ func NewTLSTransport(ctx context.Context, id, rawurl string, addrs []string, px
93
96
proxies : px ,
94
97
rd : rd ,
95
98
relay : relay ,
99
+ pool : core.NewMultConnPool [uintptr ](ctx ),
96
100
est : core .NewP50Estimator (ctx ),
97
101
}
98
102
ech := t .ech ()
@@ -153,13 +157,19 @@ func (t *dot) doQuery(pid string, q *dns.Msg) (response *dns.Msg, elapsed time.D
153
157
return
154
158
}
155
159
156
- func (t * dot ) tlsdial (rd protect.RDialer ) (_ * dns.Conn , err error ) {
160
+ func (t * dot ) tlsdial (rd protect.RDialer ) (_ * dns.Conn , who uintptr , err error ) {
161
+ who = rd .Handle ()
162
+ if c := t .fromPool (who ); c != nil {
163
+ return c , who , nil
164
+ }
165
+
166
+ var usingech bool
157
167
var c net.Conn = nil // dot is always tcp
158
168
addr := t .addr // t.addr may be ip or hostname
159
169
if t .c3 != nil { // may be nil if ech is not available
160
170
cfg := t .c3 .TLSConfig // don't clone; may be modified by dialers.DialWithTls
161
171
c , err = dialers .DialWithTls (rd , cfg , "tcp" , addr )
162
- log . W ( "dot: tlsdial: (%s) ech; err? %v" , t . id , err )
172
+ usingech = true
163
173
}
164
174
if c == nil && core .IsNil (c ) { // no ech or ech failed
165
175
cfg := t .c .TLSConfig
@@ -169,34 +179,64 @@ func (t *dot) tlsdial(rd protect.RDialer) (_ *dns.Conn, err error) {
169
179
_ = c .SetDeadline (time .Now ().Add (dottimeout ))
170
180
// todo: higher timeout for if using proxy dialer
171
181
// _ = c.SetDeadline(time.Now().Add(dottimeout * 2))
172
- return & dns.Conn {Conn : c , UDPSize : t .c .UDPSize }, err
182
+ return & dns.Conn {Conn : c , UDPSize : t .c .UDPSize }, who , err
173
183
} else {
174
184
if err == nil {
175
- log .W ("dot: tlsdial: (%s) nil conn/err for %s" , t .id , addr )
176
185
err = errNoNet
177
186
}
187
+ log .W ("dot: tlsdial: (%s) nil conn/err for %s, ech? %t; err? %v" ,
188
+ t .id , addr , usingech , err )
178
189
}
179
- return nil , err
190
+ return nil , who , err
180
191
}
181
192
182
- func (t * dot ) pxdial (pid string ) (* dns.Conn , error ) {
193
+ func (t * dot ) pxdial (pid string ) (* dns.Conn , uintptr , error ) {
183
194
var px ipn.Proxy
184
195
if t .relay != nil { // relay takes precedence
185
196
px = t .relay
186
197
} else if t .proxies != nil { // use proxy, if specified
187
198
var err error
188
199
if px , err = t .proxies .ProxyFor (pid ); err != nil {
189
- return nil , err
200
+ return nil , core . Nobody , err
190
201
}
191
202
}
192
203
if px == nil {
193
- return nil , dnsx .ErrNoProxyProvider
204
+ return nil , core . Nobody , dnsx .ErrNoProxyProvider
194
205
}
206
+ pid = px .ID ()
195
207
log .V ("dot: pxdial: (%s) using relay/proxy %s at %s" ,
196
- t .id , px .ID (), px .GetAddr ())
208
+ t .id , pid , px .GetAddr ())
209
+
197
210
return t .tlsdial (px .Dialer ())
198
211
}
199
212
213
+ func (t * dot ) toPool (id uintptr , c * dns.Conn ) {
214
+ if ! usepool || id == core .Nobody {
215
+ clos (c )
216
+ return
217
+ }
218
+ ok := t .pool .Put (id , c )
219
+ log .V ("dot: pool: (%s) put for %v; ok? %t" , t .id , id , ok )
220
+ }
221
+
222
+ func (t * dot ) fromPool (id uintptr ) (c * dns.Conn ) {
223
+ if ! usepool || id == core .Nobody {
224
+ return
225
+ }
226
+
227
+ pooled := t .pool .Get (id )
228
+ if pooled == nil || core .IsNil (pooled ) {
229
+ return
230
+ }
231
+ var ok bool
232
+ if c , ok = pooled .(* dns.Conn ); ! ok { // unlikely
233
+ clos (pooled )
234
+ return
235
+ }
236
+ log .V ("dot: pool: (%s) got conn from %v; %d" , t .id , id )
237
+ return
238
+ }
239
+
200
240
func clos (c net.Conn ) {
201
241
core .CloseConn (c )
202
242
}
@@ -210,18 +250,17 @@ func (t *dot) sendRequest(pid string, q *dns.Msg) (ans *dns.Msg, elapsed time.Du
210
250
}
211
251
212
252
var conn * dns.Conn
253
+ var who uintptr
213
254
userelay := t .relay != nil
214
255
useproxy := len (pid ) != 0 // pid == dnsx.NetNoProxy => ipn.Base
215
256
if useproxy || userelay {
216
- conn , err = t .pxdial (pid )
257
+ conn , who , err = t .pxdial (pid )
217
258
} else { // ref dns.Client.Dial
218
- conn , err = t .tlsdial (t .rd )
259
+ conn , who , err = t .tlsdial (t .rd )
219
260
}
220
261
221
262
if err == nil {
222
- // FIXME: conn pooling using t.c.Dial + ExchangeWithConn
223
263
ans , elapsed , err = t .c .ExchangeWithConn (q , conn )
224
- clos (conn )
225
264
} // fallthrough
226
265
227
266
raddr := remoteAddrIfAny (conn )
@@ -232,6 +271,7 @@ func (t *dot) sendRequest(pid string, q *dns.Msg) (ans *dns.Msg, elapsed time.Du
232
271
t .id , xdns .Size (q ), xdns .EDNS0PadLen (q ), err , ok , t .host , raddr )
233
272
qerr = dnsx .NewSendFailedQueryError (err )
234
273
} else {
274
+ t .toPool (who , conn ) // or close
235
275
dialers .Confirm2 (t .host , raddr )
236
276
}
237
277
return
@@ -321,3 +361,10 @@ func url2addr(url string) string {
321
361
}
322
362
return url
323
363
}
364
+
365
+ func logev (err error ) log.LogFn {
366
+ if err != nil {
367
+ return log .E
368
+ }
369
+ return log .V
370
+ }
0 commit comments