"github.com/dustin/go-humanize"
        "github.com/google/btree"
        "golang.org/x/time/rate"
+       "golang.org/x/xerrors"
 )
 
 // Clients contain zero or more Torrents. A Client manages a blocklist, the
        if err != nil {
                panic(err)
        }
-       ok, err = cl.initiateHandshakes(c, t)
-       if !ok {
-               c = nil
-       }
+       err = cl.initiateHandshakes(c, t)
        return
 }
 
 // Returns nil connection and nil error if no connection could be established
 // for valid reasons.
-func (cl *Client) establishOutgoingConnEx(t *Torrent, addr IpPort, obfuscatedHeader bool) (c *connection, err error) {
+func (cl *Client) establishOutgoingConnEx(t *Torrent, addr IpPort, obfuscatedHeader bool) (*connection, error) {
        ctx, cancel := context.WithTimeout(context.Background(), func() time.Duration {
                cl.rLock()
                defer cl.rUnlock()
        dr := cl.dialFirst(ctx, addr.String())
        nc := dr.Conn
        if nc == nil {
-               return
-       }
-       defer func() {
-               if c == nil || err != nil {
-                       nc.Close()
+               if ctx.Err() != nil {
+                       return nil, ctx.Err()
                }
-       }()
-       return cl.handshakesConnection(ctx, nc, t, obfuscatedHeader, addr, dr.Network)
+               return nil, errors.New("dial failed")
+       }
+       c, err := cl.handshakesConnection(ctx, nc, t, obfuscatedHeader, addr, dr.Network)
+       if err != nil {
+               nc.Close()
+       }
+       return c, err
 }
 
 // Returns nil connection and nil error if no connection could be established
        torrent.Add("establish outgoing connection", 1)
        obfuscatedHeaderFirst := cl.config.HeaderObfuscationPolicy.Preferred
        c, err = cl.establishOutgoingConnEx(t, addr, obfuscatedHeaderFirst)
-       if err != nil {
-               //cl.logger.Printf("error establish connection to %s (obfuscatedHeader=%t): %v", addr, obfuscatedHeaderFirst, err)
-       }
-       if c != nil {
+       if err == nil {
                torrent.Add("initiated conn with preferred header obfuscation", 1)
                return
        }
+       //cl.logger.Printf("error establishing connection to %s (obfuscatedHeader=%t): %v", addr, obfuscatedHeaderFirst, err)
        if cl.config.HeaderObfuscationPolicy.RequirePreferred {
                // We should have just tried with the preferred header obfuscation. If it was required,
                // there's nothing else to try.
        }
        // Try again with encryption if we didn't earlier, or without if we did.
        c, err = cl.establishOutgoingConnEx(t, addr, !obfuscatedHeaderFirst)
-       if c != nil {
+       if err == nil {
                torrent.Add("initiated conn with fallback header obfuscation", 1)
        }
+       //cl.logger.Printf("error establishing fallback connection to %v: %v", addr, err)
        return
 }
 
                }
                return
        }
-       if c == nil {
-               return
-       }
        defer c.Close()
        c.Discovery = ps
        cl.runHandshookConn(c, t)
        return cl.LocalPort()
 }
 
-func (cl *Client) initiateHandshakes(c *connection, t *Torrent) (ok bool, err error) {
+func (cl *Client) initiateHandshakes(c *connection, t *Torrent) error {
        if c.headerEncrypted {
                var rw io.ReadWriter
+               var err error
                rw, c.cryptoMethod, err = mse.InitiateHandshake(
                        struct {
                                io.Reader
                )
                c.setRW(rw)
                if err != nil {
-                       return
+                       return xerrors.Errorf("header obfuscation handshake: %w", err)
                }
        }
-       ih, ok, err := cl.connBTHandshake(c, &t.infoHash)
+       ih, err := cl.connBtHandshake(c, &t.infoHash)
+       if err != nil {
+               return xerrors.Errorf("bittorrent protocol handshake: %w", err)
+       }
        if ih != t.infoHash {
-               ok = false
+               return errors.New("bittorrent protocol handshake: peer infohash didn't match")
        }
-       return
+       return nil
 }
 
 // Calls f with any secret keys.
                err = errors.New("connection not have required header obfuscation")
                return
        }
-       ih, ok, err := cl.connBTHandshake(c, nil)
+       ih, err := cl.connBtHandshake(c, nil)
        if err != nil {
-               err = fmt.Errorf("error during bt handshake: %s", err)
-               return
-       }
-       if !ok {
+               err = xerrors.Errorf("during bt handshake: %w", err)
                return
        }
        cl.lock()
        return
 }
 
-// Returns !ok if handshake failed for valid reasons.
-func (cl *Client) connBTHandshake(c *connection, ih *metainfo.Hash) (ret metainfo.Hash, ok bool, err error) {
-       res, ok, err := pp.Handshake(c.rw(), ih, cl.peerID, cl.extensionBytes)
-       if err != nil || !ok {
+func (cl *Client) connBtHandshake(c *connection, ih *metainfo.Hash) (ret metainfo.Hash, err error) {
+       res, err := pp.Handshake(c.rw(), ih, cl.peerID, cl.extensionBytes)
+       if err != nil {
                return
        }
        ret = res.Hash
 
        "fmt"
        "io"
 
+       "golang.org/x/xerrors"
+
        "github.com/anacrolix/missinggo"
        "github.com/anacrolix/torrent/metainfo"
 )
 func Handshake(
        sock io.ReadWriter, ih *metainfo.Hash, peerID [20]byte, extensions PeerExtensionBits,
 ) (
-       res HandshakeResult, ok bool, err error,
+       res HandshakeResult, err error,
 ) {
        // Bytes to be sent to the peer. Should never block the sender.
        postCh := make(chan []byte, 4)
 
        defer func() {
                close(postCh) // Done writing.
-               if !ok {
-                       return
-               }
                if err != nil {
-                       panic(err)
+                       return
                }
                // Wait until writes complete before returning from handshake.
                err = <-writeDone
        var b [68]byte
        _, err = io.ReadFull(sock, b[:68])
        if err != nil {
-               err = nil
+               err = xerrors.Errorf("while reading: %w", err)
                return
        }
        if string(b[:20]) != Protocol {
+               err = xerrors.Errorf("unexpected protocol string")
                return
        }
        missinggo.CopyExact(&res.PeerExtensionBits, b[20:28])
                post(peerID[:])
        }
 
-       ok = true
        return
 }