/// <summary> /// Gets the peers from DHT and generates AnnounceParameters of a list of /// peers and puts the peer info of this announcing peer to DHT /// </summary> /// <param name="parameters"> /// AnnounceParameters from the requesting client. It's modified in method. /// </param> internal void HandleAnnounceRequest(AnnounceParameters parameters) { IEnumerable <PeerEntry> entries = _proxy.GetPeers(parameters.InfoHash.ToArray()); foreach (PeerEntry entry in entries) { AnnounceParameters par = GenerateAnnounceParameters( parameters.InfoHash.ToArray(), entry); if (par.IsValid) { // Tracker will write to the par.Response but we don't use it // ListenerBase.Handle use par.ClientAddress to generate // AnnounceParameters again. Handle(par.Parameters, par.ClientAddress.Address, false); } else { Logger.WriteLineIf(LogLevel.Error, _log_props, string.Format( "Parameters invalid!")); continue; } //Logger.WriteLineIf(LogLevel.Verbose, _log_props, // string.Format("Tracker's response for this peer {0} from DHT: {1}", // par.ClientAddress, par.Response.ToString())); } // Got all I need, now announce myself to DHT. try { _proxy.AnnouncePeer(parameters.InfoHash.ToArray(), parameters); } catch (Exception ex) { // It is OK to temporarily unable to announce to Dht. We can try the next time. Logger.WriteLineIf(LogLevel.Error, _log_props, string.Format( "Unable to reach Dht. We can try the next time.\n{0}", ex)); } Logger.WriteLineIf(LogLevel.Info, _log_props, string.Format("DhtListener finished handling annoucement from {0}", parameters.RemoteAddress)); }
/// <summary> /// Downloads the torrent of the piece and write it to /// </summary> /// <param name="nameSpace">The name space.</param> /// <param name="name">The name.</param> /// <param name="wholeTorrent">The whole torrent.</param> /// <param name="pieceIndex">Index of the piece.</param> byte[] DownloadPieceTorrent(string nameSpace, string name, Torrent wholeTorrent, int pieceIndex) { var wholeTorrentDhtKeyStr = ServiceUtil.GetDictKeyString(nameSpace, name); var pieceKeyStr = MakePieceTorrentKey(wholeTorrentDhtKeyStr, pieceIndex); var torrentFilePath = _bittorrentCache.GetTorrentFilePath(nameSpace, name); byte[] pieceTorrentBytes; bool succ = _torrentHelper.TryReadOrDownloadTorrent( nameSpace, name, _dhtProxy, out pieceTorrentBytes); if (succ) { // Somebody else already requested this piece. return(pieceTorrentBytes); } else { // We need to request the seeder to make a new piece. IEnumerable <PeerEntry> peers = _dhtProxy.GetPeers(wholeTorrent.InfoHash.ToArray()); bool foundCompletePeer = false; // The list most likely has only one entry. var trackerIPs = new List <string>(); foreach (var tiers in wholeTorrent.AnnounceUrls) { foreach (var trackerUrl in tiers) { // Given that we don't use domain names for hosts. trackerIPs.Add(new Uri(trackerUrl).Host); } } // Completed -> Downloader has the whole data. // PeerIP == Tracker -> Original Seeder(s). var peerIPs = (from peer in peers where (peer.PeerState == TorrentEvent.Completed || trackerIPs.Contains(peer.PeerIP)) select peer.PeerIP).Distinct(); Logger.WriteLineIf(LogLevel.Verbose, _log_props, string.Format( "{0} peers to try for piece info.", peerIPs.Count())); foreach (var peerIP in peerIPs) { foundCompletePeer = true; // The first complete peer should be able to serve the piece we want. bool succPieceInfo = TryDownloadPieceTorrentFromPeer(nameSpace, name, pieceIndex, peerIP, _pieceInfoServerPort, out pieceTorrentBytes); if (succPieceInfo) { Logger.WriteLineIf(LogLevel.Verbose, _log_props, string.Format("Piece info downloaded from {0}", peerIP)); return(pieceTorrentBytes); } else { // Try the next completePeer continue; } } if (!foundCompletePeer) { throw new DictionaryKeyNotFoundException("No peer is complete."); } else if (pieceTorrentBytes == null) { throw new DictionaryKeyNotFoundException( "No complete peer(s) can return the piece Info"); } else { // This shouldn't happen return(pieceTorrentBytes); } } }