diff --git a/ClientContext.cpp b/ClientContext.cpp index ea459a13..2cdd3ae9 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -100,15 +100,21 @@ namespace client void ClientContext::Stop () { - LogPrint(eLogInfo, "Clients: stopping HTTP Proxy"); - m_HttpProxy->Stop(); - delete m_HttpProxy; - m_HttpProxy = nullptr; + if (m_HttpProxy) + { + LogPrint(eLogInfo, "Clients: stopping HTTP Proxy"); + m_HttpProxy->Stop(); + delete m_HttpProxy; + m_HttpProxy = nullptr; + } - LogPrint(eLogInfo, "Clients: stopping SOCKS Proxy"); - m_SocksProxy->Stop(); - delete m_SocksProxy; - m_SocksProxy = nullptr; + if (m_SocksProxy) + { + LogPrint(eLogInfo, "Clients: stopping SOCKS Proxy"); + m_SocksProxy->Stop(); + delete m_SocksProxy; + m_SocksProxy = nullptr; + } for (auto& it: m_ClientTunnels) { diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 85dbec42..3b92d4bc 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -447,6 +447,13 @@ namespace util s << "
\r\nRouters: " << i2p::data::netdb.GetNumRouters () << " "; s << "Floodfills: " << i2p::data::netdb.GetNumFloodfills () << " "; s << "LeaseSets: " << i2p::data::netdb.GetNumLeaseSets () << "
\r\n"; + + size_t clientTunnelCount = i2p::tunnel::tunnels.CountOutboundTunnels(); + clientTunnelCount += i2p::tunnel::tunnels.CountInboundTunnels(); + size_t transitTunnelCount = i2p::tunnel::tunnels.CountTransitTunnels(); + + s << "Client Tunnels: " << std::to_string(clientTunnelCount) << " "; + s << "Transit Tunnels: " << std::to_string(transitTunnelCount) << "
\r\n"; } void HTTPConnection::HandleCommand (const std::string& command, std::stringstream& s) @@ -603,13 +610,13 @@ namespace util for (auto it: i2p::tunnel::tunnels.GetInboundTunnels ()) { - it.second->Print (s); - auto state = it.second->GetState (); + it->Print (s); + auto state = it->GetState (); if (state == i2p::tunnel::eTunnelStateFailed) s << " " << "Failed"; else if (state == i2p::tunnel::eTunnelStateExpiring) s << " " << "Exp"; - s << " " << (int)it.second->GetNumReceivedBytes () << "
\r\n"; + s << " " << (int)it->GetNumReceivedBytes () << "
\r\n"; s << std::endl; } } @@ -619,13 +626,13 @@ namespace util s << "Transit tunnels:
\r\n
\r\n"; for (auto it: i2p::tunnel::tunnels.GetTransitTunnels ()) { - if (dynamic_cast(it.second)) - s << it.second->GetTunnelID () << " ⇒ "; - else if (dynamic_cast(it.second)) - s << " ⇒ " << it.second->GetTunnelID (); + if (std::dynamic_pointer_cast(it)) + s << it->GetTunnelID () << " ⇒ "; + else if (std::dynamic_pointer_cast(it)) + s << " ⇒ " << it->GetTunnelID (); else - s << " ⇒ " << it.second->GetTunnelID () << " ⇒ "; - s << " " << it.second->GetNumTransmittedBytes () << "
\r\n"; + s << " ⇒ " << it->GetTunnelID () << " ⇒ "; + s << " " << it->GetNumTransmittedBytes () << "
\r\n"; } } diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index dff66951..7cebf96a 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -301,8 +301,7 @@ namespace i2p i2p::tunnel::tunnels.GetTransitTunnels ().size () <= MAX_NUM_TRANSIT_TUNNELS && !i2p::transport::transports.IsBandwidthExceeded ()) { - i2p::tunnel::TransitTunnel * transitTunnel = - i2p::tunnel::CreateTransitTunnel ( + auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), diff --git a/NetDb.cpp b/NetDb.cpp index 501852bb..eb1380de 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -677,7 +677,7 @@ namespace data excludedRouters.insert (excluded); excluded += 32; } - replyMsg = CreateDatabaseSearchReply (ident, GetClosestFloodfills (ident, 3, excludedRouters)); + replyMsg = CreateDatabaseSearchReply (ident, GetClosestFloodfills (ident, 3, excludedRouters, true)); } } @@ -884,7 +884,7 @@ namespace data } std::vector NetDb::GetClosestFloodfills (const IdentHash& destination, size_t num, - std::set& excluded) const + std::set& excluded, bool closeThanUsOnly) const { struct Sorted { @@ -895,6 +895,8 @@ namespace data std::set sorted; IdentHash destKey = CreateRoutingKey (destination); + XORMetric ourMetric; + if (closeThanUsOnly) ourMetric = destKey ^ i2p::context.GetIdentHash (); { std::unique_lock l(m_FloodfillsMutex); for (auto it: m_Floodfills) @@ -902,6 +904,7 @@ namespace data if (!it->IsUnreachable ()) { XORMetric m = destKey ^ it->GetIdentHash (); + if (closeThanUsOnly && ourMetric < m) continue; if (sorted.size () < num) sorted.insert ({it, m}); else if (m < sorted.rbegin ()->metric) @@ -960,9 +963,9 @@ namespace data auto ts = i2p::util::GetMillisecondsSinceEpoch (); for (auto it = m_LeaseSets.begin (); it != m_LeaseSets.end ();) { - if (ts > it->second->GetExpirationTime ()) + if (ts > it->second->GetExpirationTime () - LEASE_ENDDATE_THRESHOLD) { - LogPrint (eLogWarning, "NetDb: LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired"); + LogPrint (eLogInfo, "NetDb: LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired"); it = m_LeaseSets.erase (it); } else diff --git a/NetDb.h b/NetDb.h index 7b196330..536ff644 100644 --- a/NetDb.h +++ b/NetDb.h @@ -60,7 +60,7 @@ namespace data std::shared_ptr GetRandomIntroducer () const; std::shared_ptr GetClosestFloodfill (const IdentHash& destination, const std::set& excluded, bool closeThanUsOnly = false) const; std::vector GetClosestFloodfills (const IdentHash& destination, size_t num, - std::set& excluded) const; + std::set& excluded, bool closeThanUsOnly = false) const; std::shared_ptr GetClosestNonFloodfill (const IdentHash& destination, const std::set& excluded) const; void SetUnreachable (const IdentHash& ident, bool unreachable); diff --git a/TransitTunnel.cpp b/TransitTunnel.cpp index 81773bb5..0d54fc11 100644 --- a/TransitTunnel.cpp +++ b/TransitTunnel.cpp @@ -85,7 +85,7 @@ namespace tunnel m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg); } - TransitTunnel * CreateTransitTunnel (uint32_t receiveTunnelID, + std::shared_ptr CreateTransitTunnel (uint32_t receiveTunnelID, const uint8_t * nextIdent, uint32_t nextTunnelID, const uint8_t * layerKey,const uint8_t * ivKey, bool isGateway, bool isEndpoint) @@ -93,17 +93,17 @@ namespace tunnel if (isEndpoint) { LogPrint (eLogInfo, "TransitTunnel: endpoint ", receiveTunnelID, " created"); - return new TransitTunnelEndpoint (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey); + return std::make_shared (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey); } else if (isGateway) { LogPrint (eLogInfo, "TransitTunnel: gateway ", receiveTunnelID, " created"); - return new TransitTunnelGateway (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey); + return std::make_shared (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey); } else { LogPrint (eLogInfo, "TransitTunnel: ", receiveTunnelID, "->", nextTunnelID, " created"); - return new TransitTunnelParticipant (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey); + return std::make_shared (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey); } } } diff --git a/TransitTunnel.h b/TransitTunnel.h index e611d685..2a1908df 100644 --- a/TransitTunnel.h +++ b/TransitTunnel.h @@ -93,7 +93,7 @@ namespace tunnel TunnelEndpoint m_Endpoint; }; - TransitTunnel * CreateTransitTunnel (uint32_t receiveTunnelID, + std::shared_ptr CreateTransitTunnel (uint32_t receiveTunnelID, const uint8_t * nextIdent, uint32_t nextTunnelID, const uint8_t * layerKey,const uint8_t * ivKey, bool isGateway, bool isEndpoint); diff --git a/Tunnel.cpp b/Tunnel.cpp index f7102327..37dd6d67 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -205,6 +205,26 @@ namespace tunnel PrintHops (s); s << " ⇒ " << GetTunnelID () << ":me"; } + + ZeroHopsInboundTunnel::ZeroHopsInboundTunnel (): + InboundTunnel (std::make_shared ()), + m_NumReceivedBytes (0) + { + } + + void ZeroHopsInboundTunnel::SendTunnelDataMsg (std::shared_ptr msg) + { + if (msg) + { + m_NumReceivedBytes += msg->GetLength (); + HandleI2NPMessage (msg); + } + } + + void ZeroHopsInboundTunnel::Print (std::stringstream& s) const + { + s << " ⇒ " << GetTunnelID () << ":me"; + } void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr msg) { @@ -257,27 +277,16 @@ namespace tunnel Tunnels::~Tunnels () { - for (auto& it : m_TransitTunnels) - delete it.second; - m_TransitTunnels.clear (); } - - std::shared_ptr Tunnels::GetInboundTunnel (uint32_t tunnelID) + + std::shared_ptr Tunnels::GetTunnel (uint32_t tunnelID) { - auto it = m_InboundTunnels.find(tunnelID); - if (it != m_InboundTunnels.end ()) + auto it = m_Tunnels.find(tunnelID); + if (it != m_Tunnels.end ()) return it->second; return nullptr; } - - TransitTunnel * Tunnels::GetTransitTunnel (uint32_t tunnelID) - { - auto it = m_TransitTunnels.find(tunnelID); - if (it != m_TransitTunnels.end ()) - return it->second; - return nullptr; - } - + std::shared_ptr Tunnels::GetPendingInboundTunnel (uint32_t replyMsgID) { return GetPendingTunnel (replyMsgID, m_PendingInboundTunnels); @@ -306,11 +315,11 @@ namespace tunnel size_t minReceived = 0; for (auto it : m_InboundTunnels) { - if (!it.second->IsEstablished ()) continue; - if (!tunnel || it.second->GetNumReceivedBytes () < minReceived) + if (!it->IsEstablished ()) continue; + if (!tunnel || it->GetNumReceivedBytes () < minReceived) { - tunnel = it.second; - minReceived = it.second->GetNumReceivedBytes (); + tunnel = it; + minReceived = it->GetNumReceivedBytes (); } } return tunnel; @@ -363,14 +372,12 @@ namespace tunnel } } - void Tunnels::AddTransitTunnel (TransitTunnel * tunnel) + void Tunnels::AddTransitTunnel (std::shared_ptr tunnel) { - std::unique_lock l(m_TransitTunnelsMutex); - if (!m_TransitTunnels.insert (std::make_pair (tunnel->GetTunnelID (), tunnel)).second) - { - LogPrint (eLogError, "Tunnel: transit tunnel with id ", tunnel->GetTunnelID (), " already exists"); - delete tunnel; - } + if (m_Tunnels.emplace (tunnel->GetTunnelID (), tunnel).second) + m_TransitTunnels.push_back (tunnel); + else + LogPrint (eLogError, "Tunnel: tunnel with id ", tunnel->GetTunnelID (), " already exists"); } void Tunnels::Start () @@ -404,10 +411,10 @@ namespace tunnel if (msg) { uint32_t prevTunnelID = 0, tunnelID = 0; - TunnelBase * prevTunnel = nullptr; + std::shared_ptr prevTunnel; do { - TunnelBase * tunnel = nullptr; + std::shared_ptr tunnel; uint8_t typeID = msg->GetTypeID (); switch (typeID) { @@ -420,10 +427,8 @@ namespace tunnel else if (prevTunnel) prevTunnel->FlushTunnelDataMsgs (); - if (!tunnel && typeID == eI2NPTunnelData) - tunnel = GetInboundTunnel (tunnelID).get (); if (!tunnel) - tunnel = GetTransitTunnel (tunnelID); + tunnel = GetTunnel (tunnelID); if (tunnel) { if (typeID == eI2NPTunnelData) @@ -471,7 +476,7 @@ namespace tunnel } } - void Tunnels::HandleTunnelGatewayMsg (TunnelBase * tunnel, std::shared_ptr msg) + void Tunnels::HandleTunnelGatewayMsg (std::shared_ptr tunnel, std::shared_ptr msg) { if (!tunnel) { @@ -580,6 +585,7 @@ namespace tunnel auto pool = tunnel->GetTunnelPool (); if (pool) pool->TunnelExpired (tunnel); + // we don't have outbound tunnels in m_Tunnels it = m_OutboundTunnels.erase (it); } else @@ -621,13 +627,14 @@ namespace tunnel { for (auto it = m_InboundTunnels.begin (); it != m_InboundTunnels.end ();) { - auto tunnel = it->second; + auto tunnel = *it; if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) { LogPrint (eLogDebug, "Tunnel: tunnel with id ", tunnel->GetTunnelID (), " expired"); auto pool = tunnel->GetTunnelPool (); if (pool) pool->TunnelExpired (tunnel); + m_Tunnels.erase (tunnel->GetTunnelID ()); it = m_InboundTunnels.erase (it); } else @@ -682,15 +689,12 @@ namespace tunnel uint32_t ts = i2p::util::GetSecondsSinceEpoch (); for (auto it = m_TransitTunnels.begin (); it != m_TransitTunnels.end ();) { - if (ts > it->second->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) + auto tunnel = *it; + if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) { - auto tmp = it->second; - LogPrint (eLogDebug, "Tunnel: Transit tunnel with id ", tmp->GetTunnelID (), " expired"); - { - std::unique_lock l(m_TransitTunnelsMutex); - it = m_TransitTunnels.erase (it); - } - delete tmp; + LogPrint (eLogDebug, "Tunnel: Transit tunnel with id ", tunnel->GetTunnelID (), " expired"); + m_Tunnels.erase (tunnel->GetTunnelID ()); + it = m_TransitTunnels.erase (it); } else it++; @@ -744,6 +748,7 @@ namespace tunnel void Tunnels::AddOutboundTunnel (std::shared_ptr newTunnel) { + // we don't need to insert it to m_Tunnels m_OutboundTunnels.push_back (newTunnel); auto pool = newTunnel->GetTunnelPool (); if (pool && pool->IsActive ()) @@ -754,46 +759,79 @@ namespace tunnel void Tunnels::AddInboundTunnel (std::shared_ptr newTunnel) { - m_InboundTunnels[newTunnel->GetTunnelID ()] = newTunnel; - auto pool = newTunnel->GetTunnelPool (); - if (!pool) - { - // build symmetric outbound tunnel - CreateTunnel (std::make_shared(newTunnel->GetInvertedPeers (), - newTunnel->GetNextTunnelID (), newTunnel->GetNextIdentHash ()), - GetNextOutboundTunnel ()); + if (m_Tunnels.emplace (newTunnel->GetTunnelID (), newTunnel).second) + { + m_InboundTunnels.push_back (newTunnel); + auto pool = newTunnel->GetTunnelPool (); + if (!pool) + { + // build symmetric outbound tunnel + CreateTunnel (std::make_shared(newTunnel->GetInvertedPeers (), + newTunnel->GetNextTunnelID (), newTunnel->GetNextIdentHash ()), + GetNextOutboundTunnel ()); + } + else + { + if (pool->IsActive ()) + pool->TunnelCreated (newTunnel); + else + newTunnel->SetTunnelPool (nullptr); + } } else - { - if (pool->IsActive ()) - pool->TunnelCreated (newTunnel); - else - newTunnel->SetTunnelPool (nullptr); - } + LogPrint (eLogError, "Tunnel: tunnel with id ", newTunnel->GetTunnelID (), " already exists"); } void Tunnels::CreateZeroHopsInboundTunnel () { - CreateTunnel ( + /*CreateTunnel ( std::make_shared (std::vector > { i2p::context.GetIdentity () - })); + }));*/ + auto inboundTunnel = std::make_shared (); + m_InboundTunnels.push_back (inboundTunnel); + m_Tunnels[inboundTunnel->GetTunnelID ()] = inboundTunnel; + + // create paired outbound tunnel, TODO: move to separate function + CreateTunnel ( + std::make_shared (std::vector > + { + i2p::context.GetIdentity () + }, inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ())); } int Tunnels::GetTransitTunnelsExpirationTimeout () { int timeout = 0; uint32_t ts = i2p::util::GetSecondsSinceEpoch (); - std::unique_lock l(m_TransitTunnelsMutex); + // TODO: possible race condition with I2PControl for (auto it: m_TransitTunnels) { - int t = it.second->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT - ts; + int t = it->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT - ts; if (t > timeout) timeout = t; } return timeout; - } + } + + size_t Tunnels::CountTransitTunnels() const + { + // TODO: locking + return m_TransitTunnels.size(); + } + + size_t Tunnels::CountInboundTunnels() const + { + // TODO: locking + return m_InboundTunnels.size(); + } + + size_t Tunnels::CountOutboundTunnels() const + { + // TODO: locking + return m_OutboundTunnels.size(); + } } } diff --git a/Tunnel.h b/Tunnel.h index 138a48fc..34d0a0ab 100644 --- a/Tunnel.h +++ b/Tunnel.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -71,6 +72,8 @@ namespace tunnel void SetTunnelPool (std::shared_ptr pool) { m_Pool = pool; }; bool HandleTunnelBuildResponse (uint8_t * msg, size_t len); + + virtual void Print (std::stringstream& s) const {}; // implements TunnelBase void SendTunnelDataMsg (std::shared_ptr msg); @@ -111,21 +114,34 @@ namespace tunnel TunnelGateway m_Gateway; i2p::data::IdentHash m_EndpointIdentHash; }; - + class InboundTunnel: public Tunnel, public std::enable_shared_from_this { public: InboundTunnel (std::shared_ptr config): Tunnel (config), m_Endpoint (true) {}; void HandleTunnelDataMsg (std::shared_ptr msg); - size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }; + virtual size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }; void Print (std::stringstream& s) const; private: TunnelEndpoint m_Endpoint; }; + + class ZeroHopsInboundTunnel: public InboundTunnel + { + public: + ZeroHopsInboundTunnel (); + void SendTunnelDataMsg (std::shared_ptr msg); + void Print (std::stringstream& s) const; + size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; + + private: + + size_t m_NumReceivedBytes; + }; class Tunnels { @@ -136,15 +152,14 @@ namespace tunnel void Start (); void Stop (); - std::shared_ptr GetInboundTunnel (uint32_t tunnelID); std::shared_ptr GetPendingInboundTunnel (uint32_t replyMsgID); std::shared_ptr GetPendingOutboundTunnel (uint32_t replyMsgID); std::shared_ptr GetNextInboundTunnel (); std::shared_ptr GetNextOutboundTunnel (); std::shared_ptr GetExploratoryPool () const { return m_ExploratoryPool; }; - TransitTunnel * GetTransitTunnel (uint32_t tunnelID); + std::shared_ptr GetTunnel (uint32_t tunnelID); int GetTransitTunnelsExpirationTimeout (); - void AddTransitTunnel (TransitTunnel * tunnel); + void AddTransitTunnel (std::shared_ptr tunnel); void AddOutboundTunnel (std::shared_ptr newTunnel); void AddInboundTunnel (std::shared_ptr newTunnel); void PostTunnelData (std::shared_ptr msg); @@ -163,7 +178,7 @@ namespace tunnel template std::shared_ptr GetPendingTunnel (uint32_t replyMsgID, const std::map >& pendingTunnels); - void HandleTunnelGatewayMsg (TunnelBase * tunnel, std::shared_ptr msg); + void HandleTunnelGatewayMsg (std::shared_ptr tunnel, std::shared_ptr msg); void Run (); void ManageTunnels (); @@ -183,10 +198,10 @@ namespace tunnel std::thread * m_Thread; std::map > m_PendingInboundTunnels; // by replyMsgID std::map > m_PendingOutboundTunnels; // by replyMsgID - std::map > m_InboundTunnels; + std::list > m_InboundTunnels; std::list > m_OutboundTunnels; - std::mutex m_TransitTunnelsMutex; - std::map m_TransitTunnels; + std::list > m_TransitTunnels; + std::unordered_map > m_Tunnels; // tunnelID->tunnel known by this id std::mutex m_PoolsMutex; std::list> m_Pools; std::shared_ptr m_ExploratoryPool; @@ -201,6 +216,11 @@ namespace tunnel const decltype(m_OutboundTunnels)& GetOutboundTunnels () const { return m_OutboundTunnels; }; const decltype(m_InboundTunnels)& GetInboundTunnels () const { return m_InboundTunnels; }; const decltype(m_TransitTunnels)& GetTransitTunnels () const { return m_TransitTunnels; }; + + size_t CountTransitTunnels() const; + size_t CountInboundTunnels() const; + size_t CountOutboundTunnels() const; + int GetQueueSize () { return m_Queue.GetSize (); }; int GetTunnelCreationSuccessRate () const // in percents { diff --git a/TunnelConfig.h b/TunnelConfig.h index 826979c8..c089b13c 100644 --- a/TunnelConfig.h +++ b/TunnelConfig.h @@ -108,7 +108,7 @@ namespace tunnel } }; - class TunnelConfig: public std::enable_shared_from_this + class TunnelConfig { public: @@ -160,26 +160,26 @@ namespace tunnel return num; } - bool IsInbound () const { return m_FirstHop->isGateway; } + virtual bool IsInbound () const { return m_FirstHop->isGateway; } - uint32_t GetTunnelID () const + virtual uint32_t GetTunnelID () const { if (!m_FirstHop) return 0; return IsInbound () ? m_LastHop->nextTunnelID : m_FirstHop->tunnelID; } - uint32_t GetNextTunnelID () const + virtual uint32_t GetNextTunnelID () const { if (!m_FirstHop) return 0; return m_FirstHop->tunnelID; } - const i2p::data::IdentHash& GetNextIdentHash () const + virtual const i2p::data::IdentHash& GetNextIdentHash () const { return m_FirstHop->ident->GetIdentHash (); } - const i2p::data::IdentHash& GetLastIdentHash () const + virtual const i2p::data::IdentHash& GetLastIdentHash () const { return m_LastHop->ident->GetIdentHash (); } @@ -196,12 +196,14 @@ namespace tunnel return peers; } - private: + protected: // this constructor can't be called from outside TunnelConfig (): m_FirstHop (nullptr), m_LastHop (nullptr) { } + + private: template void CreatePeers (const Peers& peers) @@ -222,6 +224,24 @@ namespace tunnel private: TunnelHopConfig * m_FirstHop, * m_LastHop; + }; + + class ZeroHopsTunnelConfig: public TunnelConfig + { + public: + + ZeroHopsTunnelConfig () { RAND_bytes ((uint8_t *)&m_TunnelID, 4);}; + + bool IsInbound () const { return true; }; // TODO: + uint32_t GetTunnelID () const { return m_TunnelID; }; + uint32_t GetNextTunnelID () const { return m_TunnelID; }; + const i2p::data::IdentHash& GetNextIdentHash () const { return i2p::context.GetIdentHash (); }; + const i2p::data::IdentHash& GetLastIdentHash () const { return i2p::context.GetIdentHash (); }; + + + private: + + uint32_t m_TunnelID; }; } }