public static BlockInfo?PickPiece(this IPiecePicker picker, IPeer peer, ReadOnlyBitField available, IReadOnlyList <IPeer> otherPeers)
        {
            Span <BlockInfo> buffer = stackalloc BlockInfo[1];
            var result = picker.PickPiece(peer, available, otherPeers, 0, available.Length - 1, buffer);

            return(result == 1 ? (BlockInfo?)buffer[0] : null);
        }
예제 #2
0
        internal FastResume(BEncodedDictionary dict)
        {
            CheckVersion(dict);
            CheckContent(dict, InfoHashKey);
            CheckContent(dict, BitfieldKey);
            CheckContent(dict, BitfieldLengthKey);

            // BEP52: Support backwards/forwards compatibility
            var infoHash = InfoHash.FromMemory(((BEncodedString)dict[InfoHashKey]).AsMemory());

            if (infoHash.Span.Length == 20)
            {
                InfoHashes = InfoHashes.FromV1(infoHash);
            }
            else
            {
                InfoHashes = InfoHashes.FromV2(infoHash);
            }

            var data = ((BEncodedString)dict[BitfieldKey]).Span;

            Bitfield = new ReadOnlyBitField(data, (int)((BEncodedNumber)dict[BitfieldLengthKey]).Number);

            // If we're loading up an older version of the FastResume data then we
            if (dict.ContainsKey(UnhashedPiecesKey))
            {
                data           = ((BEncodedString)dict[UnhashedPiecesKey]).Span;
                UnhashedPieces = new ReadOnlyBitField(data, Bitfield.Length);
            }
            else
            {
                UnhashedPieces = new ReadOnlyBitField(Bitfield.Length);
            }
        }
예제 #3
0
        public override int PickPiece(IPeer peer, ReadOnlyBitField available, IReadOnlyList <IPeer> otherPeers, int startIndex, int endIndex, Span <BlockInfo> requests)
        {
            if (available.AllFalse)
            {
                return(0);
            }

            if (requests.Length > 1)
            {
                return(base.PickPiece(peer, available, otherPeers, startIndex, endIndex, requests));
            }

            GenerateRarestFirst(available, otherPeers);

            while (rarest.Count > 0)
            {
                BitField current   = rarest.Pop();
                int      requested = base.PickPiece(peer, current, otherPeers, startIndex, endIndex, requests);
                spares.Push(current);

                if (requested > 0)
                {
                    return(requested);
                }
            }

            return(0);
        }
        public static BlockInfo?PickPiece(this IPiecePicker picker, IPeer peer, ReadOnlyBitField available)
        {
            Span <BlockInfo> buffer = stackalloc BlockInfo[1];
            var picked = picker.PickPiece(peer, available, Array.Empty <IPeer> (), 0, available.Length - 1, buffer);

            return(picked == 1 ? (BlockInfo?)buffer[0] : null);
        }
        public override bool IsInteresting(IPeer peer, ReadOnlyBitField bitfield)
        {
            if (temp is null || allPrioritisedPieces is null)
            {
                return(false);
            }

            if (ShouldRebuildSelectors())
            {
                BuildSelectors();
            }

            if (files.Count == 1 || files.TrueForAll(AllSamePriority))
            {
                if (files[0].Priority == Priority.DoNotDownload)
                {
                    return(false);
                }
                return(base.IsInteresting(peer, bitfield));
            }
            else
            {
                temp.From(allPrioritisedPieces).And(bitfield);
                if (temp.AllFalse)
                {
                    return(false);
                }
                return(base.IsInteresting(peer, temp));
            }
        }
예제 #6
0
        internal FastResume(InfoHashes infoHashes, ReadOnlyBitField bitfield, ReadOnlyBitField unhashedPieces)
        {
            InfoHashes     = infoHashes ?? throw new ArgumentNullException(nameof(infoHashes));
            Bitfield       = new ReadOnlyBitField(bitfield);
            UnhashedPieces = new ReadOnlyBitField(unhashedPieces);

            for (int i = 0; i < Bitfield.Length; i++)
            {
                if (bitfield[i] && unhashedPieces[i])
                {
                    throw new ArgumentException($"The bitfield is set to true at index {i} but that piece is marked as unhashed.");
                }
            }
        }
        public async Task SaveLoadFastResume()
        {
            await Manager.HashCheckAsync(false);

            Manager.MutableBitField.SetAll(true).Set(0, false);
            Manager.UnhashedPieces.SetAll(false).Set(0, true);

            var origUnhashed = new ReadOnlyBitField(Manager.UnhashedPieces);
            var origBitfield = new ReadOnlyBitField(Manager.Bitfield);
            await Manager.LoadFastResumeAsync(await Manager.SaveFastResumeAsync());

            Assert.IsTrue(origUnhashed.SequenceEqual(Manager.UnhashedPieces), "#3");
            Assert.IsTrue(origBitfield.SequenceEqual(Manager.Bitfield), "#4");
        }
예제 #8
0
        public override int PickPiece(IPeer peer, ReadOnlyBitField available, IReadOnlyList <IPeer> otherPeers, int startIndex, int endIndex, Span <BlockInfo> requests)
        {
            // Invert 'bitfield' and AND it with the peers bitfield
            // Any pieces which are 'true' in the bitfield will not be downloaded
            if (Bitfield.AllFalse)
            {
                return(base.PickPiece(peer, available, otherPeers, startIndex, endIndex, requests));
            }

            Temp.From(available).NAnd(Bitfield);
            if (Temp.AllFalse)
            {
                return(0);
            }

            return(base.PickPiece(peer, Temp, otherPeers, startIndex, endIndex, requests));
        }
        public override int PickPiece(IPeer peer, ReadOnlyBitField available, IReadOnlyList <IPeer> otherPeers, int startIndex, int endIndex, Span <BlockInfo> requests)
        {
            // Fast Path - the peer has nothing to offer
            if (available.AllFalse || temp == null)
            {
                return(0);
            }

            // Rebuild if any file changed priority
            if (ShouldRebuildSelectors())
            {
                BuildSelectors();
            }

            // Fast Path - As 'files' has been sorted highest priority first, all files
            // must be set to DoNotDownload if this is true.
            if (files[0].Priority == Priority.DoNotDownload)
            {
                return(0);
            }

            // Fast Path - If it's a single file, or if all the priorities are the same,
            // then we can just pick normally. No prioritisation is needed.
            if (files.Count == 1 || files.TrueForAll(AllSamePriority))
            {
                return(base.PickPiece(peer, available, otherPeers, startIndex, endIndex, requests));
            }

            // Start with the highest priority and work our way down.
            for (int i = 0; i < prioritised.Count; i++)
            {
                temp.From(prioritised[i]).And(available);
                if (!temp.AllFalse)
                {
                    var result = base.PickPiece(peer, temp, otherPeers, startIndex, endIndex, requests);
                    if (result > 0)
                    {
                        return(result);
                    }
                }
            }

            // None of the pieces from files marked as downloadable were available.
            return(0);
        }
        public override int PickPiece(IPeer peer, ReadOnlyBitField available, IReadOnlyList <IPeer> otherPeers, int startIndex, int endIndex, Span <BlockInfo> requests)
        {
            if (available.AllFalse)
            {
                return(0);
            }

            // If there's only one piece to choose then there isn't any midpoint.
            if (endIndex - startIndex < 2 || requests.Length > 1)
            {
                return(base.PickPiece(peer, available, otherPeers, startIndex, endIndex, requests));
            }

            // If there are two or more pieces to choose, ensure we always start *at least* one
            // piece beyond the start index.
            int midpoint  = Random.Next(startIndex + 1, endIndex);
            var requested = base.PickPiece(peer, available, otherPeers, midpoint, endIndex, requests);

            return(requested > 0 ? requested : base.PickPiece(peer, available, otherPeers, startIndex, midpoint, requests));
        }
예제 #11
0
        void GenerateRarestFirst(ReadOnlyBitField peerBitfield, IReadOnlyList <IPeer> otherPeers)
        {
            // Move anything in the rarest buffer into the spares
            while (rarest.Count > 0)
            {
                spares.Push(rarest.Pop());
            }

            BitField current = (spares.Count > 0 ? spares.Pop() : new BitField(peerBitfield.Length)).From(peerBitfield);

            // Store this bitfield as the first iteration of the Rarest First algorithm.
            rarest.Push(current);

            // Get a cloned copy of the bitfield and begin iterating to find the rarest pieces
            for (int i = 0; i < otherPeers.Count; i++)
            {
                if (otherPeers[i].BitField.AllTrue)
                {
                    continue;
                }

                current = (spares.Count > 0 ? spares.Pop() : new BitField(current.Length)).From(current);

                // currentBitfield = currentBitfield & (!otherBitfield)
                // This calculation finds the pieces this peer has that other peers *do not* have.
                // i.e. the rarest piece.
                current.NAnd(otherPeers[i].BitField);

                // If the bitfield now has no pieces we've completed our task
                if (current.AllFalse)
                {
                    spares.Push(current);
                    break;
                }

                // Otherwise push the bitfield on the stack and clone it and iterate again.
                rarest.Push(current);
            }
        }
 /// <summary>
 /// Creates a new BitfieldMessage
 /// </summary>
 /// <param name="bitfield">The bitfield to use</param>
 public BitfieldMessage(ReadOnlyBitField bitfield)
 {
     BitField  = bitfield;
     CanDecode = false;
 }
 public static int PickPiece(this IPiecePicker picker, IPeer peer, ReadOnlyBitField available, IReadOnlyList <IPeer> otherPeers, Span <BlockInfo> requests)
 {
     return(picker.PickPiece(peer, available, otherPeers, 0, available.Length - 1, requests));
 }
예제 #14
0
 public override bool IsInteresting(IPeer peer, ReadOnlyBitField bitfield)
 => !Temp.From(bitfield).NAnd(Bitfield).AllFalse &&
 base.IsInteresting(peer, Temp);
예제 #15
0
 public IgnoringPicker(ReadOnlyBitField bitfield, IPiecePicker picker)
     : base(picker)
 {
     Bitfield = bitfield;
     Temp     = new BitField(bitfield.Length);
 }
 public InitialSeedingMode(TorrentManager manager, DiskManager diskManager, ConnectionManager connectionManager, EngineSettings settings)
     : base(manager, diskManager, connectionManager, settings, new InitialSeedUnchoker(manager))
 {
     zero = new BitField(manager.Bitfield.Length);
 }