Пример #1
0
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)
				}
			}
		}
	}
}
Пример #2
0
func RunTorrents(flags *TorrentFlags, torrentFiles []string) (err error) {
	conChan, listenPort, err := ListenForPeerConnections(flags)
	if err != nil {
		log.Println("Couldn't listen for peers connection: ", err)
		return
	}
	quitChan := listenSigInt()

	createChan := make(chan string, flags.MaxActive)
	startChan := make(chan *TorrentSession, 1)
	doneChan := make(chan *TorrentSession, 1)

	var dhtNode dht.DHT
	if flags.UseDHT {
		dhtNode = *startDHT(flags.Port)
	}

	torrentSessions := make(map[string]*TorrentSession)

	go func() {
		for torrentFile := range createChan {
			ts, err := NewTorrentSession(flags, torrentFile, uint16(listenPort))
			if err != nil {
				log.Println("Couldn't create torrent session for "+torrentFile+" .", err)
				doneChan <- &TorrentSession{}
			} else {
				log.Printf("Created torrent session for %s", ts.M.Info.Name)
				startChan <- ts
			}
		}
	}()

	torrentQueue := []string{}
	if len(torrentFiles) > flags.MaxActive {
		torrentQueue = torrentFiles[flags.MaxActive:]
	}

	for i, torrentFile := range torrentFiles {
		if i < flags.MaxActive {
			createChan <- torrentFile
		} else {
			break
		}
	}

	lpd := &Announcer{}
	if flags.UseLPD {
		lpd, err = NewAnnouncer(uint16(listenPort))
		if err != nil {
			log.Println("Couldn't listen for Local Peer Discoveries: ", err)
			flags.UseLPD = false
		}
	}

	theWorldisEnding := false
mainLoop:
	for {
		select {
		case ts := <-startChan:
			if !theWorldisEnding {
				ts.dht = &dhtNode
				if flags.UseLPD {
					lpd.Announce(ts.M.InfoHash)
				}
				torrentSessions[ts.M.InfoHash] = ts
				log.Printf("Starting torrent session for %s", ts.M.Info.Name)
				go func(t *TorrentSession) {
					t.DoTorrent()
					doneChan <- t
				}(ts)
			}
		case ts := <-doneChan:
			if ts.M != nil {
				delete(torrentSessions, ts.M.InfoHash)
				if flags.UseLPD {
					lpd.StopAnnouncing(ts.M.InfoHash)
				}
			}
			if !theWorldisEnding && len(torrentQueue) > 0 {
				createChan <- torrentQueue[0]
				torrentQueue = torrentQueue[1:]
				continue mainLoop
			}

			if len(torrentSessions) == 0 {
				break mainLoop
			}
		case <-quitChan:
			theWorldisEnding = true
			for _, ts := range torrentSessions {
				go ts.Quit()
			}
		case c := <-conChan:
			//	log.Printf("New bt connection for ih %x", c.Infohash)
			if ts, ok := torrentSessions[c.Infohash]; ok {
				ts.AcceptNewPeer(c)
			}
		case dhtPeers := <-dhtNode.PeersRequestResults:
			for key, peers := range dhtPeers {
				if ts, ok := torrentSessions[string(key)]; ok {
					// log.Printf("Received %d DHT peers for torrent session %x\n", len(peers), []byte(key))
					for _, peer := range peers {
						peer = dht.DecodePeerAddress(peer)
						ts.HintNewPeer(peer)
					}
				} else {
					log.Printf("Received DHT peer for an unknown torrent session %x\n", []byte(key))
				}
			}
		case announce := <-lpd.Announces:
			hexhash, err := hex.DecodeString(announce.Infohash)
			if err != nil {
				log.Println("Err with hex-decoding:", err)
			}
			if ts, ok := torrentSessions[string(hexhash)]; ok {
				// log.Printf("Received LPD announce for ih %s", announce.Infohash)
				ts.HintNewPeer(announce.Peer)
			}
		}
	}
	if flags.UseDHT {
		dhtNode.Stop()
	}
	return
}
Пример #3
0
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)
	}
}