public override RequestMessage ContinueExistingRequest(PeerId id) { for (int req = 0; req < requests.Count; req++) { Piece p = requests[req]; // For each piece that was assigned to this peer, try to request a block from it // A piece is 'assigned' to a peer if he is the first person to request a block from that piece if (p.AllBlocksRequested || !id.Equals(p.Blocks[0].RequestedOff)) { continue; } for (int i = 0; i < p.BlockCount; i++) { if (p.Blocks[i].Requested || p.Blocks[i].Received) { continue; } p.Blocks[i].Requested = true; return(p.Blocks[i].CreateRequest(id)); } } // If we get here it means all the blocks in the pieces being downloaded by the peer are already requested return(null); }
public override void CancelRequest(PeerId peer, int piece, int startOffset, int length) { CancelWhere(delegate (Request r) { return r.Block.PieceIndex == piece && r.Block.StartOffset == startOffset && r.Block.RequestLength == length && peer.Equals(r.Peer); }); }
public override void CancelRequest(PeerId peer, int piece, int startOffset, int length) { CancelWhere(delegate(Request r) { return(r.Block.PieceIndex == piece && r.Block.StartOffset == startOffset && r.Block.RequestLength == length && peer.Equals(r.Peer)); }, false); }
public override void CancelRequest(PeerId peer, int piece, int startOffset, int length) { CancelWhere(delegate(Block b) { return(b.StartOffset == startOffset && b.RequestLength == length && b.PieceIndex == piece && peer.Equals(b.RequestedOff)); }); }
internal void CleanupSocket(TorrentManager manager, PeerId id) { if (id == null || id.Disposed) // Sometimes onEncryptoError will fire with a null id { return; } try { // We can reuse this peer if the connection says so and it's not marked as inactive bool canReuse = (id.Connection?.CanReconnect ?? false) && !manager.InactivePeerManager.InactivePeerList.Contains(id.Uri) && id.Peer.AllowedEncryption.Count > 0 && !manager.Engine !.PeerId.Equals(id.PeerID); manager.PieceManager.CancelRequests(id); id.Peer.CleanedUpCount++; id.PeerExchangeManager?.Dispose(); if (!id.AmChoking) { manager.UploadingTo--; } if (manager.Peers.ConnectedPeers.Remove(id)) { Interlocked.Decrement(ref openConnections); } manager.Peers.ActivePeers.Remove(id.Peer); // If we get our own details, this check makes sure we don't try connecting to ourselves again if (canReuse && !LocalPeerId.Equals(id.Peer.PeerId)) { if (!manager.Peers.AvailablePeers.Contains(id.Peer) && id.Peer.CleanedUpCount < 5) { manager.Peers.AvailablePeers.Insert(0, id.Peer); } else if (manager.Peers.BannedPeers.Contains(id.Peer) && id.Peer.CleanedUpCount >= 5) { manager.Peers.BannedPeers.Add(id.Peer); } } } catch (Exception ex) { logger.Exception(ex, "An unexpected error occured cleaning up a connection"); } finally { manager.RaisePeerDisconnected(new PeerDisconnectedEventArgs(manager, id)); } id.Dispose(); }
public bool Equals(Peer other) { if (other == null) { return(false); } // FIXME: Don't compare the port, just compare the IP if (BEncodedString.IsNullOrEmpty(PeerId) || BEncodedString.IsNullOrEmpty(other.PeerId)) { return(ConnectionUri.Equals(other.ConnectionUri)); } return(PeerId.Equals(other.PeerId)); }
public override bool ValidatePiece(PeerId id, int pieceIndex, int startOffset, int length, out Piece piece) { //Comparer.index = pieceIndex; int pIndex = requests.BinarySearch(null, new BinaryIndexComparer(pieceIndex)); if (pIndex < 0) { piece = null; Logger.Log(null, "Validating: {0} - {1}: ", pieceIndex, startOffset); Logger.Log(null, "No piece"); return(false); } piece = requests[pIndex]; // Pick out the block that this piece message belongs to int blockIndex = Block.IndexOf(piece.Blocks, startOffset, length); if (blockIndex == -1 || !id.Equals(piece.Blocks[blockIndex].RequestedOff)) { Logger.Log(null, "Validating: {0} - {1}: ", pieceIndex, startOffset); Logger.Log(null, "no block"); return(false); } if (piece.Blocks[blockIndex].Received) { Logger.Log(null, "Validating: {0} - {1}: ", pieceIndex, startOffset); Logger.Log(null, "received"); return(false); } if (!piece.Blocks[blockIndex].Requested) { Logger.Log(null, "Validating: {0} - {1}: ", pieceIndex, startOffset); Logger.Log(null, "not requested"); return(false); } id.AmRequestingPiecesCount--; piece.Blocks[blockIndex].Received = true; if (piece.AllBlocksReceived) { requests.RemoveAt(pIndex); } return(true); }
void ExecuteReview() { //Review current choke/unchoke position and adjust as necessary //Start by populating the lists of peers, then allocate available slots oberving the unchoke limit //Clear the lists to start with nascentPeers.Clear(); candidatePeers.Clear(); optimisticUnchokeCandidates.Clear(); int unchokedPeers = 0; foreach (PeerId connectedPeer in Unchokeable.Peers) { if (!connectedPeer.Peer.IsSeeder) { //Determine common values for use in this routine TimeSpan timeUnchoked = TimeSpan.Zero; if (!connectedPeer.AmChoking) { timeUnchoked = connectedPeer.LastUnchoked.Elapsed; unchokedPeers++; } long bytesTransferred = 0; if (Unchokeable.Seeding) { //We are seeding the torrent; determine bytesTransferred as bytes uploaded bytesTransferred = connectedPeer.Monitor.DataBytesUploaded - connectedPeer.BytesUploadedAtLastReview; } else { //The peer is unchoked and we are downloading the torrent; determine bytesTransferred as bytes downloaded bytesTransferred = connectedPeer.Monitor.DataBytesDownloaded - connectedPeer.BytesDownloadedAtLastReview; } //Reset review up and download rates to zero; peers are therefore non-responders unless we determine otherwise connectedPeer.LastReviewDownloadRate = 0; connectedPeer.LastReviewUploadRate = 0; if (!connectedPeer.AmChoking && (timeUnchoked < minimumTimeBetweenReviews || (connectedPeer.FirstReviewPeriod && bytesTransferred > 0))) { //The peer is unchoked but either it has not been unchoked for the warm up interval, // or it is the first full period and only just started transferring data nascentPeers.Add(connectedPeer); } else if ((timeUnchoked >= minimumTimeBetweenReviews) && bytesTransferred > 0) //The peer is unchoked, has been for the warm up period and has transferred data in the period { //Add to peers that are candidates for unchoking based on their performance candidatePeers.Add(connectedPeer); //Calculate the latest up/downloadrate connectedPeer.LastReviewUploadRate = (connectedPeer.Monitor.DataBytesUploaded - connectedPeer.BytesUploadedAtLastReview) / timeSinceLastReview.Elapsed.TotalSeconds; connectedPeer.LastReviewDownloadRate = (connectedPeer.Monitor.DataBytesDownloaded - connectedPeer.BytesDownloadedAtLastReview) / timeSinceLastReview.Elapsed.TotalSeconds; } else if (!Unchokeable.Seeding && connectedPeer.IsInterested && connectedPeer.AmChoking && bytesTransferred > 0) //A peer is optimistically unchoking us. Take the maximum of their current download rate and their download rate over the // review period since they might have only just unchoked us and we don't want to miss out on a good opportunity. Upload // rate is less important, so just take an average over the period. { //Add to peers that are candidates for unchoking based on their performance candidatePeers.Add(connectedPeer); //Calculate the latest up/downloadrate connectedPeer.LastReviewUploadRate = (connectedPeer.Monitor.DataBytesUploaded - connectedPeer.BytesUploadedAtLastReview) / timeSinceLastReview.Elapsed.TotalSeconds; connectedPeer.LastReviewDownloadRate = Math.Max((connectedPeer.Monitor.DataBytesDownloaded - connectedPeer.BytesDownloadedAtLastReview) / timeSinceLastReview.Elapsed.TotalSeconds, connectedPeer.Monitor.DownloadSpeed); } else if (connectedPeer.IsInterested) { //All other interested peers are candidates for optimistic unchoking optimisticUnchokeCandidates.Add(connectedPeer); } //Remember the number of bytes up and downloaded for the next review connectedPeer.BytesUploadedAtLastReview = connectedPeer.Monitor.DataBytesUploaded; connectedPeer.BytesDownloadedAtLastReview = connectedPeer.Monitor.DataBytesDownloaded; //If the peer has been unchoked for longer than one review period, unset FirstReviewPeriod if (timeUnchoked >= minimumTimeBetweenReviews) { connectedPeer.FirstReviewPeriod = false; } } } //Now sort the lists of peers so we are ready to reallocate them nascentPeers.Sort(Unchokeable.Seeding); candidatePeers.Sort(Unchokeable.Seeding); optimisticUnchokeCandidates.Sort(Unchokeable.Seeding); //If there is an optimistic unchoke peer and it is nascent, we should reallocate all the available slots //Otherwise, if all the slots are allocated to nascent peers, don't try an optimistic unchoke this time if (nascentPeers.Count >= Unchokeable.UploadSlots || nascentPeers.Contains(optimisticUnchokePeer)) { ReallocateSlots(Unchokeable.UploadSlots, unchokedPeers); } else { //We should reallocate all the slots but one and allocate the last slot to the next optimistic unchoke peer ReallocateSlots(Unchokeable.UploadSlots - 1, unchokedPeers); //In case we don't find a suitable peer, make the optimistic unchoke peer null PeerId oup = optimisticUnchokeCandidates.GetOUPeer(); if (oup != null) { Unchoke(oup); optimisticUnchokePeer = oup; } } //Finally, deallocate (any) remaining peers from the three lists while (nascentPeers.MorePeers) { PeerId nextPeer = nascentPeers.GetNextPeer(); if (!nextPeer.AmChoking) { Choke(nextPeer); } } while (candidatePeers.MorePeers) { PeerId nextPeer = candidatePeers.GetNextPeer(); if (!nextPeer.AmChoking) { Choke(nextPeer); } } while (optimisticUnchokeCandidates.MorePeers) { PeerId nextPeer = optimisticUnchokeCandidates.GetNextPeer(); if (!nextPeer.AmChoking) { //This peer is currently unchoked, choke it unless it is the optimistic unchoke peer if (optimisticUnchokePeer == null) { //There isn't an optimistic unchoke peer Choke(nextPeer); } else if (!nextPeer.Equals(optimisticUnchokePeer)) { //This isn't the optimistic unchoke peer Choke(nextPeer); } } } }
private void ExecuteReview() { //Review current choke/unchoke position and adjust as necessary //Start by populating the lists of peers, then allocate available slots oberving the unchoke limit //Clear the lists to start with nascentPeers.Clear(); candidatePeers.Clear(); optimisticUnchokeCandidates.Clear(); //No review needed or disabled by the torrent settings /////???Remove when working ////Log peer status - temporary //if (isLogging) //{ // StringBuilder logEntry = new StringBuilder(1000); // logEntry.Append(B2YN(owningTorrent.State == TorrentState.Seeding) + timeOfLastReview.ToString() + "," + DateTime.Now.ToString() + ";"); // foreach (PeerIdInternal connectedPeer in owningTorrent.Peers.ConnectedPeers) // { // if (connectedPeer.Connection != null) // if (!connectedPeer.Peer.IsSeeder) // { // { // logEntry.Append( // B2YN(connectedPeer.Peer.IsSeeder) + // B2YN(connectedPeer.AmChoking) + // B2YN(connectedPeer.AmInterested) + // B2YN(connectedPeer.IsInterested) + // B2YN(connectedPeer.Peer.FirstReviewPeriod) + // connectedPeer.Connection.Monitor.DataBytesDownloaded.ToString() + "," + // connectedPeer.Peer.BytesDownloadedAtLastReview.ToString() + "," + // connectedPeer.Connection.Monitor.DataBytesUploaded.ToString() + "," + // connectedPeer.Peer.BytesUploadedAtLastReview.ToString() + "," + // connectedPeer.Peer.Location); // DateTime? lastUnchoked = connectedPeer.Peer.LastUnchoked; // if (lastUnchoked.HasValue) // logEntry.Append( // "," + // lastUnchoked.ToString() + "," + // SecondsBetween(lastUnchoked.Value, DateTime.Now).ToString()); // logEntry.Append(";"); // } // } // } // Send2Log(logEntry.ToString()); //} //Scan the peers building the lists as we go and count number of unchoked peers int unchokedPeers = 0; foreach (PeerId connectedPeer in owningTorrent.Peers.ConnectedPeers) { if (connectedPeer.Connection != null) { if (!connectedPeer.Peer.IsSeeder) { //Determine common values for use in this routine double timeSinceLastReview = SecondsBetween(timeOfLastReview, DateTime.Now); double timeUnchoked = 0; if (!connectedPeer.AmChoking) { timeUnchoked = SecondsBetween(connectedPeer.LastUnchoked.Value, DateTime.Now); unchokedPeers++; } long bytesTransferred = 0; if (!isDownloading) { //We are seeding the torrent; determine bytesTransferred as bytes uploaded bytesTransferred = connectedPeer.Monitor.DataBytesUploaded - connectedPeer.BytesUploadedAtLastReview; } else { //The peer is unchoked and we are downloading the torrent; determine bytesTransferred as bytes downloaded bytesTransferred = connectedPeer.Monitor.DataBytesDownloaded - connectedPeer.BytesDownloadedAtLastReview; } //Reset review up and download rates to zero; peers are therefore non-responders unless we determine otherwise connectedPeer.LastReviewDownloadRate = 0; connectedPeer.LastReviewUploadRate = 0; if (!connectedPeer.AmChoking && (timeUnchoked < minimumTimeBetweenReviews || (connectedPeer.FirstReviewPeriod && bytesTransferred > 0))) { //The peer is unchoked but either it has not been unchoked for the warm up interval, // or it is the first full period and only just started transferring data nascentPeers.Add(connectedPeer); } else if ((timeUnchoked >= minimumTimeBetweenReviews) && bytesTransferred > 0) //The peer is unchoked, has been for the warm up period and has transferred data in the period { //Add to peers that are candidates for unchoking based on their performance candidatePeers.Add(connectedPeer); //Calculate the latest up/downloadrate connectedPeer.LastReviewUploadRate = (connectedPeer.Monitor.DataBytesUploaded - connectedPeer.BytesUploadedAtLastReview) / timeSinceLastReview; connectedPeer.LastReviewDownloadRate = (connectedPeer.Monitor.DataBytesDownloaded - connectedPeer.BytesDownloadedAtLastReview) / timeSinceLastReview; } else if (isDownloading && connectedPeer.IsInterested && connectedPeer.AmChoking && bytesTransferred > 0) //A peer is optimistically unchoking us. Take the maximum of their current download rate and their download rate over the // review period since they might have only just unchoked us and we don't want to miss out on a good opportunity. Upload // rate is less important, so just take an average over the period. { //Add to peers that are candidates for unchoking based on their performance candidatePeers.Add(connectedPeer); //Calculate the latest up/downloadrate connectedPeer.LastReviewUploadRate = (connectedPeer.Monitor.DataBytesUploaded - connectedPeer.BytesUploadedAtLastReview) / timeSinceLastReview; connectedPeer.LastReviewDownloadRate = Math.Max((connectedPeer.Monitor.DataBytesDownloaded - connectedPeer.BytesDownloadedAtLastReview) / timeSinceLastReview, connectedPeer.Monitor.DownloadSpeed); } else if (connectedPeer.IsInterested) { //All other interested peers are candidates for optimistic unchoking optimisticUnchokeCandidates.Add(connectedPeer); } //Remember the number of bytes up and downloaded for the next review connectedPeer.BytesUploadedAtLastReview = connectedPeer.Monitor.DataBytesUploaded; connectedPeer.BytesDownloadedAtLastReview = connectedPeer.Monitor.DataBytesDownloaded; //If the peer has been unchoked for longer than one review period, unset FirstReviewPeriod if (timeUnchoked >= minimumTimeBetweenReviews) { connectedPeer.FirstReviewPeriod = false; } } } } // Send2Log(nascentPeers.Count.ToString() + "," + candidatePeers.Count.ToString() + "," + optimisticUnchokeCandidates.Count.ToString()); //Now sort the lists of peers so we are ready to reallocate them nascentPeers.Sort(owningTorrent.State == TorrentState.Seeding); candidatePeers.Sort(owningTorrent.State == TorrentState.Seeding); optimisticUnchokeCandidates.Sort(owningTorrent.State == TorrentState.Seeding); // if (isLogging) // { // string x = ""; // while (optimisticUnchokeCandidates.MorePeers) // x += optimisticUnchokeCandidates.GetNextPeer().Location + ";"; // Send2Log(x); // optimisticUnchokeCandidates.StartScan(); // } //If there is an optimistic unchoke peer and it is nascent, we should reallocate all the available slots //Otherwise, if all the slots are allocated to nascent peers, don't try an optimistic unchoke this time if (nascentPeers.Count >= owningTorrent.Settings.UploadSlots || nascentPeers.Includes(optimisticUnchokePeer)) { ReallocateSlots(owningTorrent.Settings.UploadSlots, unchokedPeers); } else { //We should reallocate all the slots but one and allocate the last slot to the next optimistic unchoke peer ReallocateSlots(owningTorrent.Settings.UploadSlots - 1, unchokedPeers); //In case we don't find a suitable peer, make the optimistic unchoke peer null PeerId oup = optimisticUnchokeCandidates.GetOUPeer(); if (oup != null) { // Send2Log("OUP: " + oup.Location); Unchoke(oup); optimisticUnchokePeer = oup; } } //Finally, deallocate (any) remaining peers from the three lists while (nascentPeers.MorePeers) { PeerId nextPeer = nascentPeers.GetNextPeer(); if (!nextPeer.AmChoking) { Choke(nextPeer); } } while (candidatePeers.MorePeers) { PeerId nextPeer = candidatePeers.GetNextPeer(); if (!nextPeer.AmChoking) { Choke(nextPeer); } } while (optimisticUnchokeCandidates.MorePeers) { PeerId nextPeer = optimisticUnchokeCandidates.GetNextPeer(); if (!nextPeer.AmChoking) { //This peer is currently unchoked, choke it unless it is the optimistic unchoke peer if (optimisticUnchokePeer == null) { //There isn't an optimistic unchoke peer Choke(nextPeer); } else if (!nextPeer.Equals(optimisticUnchokePeer)) { //This isn't the optimistic unchoke peer Choke(nextPeer); } } } timeOfLastReview = DateTime.Now; reviewsExecuted++; }
public override void CancelRequests(PeerId peer) { CancelWhere(delegate(Block b) { return(peer.Equals(b.RequestedOff)); }); }