Skip to content

Commit d4448ee

Browse files
committed
handle Piece message
1 parent 64f4987 commit d4448ee

2 files changed

Lines changed: 74 additions & 7 deletions

File tree

libi2pd_client/Torrents.cpp

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
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
}

libi2pd_client/Torrents.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ namespace torrents
3535
constexpr int PEER_CONNECTION_MAX_IDLE = 3600; // in seconds
3636

3737
constexpr size_t HANDSHAKE_MSG_LENGTH = 68;
38-
3938
enum MessageType
4039
{
41-
eMessageTypeBitfield = 5
40+
eMessageTypeBitfield = 5,
41+
eMessageTypePiece = 7
4242
};
4343

4444
class Piece final
@@ -48,10 +48,13 @@ namespace torrents
4848
Piece (size_t size, const uint8_t * hash);
4949
~Piece ();
5050

51-
bool IsComplete () const { return BN_is_zero (m_Missing); }
51+
bool IsComplete () const { return !m_Missing || BN_is_zero (m_Missing); }
5252
bool VerifyHash () const;
5353
bool IsAvailable (int block) const;
5454

55+
void BlockReceived (const uint8_t * block, size_t len, size_t offset);
56+
void Dump (const std::string& fullPath, size_t offset);
57+
5558
private:
5659

5760
size_t m_Size;
@@ -70,8 +73,11 @@ namespace torrents
7073
void ParseTrackerResponse (std::string_view buf);
7174

7275
const std::string& GetName () const { return m_Name; }
76+
size_t GetLength () const { return m_Length; }
77+
size_t GetPieceLength () const { return m_PieceLength; }
7378
const InfoHash& GetInfoHash () const { return m_InfoHash; }
74-
size_t GetNumPieces () const { return m_Pieces.size (); };
79+
size_t GetNumPieces () const { return m_Pieces.size (); }
80+
Piece& GetPiece (int index) { return m_Pieces[index]; }
7581

7682
private:
7783

@@ -119,6 +125,7 @@ namespace torrents
119125
void SendHandshakeMsg ();
120126

121127
void HandleBitfieldMsg (const uint8_t * buf, size_t len);
128+
void HandlePieceMsg (const uint8_t * buf, size_t len);
122129

123130
private:
124131

@@ -143,6 +150,7 @@ namespace torrents
143150
void Stop () override;
144151

145152
const std::string& GetPeerID () const { return m_PeerID; }
153+
std::string GetTorrentFilePath (const std::string& filename) const;
146154
std::shared_ptr<Torrent> FindTorrent (const Torrent::InfoHash& infoHash) const;
147155
void ConnectToPeer (std::shared_ptr<Torrent> torrent, std::shared_ptr<const i2p::client::Address> peer);
148156

0 commit comments

Comments
 (0)