Browse Source

fixed race condition between local buffer creation and sending it through the transports

pull/2072/head
orignal 7 months ago
parent
commit
acbd3f897b
  1. 10
      libi2pd/NTCP2.cpp
  2. 6
      libi2pd/NetDb.hpp
  3. 11
      libi2pd/RouterContext.cpp
  4. 2
      libi2pd/RouterContext.h
  5. 6
      libi2pd/RouterInfo.cpp
  6. 2
      libi2pd/RouterInfo.h
  7. 21
      libi2pd/SSU2Session.cpp
  8. 1
      libi2pd/SSU2Session.h

10
libi2pd/NTCP2.cpp

@ -129,7 +129,8 @@ namespace transport
options[1] = 2; // ver options[1] = 2; // ver
htobe16buf (options + 2, paddingLength); // padLen htobe16buf (options + 2, paddingLength); // padLen
// m3p2Len // m3p2Len
auto bufLen = i2p::context.GetRouterInfo ().GetBufferLen (); auto riBuffer = i2p::context.CopyRouterInfoBuffer ();
auto bufLen = riBuffer->GetBufferLen ();
m3p2Len = bufLen + 4 + 16; // (RI header + RI + MAC for now) TODO: implement options m3p2Len = bufLen + 4 + 16; // (RI header + RI + MAC for now) TODO: implement options
htobe16buf (options + 4, m3p2Len); htobe16buf (options + 4, m3p2Len);
// fill m3p2 payload (RouterInfo block) // fill m3p2 payload (RouterInfo block)
@ -138,7 +139,7 @@ namespace transport
m3p2[0] = eNTCP2BlkRouterInfo; // block m3p2[0] = eNTCP2BlkRouterInfo; // block
htobe16buf (m3p2 + 1, bufLen + 1); // flag + RI htobe16buf (m3p2 + 1, bufLen + 1); // flag + RI
m3p2[3] = 0; // flag m3p2[3] = 0; // flag
memcpy (m3p2 + 4, i2p::context.GetRouterInfo ().GetBuffer (), bufLen); // TODO: own RI should be protected by mutex memcpy (m3p2 + 4, riBuffer->data (), bufLen); // TODO: eliminate extra copy
// 2 bytes reserved // 2 bytes reserved
htobe32buf (options + 8, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); // tsA, rounded to seconds htobe32buf (options + 8, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); // tsA, rounded to seconds
// 4 bytes reserved // 4 bytes reserved
@ -1200,7 +1201,8 @@ namespace transport
void NTCP2Session::SendRouterInfo () void NTCP2Session::SendRouterInfo ()
{ {
if (!IsEstablished ()) return; if (!IsEstablished ()) return;
auto riLen = i2p::context.GetRouterInfo ().GetBufferLen (); auto riBuffer = i2p::context.CopyRouterInfoBuffer ();
auto riLen = riBuffer->GetBufferLen ();
size_t payloadLen = riLen + 3 + 1 + 7; // 3 bytes block header + 1 byte RI flag + 7 bytes DateTime size_t payloadLen = riLen + 3 + 1 + 7; // 3 bytes block header + 1 byte RI flag + 7 bytes DateTime
m_NextSendBuffer = new uint8_t[payloadLen + 16 + 2 + 64]; // up to 64 bytes padding m_NextSendBuffer = new uint8_t[payloadLen + 16 + 2 + 64]; // up to 64 bytes padding
// DateTime block // DateTime block
@ -1211,7 +1213,7 @@ namespace transport
m_NextSendBuffer[9] = eNTCP2BlkRouterInfo; m_NextSendBuffer[9] = eNTCP2BlkRouterInfo;
htobe16buf (m_NextSendBuffer + 10, riLen + 1); // size htobe16buf (m_NextSendBuffer + 10, riLen + 1); // size
m_NextSendBuffer[12] = 0; // flag m_NextSendBuffer[12] = 0; // flag
memcpy (m_NextSendBuffer + 13, i2p::context.GetRouterInfo ().GetBuffer (), riLen); memcpy (m_NextSendBuffer + 13, riBuffer->data (), riLen); // TODO: eliminate extra copy
// padding block // padding block
auto paddingSize = CreatePaddingBlock (payloadLen, m_NextSendBuffer + 2 + payloadLen, 64); auto paddingSize = CreatePaddingBlock (payloadLen, m_NextSendBuffer + 2 + payloadLen, 64);
payloadLen += paddingSize; payloadLen += paddingSize;

6
libi2pd/NetDb.hpp

@ -119,7 +119,11 @@ namespace data
size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n); size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n);
void ClearRouterInfos () { m_RouterInfos.clear (); }; void ClearRouterInfos () { m_RouterInfos.clear (); };
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); }; template<typename... TArgs>
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer (TArgs&&... args)
{
return m_RouterInfoBuffersPool.AcquireSharedMt (std::forward<TArgs>(args)...);
}
bool PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r); bool PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r);
std::shared_ptr<RouterInfo::Address> NewRouterInfoAddress () { return m_RouterInfoAddressesPool.AcquireSharedMt (); }; std::shared_ptr<RouterInfo::Address> NewRouterInfoAddress () { return m_RouterInfoAddressesPool.AcquireSharedMt (); };
boost::shared_ptr<RouterInfo::Addresses> NewRouterInfoAddresses () boost::shared_ptr<RouterInfo::Addresses> NewRouterInfoAddresses ()

11
libi2pd/RouterContext.cpp

@ -78,6 +78,12 @@ namespace i2p
} }
} }
std::shared_ptr<i2p::data::RouterInfo::Buffer> RouterContext::CopyRouterInfoBuffer () const
{
std::lock_guard<std::mutex> l(m_RouterInfoMutex);
return m_RouterInfo.CopyBuffer ();
}
void RouterContext::CreateNewRouter () void RouterContext::CreateNewRouter ()
{ {
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519, m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
@ -246,7 +252,10 @@ namespace i2p
void RouterContext::UpdateRouterInfo () void RouterContext::UpdateRouterInfo ()
{ {
m_RouterInfo.CreateBuffer (m_Keys); {
std::lock_guard<std::mutex> l(m_RouterInfoMutex);
m_RouterInfo.CreateBuffer (m_Keys);
}
m_RouterInfo.SaveToFile (i2p::fs::DataDirPath (ROUTER_INFO)); m_RouterInfo.SaveToFile (i2p::fs::DataDirPath (ROUTER_INFO));
m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch (); m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch ();
} }

2
libi2pd/RouterContext.h

@ -114,6 +114,7 @@ namespace garlic
return std::shared_ptr<i2p::garlic::GarlicDestination> (this, return std::shared_ptr<i2p::garlic::GarlicDestination> (this,
[](i2p::garlic::GarlicDestination *) {}); [](i2p::garlic::GarlicDestination *) {});
} }
std::shared_ptr<i2p::data::RouterInfo::Buffer> CopyRouterInfoBuffer () const;
const uint8_t * GetNTCP2StaticPublicKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPublicKey : nullptr; }; const uint8_t * GetNTCP2StaticPublicKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPublicKey : nullptr; };
const uint8_t * GetNTCP2StaticPrivateKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPrivateKey : nullptr; }; const uint8_t * GetNTCP2StaticPrivateKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPrivateKey : nullptr; };
@ -258,6 +259,7 @@ namespace garlic
std::unordered_set<i2p::data::IdentHash> m_PublishExcluded; std::unordered_set<i2p::data::IdentHash> m_PublishExcluded;
uint32_t m_PublishReplyToken; uint32_t m_PublishReplyToken;
bool m_IsHiddenMode; // not publish bool m_IsHiddenMode; // not publish
mutable std::mutex m_RouterInfoMutex;
}; };
extern RouterContext context; extern RouterContext context;

6
libi2pd/RouterInfo.cpp

@ -1120,6 +1120,12 @@ namespace data
m_Buffer->SetBufferLen (len); m_Buffer->SetBufferLen (len);
} }
std::shared_ptr<RouterInfo::Buffer> RouterInfo::CopyBuffer () const
{
if (!m_Buffer) return nullptr;
return netdb.NewRouterInfoBuffer (*m_Buffer);
}
std::shared_ptr<RouterInfo::Buffer> RouterInfo::NewBuffer () const std::shared_ptr<RouterInfo::Buffer> RouterInfo::NewBuffer () const
{ {
return netdb.NewRouterInfoBuffer (); return netdb.NewRouterInfoBuffer ();

2
libi2pd/RouterInfo.h

@ -188,6 +188,7 @@ namespace data
Buffer () = default; Buffer () = default;
Buffer (const uint8_t * buf, size_t len); Buffer (const uint8_t * buf, size_t len);
Buffer (const Buffer& other): Buffer (other.data (), other.m_BufferLen) {};
size_t GetBufferLen () const { return m_BufferLen; }; size_t GetBufferLen () const { return m_BufferLen; };
void SetBufferLen (size_t len) { m_BufferLen = len; }; void SetBufferLen (size_t len) { m_BufferLen = len; };
@ -282,6 +283,7 @@ namespace data
size_t GetBufferLen () const { return m_Buffer ? m_Buffer->GetBufferLen () : 0; }; size_t GetBufferLen () const { return m_Buffer ? m_Buffer->GetBufferLen () : 0; };
void DeleteBuffer () { m_Buffer = nullptr; }; void DeleteBuffer () { m_Buffer = nullptr; };
std::shared_ptr<Buffer> GetSharedBuffer () const { return m_Buffer; }; std::shared_ptr<Buffer> GetSharedBuffer () const { return m_Buffer; };
std::shared_ptr<Buffer> CopyBuffer () const;
bool IsUpdated () const { return m_IsUpdated; }; bool IsUpdated () const { return m_IsUpdated; };
void SetUpdated (bool updated) { m_IsUpdated = updated; }; void SetUpdated (bool updated) { m_IsUpdated = updated; };

21
libi2pd/SSU2Session.cpp

@ -337,7 +337,7 @@ namespace transport
{ {
if (!s->IsEstablished ()) return; if (!s->IsEstablished ()) return;
uint8_t payload[SSU2_MAX_PACKET_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
size_t payloadSize = s->CreateRouterInfoBlock (payload, s->m_MaxPayloadSize - 32, i2p::context.GetSharedRouterInfo ()); size_t payloadSize = s->CreateRouterInfoBlock (payload, s->m_MaxPayloadSize - 32, i2p::context.CopyRouterInfoBuffer ());
if (payloadSize) if (payloadSize)
{ {
if (payloadSize < s->m_MaxPayloadSize) if (payloadSize < s->m_MaxPayloadSize)
@ -883,12 +883,12 @@ namespace transport
// payload // payload
size_t maxPayloadSize = m_MaxPayloadSize - 48; // for part 2, 48 is part1 size_t maxPayloadSize = m_MaxPayloadSize - 48; // for part 2, 48 is part1
uint8_t * payload = m_SentHandshakePacket->payload; uint8_t * payload = m_SentHandshakePacket->payload;
size_t payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.GetSharedRouterInfo ()); size_t payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.CopyRouterInfoBuffer ());
if (!payloadSize) if (!payloadSize)
{ {
// split by two fragments // split by two fragments
maxPayloadSize += m_MaxPayloadSize; maxPayloadSize += m_MaxPayloadSize;
payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.GetSharedRouterInfo ()); payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.CopyRouterInfoBuffer ());
header.h.flags[0] = 0x02; // frag 0, total fragments 2 header.h.flags[0] = 0x02; // frag 0, total fragments 2
// TODO: check if we need more fragments // TODO: check if we need more fragments
} }
@ -2537,19 +2537,25 @@ namespace transport
size_t SSU2Session::CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r) size_t SSU2Session::CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r)
{ {
if (!r || !r->GetBuffer () || len < 5) return 0; if (!r || len < 5) return 0;
return CreateRouterInfoBlock (buf, len, r->GetSharedBuffer ());
}
size_t SSU2Session::CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo::Buffer> riBuffer)
{
if (!riBuffer || len < 5) return 0;
buf[0] = eSSU2BlkRouterInfo; buf[0] = eSSU2BlkRouterInfo;
size_t size = r->GetBufferLen (); size_t size = riBuffer->GetBufferLen ();
if (size + 5 < len) if (size + 5 < len)
{ {
memcpy (buf + 5, r->GetBuffer (), size); memcpy (buf + 5, riBuffer->data (), size);
buf[3] = 0; // flag buf[3] = 0; // flag
} }
else else
{ {
i2p::data::GzipDeflator deflator; i2p::data::GzipDeflator deflator;
deflator.SetCompressionLevel (9); deflator.SetCompressionLevel (9);
size = deflator.Deflate (r->GetBuffer (), r->GetBufferLen (), buf + 5, len - 5); size = deflator.Deflate (riBuffer->data (), riBuffer->GetBufferLen (), buf + 5, len - 5);
if (!size) return 0; // doesn't fit if (!size) return 0; // doesn't fit
buf[3] = SSU2_ROUTER_INFO_FLAG_GZIP; // flag buf[3] = SSU2_ROUTER_INFO_FLAG_GZIP; // flag
} }
@ -2558,6 +2564,7 @@ namespace transport
return size + 5; return size + 5;
} }
size_t SSU2Session::CreateAckBlock (uint8_t * buf, size_t len) size_t SSU2Session::CreateAckBlock (uint8_t * buf, size_t len)
{ {
if (len < 8) return 0; if (len < 8) return 0;

1
libi2pd/SSU2Session.h

@ -326,6 +326,7 @@ namespace transport
size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep);
size_t CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r); size_t CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r);
size_t CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo::Buffer> riBuffer);
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); size_t CreateI2NPBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage>&& msg);

Loading…
Cancel
Save