func (d *DHT) replyAnnouncePeer(addr net.UDPAddr, node *remoteNode, r responseType) { ih := InfoHash(r.A.InfoHash) if log.V(3) { log.Infof("DHT: announce_peer. Host %v, nodeID: %x, infoHash: %x, peerPort %d, distance to me %x", addr, r.A.Id, ih, r.A.Port, hashDistance(ih, InfoHash(d.nodeId)), ) } // node can be nil if, for example, the server just restarted and received an announce_peer // from a node it doesn't yet know about. if node != nil && d.checkToken(addr, r.A.Token) { peerAddr := net.TCPAddr{IP: addr.IP, Port: r.A.Port} d.peerStore.addContact(ih, nettools.DottedPortToBinary(peerAddr.String())) // Allow searching this node immediately, since it's telling us // it has an infohash. Enables faster upgrade of other nodes to // "peer" of an infohash, if the announcement is valid. node.lastResponseTime = time.Now().Add(-searchRetryPeriod) if d.peerStore.hasLocalDownload(ih) { d.PeersRequestResults <- map[InfoHash][]string{ih: []string{nettools.DottedPortToBinary(peerAddr.String())}} } } // Always reply positively. jech says this is to avoid "back-tracking", not sure what that means. reply := replyMessage{ T: r.T, Y: "r", R: map[string]interface{}{"id": d.nodeId}, } sendMsg(d.conn, addr, reply) }
// The main loop. // Every minute, we calculate the new pex message and send it to // everyone. After it's sent, this new pex message becomes the last // pex message. // // A Pex Message has three fields: "added", "addedf" and "dropped". // // "added" represents the set of peers we are currently connected to // that we weren't connected to last time. // // "addedf" contains the same peers but instead of their address, it's // their flags (See the Flag structure for more details) // // "dropped" is the set of peers we were connected to last time that // we aren't currently connected to. func (t *TorrentSession) StartPex() { for _ = range time.Tick(1 * time.Minute) { newLastPeers := make([]pexPeer, 0) numadded := 0 added := "" addedf := "" // TODO randomize to distribute more evenly for _, peer := range t.peers.All() { newLastPeers = append(newLastPeers, pexPeer{peer.address, peer.id}) if contains(lastPeers, peer) { continue } added += nettools.DottedPortToBinary(peer.address) // We don't manage those yet addedf += string(0x00) numadded += 1 if numadded >= MAX_PEERS { break } } dropped := "" for _, lastPeer := range lastPeers { if !t.peers.Know(lastPeer.address, lastPeer.id) { dropped += nettools.DottedPortToBinary(lastPeer.address) } } for _, p := range t.peers.All() { p.sendExtensionMessage("ut_pex", PexMessage{ Added: added, AddedF: addedf, Dropped: dropped, }) } lastPeers = newLastPeers } }
func newRemoteNode(addr net.UDPAddr, id string) *remoteNode { return &remoteNode{ address: addr, addressBinaryFormat: nettools.DottedPortToBinary(addr.String()), lastQueryID: newTransactionId(), id: id, reachable: false, pendingQueries: map[string]*queryType{}, pastQueries: map[string]*queryType{}, } }
func (d *DHT) nodesForInfoHash(ih InfoHash) string { n := make([]string, 0, kNodes) for _, r := range d.routingTable.lookup(ih) { // r is nil when the node was filtered. if r != nil { n = append(n, r.id+nettools.DottedPortToBinary(r.address.String())) } } l4g.Trace("replyGetPeers: Nodes only. Giving %d", len(n)) return strings.Join(n, "") }
func (d *DHT) nodesForInfoHash(ih InfoHash) string { n := make([]string, 0, kNodes) for _, r := range d.routingTable.lookup(ih) { // r is nil when the node was filtered. if r != nil { binaryHost := r.id + nettools.DottedPortToBinary(r.address.String()) if binaryHost == "" { log.V(3).Infof("killing node with bogus address %v", r.address.String()) d.routingTable.kill(r, d.peerStore) } else { n = append(n, binaryHost) } } } log.V(3).Infof("replyGetPeers: Nodes only. Giving %d", len(n)) return strings.Join(n, "") }
func (d *DHT) replyAnnouncePeer(addr *net.UDPAddr, r responseType) { l4g.Trace(func() string { ih := InfoHash(r.A.InfoHash) return fmt.Sprintf("DHT: announce_peer. Host %v, nodeID: %x, infoHash: %x, peerPort %d, distance to me %x", addr, r.A.Id, ih, r.A.Port, hashDistance(ih, InfoHash(d.nodeId)), ) }) peerAddr := net.TCPAddr{IP: addr.IP, Port: r.A.Port} d.peerStore.addContact(InfoHash(r.A.InfoHash), nettools.DottedPortToBinary(peerAddr.String())) // Always reply positively. jech says this is to avoid "back-tracking", not sure what that means. reply := replyMessage{ T: r.T, Y: "r", R: map[string]interface{}{"id": d.nodeId}, } sendMsg(d.conn, addr, reply) }
func (d *DHT) replyAnnouncePeer(node *remoteNode, r responseType) { addr := node.address ih := InfoHash(r.A.InfoHash) if log.V(3) { log.Infof("DHT: announce_peer. Host %v, nodeID: %x, infoHash: %x, peerPort %d, distance to me %x", addr, r.A.Id, ih, r.A.Port, hashDistance(ih, InfoHash(d.nodeId)), ) } if d.checkToken(addr, r.A.Token) { peerAddr := net.TCPAddr{IP: addr.IP, Port: r.A.Port} d.peerStore.addContact(ih, nettools.DottedPortToBinary(peerAddr.String())) // Allow searching this node immediately, since it's telling us // it has an infohash. Enables faster upgrade of other nodes to // "peer" of an infohash, if the announcement is valid. node.lastResponseTime = time.Now().Add(-searchRetryPeriod) } // Always reply positively. jech says this is to avoid "back-tracking", not sure what that means. reply := replyMessage{ T: r.T, Y: "r", R: map[string]interface{}{"id": d.nodeId}, } d.sendMsg(d.conn, addr, reply) }