diff --git a/SSU.cpp b/SSU.cpp index a036d1ff..1af2aa7c 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -75,18 +75,14 @@ namespace ssu case eSessionRelayRequestSent: // relay response ProcessRelayResponse (buf,len); + m_Server.DeleteSession (this); break; - case eSessionRelayResponseReceived: + case eSessionIntroduced: // HolePunch received LogPrint ("SSU HolePuch of ", len, " bytes received"); - m_State = eSessionStateEstablished; - Established (); - break; - case eSessionRelayRequestReceived: - // HolePunch m_State = eSessionStateUnknown; Connect (); - break; + break; default: LogPrint ("SSU state not implemented yet"); } @@ -151,7 +147,7 @@ namespace ssu if (!Validate (buf, len, introKey)) { LogPrint ("MAC verification intro key failed"); - Failed (); + m_Server.DeleteSession (this); return; } @@ -273,7 +269,7 @@ namespace ssu m_Server.Send (buf, 304, m_RemoteEndpoint); } - void SSUSession::SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer) + void SSUSession::SendRelayRequest (uint32_t iTag, const uint8_t * iKey) { auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); if (!address) @@ -284,7 +280,7 @@ namespace ssu uint8_t buf[96 + 18]; uint8_t * payload = buf + sizeof (SSUHeader); - *(uint32_t *)payload = htobe32 (introducer.iTag); + *(uint32_t *)payload = htobe32 (iTag); payload += 4; *payload = 0; // no address payload++; @@ -299,7 +295,7 @@ namespace ssu uint8_t iv[16]; rnd.GenerateBlock (iv, 16); // random iv - FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, introducer.iKey, iv, introducer.iKey); + FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, iKey, iv, iKey); m_State = eSessionRelayRequestSent; m_Server.Send (buf, 96, m_RemoteEndpoint); } @@ -404,27 +400,22 @@ namespace ssu { Decrypt (buf, len, address->key); SSUHeader * header = (SSUHeader *)buf; - if ((header->flag >> 4) == PAYLOAD_TYPE_RELAY_RESPONSE) + if (header->GetPayloadType () == PAYLOAD_TYPE_RELAY_RESPONSE) { LogPrint ("Relay response received"); - m_State = eSessionRelayRequestReceived; uint8_t * payload = buf + sizeof (SSUHeader); - payload++; - boost::asio::ip::address_v4 remoteIP (be32toh (*(uint32_t* )(payload))); - payload += 4; - uint16_t remotePort = be16toh (*(uint16_t *)(payload)); - payload += 2; - boost::asio::ip::udp::endpoint newRemoteEndpoint(remoteIP, remotePort); - m_Server.ReassignSession (m_RemoteEndpoint, newRemoteEndpoint); - m_RemoteEndpoint = newRemoteEndpoint; - payload++; + payload++; // remote size + //boost::asio::ip::address_v4 remoteIP (be32toh (*(uint32_t* )(payload))); + payload += 4; // remote address + //uint16_t remotePort = be16toh (*(uint16_t *)(payload)); + payload += 2; // remote port + payload++; // our size boost::asio::ip::address_v4 ourIP (be32toh (*(uint32_t* )(payload))); - payload += 4; + payload += 4; // our address uint16_t ourPort = be16toh (*(uint16_t *)(payload)); - payload += 2; + payload += 2; // our port LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort); i2p::context.UpdateAddress (ourIP.to_string ().c_str ()); - m_State= eSessionRelayResponseReceived; } else LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); @@ -524,7 +515,7 @@ namespace ssu } } - void SSUSession::ConnectThroughIntroducer (const i2p::data::RouterInfo::Introducer& introducer) + void SSUSession::Introduce (uint32_t iTag, const uint8_t * iKey) { if (m_State == eSessionStateUnknown) { @@ -532,10 +523,19 @@ namespace ssu m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT)); m_Timer.async_wait (boost::bind (&SSUSession::HandleConnectTimer, this, boost::asio::placeholders::error)); - SendRelayRequest (introducer); + SendRelayRequest (iTag, iKey); } } + void SSUSession::WaitForIntroduction () + { + m_State = eSessionIntroduced; + // set connect timer + m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT)); + m_Timer.async_wait (boost::bind (&SSUSession::HandleConnectTimer, + this, boost::asio::placeholders::error)); + } + void SSUSession::Close () { SendSesionDestroyed (); @@ -977,11 +977,12 @@ namespace ssu else { // otherwise create new session + session = new SSUSession (*this, remoteEndpoint, router, peerTest); + m_Sessions[remoteEndpoint] = session; + if (!router->UsesIntroducer ()) { - // connect directly - session = new SSUSession (*this, remoteEndpoint, router, peerTest); - m_Sessions[remoteEndpoint] = session; + // connect directly LogPrint ("Creating new SSU session to [", router->GetIdentHashAbbreviation (), "] ", remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ()); session->Connect (); @@ -989,24 +990,27 @@ namespace ssu else { // connect through introducer + session->WaitForIntroduction (); if (address->introducers.size () > 0) { auto& introducer = address->introducers[0]; // TODO: boost::asio::ip::udp::endpoint introducerEndpoint (introducer.iHost, introducer.iPort); - it = m_Sessions.find (introducerEndpoint); - if (it == m_Sessions.end ()) - { - session = new SSUSession (*this, introducerEndpoint, router); - m_Sessions[introducerEndpoint] = session; - LogPrint ("Creating new SSU session to [", router->GetIdentHashAbbreviation (), + LogPrint ("Creating new SSU session to [", router->GetIdentHashAbbreviation (), "] through introducer ", introducerEndpoint.address ().to_string (), ":", introducerEndpoint.port ()); - session->ConnectThroughIntroducer (introducer); - } - else + it = m_Sessions.find (introducerEndpoint); + SSUSession * introducerSession = nullptr; + if (it != m_Sessions.end ()) { LogPrint ("Session to introducer already exists"); - // TODO: + introducerSession = it->second; } + else + { + LogPrint ("New session to introducer created"); + introducerSession = new SSUSession (*this, introducerEndpoint, router); + m_Sessions[introducerEndpoint] = introducerSession; + } + introducerSession->Introduce (introducer.iTag, introducer.iKey); } else LogPrint ("Router is unreachable, but not introducers presentd. Ignored"); @@ -1038,19 +1042,6 @@ namespace ssu } m_Sessions.clear (); } - - void SSUServer::ReassignSession (const boost::asio::ip::udp::endpoint& oldEndpoint, const boost::asio::ip::udp::endpoint& newEndpoint) - { - auto it = m_Sessions.find (oldEndpoint); - if (it != m_Sessions.end ()) - { - auto session = it->second; - m_Sessions.erase (it); - m_Sessions[newEndpoint] = session; - LogPrint ("SSU session reassigned from ", oldEndpoint.address ().to_string (), ":", oldEndpoint.port (), - " to ", newEndpoint.address ().to_string (), ":", newEndpoint.port ()); - } - } } } diff --git a/SSU.h b/SSU.h index ab60c71b..e41131b7 100644 --- a/SSU.h +++ b/SSU.h @@ -62,7 +62,7 @@ namespace ssu eSessionStateConfirmedReceived, eSessionRelayRequestSent, eSessionRelayRequestReceived, - eSessionRelayResponseReceived, + eSessionIntroduced, eSessionStateEstablished, eSessionStateFailed }; @@ -78,7 +78,8 @@ namespace ssu ~SSUSession (); void Connect (); - void ConnectThroughIntroducer (const i2p::data::RouterInfo::Introducer& introducer); + void Introduce (uint32_t iTag, const uint8_t * iKey); + void WaitForIntroduction (); void Close (); boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; const i2p::data::RouterInfo * GetRemoteRouter () const { return m_RemoteRouter; }; @@ -94,7 +95,7 @@ namespace ssu void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void SendSessionRequest (); - void SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer); + void SendRelayRequest (uint32_t iTag, const uint8_t * iKey); void ProcessSessionCreated (uint8_t * buf, size_t len); void SendSessionCreated (const uint8_t * x); void ProcessSessionConfirmed (uint8_t * buf, size_t len); @@ -153,7 +154,6 @@ namespace ssu boost::asio::io_service& GetService () { return m_Socket.get_io_service(); }; const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; }; void Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to); - void ReassignSession (const boost::asio::ip::udp::endpoint& oldEndpoint, const boost::asio::ip::udp::endpoint& newEndpoint); private: