diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 2640601e..693f1ccc 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -81,25 +81,44 @@ namespace i2p return CreateI2NPMessage (eI2NPDeliveryStatus, (uint8_t *)&msg, sizeof (msg)); } - I2NPMessage * CreateDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, uint32_t replyTunnelID) + I2NPMessage * CreateDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, + uint32_t replyTunnelID, bool exploratory) { -#pragma pack(1) - struct + I2NPMessage * m = NewI2NPMessage (); + uint8_t * buf = m->GetPayload (); + memcpy (buf, key, 32); // key + buf += 32; + memcpy (buf, from, 32); // from + buf += 32; + if (replyTunnelID) { - uint8_t key[32]; - uint8_t from[32]; - uint8_t flags; - uint32_t replyTunnelID; - uint16_t size; - } msg; -#pragma pack () - - memcpy (msg.key, key, 32); - memcpy (msg.from, from, 32); - msg.flags = replyTunnelID ? 0x01 : 0; - msg.replyTunnelID = htobe32 (replyTunnelID); - msg.size = 0; - return CreateI2NPMessage (eI2NPDatabaseLookup, (uint8_t *)&msg, sizeof (msg)); + *buf = 0x01; // set delivery flag + *(uint32_t *)(buf+1) = htobe32 (replyTunnelID); + buf += 5; + } + else + { + *buf = 0; // flag + buf++; + } + + if (exploratory) + { + *(uint16_t *)buf = htobe16 (1); // one exlude record + buf += 2; + // reply with non-floodfill routers only + memset (buf, 0, 32); + buf += 32; + } + else + { + // nothing to exclude + *(uint16_t *)buf = htobe16 (0); + buf += 2; + } + m->len += (buf - m->GetPayload ()); + FillI2NPMessageHeader (m, eI2NPDatabaseLookup); + return m; } I2NPMessage * CreateDatabaseStoreMsg () @@ -167,7 +186,7 @@ namespace i2p peerHash[l1] = 0; LogPrint (i,": ", peerHash); - i2p::data::netdb.RequestDestination (msg->key, buf + sizeof (*msg) +i*32); + i2p::data::netdb.HandleDatabaseSearchReply (msg->key, buf + sizeof (*msg) +i*32); } } @@ -211,8 +230,18 @@ namespace i2p i2p::tunnel::Tunnel * tunnel = i2p::tunnel::tunnels.GetPendingTunnel (replyMsgID); if (tunnel) { + // endpoint of inbound tunnel LogPrint ("VariableTunnelBuild reply for tunnel ", tunnel->GetTunnelID ()); - tunnel->HandleVariableTunnelBuildReplyMsg (buf, len); + if (tunnel->HandleTunnelBuildResponse (buf, len)) + { + LogPrint ("Inbound tunnel ", tunnel->GetTunnelID (), " has been created"); + i2p::tunnel::tunnels.AddInboundTunnel (static_cast(tunnel)); + } + else + { + LogPrint ("Inbound tunnel ", tunnel->GetTunnelID (), " has been declined"); + delete tunnel; + } } else { @@ -269,8 +298,17 @@ namespace i2p i2p::tunnel::Tunnel * tunnel = i2p::tunnel::tunnels.GetPendingTunnel (replyMsgID); if (tunnel) { - tunnel->HandleVariableTunnelBuildReplyMsg (buf, len); - LogPrint ("Tunnel ", tunnel->GetTunnelID (), " has been created"); + // reply for outbound tunnel + if (tunnel->HandleTunnelBuildResponse (buf, len)) + { + LogPrint ("Outbound tunnel ", tunnel->GetTunnelID (), " has been created"); + i2p::tunnel::tunnels.AddOutboundTunnel (static_cast(tunnel)); + } + else + { + LogPrint ("Outbound tunnel ", tunnel->GetTunnelID (), " has been declined"); + delete tunnel; + } } else LogPrint ("Pending tunnel for message ", replyMsgID, " not found"); diff --git a/I2NPProtocol.h b/I2NPProtocol.h index cc4fdf39..145b0404 100644 --- a/I2NPProtocol.h +++ b/I2NPProtocol.h @@ -27,6 +27,7 @@ namespace i2p uint16_t size; }; + struct I2NPBuildRequestRecordClearText { uint32_t receiveTunnel; @@ -104,7 +105,8 @@ namespace i2p I2NPMessage * CreateI2NPMessage (const uint8_t * buf, int len); I2NPMessage * CreateDeliveryStatusMsg (); - I2NPMessage * CreateDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, uint32_t replyTunnelID); + I2NPMessage * CreateDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, + uint32_t replyTunnelID, bool exploratory = false); I2NPMessage * CreateDatabaseStoreMsg (); void HandleDatabaseStoreMsg (uint8_t * buf, size_t len); diff --git a/NetDb.cpp b/NetDb.cpp index 840b92c8..e2d1bf16 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -2,6 +2,7 @@ #include "Log.h" #include "I2NPProtocol.h" #include "Tunnel.h" +#include "RouterContext.h" #include "NetDb.h" namespace i2p @@ -11,18 +12,45 @@ namespace data NetDb netdb; - NetDb::NetDb () + NetDb::NetDb (): m_IsRunning (false), m_Thread (0) { Load ("netDb"); } NetDb::~NetDb () { + Stop (); for (auto l:m_LeaseSets) delete l.second; for (auto r:m_RouterInfos) delete r.second; } + + void NetDb::Start () + { + m_Thread = new std::thread (std::bind (&NetDb::Run, this)); + } + + void NetDb::Stop () + { + if (m_Thread) + { + m_IsRunning = false; + m_Thread->join (); + delete m_Thread; + m_Thread = 0; + } + } + + void NetDb::Run () + { + m_IsRunning = true; + while (m_IsRunning) + { + sleep (10); + Explore (); + } + } void NetDb::AddRouterInfo (uint8_t * buf, int len) { @@ -78,10 +106,9 @@ namespace data i2p::tunnel::InboundTunnel * inbound = i2p::tunnel::tunnels.GetNextInboundTunnel (); if (inbound) { - I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (destination, inbound->GetGatewayIdentHash (), - inbound->GetGetwayTunnelID ()); + I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (destination, inbound->GetNextIdentHash (), + inbound->GetNextTunnelID ()); outbound->SendTunnelDataMsg (router, 0, msg); - i2p::DeleteI2NPMessage (msg); } else LogPrint ("No inbound tunnels found"); @@ -89,13 +116,64 @@ namespace data else LogPrint ("No outbound tunnels found"); } - - const RouterInfo * NetDb::GetNextFloodfill () const + + void NetDb::HandleDatabaseSearchReply (const uint8_t * key, const uint8_t * router) + { + if (!memcmp (m_Exploratory, key, 32)) + { + if (m_RouterInfos.find (std::string ((const char *)router, 32)) == m_RouterInfos.end ()) + LogPrint ("Found new router"); + else + LogPrint ("Bayan"); + } + else + RequestDestination (key, router); + } + + void NetDb::Explore () + { + i2p::tunnel::OutboundTunnel * outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel (); + i2p::tunnel::InboundTunnel * inbound = i2p::tunnel::tunnels.GetNextInboundTunnel (); + if (outbound && inbound) + { + const RouterInfo * floodFill = GetRandomNTCPRouter (true); + if (floodFill) + { + LogPrint ("Exploring new routers ..."); + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + rnd.GenerateBlock (m_Exploratory, 32); + I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (m_Exploratory, inbound->GetNextIdentHash (), + inbound->GetNextTunnelID (), true); + outbound->SendTunnelDataMsg (floodFill->GetIdentHash (), 0, msg); + } + } + } + + const RouterInfo * NetDb::GetRandomNTCPRouter (bool floodfillOnly) const + { + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + uint32_t ind = rnd.GenerateWord32 (0, m_RouterInfos.size () - 1), i = 0; + RouterInfo * last = nullptr; + for (auto it: m_RouterInfos) + { + if (it.second->IsNTCP () && (!floodfillOnly || it.second->IsFloodfill ())) + last = it.second; + if (i >= ind) break; + else i++; + } + return last; + } + + const RouterInfo * NetDb::GetRandomRouter () const { + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + uint32_t ind = rnd.GenerateWord32 (0, m_RouterInfos.size () - 1), i = 0; for (auto it: m_RouterInfos) - if (it.second->IsFloodfill () && it.second->IsNTCP ()) - return it.second; - return 0; + { + if (i >= ind) return it.second; + else i++; + } + return nullptr; } } } diff --git a/NetDb.h b/NetDb.h index b5cf4263..8b4eec2e 100644 --- a/NetDb.h +++ b/NetDb.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "RouterInfo.h" #include "LeaseSet.h" @@ -17,23 +18,34 @@ namespace data NetDb (); ~NetDb (); + + void Start (); + void Stop (); void AddRouterInfo (uint8_t * buf, int len); void AddLeaseSet (uint8_t * buf, int len); RouterInfo * FindRouter (const uint8_t * ident); void RequestDestination (const uint8_t * destination, const uint8_t * router); + void HandleDatabaseSearchReply (const uint8_t * key, const uint8_t * router); - const RouterInfo * GetNextFloodfill () const; + const RouterInfo * GetRandomNTCPRouter (bool floodfillOnly = false) const; + const RouterInfo * GetRandomRouter () const; private: void Load (const char * directory); - + void Run (); // exploratory thread + void Explore (); + private: std::map m_LeaseSets; std::map m_RouterInfos; + + bool m_IsRunning; + std::thread * m_Thread; + uint8_t m_Exploratory[32]; }; extern NetDb netdb;