diff --git a/libi2pd_client/Torrents.cpp b/libi2pd_client/Torrents.cpp index 284ea7a4..69a984a7 100644 --- a/libi2pd_client/Torrents.cpp +++ b/libi2pd_client/Torrents.cpp @@ -205,32 +205,32 @@ namespace torrents } } - void Piece::Dump (const std::string& fullPath, size_t offset) + void Piece::Dump (PieceFileFragment&& fragment) { m_IsSending = true; - if (m_Data) + if (m_Data && fragment.fragmentOffset + fragment.fragmentSize <= m_Size) { - std::fstream f(fullPath, std::ios::binary | std::ios::in | std::ios::out ); + std::fstream f(fragment.fullFilePath, std::ios::binary | std::ios::in | std::ios::out ); if (f) { - f.seekp (offset, std::ios::beg); - f.write ((const char *)m_Data, m_Size); - LogPrint (eLogDebug, "Torrents: Saved bytes ", offset, " - ", offset + m_Size - 1, " to ", fullPath); + f.seekp (fragment.fileOffset, std::ios::beg); + f.write ((const char *)m_Data + fragment.fragmentOffset, fragment.fragmentSize); + LogPrint (eLogDebug, "Torrents: Saved bytes ", fragment.fileOffset, " - ", fragment.fileOffset + fragment.fragmentSize - 1, " to ", fragment.fullFilePath); } } m_IsSending = false; } - bool Piece::Load (const std::string& fullPath, size_t offset) + bool Piece::Load (PieceFileFragment&& fragment) { - if (m_Data) return true; - std::ifstream f(fullPath, std::ifstream::binary); + if (fragment.fragmentOffset + fragment.fragmentSize > m_Size) return false; + std::ifstream f(fragment.fullFilePath, std::ifstream::binary); if (f) { - m_Data = new uint8_t[m_Size]; - f.seekg (offset, std::ios::beg); - f.read ((char *)m_Data, m_Size); - LogPrint (eLogDebug, "Torrents: Loaded bytes ", offset, " - ", offset + m_Size - 1, " from ", fullPath); + if (!m_Data) m_Data = new uint8_t[m_Size]; + f.seekg (fragment.fileOffset, std::ios::beg); + f.read ((char *)m_Data + fragment.fragmentOffset, fragment.fragmentSize); + LogPrint (eLogDebug, "Torrents: Loaded bytes ", fragment.fileOffset, " - ", fragment.fileOffset + fragment.fragmentSize - 1, " from ", fragment.fullFilePath); } else return false; @@ -987,13 +987,13 @@ namespace torrents { if (piece.VerifyHash ()) { - auto path = GetTorrentsTunnel ()->GetTorrentFilePath (m_Torrent->GetName () + ".part"); + PieceFileFragment fragment{ GetTorrentsTunnel ()->GetTorrentFilePath (m_Torrent->GetName () + ".part"), + index*m_Torrent->GetPieceLength (), 0, piece.GetSize () }; auto resumePath = GetTorrentsTunnel ()->GetTorrentFilePath (m_Torrent->GetName () + ".resume"); - auto offset = index*m_Torrent->GetPieceLength (); boost::asio::post (GetTorrentsTunnel ()->GetDiskIOService (), - [&piece, path, resumePath, offset, torrent = m_Torrent]() // piece belongs to torrent + [&piece, fragment = std::move (fragment), resumePath, torrent = m_Torrent]() mutable // piece belongs to torrent { - piece.Dump (path, offset); + piece.Dump (std::move (fragment)); torrent->SaveTorrentResumeFile (resumePath); }); // send have @@ -1067,21 +1067,28 @@ namespace torrents else if (!SendRequestedBlock ({index, offset, length})) // block was not sent { // try to load from file - auto path = GetTorrentsTunnel ()->GetTorrentFilePath (m_Torrent->GetName () + (m_Torrent->IsComplete () ? "" : ".part")); + PieceFileFragment fragment{ GetTorrentsTunnel ()->GetTorrentFilePath ( + m_Torrent->GetName () + (m_Torrent->IsComplete () ? "" : ".part")), + index*m_Torrent->GetPieceLength (), 0, piece.GetSize () }; + RequestedBlock requestBlock{index, offset, length}; boost::asio::post (GetTorrentsTunnel ()->GetDiskIOService (), - [&piece, path, index, offset, length, torrent = m_Torrent, s = shared_from_this ()]() // piece belongs to torrent + [&piece, fragment = std::move (fragment), requestBlock = std::move(requestBlock), + torrent = m_Torrent, s = shared_from_this ()]() mutable// piece belongs to torrent { piece.SetIsSending (true); - if (piece.Load (path, index*torrent->GetPieceLength ())) + if (piece.Load (std::move (fragment))) { - boost::asio::post (s->GetTorrentsTunnel ()->GetService (), - [requestedBlock = RequestedBlock{index, offset, length}, s]() - { - if (s->m_NumPieces < MAX_NUM_PIECES) - s->SendRequestedBlock (requestedBlock); - else - s->m_IncomingRequestsQueue.emplace_back (std::move (requestedBlock)); - }); + if (piece.VerifyHash ()) + boost::asio::post (s->GetTorrentsTunnel ()->GetService (), + [requestedBlock = std::move (requestBlock), s]() + { + if (s->m_NumPieces < MAX_NUM_PIECES) + s->SendRequestedBlock (requestedBlock); + else + s->m_IncomingRequestsQueue.emplace_back (std::move (requestedBlock)); + }); + else + LogPrint (eLogError, "Torrent: Corrupted piece ", requestBlock.index, " from ", fragment.fullFilePath); } piece.SetIsSending (false); }); diff --git a/libi2pd_client/Torrents.h b/libi2pd_client/Torrents.h index d0e8f156..20a2a3d3 100644 --- a/libi2pd_client/Torrents.h +++ b/libi2pd_client/Torrents.h @@ -73,6 +73,14 @@ namespace torrents eMessageTypeHaveNone = 15 }; + struct PieceFileFragment // fragment to save to/load from file + { + std::string fullFilePath; + size_t fileOffset = 0; + size_t fragmentOffset = 0; // from start of piece + size_t fragmentSize = 0; + }; + class PeerConnection; class Piece final { @@ -99,8 +107,8 @@ namespace torrents void SetNumPeers (size_t numPeers) { m_NumPeers = numPeers; } void BlockReceived (const uint8_t * block, size_t len, size_t offset); - void Dump (const std::string& fullPath, size_t offset); - bool Load (const std::string& fullPath, size_t offset); + void Dump (PieceFileFragment&& fragment); + bool Load (PieceFileFragment&& fragment); const uint8_t * GetData () const { return m_Data; } size_t GetSize () const { return m_Size; } bool HasBlock (size_t offset) const;