예제 #1
0
        public override bool IsInteresting(BitField bitfield)
        {
            if (ShouldRebuildSelectors())
            {
                BuildSelectors();
            }

            if (files.Count == 1 || files.TrueForAll(AllSamePriority))
            {
                if (files[0].Priority == Priority.DoNotDownload)
                {
                    return(false);
                }
                return(base.IsInteresting(bitfield));
            }
            else
            {
                temp.From(allPrioritisedPieces).And(bitfield);
                if (temp.AllFalse)
                {
                    return(false);
                }
                return(base.IsInteresting(temp));
            }
        }
예제 #2
0
 public override MessageBundle PickPiece(PeerId id, BitField peerBitfield, List <PeerId> otherPeers, int count, int startIndex, int endIndex)
 {
     // Invert 'bitfield' and AND it with the peers bitfield
     // Any pieces which are 'true' in the bitfield will not be downloaded
     temp.From(peerBitfield).NAnd(bitfield);
     if (temp.AllFalse)
     {
         return(null);
     }
     return(base.PickPiece(id, temp, otherPeers, count, startIndex, endIndex));
 }
예제 #3
0
 public override IList <PieceRequest> PickPiece(IPieceRequester peer, BitField available, IReadOnlyList <IPieceRequester> otherPeers, int count, int startIndex, int endIndex)
 {
     // Invert 'bitfield' and AND it with the peers bitfield
     // Any pieces which are 'true' in the bitfield will not be downloaded
     Temp.From(available).NAnd(Bitfield);
     if (Temp.AllFalse)
     {
         return(null);
     }
     return(base.PickPiece(peer, Temp, otherPeers, count, startIndex, endIndex));
 }
        public void LoadFastResume(FastResume data)
        {
            Check.Data(data);
            CheckMetadata();
            if (State != TorrentState.Stopped)
            {
                throw new InvalidOperationException("Can only load FastResume when the torrent is stopped");
            }
            if (InfoHash != data.Infohash || torrent.Pieces.Count != data.Bitfield.Length)
            {
                throw new ArgumentException("The fast resume data does not match this torrent", "data");
            }

            bitfield.From(data.Bitfield);
            for (int i = 0; i < torrent.Pieces.Count; i++)
            {
                RaisePieceHashed(new PieceHashedEventArgs(this, i, bitfield[i]));
            }

            this.hashChecked = true;

            if (data.Priorities != null)
            {
                if (data.Priorities.Length != torrent.Files.Length)
                {
                    throw new ArgumentException("The fast resume data does not match this torrent", "data");
                }

                for (var i = 0; i < data.Priorities.Length; i++)
                {
                    torrent.Files[i].Priority = data.Priorities[i];
                }
            }
        }
예제 #5
0
        public override MessageBundle PickPiece(PeerId id, BitField peerBitfield, List <PeerId> otherPeers, int count, int startIndex, int endIndex)
        {
            // Fast Path - the peer has nothing to offer
            if (peerBitfield.AllFalse)
            {
                return(null);
            }

            if (files.Count == 1)
            {
                if (files[0].File.Priority == Priority.DoNotDownload)
                {
                    return(null);
                }
                else
                {
                    return(base.PickPiece(id, peerBitfield, otherPeers, count, startIndex, endIndex));
                }
            }

            files.Sort();

            // Fast Path - all the files have been set to DoNotDownload
            if (files[0].File.Priority == Priority.DoNotDownload)
            {
                return(null);
            }

            // Fast Path - If all the files are the same priority, call straight into the base picker
            if (files.TrueForAll(AllSamePriority))
            {
                return(base.PickPiece(id, peerBitfield, otherPeers, count, startIndex, endIndex));
            }

            temp.From(files[0].Selector);
            for (int i = 1; i < files.Count && files[i].File.Priority != Priority.DoNotDownload; i++)
            {
                if (files[i].File.Priority != files[i - 1].File.Priority)
                {
                    temp.And(peerBitfield);
                    if (!temp.AllFalse)
                    {
                        MessageBundle message = base.PickPiece(id, temp, otherPeers, count, startIndex, endIndex);
                        if (message != null)
                        {
                            return(message);
                        }
                        temp.SetAll(false);
                    }
                }

                temp.Or(files[i].Selector);
            }

            if (temp.AllFalse || temp.And(peerBitfield).AllFalse)
            {
                return(null);
            }
            return(base.PickPiece(id, temp, otherPeers, count, startIndex, endIndex));
        }
예제 #6
0
        void BuildSelectors()
        {
            files.Sort();
            prioritised.Clear();

            // If it's a single file (or they're all the same priority) then we
            // won't need prioritised bitfields or a bitfield to check the
            // interested status. Set the IsInteresting bitfield to false so
            // it's always in a predictable state and bail out.
            //
            // If all files are set to DoNotDownload we'll bail out early here.
            if (files.Count == 1 || files.TrueForAll(AllSamePriority))
            {
                allPrioritisedPieces.SetAll(false);
                return;
            }

            // At least one file is not set to DoNotDownload
            temp.SetAll(false);
            temp.SetTrue((files[0].File.StartPieceIndex, files[0].File.EndPieceIndex));
            allPrioritisedPieces.From(temp);
            for (int i = 1; i < files.Count && files[i].Priority != Priority.DoNotDownload; i++)
            {
                allPrioritisedPieces.SetTrue((files[i].File.StartPieceIndex, files[i].File.EndPieceIndex));

                if (files[i].Priority == files[i - 1].Priority)
                {
                    temp.SetTrue((files[i].File.StartPieceIndex, files[i].File.EndPieceIndex));
                }
                else if (!temp.AllFalse)
                {
                    prioritised.Add(temp.Clone());
                    temp.SetAll(false);
                    temp.SetTrue((files[i].File.StartPieceIndex, files[i].File.EndPieceIndex));
                }
            }

            if (!temp.AllFalse)
            {
                prioritised.Add(temp.Clone());
            }
        }
예제 #7
0
        void GenerateRarestFirst(BitField peerBitfield, IReadOnlyList <IPieceRequester> otherPeers)
        {
            // Move anything in the rarest buffer into the spares
            while (rarest.Count > 0)
            {
                spares.Push(rarest.Pop());
            }

            BitField current = DequeueSpare();

            current.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 = DequeueSpare().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);
            }
        }
예제 #8
0
        public void LoadFastResume(FastResume data)
        {
            Check.Data(data);
            CheckMetadata();
            if (State != TorrentState.Stopped)
            {
                throw new InvalidOperationException("Can only load FastResume when the torrent is stopped");
            }
            if (InfoHash != data.Infohash || _torrent.Pieces.Count != data.Bitfield.Length)
            {
                throw new ArgumentException("The fast resume data does not match this torrent", "fastResumeData");
            }

            _bitfield.From(data.Bitfield);
            for (var i = 0; i < _torrent.Pieces.Count; i++)
            {
                RaisePieceHashed(new PieceHashedEventArgs(this, i, _bitfield[i]));
            }

            _hashChecked = true;
        }
예제 #9
0
 public void From_XXL()
 => Temp_XXL.From(BitField_XXL);
예제 #10
0
 public void From_M()
 => Temp_M.From(BitField_M);
예제 #11
0
 public void From_S()
 => Temp_S.From(BitField_S);
예제 #12
0
 public void NAnd()
 => Temp_L.From(BitField_L).NAnd(Selector_L);
예제 #13
0
        void TryAdvertisePiece(ChokeData data)
        {
            // If we are seeding to this peer and we have a peer waiting to unchoke
            // don't advertise more data
            if (!data.Peer.AmChoking && PendingUnchoke)
            {
                return;
            }

            int advertised = advertisedPieces.FindAll(p => p.Peer == data.Peer).Count;
            int max        = MaxAdvertised;

            if (Manager.UploadingTo < Manager.Settings.UploadSlots)
            {
                max = MaxAdvertised;
            }
            else if (data.ShareRatio < 0.25)
            {
                max = 1;
            }
            else if (data.ShareRatio < 0.35)
            {
                max = 2;
            }
            else if (data.ShareRatio < 0.50)
            {
                max = 3;
            }
            else
            {
                max = MaxAdvertised;
            }

            if (advertised >= max)
            {
                return;
            }

            // List of pieces *not* in the swarm
            temp.From(bitfield).Not();

            // List of pieces that he wants that aren't in the swarm
            temp.NAnd(data.Peer.BitField);

            // Ignore all the pieces we've already started sharing
            foreach (SeededPiece p in advertisedPieces)
            {
                temp[p.Index] = false;
            }

            int index = 0;

            while (advertised < max)
            {
                // Get the index of the first piece we can send him
                index = temp.FirstTrue(index, temp.Length);
                // Looks like he's not interested in us...
                if (index == -1)
                {
                    return;
                }

                advertised++;
                data.TotalPieces++;
                data.CurrentPieces[index] = true;
                advertisedPieces.Add(new SeededPiece(data.Peer, index, Manager.Torrent.PieceLength / Piece.BlockSize));
                data.Peer.Enqueue(new HaveMessage(index));
                index++;
            }
        }
예제 #14
0
 public override bool IsInteresting(IPeer peer, BitField bitfield)
 => !Temp.From(bitfield).NAnd(Bitfield).AllFalse &&
 base.IsInteresting(peer, Temp);