@@ -45,13 +45,21 @@ func DefaultTunSettings() *TunSettings {
4545 ChannelSize : 64 ,
4646 ProxySequenceSize : 64 ,
4747 Mtu : 1440 ,
48+
49+ DialRace : 4 ,
50+ DialRaceTimeout : 2 * time .Second ,
51+ DialTimeout : 15 * time .Second ,
4852 }
4953}
5054
5155type TunSettings struct {
5256 ChannelSize int
5357 ProxySequenceSize int
5458 Mtu int
59+
60+ DialRace int
61+ DialRaceTimeout time.Duration
62+ DialTimeout time.Duration
5563}
5664
5765var tunStack = sync .OnceValue (func () * stack.Stack {
@@ -274,7 +282,37 @@ func (self *Tun) ListenUDP(laddr *net.UDPAddr) (*gonet.UDPConn, error) {
274282
275283// safe to call from multiple goroutines
276284func (self * Tun ) DialContext (ctx context.Context , network string , address string ) (net.Conn , error ) {
285+ raceCtx , raceCancel := context .WithCancel (ctx )
286+ defer raceCancel ()
287+ raceOut := make (chan net.Conn )
288+ for range self .settings .DialRace {
289+ go connect .HandleError (func () {
290+ conn , err := self .dialContext (raceCtx , network , address )
291+ if err == nil {
292+ select {
293+ case <- raceCtx .Done ():
294+ case raceOut <- conn :
295+ }
296+ }
297+ })
298+ select {
299+ case conn := <- raceOut :
300+ return conn , nil
301+ case <- time .After (self .settings .DialRaceTimeout ):
302+ }
303+ }
304+ select {
305+ case <- raceCtx .Done ():
306+ return nil , fmt .Errorf ("Done." )
307+ case conn := <- raceOut :
308+ return conn , nil
309+ case <- time .After (self .settings .DialTimeout - self .settings .DialRaceTimeout ):
310+ return nil , fmt .Errorf ("Timeout." )
311+ }
312+ }
277313
314+ // safe to call from multiple goroutines
315+ func (self * Tun ) dialContext (ctx context.Context , network string , address string ) (net.Conn , error ) {
278316 dialCtx := self .dialCtx (ctx )
279317
280318 host , portStr , err := net .SplitHostPort (address )
0 commit comments