diff --git a/libi2pd_client/Torrents.cpp b/libi2pd_client/Torrents.cpp index 7a7bcb51..87123877 100644 --- a/libi2pd_client/Torrents.cpp +++ b/libi2pd_client/Torrents.cpp @@ -194,6 +194,7 @@ namespace torrents f.write ((const char *)m_Data, m_Size); delete[] m_Data; m_Data = nullptr; if (m_Missing) BN_free (m_Missing); + m_Connections.clear (); } } @@ -230,6 +231,11 @@ namespace torrents return { 0, 0 }; } + void Piece::AddConnection (std::shared_ptr connection) + { + m_Connections.emplace_back (connection); + } + Torrent::Torrent (std::string_view buf): m_Length (0), m_PieceLength (0), m_Interval (0) { @@ -560,8 +566,13 @@ namespace torrents return 0; } m_RemotePeerID = std::string_view ((const char *)(m_ReceiveBuffer + 48), 20); + // respond wiith handshake if incoming if (!m_IsHandshakeSent) SendHandshakeMsg (); + // send bitfield if not empty + auto bitfield = m_Torrent->CreateBitfield (); + if (bitfield.size ()) + SendBitfieldMsg (bitfield.data (), bitfield.size ()); m_IsEstablished = true; return HANDSHAKE_MSG_LENGTH; } @@ -596,6 +607,22 @@ namespace torrents BN_free (m_RemoteBitfield); m_RemoteBitfield = newBitfield; } + if (m_Torrent) + { + size_t numPieces = m_Torrent->GetNumPieces (); + for (size_t i = 0; i < numPieces; i++) + if (BN_is_bit_set (m_RemoteBitfield, numPieces - i - 1)) + m_Torrent->GetPiece (i).AddConnection (shared_from_this ()); + } + } + + void PeerConnection::SendBitfieldMsg (const uint8_t * bitfield, size_t bitfieldLen) + { + std::vector sendBuffer(bitfieldLen + 5); + htobe32buf (sendBuffer.data (), bitfieldLen + 1); // length + sendBuffer[4] = eMessageTypeBitfield; // msg ID + memcpy (sendBuffer.data () + 5, bitfield, bitfieldLen); + WriteToStream (sendBuffer.data (), sendBuffer.size ()); } void PeerConnection::HandlePieceMsg (const uint8_t * buf, size_t len) @@ -617,7 +644,7 @@ namespace torrents void PeerConnection::SendPieceMsg (uint32_t index, uint32_t offset, const uint8_t * data, size_t len) { std::vector sendBuffer(len + 8 + 5); - htobe32buf (sendBuffer.data (), len + 8); // length + htobe32buf (sendBuffer.data (), len + 8 + 1); // length sendBuffer[4] = eMessageTypePiece; // msg ID htobe32buf (sendBuffer.data () + 5, index); htobe32buf (sendBuffer.data () + 9, offset); diff --git a/libi2pd_client/Torrents.h b/libi2pd_client/Torrents.h index 6a43cf65..6fcca5a1 100644 --- a/libi2pd_client/Torrents.h +++ b/libi2pd_client/Torrents.h @@ -43,6 +43,7 @@ namespace torrents eMessageTypePiece = 7 }; + class PeerConnection; class Piece final { public: @@ -60,6 +61,8 @@ namespace torrents size_t GetSize () const { return m_Size; } std::pair GetAvailableBuffer (size_t offset, size_t len) const; // return (offset, len) of available data + void AddConnection (std::shared_ptr connection); + private: bool IsAvailable (int block) const; @@ -70,6 +73,7 @@ namespace torrents size_t m_Size; uint8_t * m_Data, m_Hash[SHA_DIGEST_LENGTH]; BIGNUM * m_Missing; // bit is set if block is missing + std::list > m_Connections; // for incomplete pieces only }; class Torrent final @@ -136,6 +140,7 @@ namespace torrents void SendHandshakeMsg (); void HandleBitfieldMsg (const uint8_t * buf, size_t len); + void SendBitfieldMsg (const uint8_t * bitfield, size_t bitfieldLen); void HandlePieceMsg (const uint8_t * buf, size_t len); void SendPieceMsg (uint32_t index, uint32_t offset, const uint8_t * data, size_t len); void HandleRequestMsg (const uint8_t * buf, size_t len);