diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 3fa23dfe..c9d6ba40 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -259,6 +259,12 @@ namespace http { s << "Our external address:" << "
\r\n" ; for (const auto& address : i2p::context.GetRouterInfo().GetAddresses()) { + if (address->IsNTCP2 ()) + { + // TODO: show actual address + s << "NTCP2   supported
\r\n"; + continue; + } switch (address->transportStyle) { case i2p::data::RouterInfo::eTransportNTCP: @@ -540,6 +546,46 @@ namespace http { } } + template + static void ShowNTCPTransports (std::stringstream& s, const Sessions& sessions, const std::string name) + { + std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0; + for (const auto& it: sessions ) + { + if (it.second && it.second->IsEstablished () && !it.second->GetSocket ().remote_endpoint ().address ().is_v6 ()) + { + // incoming connection doesn't have remote RI + if (it.second->IsOutgoing ()) tmp_s << " ⇒ "; + tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " + << it.second->GetSocket ().remote_endpoint().address ().to_string (); + if (!it.second->IsOutgoing ()) tmp_s << " ⇒ "; + tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; + tmp_s << "
\r\n" << std::endl; + cnt++; + } + if (it.second && it.second->IsEstablished () && it.second->GetSocket ().remote_endpoint ().address ().is_v6 ()) + { + if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ "; + tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " + << "[" << it.second->GetSocket ().remote_endpoint().address ().to_string () << "]"; + if (!it.second->IsOutgoing ()) tmp_s6 << " ⇒ "; + tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; + tmp_s6 << "
\r\n" << std::endl; + cnt6++; + } + } + if (!tmp_s.str ().empty ()) + { + s << "
\r\n\r\n

"; + s << tmp_s.str () << "

\r\n
\r\n"; + } + if (!tmp_s6.str ().empty ()) + { + s << "
\r\n\r\n

"; + s << tmp_s6.str () << "

\r\n
\r\n"; + } + } + void ShowTransports (std::stringstream& s) { s << "Transports:
\r\n
\r\n"; @@ -548,43 +594,14 @@ namespace http { { auto sessions = ntcpServer->GetNTCPSessions (); if (!sessions.empty ()) - { - std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0; - for (const auto& it: sessions ) - { - if (it.second && it.second->IsEstablished () && !it.second->GetSocket ().remote_endpoint ().address ().is_v6 ()) - { - // incoming connection doesn't have remote RI - if (it.second->IsOutgoing ()) tmp_s << " ⇒ "; - tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " - << it.second->GetSocket ().remote_endpoint().address ().to_string (); - if (!it.second->IsOutgoing ()) tmp_s << " ⇒ "; - tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; - tmp_s << "
\r\n" << std::endl; - cnt++; - } - if (it.second && it.second->IsEstablished () && it.second->GetSocket ().remote_endpoint ().address ().is_v6 ()) - { - if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ "; - tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " - << "[" << it.second->GetSocket ().remote_endpoint().address ().to_string () << "]"; - if (!it.second->IsOutgoing ()) tmp_s6 << " ⇒ "; - tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; - tmp_s6 << "
\r\n" << std::endl; - cnt6++; - } - } - if (!tmp_s.str ().empty ()) - { - s << "
\r\n\r\n

"; - s << tmp_s.str () << "

\r\n
\r\n"; - } - if (!tmp_s6.str ().empty ()) - { - s << "
\r\n\r\n

"; - s << tmp_s6.str () << "

\r\n
\r\n"; - } - } + ShowNTCPTransports (s, sessions, "NTCP"); + } + auto ntcp2Server = i2p::transport::transports.GetNTCP2Server (); + if (ntcp2Server) + { + auto sessions = ntcp2Server->GetNTCP2Sessions (); + if (!sessions.empty ()) + ShowNTCPTransports (s, sessions, "NTCP2"); } auto ssuServer = i2p::transport::transports.GetSSUServer (); if (ssuServer) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index fe277a63..07ae9b99 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -154,6 +154,9 @@ namespace transport m_IsTerminated = true; m_IsEstablished = false; m_Socket.close (); + transports.PeerDisconnected (shared_from_this ()); + m_Server.RemoveNTCP2Session (shared_from_this ()); + m_SendQueue.clear (); LogPrint (eLogDebug, "NTCP2: session terminated"); } } @@ -741,6 +744,14 @@ namespace transport void NTCP2Server::Stop () { + { + // we have to copy it because Terminate changes m_NTCP2Sessions + auto ntcpSessions = m_NTCP2Sessions; + for (auto& it: ntcpSessions) + it.second->Terminate (); + } + m_NTCP2Sessions.clear (); + if (m_IsRunning) { m_IsRunning = false; @@ -769,12 +780,44 @@ namespace transport } } + bool NTCP2Server::AddNTCP2Session (std::shared_ptr session) + { + if (!session || !session->GetRemoteIdentity ()) return false; + auto& ident = session->GetRemoteIdentity ()->GetIdentHash (); + auto it = m_NTCP2Sessions.find (ident); + if (it != m_NTCP2Sessions.end ()) + { + LogPrint (eLogWarning, "NTCP2: session to ", ident.ToBase64 (), " already exists"); + session->Terminate(); + return false; + } + m_NTCP2Sessions.insert (std::make_pair (ident, session)); + return true; + } + + void NTCP2Server::RemoveNTCP2Session (std::shared_ptr session) + { + if (session && session->GetRemoteIdentity ()) + m_NTCP2Sessions.erase (session->GetRemoteIdentity ()->GetIdentHash ()); + } + + std::shared_ptr NTCP2Server::FindNTCP2Session (const i2p::data::IdentHash& ident) + { + auto it = m_NTCP2Sessions.find (ident); + if (it != m_NTCP2Sessions.end ()) + return it->second; + return nullptr; + } + void NTCP2Server::Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn) { LogPrint (eLogDebug, "NTCP2: Connecting to ", address ,":", port); m_Service.post([this, address, port, conn]() { - conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn)); + if (this->AddNTCP2Session (conn)) + { + conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn)); + } }); } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 1e04587a..34d8b943 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include "RouterInfo.h" @@ -70,6 +71,9 @@ namespace transport boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; + bool IsEstablished () const { return m_IsEstablished; }; + bool IsTerminated () const { return m_IsTerminated; }; + void ClientLogin (); // Alice void ServerLogin (); // Bob void SendI2NPMessages (const std::vector >& msgs); @@ -139,6 +143,10 @@ namespace transport void Start (); void Stop (); + bool AddNTCP2Session (std::shared_ptr session); + void RemoveNTCP2Session (std::shared_ptr session); + std::shared_ptr FindNTCP2Session (const i2p::data::IdentHash& ident); + boost::asio::io_service& GetService () { return m_Service; }; void Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn); @@ -154,6 +162,12 @@ namespace transport std::thread * m_Thread; boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; + std::map > m_NTCP2Sessions; + + public: + + // for HTTP/I2PControl + const decltype(m_NTCP2Sessions)& GetNTCP2Sessions () const { return m_NTCP2Sessions; }; }; } }