lib/torrent/scheduler/conn/fake_peer.go (85 lines of code) (raw):

package conn import ( "fmt" "net" "strconv" "time" "github.com/uber/kraken/core" "github.com/uber/kraken/utils/log" "github.com/willf/bitset" ) // FakePeer is a testing utility which reciprocates handshakes against // arbitrary incoming connections, parroting back the requested torrent but // with an empty bitfield (so no pieces are requested). // // Useful for initializing real Conns against a motionless peer. type FakePeer struct { listener net.Listener id core.PeerID ip string port int msgTimeout time.Duration } // NewFakePeer creates and starts a new FakePeer. func NewFakePeer() (*FakePeer, error) { l, err := net.Listen("tcp", "localhost:0") if err != nil { return nil, err } ip, portStr, err := net.SplitHostPort(l.Addr().String()) if err != nil { return nil, err } port, err := strconv.Atoi(portStr) if err != nil { return nil, err } p := &FakePeer{ listener: l, id: core.PeerIDFixture(), ip: ip, port: port, msgTimeout: 5 * time.Second, } go func() { err := p.handshakeConns() log.Infof("Fake peer exiting: %s", err) }() return p, nil } // PeerID returns the peer's PeerID. func (p *FakePeer) PeerID() core.PeerID { return p.id } // Addr returns the ip:port of the peer. func (p *FakePeer) Addr() string { return fmt.Sprintf("%s:%d", p.ip, p.port) } // PeerInfo returns the peers' PeerInfo. func (p *FakePeer) PeerInfo() *core.PeerInfo { return core.NewPeerInfo(p.id, p.ip, p.port, false, false) } // Close shuts down the peer. func (p *FakePeer) Close() { p.listener.Close() } func (p *FakePeer) handshakeConns() error { for { nc, err := p.listener.Accept() if err != nil { return err } reqMsg, err := readMessageWithTimeout(nc, p.msgTimeout) if err != nil { return err } req, err := handshakeFromP2PMessage(reqMsg) if err != nil { return err } resp := &handshake{ peerID: p.id, digest: req.digest, infoHash: req.infoHash, // Oh darn, we have no pieces! bitfield: bitset.New(req.bitfield.Len()), namespace: req.namespace, } respMsg, err := resp.toP2PMessage() if err != nil { return err } if err := sendMessageWithTimeout(nc, respMsg, p.msgTimeout); err != nil { return err } } }