#ifndef SSU_DATA_H__ #define SSU_DATA_H__ #include #include #include #include #include #include #include #include "I2NPProtocol.h" #include "Identity.h" #include "RouterInfo.h" namespace i2p { namespace transport { const size_t SSU_MTU_V4 = 1484; const size_t SSU_MTU_V6 = 1472; const size_t IPV4_HEADER_SIZE = 20; const size_t IPV6_HEADER_SIZE = 40; const size_t UDP_HEADER_SIZE = 8; const size_t SSU_V4_MAX_PACKET_SIZE = SSU_MTU_V4 - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; // 1456 const size_t SSU_V6_MAX_PACKET_SIZE = SSU_MTU_V6 - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // 1424 const int RESEND_INTERVAL = 3; // in seconds const int MAX_NUM_RESENDS = 5; const int DECAY_INTERVAL = 20; // in seconds const int MAX_NUM_RECEIVED_MESSAGES = 1000; // how many msgID we store for duplicates check const int INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds // data flags const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02; const uint8_t DATA_FLAG_WANT_REPLY = 0x04; const uint8_t DATA_FLAG_REQUEST_PREVIOUS_ACKS = 0x08; const uint8_t DATA_FLAG_EXPLICIT_CONGESTION_NOTIFICATION = 0x10; const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40; const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80; struct Fragment { int fragmentNum; size_t len; bool isLast; uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18]; // use biggest Fragment () = default; Fragment (int n, const uint8_t * b, int l, bool last): fragmentNum (n), len (l), isLast (last) { memcpy (buf, b, len); }; }; struct FragmentCmp { bool operator() (const std::unique_ptr& f1, const std::unique_ptr& f2) const { return f1->fragmentNum < f2->fragmentNum; }; }; struct IncompleteMessage { I2NPMessage * msg; int nextFragmentNum; uint32_t lastFragmentInsertTime; // in seconds std::set, FragmentCmp> savedFragments; IncompleteMessage (I2NPMessage * m): msg (m), nextFragmentNum (0), lastFragmentInsertTime (0) {}; ~IncompleteMessage () { if (msg) DeleteI2NPMessage (msg); }; }; struct SentMessage { std::vector > fragments; uint32_t nextResendTime; // in seconds int numResends; }; class SSUSession; class SSUData { public: SSUData (SSUSession& session); ~SSUData (); void Start (); void Stop (); void ProcessMessage (uint8_t * buf, size_t len); void Send (i2p::I2NPMessage * msg); void UpdatePacketSize (const i2p::data::IdentHash& remoteIdent); private: void SendMsgAck (uint32_t msgID); void SendFragmentAck (uint32_t msgID, int fragmentNum); void ProcessAcks (uint8_t *& buf, uint8_t flag); void ProcessFragments (uint8_t * buf); void ProcessSentMessageAck (uint32_t msgID); void ScheduleResend (); void HandleResendTimer (const boost::system::error_code& ecode); void ScheduleDecay (); void HandleDecayTimer (const boost::system::error_code& ecode); void ScheduleIncompleteMessagesCleanup (); void HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode); void AdjustPacketSize (const i2p::data::RouterInfo& remoteRouter); private: SSUSession& m_Session; std::map > m_IncompleteMessages; std::map > m_SentMessages; std::set m_ReceivedMessages; boost::asio::deadline_timer m_ResendTimer, m_DecayTimer, m_IncompleteMessagesCleanupTimer; int m_MaxPacketSize, m_PacketSize; i2p::I2NPMessagesHandler m_Handler; }; } } #endif