/// <summary> /// Process any piece requests in buffer and send to remote peer. /// </summary> /// <param name="cancelTask"></param> /// <returns></returns> private void PieceRequestProcessing(CancellationToken cancelTask) { try { Log.Logger.Info("Piece request processing task started..."); while (true) { Peer remotePeer = null; PieceRequest request = pieceRequestQueue.Take(cancelTask); try { Log.Logger.Info($"Piece Reqeuest {request.pieceNumber} {request.blockOffset} {request.blockSize}."); if (_manager.GetPeer(request.infoHash, request.ip, out remotePeer)) { PieceBuffer requestBuffer = GetPieceFromTorrent(remotePeer, request.pieceNumber); byte[] requestBlock = new byte[request.blockSize]; Array.Copy(requestBuffer.Buffer, (Int32)request.blockOffset, requestBlock, 0, (Int32)request.blockSize); PWP.Piece(remotePeer, request.pieceNumber, request.blockOffset, requestBlock); remotePeer.Tc.TotalBytesUploaded += request.blockSize; } } catch (Exception ex) { Log.Logger.Error(ex); // Remote peer most probably closed socket so close connection remotePeer?.Close(); } } } catch (Exception ex) { Log.Logger.Debug(ex); } Log.Logger.Info("Piece request processing task terminated."); }
internal BlockingCollection <PieceRequest> pieceRequestQueue; // Piece request read queue /// <summary> /// Read/Write piece buffers to/from torrent on disk. /// </summary> /// <param name="tc"></param> /// <param name="transferBuffer"></param> /// <param name="read"></param> /// <summary> private void TransferPiece(TorrentContext tc, PieceBuffer transferBuffer, bool read) { int bytesTransferred = 0; UInt64 startOffset = transferBuffer.Number * tc.pieceLength; UInt64 endOffset = startOffset + transferBuffer.Length; foreach (var file in tc.filesToDownload) { if ((startOffset <= (file.offset + file.length)) && (file.offset <= endOffset)) { UInt64 startTransfer = Math.Max(startOffset, file.offset); UInt64 endTransfer = Math.Min(endOffset, file.offset + file.length); using (Stream stream = new FileStream(file.name, FileMode.Open)) { stream.Seek((Int64)(startTransfer - file.offset), SeekOrigin.Begin); if (read) { stream.Read(transferBuffer.Buffer, (Int32)(startTransfer % tc.pieceLength), (Int32)(endTransfer - startTransfer)); } else { stream.Write(transferBuffer.Buffer, (Int32)(startTransfer % tc.pieceLength), (Int32)(endTransfer - startTransfer)); } } bytesTransferred += (Int32)(endTransfer - startTransfer); if (bytesTransferred == tc.GetPieceLength(transferBuffer.Number)) { break; } } } }
/// <summary> /// Read piece from torrent /// </summary> /// <param name="remotePeer"></param> /// <param name="pieceNumber"></param> /// <returns></returns> private PieceBuffer GetPieceFromTorrent(Peer remotePeer, UInt32 pieceNumber) { PieceBuffer pieceBuffer = new PieceBuffer(remotePeer.Tc, pieceNumber, remotePeer.Tc.GetPieceLength(pieceNumber)); Log.Logger.Debug($"Read piece ({pieceBuffer.Number}) from file."); TransferPiece(remotePeer.Tc, pieceBuffer, true); Log.Logger.Debug($"Piece ({pieceBuffer.Number}) read from file."); return(pieceBuffer); }
/// <summary> /// Task to take a queued download piece and write it away to the relevant file /// sections to which it belongs within a torrent. /// </summary> /// <param name="cancelTask"></param> /// <returns></returns> private void PieceBufferDiskWriter(CancellationToken cancelTask) { try { Log.Logger.Info("Piece Buffer disk writer task starting..."); while (true) { PieceBuffer pieceBuffer = pieceWriteQueue.Take(cancelTask); Log.Logger.Debug($"Write piece ({pieceBuffer.Number}) to file."); if (!pieceBuffer.Tc.downloadFinished.WaitOne(0)) { TransferPiece(pieceBuffer.Tc, pieceBuffer, false); pieceBuffer.Tc.TotalBytesDownloaded += pieceBuffer.Tc.GetPieceLength((pieceBuffer.Number)); Log.Logger.Info((pieceBuffer.Tc.TotalBytesDownloaded / (double)pieceBuffer.Tc.TotalBytesToDownload).ToString("0.00%")); Log.Logger.Debug($"Piece ({pieceBuffer.Number}) written to file."); if (pieceBuffer.Tc.BytesLeftToDownload() == 0) { pieceBuffer.Tc.downloadFinished.Set(); } // Make sure progress call back does not termiate the task. try { pieceBuffer.Tc.CallBack?.Invoke(pieceBuffer.Tc.CallBackData); } catch (Exception ex) { Log.Logger.Error(ex); } } } } catch (Exception ex) { Log.Logger.Error(ex); } Log.Logger.Info("Piece Buffer disk writer task terminated."); }