BlockInfo?GetFromList(IPeer peer, BitField bitfield, IList <int> pieces) { if (!peer.SupportsFastPeer || !ClientEngine.SupportsFastPeer) { return(null); } for (int i = 0; i < pieces.Count; i++) { int index = pieces[i]; // A peer should only suggest a piece he has, but just in case. if (index >= bitfield.Length || !bitfield[index] || AlreadyRequested(index)) { continue; } pieces.RemoveAt(i); var p = new Piece(index, TorrentData.BytesPerPiece(index)); requests.Add(p); return(p.Blocks[0].CreateRequest(peer)); } return(null); }
IList <BlockInfo> GetStandardRequest(IPeer peer, BitField current, int startIndex, int endIndex, int count) { int piecesNeeded = (count * Piece.BlockSize) / TorrentData.PieceLength; if ((count * Piece.BlockSize) % TorrentData.PieceLength != 0) { piecesNeeded++; } int checkIndex = CanRequest(current, startIndex, endIndex, ref piecesNeeded); // Nothing to request. if (checkIndex == -1) { return(null); } var bundle = new List <BlockInfo> (count); for (int i = 0; bundle.Count < count && i < piecesNeeded; i++) { // Request the piece var p = new Piece(checkIndex + i, TorrentData.BytesPerPiece(checkIndex + i)); requests.Add(p); for (int j = 0; j < p.Blocks.Length && bundle.Count < count; j++) { bundle.Add(p.Blocks[j].CreateRequest(peer)); } } return(bundle); }
BlockInfo?ContinueExistingRequest(IPeer peer, int startIndex, int endIndex, int maxDuplicateRequests, bool allowAbandoned, bool allowAny) { for (int req = 0; req < requests.Count; req++) { Piece p = requests[req]; int index = p.Index; if (p.AllBlocksRequested || index < startIndex || index > endIndex || !peer.BitField[index]) { continue; } // 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 (allowAny || (allowAbandoned && p.Abandoned) || peer == p.Blocks[0].RequestedOff) { for (int i = 0; i < p.BlockCount; i++) { if (!p.Blocks[i].Received && !p.Blocks[i].Requested) { return(p.Blocks[i].CreateRequest(peer)); } } } } // If all blocks have been requested at least once and we're allowed more than 1 request then // let's try and issue a duplicate! for (int duplicate = 1; duplicate < maxDuplicateRequests; duplicate++) { for (int req = 0; req < requests.Count; req++) { Piece primaryPiece = requests[req]; if (primaryPiece.Index < startIndex || primaryPiece.Index > endIndex || !peer.BitField[primaryPiece.Index]) { continue; } if (!duplicates.TryGetValue(primaryPiece.Index, out List <Piece> extraPieces)) { duplicates[primaryPiece.Index] = extraPieces = new List <Piece> (); } if (extraPieces.Count < duplicate) { var newPiece = new Piece(primaryPiece.Index, TorrentData.BytesPerPiece(primaryPiece.Index)); for (int i = 0; i < primaryPiece.BlockCount; i++) { if (primaryPiece.Blocks[i].Received) { newPiece.Blocks[i].TrySetReceived(primaryPiece.Blocks[i].RequestedOff); } } extraPieces.Add(newPiece); } for (int extraPieceIndex = 0; extraPieceIndex < extraPieces.Count; extraPieceIndex++) { var extraPiece = extraPieces[extraPieceIndex]; for (int i = 0; i < extraPiece.BlockCount; i++) { if (!extraPiece.Blocks[i].Requested && !HasAlreadyRequestedBlock(primaryPiece, extraPieces, peer, i)) { return(extraPiece.Blocks[i].CreateRequest(peer)); } } } } } // If we get here it means all the blocks in the pieces being downloaded by the peer are already requested return(null); }