func main() { flag.Parse() // To see logs, use the -logtostderr flag and change the verbosity with // -v 0 (less verbose) up to -v 5 (more verbose). if len(flag.Args()) != 1 { fmt.Fprintf(os.Stderr, "Usage: %v <infohash>\n\n", os.Args[0]) fmt.Fprintf(os.Stderr, "Example infohash: %v\n", exampleIH) flag.PrintDefaults() os.Exit(1) } ih, err := dht.DecodeInfoHash(flag.Args()[0]) if err != nil { fmt.Fprintf(os.Stderr, "DecodeInfoHash error: %v\n", err) os.Exit(1) } // Starts a DHT node with the default options. It picks a random UDP port. To change this, see dht.NewConfig. d, err := dht.New(nil) if err != nil { fmt.Fprintf(os.Stderr, "New DHT error: %v", err) os.Exit(1) } // For debugging. go http.ListenAndServe(fmt.Sprintf(":%d", httpPortTCP), nil) go d.Run() go drainresults(d) for { d.PeersRequest(string(ih), false) time.Sleep(5 * time.Second) } }
// Sets up the DHT node for peer bootstrapping func (self *DHT) Init() error { sum := sha1.Sum([]byte(self.Config.Info)) // Create a hex encoded sha1 sum of a string to be used for DH infoHash, err := dht.DecodeInfoHash(hex.EncodeToString(sum[:])) if err != nil { return err } cfg := dht.NewConfig() cfg.Port = self.Config.port cfg.NumTargetPeers = self.Config.DesiredPeers d, err := dht.New(cfg) if err != nil { return err } self.InfoHash = infoHash self.DHT = d if self.Config.Disabled { // We have to initialize the DHT anyway because daemon loop needs // to read from its initialized chans. As long as Start() is prevented, // the DHT will not run. logger.Info("DHT is disabled") } else { logger.Info("Init DHT on port %d", self.Config.port) } return nil }
func DiscoverPeers(cm *network.ConnectionManager, address string) { // Hex encoded string: "The Distributed Bay!" ih, err := dht.DecodeInfoHash("5468652044697374726962757465642042617921") if err != nil { log.Fatalf("DHT DecodeInfoHash error: %v\n", err) } _, portStr, err := net.SplitHostPort(address) if err != nil { log.Fatal("Bind address error!", err) } port, err := strconv.Atoi(portStr) if err != nil { log.Fatal(err) } config := dht.NewConfig() config.Port = port config.NumTargetPeers = 10 node, err := dht.New(config) if err != nil { log.Fatal("Error creating DHT node!") } go node.Run() go checkPeers(node, cm) log.Println("Requesting peers from the DHT!") for { node.PeersRequest(string(ih), true) time.Sleep(15 * time.Second) } }
func downloadManager(d *dht.DHT, filesToDownload <-chan string, finished chan<- bool) { currentDownloads := make(map[dht.InfoHash]chan []string) downloadEvents := make(chan downloadEvent) for { select { case newInfoHashString := <-filesToDownload: newFile, err := dht.DecodeInfoHash(newInfoHashString) if err != nil { //TODO: better error handling log.Errorf("WINSTON: DecodeInfoHash error: %v\n", err) } if _, ok := currentDownloads[newFile]; ok { log.V(3).Infof("WINSTON: File %x is already downloading, skipping...\n", newFile) continue } log.V(3).Infof("WINSTON: Accepted %x for download...\n", newFile) // Create a channel for all the found peers currentDownloads[newFile] = make(chan []string) bufferedPeerChannel := makePeerBuffer(currentDownloads[newFile]) // Ask that nice DHT fellow to find those peers :) d.PeersRequest(string(newFile), false) // Create a new gorouite that manages the download for the specific file go downloadFile(newFile, bufferedPeerChannel, downloadEvents) case newEvent := <-downloadEvents: if newEvent.eventType == eventSucessfulDownload { log.V(1).Infof("WINSTON: Download of %x completed :)\n", newEvent.infoHash) } else if newEvent.eventType == eventTimeout { log.V(1).Infof("WINSTON: Download of %x failed: time out :(\n", newEvent.infoHash) } close(currentDownloads[newEvent.infoHash]) delete(currentDownloads, newEvent.infoHash) if len(currentDownloads) == 0 { finished <- true } case newPeers, chanOk := <-d.PeersRequestResults: if !chanOk { // Something went wrong, mayday, mayday! panic("WINSTON: BORK!\n") } for ih, peers := range newPeers { // Check if download is still active if currentPeersChan, ok := currentDownloads[ih]; ok { log.V(3).Infof("WINSTON: Received %d new peers for file %x\n", len(peers), ih) currentPeersChan <- peers } else { log.V(3).Infof("WINSTON: Received %d peers for non-current file %x (probably completed or timed out)\n", len(peers), ih) } } } } }
func NewMetaInfoFromMagnet(torrent string) (m *MetaInfo, err error) { magnet, err := parseMagnet(torrent) if err != nil { log.Println("Couldn't parse magnet: ", err) return } ih, err := dht.DecodeInfoHash(magnet.InfoHashes[0]) if err != nil { return } m = &MetaInfo{InfoHash: string(ih)} return }
func main() { flag.Parse() // Change to l4g.DEBUG to see *lots* of debugging information. l4g.AddFilter("stdout", l4g.WARNING, l4g.NewConsoleLogWriter()) if len(flag.Args()) != 1 { fmt.Fprintf(os.Stderr, "Usage: %v <infohash>\n\n", os.Args[0]) fmt.Fprintf(os.Stderr, "Example infohash: d1c5676ae7ac98e8b19f63565905105e3c4c37a2\n") flag.PrintDefaults() os.Exit(1) } ih, err := dht.DecodeInfoHash(flag.Args()[0]) if err != nil { l4g.Critical("DecodeInfoHash error: %v\n", err) os.Exit(1) } // This is a hint to the DHT of the minimum number of peers it will try to // find for the given node. This is not a reliable limit. In the future this // might be moved to "PeersRequest()", so the controlling client can have // different targets at different moments or for different infohashes. targetNumPeers := 5 d, err := dht.NewDHTNode(dhtPortUDP, targetNumPeers, false) if err != nil { l4g.Critical("NewDHTNode error: %v", err) os.Exit(1) } // For debugging. go http.ListenAndServe(fmt.Sprintf(":%d", httpPortTCP), nil) go d.DoDHT() go drainresults(d) for { // Give the DHT some time to "warm-up" its routing table. time.Sleep(5 * time.Second) d.PeersRequest(string(ih), false) } }
func main() { // randomly generated hash: AE6D4306F4AE6D4306F4AE6D4306F4AE6D4306F4 // ubuntu-12.04.4-desktop-amd64.iso: deca7a89a1dbdc4b213de1c0d5351e92582f31fb ih, err := dht.DecodeInfoHash("AE6D4306F4AE6D4306F4AE6D4306F4AE6D4306F4") if err != nil { fmt.Fprintf(os.Stderr, "DecodeInfoHash error: %v\n", err) os.Exit(1) } // Starts a DHT node with the default options. It picks a random UDP port. To change this, see dht.NewConfig. d, err := dht.New(nil) if err != nil { fmt.Fprintf(os.Stderr, "New DHT error: %v", err) os.Exit(1) } go d.Run() go drain(d) for { d.PeersRequest(string(ih), false) time.Sleep(5 * time.Second) } }
func (d *DiscoveryDHT) Run() error { var err error d.ih, err = dht.DecodeInfoHash(d.localNode.Config().NetworkID) if err != nil { return fmt.Errorf("decode infohash err: %s", err) } config := dht.NewConfig() config.Port = d.localNode.State().ListenPort d.node, err = dht.New(config) if err != nil { return fmt.Errorf("new dht init err: %s", err) } if err = d.node.Start(); err != nil { return fmt.Errorf("dht start err: %s", err) } d.waitGroup.Add(2) go d.process() go d.awaitPeers() d.waitGroup.Wait() return nil }
// Requests peers from the DHT func (self *DHT) RequestPeers(infoHashString string) { if self.Config.Disabled { return } sum := sha1.Sum([]byte(infoHashString)) // Create a hex encoded sha1 sum of a string to be used for DH infoHash, err := dht.DecodeInfoHash(hex.EncodeToString(sum[:])) if err != nil { log.Panic() } ih := string(infoHash) if ih == "" { log.Panic("InfoHash is not initialized") return } self.InfoHashes[ih] = infoHashString logger.Info("Requesting DHT Peers: infoHashString= %s", infoHashString) self.DHT.PeersRequest(ih, true) }
func getMetaInfo(torrent string) (metaInfo *MetaInfo, err error) { var input io.ReadCloser if strings.HasPrefix(torrent, "http:") { r, err := proxyHttpGet(torrent) if err != nil { return nil, err } input = r.Body } else if strings.HasPrefix(torrent, "magnet:") { magnet, err := parseMagnet(torrent) if err != nil { log.Println("Couldn't parse magnet: ", err) return nil, err } ih, err := dht.DecodeInfoHash(magnet.InfoHashes[0]) if err != nil { return nil, err } metaInfo = &MetaInfo{InfoHash: string(ih)} return metaInfo, err } else { if input, err = os.Open(torrent); err != nil { return } } // We need to calcuate the sha1 of the Info map, including every value in the // map. The easiest way to do this is to read the data using the Decode // API, and then pick through it manually. var m interface{} m, err = bencode.Decode(input) input.Close() if err != nil { err = errors.New("Couldn't parse torrent file phase 1: " + err.Error()) return } topMap, ok := m.(map[string]interface{}) if !ok { err = errors.New("Couldn't parse torrent file phase 2.") return } infoMap, ok := topMap["info"] if !ok { err = errors.New("Couldn't parse torrent file. info") return } var b bytes.Buffer if err = bencode.Marshal(&b, infoMap); err != nil { return } hash := sha1.New() hash.Write(b.Bytes()) var m2 MetaInfo err = bencode.Unmarshal(&b, &m2.Info) if err != nil { return } m2.InfoHash = string(hash.Sum(nil)) m2.Announce = getString(topMap, "announce") m2.AnnounceList = getSliceSliceString(topMap, "announce-list") m2.CreationDate = getString(topMap, "creation date") m2.Comment = getString(topMap, "comment") m2.CreatedBy = getString(topMap, "created by") m2.Encoding = getString(topMap, "encoding") metaInfo = &m2 return }
func main() { ipv6Address := flag.String("v6", "", "Address to bind to IPv6 interface") flag.Parse() // To see logs, use the -logtostderr flag and change the verbosity with // -v 0 (less verbose) up to -v 5 (more verbose). if len(flag.Args()) != 1 { fmt.Fprintf(os.Stderr, "Usage: %v <infohash>\n\n", os.Args[0]) fmt.Fprintf(os.Stderr, "Example infohash: %v\n", exampleIH) flag.PrintDefaults() os.Exit(1) } ih, err := dht.DecodeInfoHash(flag.Args()[0]) if err != nil { fmt.Fprintf(os.Stderr, "DecodeInfoHash error: %v\n", err) os.Exit(1) } conf4 := dht.NewConfig() conf4.UDPProto = "udp4" conf4.Port = 8445 // standard IPv4 bootstrap nodes = dht.transmissionbt.com // router.utorrent.com router.bittorrent.com conf6 := dht.NewConfig() conf6.UDPProto = "udp6" conf6.Port = 8445 conf6.Address = *ipv6Address // Starts a DHT node with the default options. It picks a random UDP port. To change this, see dht.NewConfig. d4, err := dht.New(conf4) if err != nil { fmt.Fprintf(os.Stderr, "New DHT error: %v", err) os.Exit(1) } var d6 *dht.DHT if len(*ipv6Address) > 1 { fmt.Printf("Tring to bind to IPv6=%s\n", *ipv6Address) d6, err = dht.New(conf6) if err != nil { fmt.Fprintf(os.Stderr, "New DHT error: %v", err) os.Exit(1) } if err = d6.Start(); err != nil { fmt.Fprintf(os.Stderr, "DHT start error: %v", err) os.Exit(1) } go drainresults(d6) } else { fmt.Fprintf(os.Stderr, "Not binding to IPv6 interface. If desired pass -v6=[address] for the\n") fmt.Fprintf(os.Stderr, "address you want the DHT to bind to. Privacy addresses are not recommended\n") fmt.Fprintf(os.Stderr, "Since they can expire and connections will fail\n\n") } // For debugging. go http.ListenAndServe(fmt.Sprintf(":%d", httpPortTCP), nil) if err = d4.Start(); err != nil { fmt.Fprintf(os.Stderr, "DHT start error: %v", err) os.Exit(1) } go drainresults(d4) for { d4.PeersRequest(string(ih), true) if len(*ipv6Address) > 1 { d6.PeersRequest(string(ih), true) } time.Sleep(5 * time.Second) } }