"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
}