if tc, ok := nc.(*net.TCPConn); ok {
tc.SetLinger(0)
}
- c := cl.newConnection(nc, false)
+ c := cl.newConnection(nc, false, ipPortFromNetAddr(nc.RemoteAddr()), nc.RemoteAddr().Network())
c.Discovery = peerSourceIncoming
cl.runReceivedConn(c)
}
}
type dialResult struct {
- Conn net.Conn
+ Conn net.Conn
+ Network string
}
func countDialResult(err error) {
}
// Returns a connection over UTP or TCP, whichever is first to connect.
-func (cl *Client) dialFirst(ctx context.Context, addr string) net.Conn {
+func (cl *Client) dialFirst(ctx context.Context, addr string) dialResult {
ctx, cancel := context.WithCancel(ctx)
// As soon as we return one connection, cancel the others.
defer cancel()
left := 0
resCh := make(chan dialResult, left)
- dial := func(f func(_ context.Context, addr string) (net.Conn, error)) {
- left++
- go func() {
- c, err := f(ctx, addr)
- // This is a bit optimistic, but it looks non-trivial to thread
- // this through the proxy code. Set it now in case we close the
- // connection forthwith.
- if tc, ok := c.(*net.TCPConn); ok {
- tc.SetLinger(0)
- }
- countDialResult(err)
- resCh <- dialResult{c}
- }()
- }
func() {
cl.lock()
defer cl.unlock()
cl.eachListener(func(s socket) bool {
- if peerNetworkEnabled(s.Addr().Network(), cl.config) {
- dial(s.dial)
+ network := s.Addr().Network()
+ if peerNetworkEnabled(network, cl.config) {
+ left++
+ go func() {
+ c, err := s.dial(ctx, addr)
+ // This is a bit optimistic, but it looks non-trivial to thread
+ // this through the proxy code. Set it now in case we close the
+ // connection forthwith.
+ if tc, ok := c.(*net.TCPConn); ok {
+ tc.SetLinger(0)
+ }
+ countDialResult(err)
+ resCh <- dialResult{c, network}
+ }()
}
return true
})
if res.Conn != nil {
go torrent.Add(fmt.Sprintf("network dialed first: %s", res.Conn.RemoteAddr().Network()), 1)
}
- return res.Conn
+ return res
}
func (cl *Client) noLongerHalfOpen(t *Torrent, addr string) {
// Performs initiator handshakes and returns a connection. Returns nil
// *connection if no connection for valid reasons.
-func (cl *Client) handshakesConnection(ctx context.Context, nc net.Conn, t *Torrent, encryptHeader bool) (c *connection, err error) {
- c = cl.newConnection(nc, true)
+func (cl *Client) handshakesConnection(ctx context.Context, nc net.Conn, t *Torrent, encryptHeader bool, remoteAddr ipPort, network string) (c *connection, err error) {
+ c = cl.newConnection(nc, true, remoteAddr, network)
c.headerEncrypted = encryptHeader
ctx, cancel := context.WithTimeout(ctx, cl.config.HandshakesTimeout)
defer cancel()
// Returns nil connection and nil error if no connection could be established
// for valid reasons.
-func (cl *Client) establishOutgoingConnEx(t *Torrent, addr string, ctx context.Context, obfuscatedHeader bool) (c *connection, err error) {
- nc := cl.dialFirst(ctx, addr)
+func (cl *Client) establishOutgoingConnEx(t *Torrent, addr ipPort, ctx context.Context, obfuscatedHeader bool) (c *connection, err error) {
+ dr := cl.dialFirst(ctx, addr.String())
+ nc := dr.Conn
if nc == nil {
return
}
nc.Close()
}
}()
- return cl.handshakesConnection(ctx, nc, t, obfuscatedHeader)
+ return cl.handshakesConnection(ctx, nc, t, obfuscatedHeader, addr, dr.Network)
}
// Returns nil connection and nil error if no connection could be established
// for valid reasons.
-func (cl *Client) establishOutgoingConn(t *Torrent, addr string) (c *connection, err error) {
+func (cl *Client) establishOutgoingConn(t *Torrent, addr ipPort) (c *connection, err error) {
torrent.Add("establish outgoing connection", 1)
ctx, cancel := context.WithTimeout(context.Background(), func() time.Duration {
cl.rLock()
// 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 string, ps peerSource) {
+func (cl *Client) outgoingConnection(t *Torrent, addr ipPort, ps peerSource) {
cl.dialRateLimiter.Wait(context.Background())
c, err := cl.establishOutgoingConn(t, addr)
cl.lock()
defer cl.unlock()
// Don't release lock between here and addConnection, unless it's for
// failure.
- cl.noLongerHalfOpen(t, addr)
+ cl.noLongerHalfOpen(t, addr.String())
if err != nil {
if cl.config.Debug {
log.Printf("error establishing outgoing connection: %s", err)
).AddValue(
debugLogValue,
).Add(
- "network", c.remoteAddr().Network(),
+ "network", c.network,
).Log(cl.logger)
torrent.Add("error receiving handshake", 1)
cl.lock()
- cl.onBadAccept(c.remoteAddr())
+ cl.onBadAccept(c.remoteAddr)
cl.unlock()
return
}
if t == nil {
torrent.Add("received handshake for unloaded torrent", 1)
cl.lock()
- cl.onBadAccept(c.remoteAddr())
+ cl.onBadAccept(c.remoteAddr)
cl.unlock()
return
}
},
V: cl.config.ExtendedHandshakeClientVersion,
Reqq: 64, // TODO: Really?
- YourIp: pp.CompactIp(missinggo.AddrIP(conn.remoteAddr())),
+ YourIp: pp.CompactIp(conn.remoteAddr.IP),
Encryption: !cl.config.DisableEncryption,
Port: cl.incomingPeerPort(),
MetadataSize: torrent.metadataSize(),
cl.badPeerIPs[ip.String()] = struct{}{}
}
-func (cl *Client) newConnection(nc net.Conn, outgoing bool) (c *connection) {
+func (cl *Client) newConnection(nc net.Conn, outgoing bool, remoteAddr ipPort, network string) (c *connection) {
c = &connection{
conn: nc,
outgoing: outgoing,
PeerChoked: true,
PeerMaxRequests: 250,
writeBuffer: new(bytes.Buffer),
+ remoteAddr: remoteAddr,
+ network: network,
}
c.writerCond.L = cl.locker()
c.setRW(connStatsReadWriter{nc, c})
return
}
-func (cl *Client) onBadAccept(addr net.Addr) {
- ip := maskIpForAcceptLimiting(missinggo.AddrIP(addr))
+func (cl *Client) onBadAccept(addr ipPort) {
+ ip := maskIpForAcceptLimiting(addr.IP)
if cl.acceptLimiter == nil {
cl.acceptLimiter = make(map[ipStr]int)
}
t *Torrent
// The actual Conn, used for closing, and setting socket options.
- conn net.Conn
- outgoing bool
+ conn net.Conn
+ outgoing bool
+ network string
+ remoteAddr ipPort
// The Reader and Writer for this Conn, with hooks installed for stats,
// limiting, deadlines etc.
w io.Writer
// Returns true if the connection is over IPv6.
func (cn *connection) ipv6() bool {
- ip := missinggo.AddrIP(cn.remoteAddr())
+ ip := cn.remoteAddr.IP
if ip.To4() != nil {
return false
}
return cn.t.cl.locker()
}
-func (cn *connection) remoteAddr() net.Addr {
- return cn.conn.RemoteAddr()
-}
-
func (cn *connection) localAddr() net.Addr {
return cn.conn.LocalAddr()
}
}
func (cn *connection) utp() bool {
- return isUtpNetwork(cn.remoteAddr().Network())
+ return isUtpNetwork(cn.network)
}
// Inspired by https://github.com/transmission/transmission/wiki/Peer-Status-Text.
func (cn *connection) WriteStatus(w io.Writer, t *Torrent) {
// \t isn't preserved in <pre> blocks?
- fmt.Fprintf(w, "%+-55q %s %s-%s\n", cn.PeerID, cn.PeerExtensionBytes, cn.localAddr(), cn.remoteAddr())
+ fmt.Fprintf(w, "%+-55q %s %s-%s\n", cn.PeerID, cn.PeerExtensionBytes, cn.localAddr(), cn.remoteAddr)
fmt.Fprintf(w, " last msg: %s, connected: %s, last helpful: %s, itime: %s, etime: %s\n",
eventAgeString(cn.lastMessageReceived),
eventAgeString(cn.completedHandshake),
case pp.Extended:
err = c.onReadExtendedMsg(msg.ExtendedID, msg.ExtendedPayload)
case pp.Port:
- pingAddr, err := net.ResolveUDPAddr("", c.remoteAddr().String())
- if err != nil {
- panic(err)
+ pingAddr := net.UDPAddr{
+ IP: c.remoteAddr.IP,
+ Port: int(c.remoteAddr.Port),
}
if msg.Port != 0 {
pingAddr.Port = int(msg.Port)
}
cl.eachDhtServer(func(s *dht.Server) {
- go s.Ping(pingAddr, nil)
+ go s.Ping(&pingAddr, nil)
})
case pp.AllowedFast:
torrent.Add("allowed fasts received", 1)
}
func (c *connection) remoteIp() net.IP {
- return missinggo.AddrIP(c.remoteAddr())
+ return c.remoteAddr.IP
}
+// ???
func (c *connection) remoteIpPort() ipPort {
- return ipPort{missinggo.AddrIP(c.remoteAddr()), uint16(missinggo.AddrPort(c.remoteAddr()))}
+ return c.remoteAddr
}
"net"
"net/url"
"os"
- "strconv"
"sync"
"text/tabwriter"
"time"
// Add active peers to the list
for conn := range t.conns {
- host, portString, err := net.SplitHostPort(conn.remoteAddr().String())
- if err != nil {
- panic(err)
- }
-
- ip := net.ParseIP(host)
- port, err := strconv.Atoi(portString)
- if err != nil {
- panic(err)
- }
ks = append(ks, Peer{
Id: conn.PeerID,
- IP: ip,
- Port: port,
+ IP: conn.remoteAddr.IP,
+ Port: int(conn.remoteAddr.Port),
Source: conn.Discovery,
// > If the connection is encrypted, that's certainly enough to set SupportsEncryption.
// > But if we're not connected to them with an encrypted connection, I couldn't say
return true
}
for c := range t.conns {
- ra := c.remoteAddr()
- if ra == nil {
- continue
- }
+ ra := c.remoteAddr
if ra.String() == addr {
return true
}
}())
}
c := touchers[0]
- t.cl.banPeerIP(missinggo.AddrIP(c.remoteAddr()))
+ t.cl.banPeerIP(c.remoteAddr.IP)
c.Drop()
}
t.onIncompletePiece(piece)
if t.cl.badPeerIPPort(peer.IP, peer.Port) {
return
}
- addr := net.JoinHostPort(peer.IP.String(), fmt.Sprintf("%d", peer.Port))
- if t.addrActive(addr) {
+ addr := ipPort{peer.IP, uint16(peer.Port)}
+ if t.addrActive(addr.String()) {
return
}
- t.halfOpen[addr] = peer
+ t.halfOpen[addr.String()] = peer
go t.cl.outgoingConnection(t, addr, peer.Source)
}