diff --git a/Destination.cpp b/Destination.cpp index 349c5785..73fa7a0c 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -168,7 +168,7 @@ namespace client else return false; } - + std::shared_ptr LeaseSetDestination::FindLeaseSet (const i2p::data::IdentHash& ident) { std::lock_guard lock(m_RemoteLeaseSetsMutex); @@ -665,7 +665,8 @@ namespace client ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params): LeaseSetDestination (isPublic, params), - m_Keys (keys), m_DatagramDestination (nullptr) + m_Keys (keys), m_DatagramDestination (nullptr), + m_ReadyChecker(GetService()) { if (isPublic) PersistTemporaryKeys (); @@ -697,6 +698,7 @@ namespace client { if (LeaseSetDestination::Stop ()) { + m_ReadyChecker.cancel(); m_StreamingDestination->Stop (); m_StreamingDestination = nullptr; for (auto& it: m_StreamingDestinationsByPorts) @@ -710,6 +712,30 @@ namespace client return false; } + void ClientDestination::Ready(ReadyPromise & p) + { + ScheduleCheckForReady(&p); + } + + void ClientDestination::ScheduleCheckForReady(ReadyPromise * p) + { + // tick every 100ms + m_ReadyChecker.expires_from_now(boost::posix_time::milliseconds(100)); + m_ReadyChecker.async_wait([&, p] (const boost::system::error_code & ecode) { + HandleCheckForReady(ecode, p); + }); + } + + void ClientDestination::HandleCheckForReady(const boost::system::error_code & ecode, ReadyPromise * p) + { + if(ecode) // error happened + p->set_value(nullptr); + else if(IsReady()) // we are ready + p->set_value(std::shared_ptr(this)); + else // we are not ready + ScheduleCheckForReady(p); + } + void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len) { uint32_t length = bufbe32toh (buf); diff --git a/Destination.h b/Destination.h index 3faab9cc..8150c72d 100644 --- a/Destination.h +++ b/Destination.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "Identity.h" #include "TunnelPool.h" @@ -143,13 +144,19 @@ namespace client class ClientDestination: public LeaseSetDestination { public: - + // type for informing that a client destination is ready + typedef std::promise > ReadyPromise; + ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params = nullptr); ~ClientDestination (); bool Start (); bool Stop (); - + + // informs promise with shared_from_this() when this destination is ready to use + // if cancelled before ready, informs promise with nullptr + void Ready(ReadyPromise & p); + const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); }; @@ -183,6 +190,9 @@ namespace client { return std::static_pointer_cast(shared_from_this ()); } void PersistTemporaryKeys (); + void ScheduleCheckForReady(ReadyPromise * p); + void HandleCheckForReady(const boost::system::error_code & ecode, ReadyPromise * p); + private: i2p::data::PrivateKeys m_Keys; @@ -192,6 +202,8 @@ namespace client std::map > m_StreamingDestinationsByPorts; i2p::datagram::DatagramDestination * m_DatagramDestination; + boost::asio::deadline_timer m_ReadyChecker; + public: // for HTTP only