Beispiel #1
0
        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);
        }
Beispiel #2
0
 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);
     });
 }
Beispiel #3
0
 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);
 }
Beispiel #4
0
 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));
     });
 }
Beispiel #5
0
        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();
        }
Beispiel #6
0
        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));
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        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);
                    }
                }
            }
        }
Beispiel #9
0
        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++;
        }
Beispiel #10
0
 public override void CancelRequests(PeerId peer)
 {
     CancelWhere(delegate(Block b) { return(peer.Equals(b.RequestedOff)); });
 }