+ addr := opts.peerInfo.Addr
+ dialPool := dialPool{
+ resCh: make(chan DialResult),
+ addr: addr.String(),
+ }
+ defer dialPool.startDrainer()
+ dialTimeout := opts.t.getDialTimeoutUnlocked()
+ {
+ ctx, cancel := context.WithTimeout(context.Background(), dialTimeout)
+ defer cancel()
+ for _, d := range cl.dialers {
+ dialPool.add(ctx, d)
+ }
+ }
+ holepunchAddr, holepunchAddrErr := addrPortFromPeerRemoteAddr(addr)
+ if holepunchAddrErr == nil && opts.receivedHolepunchConnect {
+ cl.lock()
+ if g.MapContains(cl.undialableWithoutHolepunch, holepunchAddr) {
+ g.MakeMapIfNilAndSet(
+ &cl.undialableWithoutHolepunchDialedAfterHolepunchConnect,
+ holepunchAddr,
+ struct{}{},
+ )
+ }
+ cl.unlock()
+ }
+ headerObfuscationPolicy := opts.HeaderObfuscationPolicy
+ obfuscatedHeaderFirst := headerObfuscationPolicy.Preferred
+ firstDialResult := dialPool.getFirst()
+ if firstDialResult.Conn == nil {
+ // No dialers worked. Try to initiate a holepunching rendezvous.
+ if holepunchAddrErr == nil {
+ cl.lock()
+ if !opts.receivedHolepunchConnect {
+ g.MakeMapIfNilAndSet(&cl.undialableWithoutHolepunch, holepunchAddr, struct{}{})
+ }
+ opts.t.startHolepunchRendezvous(holepunchAddr)
+ cl.unlock()
+ }
+ err = fmt.Errorf("all initial dials failed")
+ return
+ }
+ if opts.receivedHolepunchConnect && holepunchAddrErr == nil {
+ cl.lock()
+ if g.MapContains(cl.undialableWithoutHolepunch, holepunchAddr) {
+ g.MakeMapIfNilAndSet(&cl.dialableOnlyAfterHolepunch, holepunchAddr, struct{}{})
+ }
+ g.MakeMapIfNil(&cl.dialedSuccessfullyAfterHolepunchConnect)
+ g.MapInsert(cl.dialedSuccessfullyAfterHolepunchConnect, holepunchAddr, struct{}{})
+ cl.unlock()
+ }
+ c, err = doProtocolHandshakeOnDialResult(
+ opts.t,
+ obfuscatedHeaderFirst,
+ addr,
+ firstDialResult,
+ )