mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-03-10 05:11:10 +00:00
send I2NP messages
This commit is contained in:
parent
f9925c7374
commit
2024e790ca
@ -69,6 +69,7 @@ namespace transport
|
|||||||
m_State = eSSU2SessionStateTerminated;
|
m_State = eSSU2SessionStateTerminated;
|
||||||
transports.PeerDisconnected (shared_from_this ());
|
transports.PeerDisconnected (shared_from_this ());
|
||||||
m_Server.RemoveSession (m_SourceConnID);
|
m_Server.RemoveSession (m_SourceConnID);
|
||||||
|
m_SendQueue.clear ();
|
||||||
LogPrint (eLogDebug, "SSU2: Session terminated");
|
LogPrint (eLogDebug, "SSU2: Session terminated");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,6 +86,65 @@ namespace transport
|
|||||||
m_EphemeralKeys = nullptr;
|
m_EphemeralKeys = nullptr;
|
||||||
m_NoiseState.reset (nullptr);
|
m_NoiseState.reset (nullptr);
|
||||||
SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT);
|
SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT);
|
||||||
|
transports.PeerConnected (shared_from_this ());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSU2Session::Done ()
|
||||||
|
{
|
||||||
|
m_Server.GetService ().post (std::bind (&SSU2Session::Terminate, shared_from_this ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSU2Session::SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
|
||||||
|
{
|
||||||
|
m_Server.GetService ().post (std::bind (&SSU2Session::PostI2NPMessages, shared_from_this (), msgs));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSU2Session::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs)
|
||||||
|
{
|
||||||
|
for (auto it: msgs)
|
||||||
|
m_SendQueue.push_back (it);
|
||||||
|
SendQueue ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSU2Session::SendQueue ()
|
||||||
|
{
|
||||||
|
if (!m_SendQueue.empty ())
|
||||||
|
{
|
||||||
|
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE];
|
||||||
|
size_t payloadSize = 0;
|
||||||
|
payloadSize += CreateAckBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize);
|
||||||
|
while (!m_SendQueue.empty ())
|
||||||
|
{
|
||||||
|
auto msg = m_SendQueue.front ();
|
||||||
|
size_t len = msg->GetNTCP2Length ();
|
||||||
|
if (len + 3 < SSU2_MAX_PAYLOAD_SIZE - payloadSize)
|
||||||
|
{
|
||||||
|
m_SendQueue.pop_front ();
|
||||||
|
payloadSize += CreateI2NPBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize, std::move (msg));
|
||||||
|
}
|
||||||
|
else if (len > SSU2_MAX_PAYLOAD_SIZE - 32) // message too long
|
||||||
|
m_SendQueue.pop_front (); // drop it. TODO: fragmentation
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// send right a way
|
||||||
|
if (payloadSize + 16 < SSU2_MAX_PAYLOAD_SIZE)
|
||||||
|
payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize);
|
||||||
|
auto packet = SendData (payload, payloadSize);
|
||||||
|
if (packet)
|
||||||
|
m_SentPackets.emplace (packet->packetNum, packet);
|
||||||
|
payloadSize = 0;
|
||||||
|
payloadSize += CreateAckBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (payloadSize)
|
||||||
|
{
|
||||||
|
if (payloadSize + 16 < SSU2_MAX_PAYLOAD_SIZE)
|
||||||
|
payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize);
|
||||||
|
auto packet = SendData (payload, payloadSize);
|
||||||
|
if (packet)
|
||||||
|
m_SentPackets.emplace (packet->packetNum, packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSU2Session::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len)
|
void SSU2Session::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len)
|
||||||
@ -534,28 +594,33 @@ namespace transport
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSU2Session::SendData (const uint8_t * buf, size_t len)
|
std::shared_ptr<SSU2Session::SentPacket> SSU2Session::SendData (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
if (len < 8)
|
if (len < 8)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "SSU2: Data message payload is too short ", (int)len);
|
LogPrint (eLogWarning, "SSU2: Data message payload is too short ", (int)len);
|
||||||
return;
|
return nullptr;
|
||||||
}
|
}
|
||||||
Header header;
|
auto packet = std::make_shared<SentPacket>();
|
||||||
|
packet->packetNum = m_SendPacketNum;
|
||||||
|
packet->numResends = 0;
|
||||||
|
Header& header = packet->header;
|
||||||
header.h.connID = m_DestConnID;
|
header.h.connID = m_DestConnID;
|
||||||
header.h.packetNum = htobe32 (m_SendPacketNum);
|
header.h.packetNum = htobe32 (m_SendPacketNum);
|
||||||
header.h.type = eSSU2Data;
|
header.h.type = eSSU2Data;
|
||||||
memset (header.h.flags, 0, 3);
|
memset (header.h.flags, 0, 3);
|
||||||
uint8_t payload[SSU2_MTU];
|
|
||||||
uint8_t nonce[12];
|
uint8_t nonce[12];
|
||||||
CreateNonce (m_SendPacketNum, nonce);
|
CreateNonce (m_SendPacketNum, nonce);
|
||||||
i2p::crypto::AEADChaCha20Poly1305 (buf, len, header.buf, 16, m_KeyDataSend, nonce, payload, SSU2_MTU, true);
|
i2p::crypto::AEADChaCha20Poly1305 (buf, len, header.buf, 16, m_KeyDataSend, nonce, packet->payload, SSU2_MTU, true);
|
||||||
header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (len - 8));
|
header.ll[0] ^= CreateHeaderMask (m_Address->i, packet->payload + (len - 8));
|
||||||
header.ll[1] ^= CreateHeaderMask (m_KeyDataSend + 32, payload + (len + 4));
|
header.ll[1] ^= CreateHeaderMask (m_KeyDataSend + 32, packet->payload + (len + 4));
|
||||||
m_Server.Send (header.buf, 16, payload, len + 16, m_RemoteEndpoint);
|
packet->payloadLen = len + 16;
|
||||||
|
m_Server.Send (header.buf, 16, packet->payload, packet->payloadLen, m_RemoteEndpoint);
|
||||||
m_SendPacketNum++;
|
m_SendPacketNum++;
|
||||||
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||||
m_NumSentBytes += len + 32;
|
packet->nextResendTime = m_LastActivityTimestamp + SSU2_RESEND_INTERVAL;
|
||||||
|
m_NumSentBytes += packet->payloadLen + 16;
|
||||||
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSU2Session::ProcessData (uint8_t * buf, size_t len)
|
void SSU2Session::ProcessData (uint8_t * buf, size_t len)
|
||||||
@ -797,6 +862,18 @@ namespace transport
|
|||||||
return 0;
|
return 0;
|
||||||
return paddingSize + 3;
|
return paddingSize + 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t SSU2Session::CreateI2NPBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage>&& msg)
|
||||||
|
{
|
||||||
|
msg->ToNTCP2 ();
|
||||||
|
auto msgBuf = msg->GetNTCP2Header ();
|
||||||
|
auto msgLen = msg->GetNTCP2Length ();
|
||||||
|
if (msgLen + 3 > len) msgLen = len - 3;
|
||||||
|
buf[0] = eSSU2BlkI2NPMessage;
|
||||||
|
htobe16buf (buf + 1, msgLen); // size
|
||||||
|
memcpy (buf + 3, msgBuf, msgLen);
|
||||||
|
return msgLen + 3;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> SSU2Session::ExtractRouterInfo (const uint8_t * buf, size_t size)
|
std::shared_ptr<const i2p::data::RouterInfo> SSU2Session::ExtractRouterInfo (const uint8_t * buf, size_t size)
|
||||||
{
|
{
|
||||||
|
@ -29,6 +29,9 @@ namespace transport
|
|||||||
const size_t SSU2_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K
|
const size_t SSU2_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K
|
||||||
const size_t SSU2_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K
|
const size_t SSU2_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K
|
||||||
const size_t SSU2_MTU = 1488;
|
const size_t SSU2_MTU = 1488;
|
||||||
|
const size_t SSU2_MAX_PAYLOAD_SIZE = SSU2_MTU - 32;
|
||||||
|
const int SSU2_RESEND_INTERVAL = 3; // in seconds
|
||||||
|
const int SSU2_MAX_NUM_RESENDS = 5;
|
||||||
|
|
||||||
enum SSU2MessageType
|
enum SSU2MessageType
|
||||||
{
|
{
|
||||||
@ -97,9 +100,10 @@ namespace transport
|
|||||||
|
|
||||||
struct SentPacket
|
struct SentPacket
|
||||||
{
|
{
|
||||||
Header h;
|
Header header;
|
||||||
uint8_t payload[SSU2_MTU];
|
uint8_t payload[SSU2_MTU];
|
||||||
size_t payloadLen;
|
size_t payloadLen;
|
||||||
|
uint32_t packetNum;
|
||||||
uint32_t nextResendTime; // in seconds
|
uint32_t nextResendTime; // in seconds
|
||||||
int numResends;
|
int numResends;
|
||||||
};
|
};
|
||||||
@ -116,8 +120,8 @@ namespace transport
|
|||||||
void Connect ();
|
void Connect ();
|
||||||
void Terminate ();
|
void Terminate ();
|
||||||
void TerminateByTimeout ();
|
void TerminateByTimeout ();
|
||||||
void Done () override {};
|
void Done () override;
|
||||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override {};
|
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
|
||||||
bool IsEstablished () const { return m_State == eSSU2SessionStateEstablished; };
|
bool IsEstablished () const { return m_State == eSSU2SessionStateEstablished; };
|
||||||
uint64_t GetConnID () const { return m_SourceConnID; };
|
uint64_t GetConnID () const { return m_SourceConnID; };
|
||||||
|
|
||||||
@ -130,6 +134,8 @@ namespace transport
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
void Established ();
|
void Established ();
|
||||||
|
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
||||||
|
void SendQueue ();
|
||||||
|
|
||||||
void ProcessSessionRequest (Header& header, uint8_t * buf, size_t len);
|
void ProcessSessionRequest (Header& header, uint8_t * buf, size_t len);
|
||||||
void ProcessTokenRequest (Header& header, uint8_t * buf, size_t len);
|
void ProcessTokenRequest (Header& header, uint8_t * buf, size_t len);
|
||||||
@ -140,7 +146,7 @@ namespace transport
|
|||||||
void KDFDataPhase (uint8_t * keydata_ab, uint8_t * keydata_ba);
|
void KDFDataPhase (uint8_t * keydata_ab, uint8_t * keydata_ba);
|
||||||
void SendTokenRequest ();
|
void SendTokenRequest ();
|
||||||
void SendRetry ();
|
void SendRetry ();
|
||||||
void SendData (const uint8_t * buf, size_t len);
|
std::shared_ptr<SentPacket> SendData (const uint8_t * buf, size_t len);
|
||||||
void SendQuickAck ();
|
void SendQuickAck ();
|
||||||
void SendTermination ();
|
void SendTermination ();
|
||||||
|
|
||||||
@ -154,6 +160,7 @@ namespace transport
|
|||||||
size_t CreateAddressBlock (const boost::asio::ip::udp::endpoint& ep, uint8_t * buf, size_t len);
|
size_t CreateAddressBlock (const boost::asio::ip::udp::endpoint& ep, uint8_t * buf, size_t len);
|
||||||
size_t CreateAckBlock (uint8_t * buf, size_t len);
|
size_t CreateAckBlock (uint8_t * buf, size_t len);
|
||||||
size_t CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize = 0);
|
size_t CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize = 0);
|
||||||
|
size_t CreateI2NPBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage>&& msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -168,6 +175,7 @@ namespace transport
|
|||||||
uint32_t m_SendPacketNum, m_ReceivePacketNum;
|
uint32_t m_SendPacketNum, m_ReceivePacketNum;
|
||||||
std::set<uint32_t> m_OutOfSequencePackets; // packet nums > receive packet num
|
std::set<uint32_t> m_OutOfSequencePackets; // packet nums > receive packet num
|
||||||
std::map<uint32_t, std::shared_ptr<SentPacket> > m_SentPackets; // packetNum -> packet
|
std::map<uint32_t, std::shared_ptr<SentPacket> > m_SentPackets; // packetNum -> packet
|
||||||
|
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
||||||
i2p::I2NPMessagesHandler m_Handler;
|
i2p::I2NPMessagesHandler m_Handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user