diff --git a/RouterContext.cpp b/RouterContext.cpp index d9f902dc..a4f99ba7 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -95,9 +95,9 @@ namespace i2p } } - void RouterContext::RemoveIntroducer (uint32_t tag) + void RouterContext::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e) { - if (m_RouterInfo.RemoveIntroducer (tag)) + if (m_RouterInfo.RemoveIntroducer (e)) UpdateRouterInfo (); } diff --git a/RouterContext.h b/RouterContext.h index f7ac4905..27c289d8 100644 --- a/RouterContext.h +++ b/RouterContext.h @@ -29,7 +29,7 @@ namespace i2p void OverrideNTCPAddress (const char * host, int port); // temporary void UpdateAddress (const char * host); // called from SSU void AddIntroducer (const i2p::data::RouterInfo& routerInfo, uint32_t tag); - void RemoveIntroducer (uint32_t tag); + void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); // implements LocalDestination const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 90fa0170..b951db6c 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -507,14 +507,14 @@ namespace data return false; } - bool RouterInfo::RemoveIntroducer (uint32_t tag) + bool RouterInfo::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e) { for (auto& addr : m_Addresses) { if (addr.transportStyle == eTransportSSU && addr.host.is_v4 ()) { for (std::vector::iterator it = addr.introducers.begin (); it != addr.introducers.begin (); it++) - if (it->iTag == tag) + if ( boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e) { addr.introducers.erase (it); return true; diff --git a/RouterInfo.h b/RouterInfo.h index 6acd5885..8959186c 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -97,7 +97,7 @@ namespace data void AddNTCPAddress (const char * host, int port); void AddSSUAddress (const char * host, int port, const uint8_t * key); bool AddIntroducer (const Address * address, uint32_t tag); - bool RemoveIntroducer (uint32_t tag); + bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); void SetProperty (const char * key, const char * value); const char * GetProperty (const char * key) const; bool IsFloodfill () const; diff --git a/SSU.cpp b/SSU.cpp index 0daf32f8..a30b116e 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -18,8 +18,8 @@ namespace ssu SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint, const i2p::data::RouterInfo * router, bool peerTest ): m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_RemoteRouter (router), - m_Timer (m_Server.GetService ()), m_PeerTest (peerTest), m_ToIntroducer (false), - m_State (eSessionStateUnknown), m_IsSessionKey (false), m_RelayTag (0), m_Data (*this), + m_Timer (m_Server.GetService ()), m_PeerTest (peerTest), m_State (eSessionStateUnknown), + m_IsSessionKey (false), m_RelayTag (0), m_Data (*this), m_NumSentBytes (0), m_NumReceivedBytes (0) { m_DHKeysPair = i2p::transports.GetNextDHKeysPair (); @@ -88,7 +88,7 @@ namespace ssu else { if (!len) return; // ignore zero-length packets - if (m_State == eSessionStateEstablished && !m_ToIntroducer) + if (m_State == eSessionStateEstablished) ScheduleTermination (); if (m_IsSessionKey && Validate (buf, len, m_MacKey)) // try session key first @@ -687,21 +687,6 @@ namespace ssu } } - void SSUSession::ScheduleKeepAlive () - { - m_Timer.cancel (); - m_Timer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INETRVAL)); - m_Timer.async_wait (boost::bind (&SSUSession::HandleKeepAliveTimer, - this, boost::asio::placeholders::error)); - } - - void SSUSession::HandleKeepAliveTimer (const boost::system::error_code& ecode) - { - if (ecode != boost::asio::error::operation_aborted) - SendKeepAlive (); - } - - const uint8_t * SSUSession::GetIntroKey () const { if (m_RemoteRouter) @@ -852,15 +837,19 @@ namespace ssu void SSUSession::SendKeepAlive () { - uint8_t buf[48 + 18]; - uint8_t * payload = buf + sizeof (SSUHeader); - *payload = 0; // flags - payload++; - *payload = 0; // num fragments - // encrypt message with session key - FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48); - Send (buf, 48); - LogPrint ("SSU keep-alive sent"); + if (m_State == eSessionStateEstablished) + { + uint8_t buf[48 + 18]; + uint8_t * payload = buf + sizeof (SSUHeader); + *payload = 0; // flags + payload++; + *payload = 0; // num fragments + // encrypt message with session key + FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48); + Send (buf, 48); + LogPrint ("SSU keep-alive sent"); + ScheduleTermination (); + } } void SSUSession::SendSesionDestroyed () @@ -896,26 +885,10 @@ namespace ssu m_Server.Send (buf, size, m_RemoteEndpoint); } - void SSUSession::StartToIntroducer () - { - if (m_State == eSessionStateEstablished) - { - m_ToIntroducer = true; - ScheduleKeepAlive (); - } - } - - void SSUSession::StopToIntroducer () - { - if (m_State == eSessionStateEstablished) - { - m_ToIntroducer = false; - ScheduleTermination (); - } - } SSUServer::SSUServer (int port): m_Thread (nullptr), m_Work (m_Service), - m_Endpoint (boost::asio::ip::udp::v4 (), port), m_Socket (m_Service, m_Endpoint) + m_Endpoint (boost::asio::ip::udp::v4 (), port), m_Socket (m_Service, m_Endpoint), + m_IntroducersUpdateTimer (m_Service) { m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (65535)); m_Socket.set_option (boost::asio::socket_base::send_buffer_size (65535)); @@ -1147,7 +1120,7 @@ namespace ssu ); } - std::set SSUServer::GetIntroducers (int maxNumIntroducers) + std::set SSUServer::FindIntroducers (int maxNumIntroducers) { std::set ret; for (int i = 0; i < maxNumIntroducers; i++) @@ -1167,6 +1140,51 @@ namespace ssu } return ret; } + + void SSUServer::ScheduleIntroducersUpdateTimer () + { + m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL)); + m_IntroducersUpdateTimer.async_wait (boost::bind (&SSUServer::HandleIntroducersUpdateTimer, + this, boost::asio::placeholders::error)); + } + + void SSUServer::HandleIntroducersUpdateTimer (const boost::system::error_code& ecode) + { + if (!ecode) + { + // timeout expired + std::list newList; + int numIntroducers = 0; + for (auto it :m_Introducers) + { + auto session = FindSession (it); + if (session) + { + session->SendKeepAlive (); + newList.push_back (it); + numIntroducers++; + } + else + i2p::context.RemoveIntroducer (it); + } + + if (!numIntroducers) + { + // create new + auto introducers = FindIntroducers (SSU_MAX_NUM_INTRODUCERS); + if (introducers.size () > 0) + { + for (auto it1: introducers) + { + i2p::context.AddIntroducer (*it1->GetRemoteRouter (), it1->GetRelayTag ()); + newList.push_back (it1->GetRemoteEndpoint ()); + } + } + } + m_Introducers = newList; + ScheduleIntroducersUpdateTimer (); + } + } } } diff --git a/SSU.h b/SSU.h index c5a1f61f..bbaf94ad 100644 --- a/SSU.h +++ b/SSU.h @@ -33,8 +33,9 @@ namespace ssu const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes - const int SSU_KEEP_ALIVE_INETRVAL = 30; // 30 seconds + const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds const int SSU_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour + const int SSU_MAX_NUM_INTRODUCERS = 3; // payload types (4 bits) const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0; @@ -78,8 +79,7 @@ namespace ssu size_t GetNumSentBytes () const { return m_NumSentBytes; }; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; - void StartToIntroducer (); - void StopToIntroducer (); + void SendKeepAlive (); uint32_t GetRelayTag () const { return m_RelayTag; }; private: @@ -109,7 +109,6 @@ namespace ssu void SendPeerTest (uint32_t nonce, uint32_t address, uint16_t port, const uint8_t * introKey, bool toAddress = true); void ProcessData (uint8_t * buf, size_t len); void SendSesionDestroyed (); - void SendKeepAlive (); void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key void Send (const uint8_t * buf, size_t size); @@ -122,9 +121,6 @@ namespace ssu void ScheduleTermination (); void HandleTerminationTimer (const boost::system::error_code& ecode); - - void ScheduleKeepAlive (); - void HandleKeepAliveTimer (const boost::system::error_code& ecode); private: @@ -134,7 +130,7 @@ namespace ssu const i2p::data::RouterInfo * m_RemoteRouter; boost::asio::deadline_timer m_Timer; i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server - bool m_PeerTest, m_ToIntroducer; + bool m_PeerTest; SessionState m_State; bool m_IsSessionKey; uint32_t m_RelayTag; @@ -172,13 +168,15 @@ namespace ssu void Run (); void Receive (); - void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred); - - std::set GetIntroducers (int maxNumIntroducers); + void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred); template SSUSession * GetRandomSession (Filter filter); - + + std::set FindIntroducers (int maxNumIntroducers); + void ScheduleIntroducersUpdateTimer (); + void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode); + private: bool m_IsRunning; @@ -188,6 +186,8 @@ namespace ssu boost::asio::ip::udp::endpoint m_Endpoint; boost::asio::ip::udp::socket m_Socket; boost::asio::ip::udp::endpoint m_SenderEndpoint; + boost::asio::deadline_timer m_IntroducersUpdateTimer; + std::list m_Introducers; // introducers we are connected to uint8_t m_ReceiveBuffer[2*SSU_MTU]; std::map m_Sessions; std::map m_Relays; // we are introducer