nc net.Conn,
t *Torrent,
outgoing, encryptHeader bool,
- remoteAddr net.Addr,
+ remoteAddr PeerRemoteAddr,
network, connString string,
) (
c *PeerConn, err error,
}
// Returns nil connection and nil error if no connection could be established for valid reasons.
-func (cl *Client) establishOutgoingConnEx(t *Torrent, addr net.Addr, obfuscatedHeader bool) (*PeerConn, error) {
+func (cl *Client) establishOutgoingConnEx(t *Torrent, addr PeerRemoteAddr, obfuscatedHeader bool) (*PeerConn, error) {
dialCtx, cancel := context.WithTimeout(context.Background(), func() time.Duration {
cl.rLock()
defer cl.rUnlock()
// Returns nil connection and nil error if no connection could be established
// for valid reasons.
-func (cl *Client) establishOutgoingConn(t *Torrent, addr net.Addr) (c *PeerConn, err error) {
+func (cl *Client) establishOutgoingConn(t *Torrent, addr PeerRemoteAddr) (c *PeerConn, err error) {
torrent.Add("establish outgoing connection", 1)
obfuscatedHeaderFirst := cl.config.HeaderObfuscationPolicy.Preferred
c, err = cl.establishOutgoingConnEx(t, addr, obfuscatedHeaderFirst)
// Called to dial out and run a connection. The addr we're given is already
// considered half-open.
-func (cl *Client) outgoingConnection(t *Torrent, addr net.Addr, ps PeerSource, trusted bool) {
+func (cl *Client) outgoingConnection(t *Torrent, addr PeerRemoteAddr, ps PeerSource, trusted bool) {
cl.dialRateLimiter.Wait(context.Background())
c, err := cl.establishOutgoingConn(t, addr)
cl.lock()
// that might be used to cache pending writes. Assuming 512KiB cached for
// sending, for 16KiB chunks.
Reqq: 1 << 5,
- YourIp: pp.CompactIp(addrIpOrNil(conn.RemoteAddr)),
+ YourIp: pp.CompactIp(conn.remoteIp()),
Encryption: cl.config.HeaderObfuscationPolicy.Preferred || !cl.config.HeaderObfuscationPolicy.RequirePreferred,
Port: cl.incomingPeerPort(),
MetadataSize: torrent.metadataSize(),
}
}
-func (cl *Client) badPeerAddr(addr net.Addr) bool {
+func (cl *Client) badPeerAddr(addr PeerRemoteAddr) bool {
if ipa, ok := tryIpPortFromNetAddr(addr); ok {
return cl.badPeerIPPort(ipa.IP, ipa.Port)
}
peers: prioritizedPeers{
om: btree.New(32),
getPrio: func(p PeerInfo) peerPriority {
- return bep40PriorityIgnoreError(cl.publicAddr(addrIpOrNil(p.Addr)), p.addr())
+ ipPort := p.addr()
+ return bep40PriorityIgnoreError(cl.publicAddr(ipPort.IP), ipPort)
},
},
conns: make(map[*PeerConn]struct{}, 2*cl.config.EstablishedConnsPerTorrent),
cl.badPeerIPs[ip.String()] = struct{}{}
}
-func (cl *Client) newConnection(nc net.Conn, outgoing bool, remoteAddr net.Addr, network, connString string) (c *PeerConn) {
+func (cl *Client) newConnection(nc net.Conn, outgoing bool, remoteAddr PeerRemoteAddr, network, connString string) (c *PeerConn) {
c = &PeerConn{
Peer: Peer{
outgoing: outgoing,
return
}
-func (cl *Client) onBadAccept(addr net.Addr) {
+func (cl *Client) onBadAccept(addr PeerRemoteAddr) {
ipa, ok := tryIpPortFromNetAddr(addr)
if !ok {
return
return net.JoinHostPort(me.IP.String(), strconv.FormatInt(int64(me.Port), 10))
}
-func tryIpPortFromNetAddr(na net.Addr) (ret ipPortAddr, ok bool) {
- ret.IP = addrIpOrNil(na)
- if ret.IP == nil {
- return
+func tryIpPortFromNetAddr(addr PeerRemoteAddr) (ipPortAddr, bool) {
+ ok := true
+ host, port, err := net.SplitHostPort(addr.String())
+ if err != nil {
+ ok = false
}
- ret.Port = addrPortOrZero(na)
- ok = true
- return
+ portI64, err := strconv.ParseInt(port, 10, 0)
+ if err != nil {
+ ok = false
+ }
+ return ipPortAddr{net.ParseIP(host), int(portI64)}, ok
}
package torrent
import (
- "net"
-
"github.com/anacrolix/dht/v2/krpc"
"github.com/anacrolix/torrent/peer_protocol"
// Peer connection info, handed about publicly.
type PeerInfo struct {
Id [20]byte
- Addr net.Addr
+ Addr PeerRemoteAddr
Source PeerSource
// Peer is known to support encryption.
SupportsEncryption bool
}
func (me PeerInfo) addr() IpPort {
- return IpPort{IP: addrIpOrNil(me.Addr), Port: uint16(addrPortOrZero(me.Addr))}
+ ipPort, _ := tryIpPortFromNetAddr(me.Addr)
+ return IpPort{ipPort.IP, uint16(ipPort.Port)}
}
data []byte
}
+type PeerRemoteAddr interface {
+ String() string
+}
+
type Peer struct {
// First to ensure 64-bit alignment for atomics. See #262.
_stats ConnStats
outgoing bool
network string
- RemoteAddr net.Addr
+ RemoteAddr PeerRemoteAddr
// True if the connection is operating over MSE obfuscation.
headerEncrypted bool
cryptoMethod mse.CryptoMethod
// Returns true if the connection is over IPv6.
func (cn *PeerConn) ipv6() bool {
- ip := addrIpOrNil(cn.RemoteAddr)
+ ip := cn.remoteIp()
if ip.To4() != nil {
return false
}
}
func (c *Peer) remoteIp() net.IP {
- return addrIpOrNil(c.RemoteAddr)
+ host, _, _ := net.SplitHostPort(c.RemoteAddr.String())
+ return net.ParseIP(host)
}
func (c *Peer) remoteIpPort() IpPort {
if c.outgoing {
f |= pp.PexOutgoingConn
}
- if c.RemoteAddr != nil && strings.Contains(c.RemoteAddr.Network(), "udp") {
+ if c.utp() {
f |= pp.PexSupportsUtp
}
return f
// This returns the address to use if we want to dial the peer again. It incorporates the peer's
// advertised listen port.
-func (c *PeerConn) dialAddr() net.Addr {
+func (c *PeerConn) dialAddr() PeerRemoteAddr {
if !c.outgoing && c.PeerListenPort != 0 {
switch addr := c.RemoteAddr.(type) {
case *net.TCPAddr:
{&PeerConn{Peer: Peer{outgoing: false, PeerPrefersEncryption: true}}, pp.PexPrefersEncryption},
{&PeerConn{Peer: Peer{outgoing: true, PeerPrefersEncryption: false}}, pp.PexOutgoingConn},
{&PeerConn{Peer: Peer{outgoing: true, PeerPrefersEncryption: true}}, pp.PexOutgoingConn | pp.PexPrefersEncryption},
- {&PeerConn{Peer: Peer{RemoteAddr: udpAddr}}, pp.PexSupportsUtp},
- {&PeerConn{Peer: Peer{RemoteAddr: udpAddr, outgoing: true}}, pp.PexOutgoingConn | pp.PexSupportsUtp},
- {&PeerConn{Peer: Peer{RemoteAddr: tcpAddr, outgoing: true}}, pp.PexOutgoingConn},
- {&PeerConn{Peer: Peer{RemoteAddr: tcpAddr}}, 0},
+ {&PeerConn{Peer: Peer{RemoteAddr: udpAddr, network: udpAddr.Network()}}, pp.PexSupportsUtp},
+ {&PeerConn{Peer: Peer{RemoteAddr: udpAddr, network: udpAddr.Network(), outgoing: true}}, pp.PexOutgoingConn | pp.PexSupportsUtp},
+ {&PeerConn{Peer: Peer{RemoteAddr: tcpAddr, network: tcpAddr.Network(), outgoing: true}}, pp.PexOutgoingConn},
+ {&PeerConn{Peer: Peer{RemoteAddr: tcpAddr, network: tcpAddr.Network()}}, 0},
}
for i, tc := range testcases {
f := tc.conn.pexPeerFlags()
}{
{
pexAdd,
- &PeerConn{Peer: Peer{RemoteAddr: udpAddr}},
+ &PeerConn{Peer: Peer{RemoteAddr: udpAddr, network: udpAddr.Network()}},
pexEvent{pexAdd, udpAddr, pp.PexSupportsUtp},
},
{
pexDrop,
- &PeerConn{Peer: Peer{RemoteAddr: tcpAddr, outgoing: true, PeerListenPort: dialTcpAddr.Port}},
+ &PeerConn{Peer: Peer{RemoteAddr: tcpAddr, network: tcpAddr.Network(), outgoing: true, PeerListenPort: dialTcpAddr.Port}},
pexEvent{pexDrop, tcpAddr, pp.PexOutgoingConn},
},
{
pexAdd,
- &PeerConn{Peer: Peer{RemoteAddr: tcpAddr, PeerListenPort: dialTcpAddr.Port}},
+ &PeerConn{Peer: Peer{RemoteAddr: tcpAddr, network: tcpAddr.Network(), PeerListenPort: dialTcpAddr.Port}},
pexEvent{pexAdd, dialTcpAddr, 0},
},
{
pexDrop,
- &PeerConn{Peer: Peer{RemoteAddr: udpAddr, PeerListenPort: dialUdpAddr.Port}},
+ &PeerConn{Peer: Peer{RemoteAddr: udpAddr, network: udpAddr.Network(), PeerListenPort: dialUdpAddr.Port}},
pexEvent{pexDrop, dialUdpAddr, pp.PexSupportsUtp},
},
}
// represents a single connection (t=pexAdd) or disconnection (t=pexDrop) event
type pexEvent struct {
t pexEventType
- addr net.Addr
+ addr PeerRemoteAddr
f pp.PexPeerFlags
}
type addrKey string
// Returns the key to use to identify a given addr in the factory.
-func (me *pexMsgFactory) addrKey(addr net.Addr) addrKey {
+func (me *pexMsgFactory) addrKey(addr PeerRemoteAddr) addrKey {
return addrKey(addr.String())
}
// Convert an arbitrary torrent peer Addr into one that can be represented by the compact addr
// format.
-func nodeAddr(addr net.Addr) (_ krpc.NodeAddr, ok bool) {
- ipport, ok := tryIpPortFromNetAddr(addr)
- if !ok {
- return
- }
- return krpc.NodeAddr{IP: shortestIP(ipport.IP), Port: ipport.Port}, true
+func nodeAddr(addr PeerRemoteAddr) (krpc.NodeAddr, bool) {
+ ipport, _ := tryIpPortFromNetAddr(addr)
+ ok := ipport.IP != nil
+ return krpc.NodeAddr{IP: shortestIP(ipport.IP), Port: ipport.Port}, ok
}
// mainly for the krpc marshallers