"strings"
"time"
- utHolepunch "github.com/anacrolix/torrent/peer_protocol/ut-holepunch"
-
"github.com/RoaringBitmap/roaring"
+ "github.com/anacrolix/generics"
. "github.com/anacrolix/generics"
"github.com/anacrolix/log"
"github.com/anacrolix/missinggo/v2/bitmap"
"github.com/anacrolix/multiless"
+ "golang.org/x/exp/maps"
"golang.org/x/time/rate"
"github.com/anacrolix/torrent/bencode"
"github.com/anacrolix/torrent/metainfo"
"github.com/anacrolix/torrent/mse"
pp "github.com/anacrolix/torrent/peer_protocol"
+ utHolepunch "github.com/anacrolix/torrent/peer_protocol/ut-holepunch"
)
// Maintains the state of a BitTorrent-protocol based connection with a peer.
// See BEP 3 etc.
PeerID PeerID
PeerExtensionBytes pp.PeerExtensionBits
+ PeerListenPort int
// The actual Conn, used for closing, and setting socket options. Do not use methods on this
// while holding any mutexes.
outstandingHolepunchingRendezvous map[netip.AddrPort]struct{}
}
+func (cn *PeerConn) pexStatus() string {
+ if !cn.bitExtensionEnabled(pp.ExtensionBitLtep) {
+ return "extended protocol disabled"
+ }
+ if cn.PeerExtensionIDs == nil {
+ return "pending extended handshake"
+ }
+ if !cn.supportsExtension(pp.ExtensionNamePex) {
+ return "unsupported"
+ }
+ if true {
+ return fmt.Sprintf(
+ "%v conns, %v unsent events",
+ len(cn.pex.remoteLiveConns),
+ cn.pex.numPending(),
+ )
+ } else {
+ // This alternative branch prints out the remote live conn addresses.
+ return fmt.Sprintf(
+ "%v conns, %v unsent events",
+ strings.Join(generics.SliceMap(
+ maps.Keys(cn.pex.remoteLiveConns),
+ func(from netip.AddrPort) string {
+ return from.String()
+ }), ","),
+ cn.pex.numPending(),
+ )
+
+ }
+}
+
func (cn *PeerConn) peerImplStatusLines() []string {
- lines := make([]string, 0, 2)
- lines = append(
- lines,
- fmt.Sprintf("%+-55q %v %s", cn.PeerID, cn.PeerExtensionBytes, cn.connString))
- if cn.supportsExtension(pp.ExtensionNamePex) {
- lines = append(
- lines,
- fmt.Sprintf(
- "pex: %v conns, %v unsent events",
- cn.pex.remoteLiveConns,
- cn.pex.numPending()))
+ return []string{
+ cn.connString,
+ fmt.Sprintf("peer id: %+q", cn.PeerID),
+ fmt.Sprintf("extensions: %v", cn.PeerExtensionBytes),
+ fmt.Sprintf("pex: %s", cn.pexStatus()),
}
- return lines
}
// Returns true if the connection is over IPv6.
return len(ip) == net.IPv6len
}
-// Returns true the if the dialer/initiator has the lower client peer ID. TODO: Find the
-// specification for this.
+// Returns true the if the dialer/initiator has the higher client peer ID. See
+// https://github.com/arvidn/libtorrent/blame/272828e1cc37b042dfbbafa539222d8533e99755/src/bt_peer_connection.cpp#L3536-L3557.
+// As far as I can tell, Transmission just keeps the oldest connection.
func (cn *PeerConn) isPreferredDirection() bool {
- return bytes.Compare(cn.t.cl.peerID[:], cn.PeerID[:]) < 0 == cn.outgoing
+ // True if our client peer ID is higher than the remote's peer ID.
+ return bytes.Compare(cn.PeerID[:], cn.t.cl.peerID[:]) < 0 == cn.outgoing
}
// Returns whether the left connection should be preferred over the right one,
err = fmt.Errorf("unmarshalling ut_holepunch message: %w", err)
return
}
+ err = c.t.handleReceivedUtHolepunchMsg(msg, c)
+ return
default:
return fmt.Errorf("unexpected extended message ID: %v", id)
}
dialAddr := *addr
dialAddr.Port = c.PeerListenPort
return &dialAddr
+ default:
+ panic(addr)
}
}
return c.RemoteAddr
AddrPort() netip.AddrPort
}).AddrPort())
}
+
+func (pc *PeerConn) remoteDialAddrPort() (netip.AddrPort, error) {
+ dialAddr := pc.dialAddr()
+ return addrPortFromPeerRemoteAddr(dialAddr)
+}
+
+func (pc *PeerConn) bitExtensionEnabled(bit pp.ExtensionBit) bool {
+ return pc.t.cl.config.Extensions.GetBit(bit) && pc.PeerExtensionBytes.GetBit(bit)
+}