6 "github.com/anacrolix/dht/v2/krpc"
7 pp "github.com/anacrolix/torrent/peer_protocol"
13 pexAdd pexEventType = iota
17 // internal, based on BEP11
19 pexTargAdded = 25 // put drops on hold when the number of alive connections is lower than this
20 pexMaxHold = 25 // length of the drop hold-back buffer
21 pexMaxDelta = 50 // upper bound on added+added6 and dropped+dropped6 in a single PEX message
24 // represents a single connection (t=pexAdd) or disconnection (t=pexDrop) event
25 type pexEvent struct {
31 // records the event into the peer protocol PEX message
32 func (e *pexEvent) put(m *pp.PexMsg) {
35 m.Add(nodeAddr(e.addr), e.f)
37 m.Drop(nodeAddr(e.addr))
41 func nodeAddr(addr net.Addr) krpc.NodeAddr {
42 ipport, _ := tryIpPortFromNetAddr(addr)
43 return krpc.NodeAddr{IP: shortestIP(ipport.IP), Port: ipport.Port}
46 // mainly for the krpc marshallers
47 func shortestIP(ip net.IP) net.IP {
48 if ip4 := ip.To4(); ip4 != nil {
54 // Per-torrent PEX state
55 type pexState struct {
56 ev []pexEvent // event feed, append-only
57 hold []pexEvent // delayed drops
58 nc int // net number of alive conns
61 func (s *pexState) Reset() {
67 func (s *pexState) Add(c *PeerConn) {
69 if s.nc >= pexTargAdded {
70 s.ev = append(s.ev, s.hold...)
73 e := c.pexEvent(pexAdd)
74 s.ev = append(s.ev, e)
78 func (s *pexState) Drop(c *PeerConn) {
80 // skip connections which were not previously Added
83 e := c.pexEvent(pexDrop)
85 if s.nc < pexTargAdded && len(s.hold) < pexMaxHold {
86 s.hold = append(s.hold, e)
88 s.ev = append(s.ev, e)
92 // Generate a PEX message based on the event feed.
93 // Also returns an index to pass to the subsequent calls, producing incremental deltas.
94 func (s *pexState) Genmsg(start int) (*pp.PexMsg, int) {
97 for _, e := range s.ev[start:] {
98 if start > 0 && m.DeltaLen() >= pexMaxDelta {