1010#include < stdlib.h>
1111#include < charconv>
1212#include < fstream>
13+ #include < sstream>
1314#include < functional>
1415#include " Log.h"
1516#include " FS.h"
@@ -131,8 +132,8 @@ namespace torrents
131132 memcpy (m_Hash, hash, SHA_DIGEST_LENGTH );
132133 m_Missing = BN_new ();
133134 auto d = lldiv (m_Size, REQUEST_BLOCK_SIZE );
134- int numBlocks = d.quot ;
135- if (d.rem > 0 ) d. quot ++;
135+ int numBlocks = d.quot ;
136+ if (d.rem > 0 ) numBlocks ++;
136137 // set all missing bits
137138 for (int i = 0 ; i < numBlocks; i++)
138139 BN_set_bit (m_Missing, i);
@@ -158,6 +159,36 @@ namespace torrents
158159 return !BN_is_bit_set (m_Missing, block);
159160 }
160161
162+ void Piece::BlockReceived (const uint8_t * block, size_t len, size_t offset)
163+ {
164+ if (offset + len >= m_Size) return ;
165+ if (!m_Data) m_Data = new uint8_t [m_Size];
166+ memcpy (m_Data + offset, block, len);
167+ if (m_Missing)
168+ {
169+ int block = offset/REQUEST_BLOCK_SIZE ;
170+ auto d = lldiv (len, REQUEST_BLOCK_SIZE );
171+ int numBlocks = d.quot ;
172+ if (d.rem > 0 ) numBlocks++;
173+ for (int i = 0 ; i < numBlocks; i++)
174+ BN_clear_bit (m_Missing, block + i);
175+ }
176+
177+ }
178+
179+ void Piece::Dump (const std::string& fullPath, size_t offset)
180+ {
181+ if (!m_Data) return ;
182+ std::ofstream f (fullPath, std::ifstream::binary);
183+ if (f.is_open ())
184+ {
185+ f.seekp (offset, std::ios::beg);
186+ f.write ((const char *)m_Data, m_Size);
187+ delete[] m_Data; m_Data = nullptr ;
188+ if (m_Missing) BN_free (m_Missing);
189+ }
190+ }
191+
161192 Torrent::Torrent (std::string_view buf):
162193 m_Length (0 ), m_PieceLength (0 ), m_Interval (0 )
163194 {
@@ -426,6 +457,9 @@ namespace torrents
426457 case eMessageTypeBitfield:
427458 HandleBitfieldMsg (m_ReceiveBuffer + offset + 1 , msgLen - 1 );
428459 break ;
460+ case eMessageTypePiece:
461+ HandlePieceMsg (m_ReceiveBuffer + offset + 1 , msgLen - 1 );
462+ break ;
429463 default :
430464 LogPrint (eLogWarning, " Torrents: Unexpected message type " , (int )m_ReceiveBuffer[offset], " . Ignored" );
431465 };
@@ -499,6 +533,22 @@ namespace torrents
499533 }
500534 }
501535
536+ void PeerConnection::HandlePieceMsg (const uint8_t * buf, size_t len)
537+ {
538+ if (len < 8 ) return ;
539+ uint32_t index = bufbe32toh (buf);
540+ uint32_t offset = bufbe32toh (buf + 4 );
541+ len -= 8 ;
542+ if (len && index < m_Torrent->GetNumPieces ())
543+ {
544+ Piece& piece = m_Torrent->GetPiece (index);
545+ piece.BlockReceived (buf + 8 , len, offset);
546+ if (piece.IsComplete () && piece.VerifyHash ())
547+ piece.Dump (GetTorrentsTunnel ()->GetTorrentFilePath (m_Torrent->GetName ()),
548+ index*m_Torrent->GetPieceLength ());
549+ }
550+ }
551+
502552 TorrentsTunnel::TorrentsTunnel (std::shared_ptr<i2p::client::ClientDestination> localDestination, std::string_view torrentsDir):
503553 i2p::client::I2PService (localDestination), m_TorrentsDir (torrentsDir),
504554 m_PeerID (" -I2PD-" )
@@ -540,7 +590,7 @@ namespace torrents
540590 void TorrentsTunnel::ReadTorrentFile (const std::string& path)
541591 {
542592 std::ifstream s (path, std::ifstream::binary);
543- if (s. is_open () )
593+ if (s)
544594 {
545595 s.seekg (0 ,std::ios::end);
546596 size_t len = s.tellg ();
@@ -552,6 +602,7 @@ namespace torrents
552602 auto torrent = std::make_shared<Torrent>(std::string_view{buf, len});
553603 delete[] buf;
554604 m_Torrents.emplace (torrent->GetInfoHash (), torrent);
605+ i2p::fs::CreateAndReserveFile (GetTorrentFilePath (torrent->GetName ()), torrent->GetLength ());
555606 }
556607 else
557608 LogPrint (eLogError, " Torrents: Empty file " , path);
@@ -704,5 +755,13 @@ namespace torrents
704755 LogPrint (eLogInfo, " Torrents: Can't connect to peer" );
705756 }, peer, 6881 );
706757 }
758+
759+ std::string TorrentsTunnel::GetTorrentFilePath (const std::string& filename) const
760+ {
761+ std::stringstream s (" " );
762+ s << m_TorrentsDir;
763+ i2p::fs::_ExpandPath (s, filename);
764+ return s.str ();
765+ }
707766}
708767}
0 commit comments