/* CLIENT */ func (n *Node) Dial(peerPubKey *rsa.PublicKey) (conn Conn, err error) { infoHash, err := pubKeyToInfoHash(peerPubKey) if err != nil { return } peerNotifications := make(chan string, peerChanBufferCapacity) n.dht.subscribeToInfoHash(dht.InfoHash(infoHash), peerNotifications) // ask for the infohash n.dht.PeersRequest(infoHash, false) connSuccessChan := make(chan interface{}) for peerNotification := range peerNotifications { go func(peerNotification string) { // ASSUMPTION: peerNotifications doesn't yield duplicates. someConn, connErr := n.handlePotentialPeer(peerNotification, peerPubKey) if err != nil { Log(LOG_INFO, "Failed to connect to potential peer %s: %s", peerNotification, connErr) } connSuccessChan <- someConn }(peerNotification) } maybeConn, err := netutils.ReadWithTimeout(connSuccessChan, 30000) if err != nil { return } return maybeConn.(Conn), nil }
// infohash used for this wherez lookup. This should be somewhat hard to guess // but it's not exactly a secret. func infoHash(passphrase []byte) (dht.InfoHash, error) { // SHA256 of the passphrase. h256 := sha256.New() h256.Write(passphrase) h := h256.Sum(nil) // Assuming perfect rainbow databases, it's better if the infohash does not // give out too much about the passphrase. Take half of this hash, then // generate a SHA1 hash from it. h2 := h[0 : sha256.Size/2] // Mainline DHT uses sha1. h160 := sha1.New() h160.Write(h2) h3 := h160.Sum(nil) return dht.InfoHash(h3[:]), nil }
func TestReceivePeers(t *testing.T) { cleanupPeers() d := NewDHT(NewDHTConfig()) peers := NewPeers(NewPeersConfig()) peers.Init() m := make(map[dht.InfoHash][]string) ps := make([]string, 0) ps = append(ps, string([]byte{013, 026, 041, 054, 013, 013})) ps = append(ps, string([]byte{013, 026, 041, 055, 013, 013})) m[dht.InfoHash("")] = ps d.ReceivePeers(m, peers.Peers) assert.Equal(t, len(peers.Peers.Peerlist), 2) assert.NotNil(t, peers.Peers.Peerlist["11.22.33.45:2827"]) assert.NotNil(t, peers.Peers.Peerlist["11.22.33.44:2827"]) wait() d.Shutdown() wait() }
func trackerHandler(w http.ResponseWriter, r *http.Request) { if r.FormValue("compact") != "1" { http.Error(w, "Only compact protocol supported.", 400) return } info_hash := dht.InfoHash(r.FormValue("info_hash")) if len(info_hash) != 20 { http.Error(w, "Bad info_hash.", 400) return } response := TrackerResponse{ Interval: 300, MinInterval: 60, } peers, ok := peerCache.Get(info_hash) dhtNode.Find(info_hash) if !ok || len(peers) == 0 { response.Interval = 30 response.MinInterval = 10 time.Sleep(5 * time.Second) peers, ok = peerCache.Get(info_hash) } if ok && len(peers) > 0 { response.Incomplete = len(peers) response.Peers = strings.Join(peers, "") } w.Header().Set("Content-Type", "application/octet-stream") if err := bencode.Marshal(w, response); err != nil { http.Error(w, err.Error(), 500) } }