From 3547a4042c2d692b36657acfbc26c9da1f0adee4 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 25 Dec 2014 16:47:15 -0500 Subject: [PATCH] request and handle LeaseSets through local destination only --- AddressBook.cpp | 2 +- BOB.cpp | 3 +- Destination.cpp | 146 +++++++++++++++++++++++++++++++++++++++++++++++- Destination.h | 27 ++++++++- HTTPServer.cpp | 2 +- I2PTunnel.cpp | 3 +- SAM.cpp | 4 +- 7 files changed, 173 insertions(+), 14 deletions(-) diff --git a/AddressBook.cpp b/AddressBook.cpp index 23fcfce3..cd97ae27 100644 --- a/AddressBook.cpp +++ b/AddressBook.cpp @@ -433,7 +433,7 @@ namespace client const i2p::data::LeaseSet * leaseSet = i2p::data::netdb.FindLeaseSet (ident); if (!leaseSet) { - i2p::data::netdb.RequestDestination (ident, true, i2p::client::context.GetSharedLocalDestination ()->GetTunnelPool ()); + i2p::client::context.GetSharedLocalDestination ()->RequestDestination (ident); std::this_thread::sleep_for (std::chrono::seconds (5)); // wait for 5 seconds leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (ident); } diff --git a/BOB.cpp b/BOB.cpp index 3d271e4e..d4c9eba3 100644 --- a/BOB.cpp +++ b/BOB.cpp @@ -1,7 +1,6 @@ #include #include #include "Log.h" -#include "NetDb.h" #include "ClientContext.h" #include "BOB.h" @@ -97,7 +96,7 @@ namespace client CreateConnection (receiver, leaseSet); else { - i2p::data::netdb.RequestDestination (ident, true, GetLocalDestination ()->GetTunnelPool ()); + GetLocalDestination ()->RequestDestination (ident); m_Timer.expires_from_now (boost::posix_time::seconds (I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT)); m_Timer.async_wait (std::bind (&BOBI2PInboundTunnel::HandleDestinationRequestTimer, this, std::placeholders::_1, receiver, ident)); diff --git a/Destination.cpp b/Destination.cpp index d12a7843..7fa9e9f4 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -3,6 +3,7 @@ #include #include "Log.h" #include "util.h" +#include "Timestamp.h" #include "NetDb.h" #include "Destination.h" @@ -53,6 +54,8 @@ namespace client { if (m_IsRunning) Stop (); + for (auto it: m_LeaseSetRequests) + delete it.second; for (auto it: m_RemoteLeaseSets) delete it.second; if (m_Pool) @@ -193,7 +196,9 @@ namespace client break; case eI2NPDatabaseStore: HandleDatabaseStoreMessage (buf + sizeof (I2NPHeader), be16toh (header->size)); - i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from)); // TODO: remove + break; + case eI2NPDatabaseSearchReply: + HandleDatabaseSearchReplyMessage (buf + sizeof (I2NPHeader), be16toh (header->size)); break; default: i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from)); @@ -203,6 +208,12 @@ namespace client void ClientDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len) { I2NPDatabaseStoreMsg * msg = (I2NPDatabaseStoreMsg *)buf; + auto it1 = m_LeaseSetRequests.find (msg->key); + if (it1 != m_LeaseSetRequests.end ()) + { + delete it1->second; + m_LeaseSetRequests.erase (it1); + } size_t offset = sizeof (I2NPDatabaseStoreMsg); if (msg->replyToken) // TODO: offset += 36; @@ -225,6 +236,46 @@ namespace client LogPrint (eLogError, "Unexpected client's DatabaseStore type ", msg->type, ". Dropped"); } + void ClientDestination::HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len) + { + i2p::data::IdentHash key (buf); + int num = buf[32]; // num + LogPrint ("DatabaseSearchReply for ", key.ToBase64 (), " num=", num); + auto it = m_LeaseSetRequests.find (key); + if (it != m_LeaseSetRequests.end ()) + { + bool found = false; + if (it->second->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST) + { + for (int i = 0; i < num; i++) + { + i2p::data::IdentHash peerHash (buf + 33 + i*32); + auto floodfill = i2p::data::netdb.FindRouter (peerHash); + if (floodfill) + { + found = true; + SendLeaseSetRequest (key, floodfill, it->second); + } + else + { + LogPrint (eLogInfo, "Found new floodfill. Request it"); + i2p::data::netdb.RequestDestination (peerHash); + } + } + } + else + LogPrint (eLogInfo, key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST," floodfills"); + if (!found) + { + LogPrint (eLogError, "Suggested floodfills are not presented in netDb"); + delete it->second; + m_LeaseSetRequests.erase (it); + } + } + else + LogPrint ("Request for ", key.ToBase64 (), " not found"); + } + void ClientDestination::HandleDeliveryStatusMessage (I2NPMessage * msg) { I2NPDeliveryStatusMsg * deliveryStatus = (I2NPDeliveryStatusMsg *)msg->GetPayload (); @@ -247,7 +298,7 @@ namespace client if (m_IsPublic) Publish (); } - + void ClientDestination::Publish () { if (!m_LeaseSet || !m_Pool) @@ -355,5 +406,96 @@ namespace client m_DatagramDestination = new i2p::datagram::DatagramDestination (*this); return m_DatagramDestination; } + + bool ClientDestination::RequestDestination (const i2p::data::IdentHash& dest) + { + if (!m_Pool || !IsReady ()) return false; + m_Service.post (std::bind (&ClientDestination::RequestLeaseSet, this, dest)); + return true; + } + + void ClientDestination::RequestLeaseSet (const i2p::data::IdentHash& dest) + { + std::set excluded; + auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, excluded); + if (floodfill) + { + LeaseSetRequest * request = new LeaseSetRequest (m_Service); + m_LeaseSetRequests[dest] = request; + SendLeaseSetRequest (dest, floodfill, request); + } + else + LogPrint (eLogError, "No floodfills found"); + } + + void ClientDestination::SendLeaseSetRequest (const i2p::data::IdentHash& dest, + std::shared_ptr nextFloodfill, LeaseSetRequest * request) + { + auto replyTunnel = m_Pool->GetNextInboundTunnel (); + if (!replyTunnel) LogPrint (eLogError, "No inbound tunnels found"); + + auto outboundTunnel = m_Pool->GetNextOutboundTunnel (); + if (!outboundTunnel) LogPrint (eLogError, "No outbound tunnels found"); + + if (replyTunnel && outboundTunnel) + { + request->excluded.insert (nextFloodfill->GetIdentHash ()); + request->requestTime = i2p::util::GetSecondsSinceEpoch (); + request->requestTimeoutTimer.cancel (); + + I2NPMessage * msg = WrapMessage (*nextFloodfill, + CreateDatabaseLookupMsg (dest, replyTunnel->GetNextIdentHash (), + replyTunnel->GetNextTunnelID (), false, &request->excluded, true, m_Pool)); + outboundTunnel->SendTunnelDataMsg ( + { + i2p::tunnel::TunnelMessageBlock + { + i2p::tunnel::eDeliveryTypeRouter, + nextFloodfill->GetIdentHash (), 0, msg + } + }); + request->requestTimeoutTimer.expires_from_now (boost::posix_time::seconds(LEASESET_REQUEST_TIMEOUT)); + request->requestTimeoutTimer.async_wait (std::bind (&ClientDestination::HandleRequestTimoutTimer, + this, std::placeholders::_1, dest)); + } + else + { + // request failed + delete request; + m_LeaseSetRequests.erase (dest); + } + } + + void ClientDestination::HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest) + { + if (ecode != boost::asio::error::operation_aborted) + { + auto it = m_LeaseSetRequests.find (dest); + if (it != m_LeaseSetRequests.end ()) + { + bool done = false; + uint64_t ts = i2p::util::GetSecondsSinceEpoch (); + if (ts < it->second->requestTime + MAX_LEASESET_REQUEST_TIMEOUT) + { + auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, it->second->excluded); + if (floodfill) + SendLeaseSetRequest (dest, floodfill, it->second); + else + done = true; + } + else + { + LogPrint (eLogInfo, dest.ToBase64 (), " was not found within ", MAX_LEASESET_REQUEST_TIMEOUT, " seconds"); + done = true; + } + + if (done) + { + delete it->second; + m_LeaseSetRequests.erase (it); + } + } + } + } } } diff --git a/Destination.h b/Destination.h index f880e7ee..fe665db5 100644 --- a/Destination.h +++ b/Destination.h @@ -5,12 +5,15 @@ #include #include #include +#include #include +#include #include "Identity.h" #include "TunnelPool.h" #include "CryptoConst.h" #include "LeaseSet.h" #include "Garlic.h" +#include "NetDb.h" #include "Streaming.h" #include "Datagram.h" @@ -22,7 +25,10 @@ namespace client const uint8_t PROTOCOL_TYPE_DATAGRAM = 17; const uint8_t PROTOCOL_TYPE_RAW = 18; const int PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds - + const int LEASESET_REQUEST_TIMEOUT = 5; // in seconds + const int MAX_LEASESET_REQUEST_TIMEOUT = 40; // in seconds + const int MAX_NUM_FLOODFILLS_PER_REQUEST = 7; + // I2CP const char I2CP_PARAM_INBOUND_TUNNEL_LENGTH[] = "inbound.length"; const int DEFAULT_INBOUND_TUNNEL_LENGTH = 3; @@ -31,6 +37,14 @@ namespace client class ClientDestination: public i2p::garlic::GarlicDestination { + struct LeaseSetRequest + { + LeaseSetRequest (boost::asio::io_service& service): requestTime (0), requestTimeoutTimer (service) {}; + std::set excluded; + uint64_t requestTime; + boost::asio::deadline_timer requestTimeoutTimer; + }; + public: ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params = nullptr); @@ -43,7 +57,8 @@ namespace client i2p::tunnel::TunnelPool * GetTunnelPool () { return m_Pool; }; bool IsReady () const { return m_LeaseSet && m_LeaseSet->HasNonExpiredLeases (); }; const i2p::data::LeaseSet * FindLeaseSet (const i2p::data::IdentHash& ident); - + bool RequestDestination (const i2p::data::IdentHash& dest); + // streaming i2p::stream::StreamingDestination * GetStreamingDestination () const { return m_StreamingDestination; }; std::shared_ptr CreateStream (const i2p::data::LeaseSet& remote, int port = 0); @@ -79,9 +94,14 @@ namespace client void UpdateLeaseSet (); void Publish (); void HandlePublishConfirmationTimer (const boost::system::error_code& ecode); - void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len); + void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len); + void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len); void HandleDeliveryStatusMessage (I2NPMessage * msg); + void RequestLeaseSet (const i2p::data::IdentHash& dest); + void SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr nextFloodfill, LeaseSetRequest * request); + void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest); + private: bool m_IsRunning; @@ -91,6 +111,7 @@ namespace client i2p::data::PrivateKeys m_Keys; uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256]; std::map m_RemoteLeaseSets; + std::map m_LeaseSetRequests; i2p::tunnel::TunnelPool * m_Pool; i2p::data::LeaseSet * m_LeaseSet; diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 0a58c9b2..2248ff83 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -874,7 +874,7 @@ namespace util SendToDestination (leaseSet, port, buf, len); else { - i2p::data::netdb.RequestDestination (destination, true, i2p::client::context.GetSharedLocalDestination ()->GetTunnelPool ()); + i2p::client::context.GetSharedLocalDestination ()->RequestDestination (destination); m_Timer.expires_from_now (boost::posix_time::seconds(HTTP_DESTINATION_REQUEST_TIMEOUT)); m_Timer.async_wait (boost::bind (&HTTPConnection::HandleDestinationRequestTimeout, this, boost::asio::placeholders::error, destination, port, buf, len)); diff --git a/I2PTunnel.cpp b/I2PTunnel.cpp index 567e1635..a031b322 100644 --- a/I2PTunnel.cpp +++ b/I2PTunnel.cpp @@ -1,6 +1,5 @@ #include "base64.h" #include "Log.h" -#include "NetDb.h" #include "Destination.h" #include "ClientContext.h" #include "I2PTunnel.h" @@ -214,7 +213,7 @@ namespace client CreateConnection (socket); else { - i2p::data::netdb.RequestDestination (*m_DestinationIdentHash, true, GetLocalDestination ()->GetTunnelPool ()); + GetLocalDestination ()->RequestDestination (*m_DestinationIdentHash); m_Timer.expires_from_now (boost::posix_time::seconds (I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT)); m_Timer.async_wait (std::bind (&I2PClientTunnel::HandleDestinationRequestTimer, this, std::placeholders::_1, socket)); diff --git a/SAM.cpp b/SAM.cpp index 02251cc6..7cc71f20 100644 --- a/SAM.cpp +++ b/SAM.cpp @@ -7,7 +7,6 @@ #include "base64.h" #include "Identity.h" #include "Log.h" -#include "NetDb.h" #include "Destination.h" #include "ClientContext.h" #include "SAM.h" @@ -757,8 +756,7 @@ namespace client else { LogPrint ("SAM datagram destination not found"); - i2p::data::netdb.RequestDestination (dest.GetIdentHash (), true, - session->localDestination->GetTunnelPool ()); + session->localDestination->RequestDestination (dest.GetIdentHash ()); } } else