diff --git a/.travis.yml b/.travis.yml index 2392878e..55c13a58 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,7 @@ env: global: - # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created - # via the "travis encrypt" command using the project repo's public key - #- secure: "Z3IXrEUCV/gada+XZ0mMTnIIlto/rutD3aDKZhrGzwNT19U41bLr75aXmQC5I8FtXW49J3UtxsYa51sb/sqwBdCeCpD8xhXFbW4ekTl+colIE43xv9A0xSU+LU9Cyi9kS5TtAxLii/OhNk2GV0c3mcxQBCkQGeZmu9m46OeOc44hl1Xa7ujlvSbFb9ITiUqYSsj0PQAM7aPhntXTvuDnXbfhqp/MMs/mObVjEDvahUjUxN2TxIBBBnljMX9XKiYEL/UjHe4vamlX0AlB+7sY6sYVLLTp1g5MDxFaPyc3+a6UVGE3dieQOKnGuMDPC2iZfOL29scAJ0BcxI4yFxxZS0Ozb46LMYEUcUHQlX8llLSiA9ELtVxwUrLCtsXxDz/lzgzxx6eomOzHnOvymi5oo/pY3QpGuoPq+ikgpUKxXyN89ppH0d7tuemCcGdAwv32UGyPL2Kus08bRU12+bF3dEroCmkQ/aYpF9wL9ZTES7pUQBZPnuVsT6v0bSJd3iQiopUIgPNjPlmOaGaLtue+KExj5cu/pynjtFGTGGD21hKLxO8yXOTFmhxytuPb4jjEPddng5h7FKqcUJShqCPpOqoA6zOvp2U/D5btaySb/WfyghGVO/BuIoIdKkwIHClPV7e4Q7s8eWIfYk9R93MdQCmcoCziPgc5UrZ4ZoJ9rss=" - GCC_VERSION=5 + - secure: J4o/q57D7PAqV+hG5VUhwGJLH4ryFWy8YGVAlAOyrRVv9UxfbiihhyE5Yh68tjukdFqLt3WcHB3hoPz0VfbxWGdLQ9OR0r7xxYPetA0qVYcttpumcVSBra17CCRBYOcyRCfbgUY/LVRbKlr8zgkubRUW0skUcAgELyZJA6k/k+3pd1oDjdBLMLp+TeQvQnUtekw7eEzBl31bgpku3vHQEiYxMRY6FhBC0vojNJSjT56pqYzA/bOVrPNDATxHqDAxuEWfNiNQym4P2T+LmkC2utCWlwLBSqTauy54z4nKM6+0xEmRq2hmBWZeSv1tYuKJi8rmtAH5OozyVGSaXpuelcaWE4YrNCGEXOJZQvuD+IEuFVSkqXItoUIjlE1kP/zIDAZERMaISzXkp2xpPQFes8NLE3lNdcvMYYUjVfyUpYN0qE5/XX6Opii6Y8Sj6wQaz1Y5n3g1Lp5TMlQIVmmTUPAWoCq3U2BTPn+Ub8O8Z7Y/9Zr1xdz3gBEJaYv1CuxrSb3z3lQ9BjodBL1u+l5me+16dBe4RbpPwoWvLramJAvKEuDHMx93UnYU+PWs9B9UyIwEh/FxpvRyu8iyI6pfNWIsrc1jJ2nzf1YrnXOHb0C0CdwHH6p6Nzy/bOfaBOihiwc6o9r80AHq0RBbkH7euPOGFAo4iUgYTaS7R9Pw6Rk= sudo: required dist: trusty language: cpp @@ -24,10 +22,10 @@ addons: - ubuntu-toolchain-r-test coverity_scan: project: - name: "monero-project/kovri" - description: "The Kovri I2P Router Project" + name: monero-project/kovri + description: The Kovri I2P Router Project notification_email: anonimal@i2pmail.org - build_command: "cd build && cmake -DWITH_TESTS=ON -DWITH_BENCHMARKS=ON -DWITH_UPNP=ON -DWITH_DOXYGEN=ON ../ && make -j2" + build_command: export CC=gcc-${GCC_VERSION} CXX=g++-${GCC_VERSION} && cd build && cmake -DWITH_TESTS=ON -DWITH_BENCHMARKS=ON -DWITH_UPNP=ON -DWITH_DOXYGEN=ON ../ && make -j2 branch_pattern: coverity_scan before_script: export CC=gcc-${GCC_VERSION} CXX=g++-${GCC_VERSION} script: if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then cd build && cmake -DWITH_TESTS=ON -DWITH_BENCHMARKS=ON -DWITH_UPNP=ON -DWITH_DOXYGEN=ON ../ && make doc && make -j2 ; fi diff --git a/README.md b/README.md index bf1f5e20..a92e0936 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ 2. A secure, private, untraceable C++ implementation of the [I2P](https://geti2p.net) anonymous network. [![Build Status](https://travis-ci.org/monero-project/kovri.svg?branch=master)](https://travis-ci.org/monero-project/kovri) +[![Coverity status](https://scan.coverity.com/projects/7621/badge.svg)](https://scan.coverity.com/projects/7621/) [![Documentation](https://codedocs.xyz/monero-project/kovri.svg)](https://codedocs.xyz/monero-project/kovri/) ## Disclaimer @@ -12,22 +13,28 @@ - See branch ```development``` for most recent activity ## Quickstart -1. Read [BUILDING.md](https://github.com/monero-project/kovri/blob/master/doc/BUILDING.md) and build instructions and minimum version requirements +1. Read [Build Instructions](https://github.com/monero-project/kovri/blob/master/doc/BUILDING.md) for instructions and minimum version requirements 1. Choose a port between ```9111``` and ```30777``` -2. Open your NAT/Firewall to allow incoming TCP/UDP connections to your chosen port (UPnP optional; see [BUILDING.md](https://github.com/monero-project/kovri/blob/master/doc/BUILDING.md)) +2. Open your NAT/Firewall to allow incoming TCP/UDP connections to your chosen port (UPnP optional; see [Build Instructions](https://github.com/monero-project/kovri/blob/master/doc/BUILDING.md)) 3. Clone, build, and run Kovri: ```bash $ git clone https://github.com/monero-project/kovri $ cd kovri/build && cmake ../ && make $ ./kovri -p [your chosen port number] ``` +- For quick help options: ```$ ./kovri --help``` +- For a detailed listing of options: ```$ ./kovri --help-with all``` ## Documentation -- See [FAQ.md](https://github.com/monero-project/kovri/blob/master/doc/FAQ.md) or join us in ```#kovri``` or ```#kovri-dev``` on Freenode or Irc2P +- Read our [FAQ](https://github.com/monero-project/kovri/blob/master/doc/FAQ.md) or join us in ```#kovri``` or ```#kovri-dev``` on Freenode or Irc2P - All other documentation is on our [doc](https://github.com/monero-project/kovri/tree/master/doc) directory ## Developers -- See [CONTRIBUTING.md](https://github.com/monero-project/kovri/blob/master/doc/CONTRIBUTING.md) before sending PR +- Visit our [Forum Funding System](https://forum.getmonero.org/8/funding-required) to get funded for your work +- Read our [Contributing Guide](https://github.com/monero-project/kovri/blob/master/doc/CONTRIBUTING.md) before sending PR + +## Donations +- Visit our [Donations Page](https://getmonero.org/getting-started/donate/) help Kovri with your donations ## Vulnerability Response - Please, submit a report via [HackerOne](https://hackerone.com/kovri) diff --git a/doc/FAQ.md b/doc/FAQ.md index 51728314..efcbd615 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -25,9 +25,9 @@ Key fingerprint = 1218 6272 CD48 E253 9E2D D29B 66A7 6ECF 9144 09F1 As we are currently in pre-alpha, we are working on following: - We provide both end-users and developers a [quality assurance](https://github.com/monero-project/kovri/issues/58) and [development model](https://github.com/monero-project/kovri/blob/master/doc/CONTRIBUTING.md) in order to provide better software for everyone. -- We focus on implementing an [I2CP](https://geti2p.net/en/docs/spec/i2cp) server for any application to connect to and use the I2P network; this includes Monero. +- We provide a [Forum Funding System](https://forum.getmonero.org/8/funding-required) for features/development. - We focus on creating a ["secure by default"](http://www.openbsd.org/security.html), easily maintainable, more-likely-to-be-reviewed I2P router. This will come with the cost of dropping lesser-used features found in the other routers, but core functionality and I2CP will be fully intact. By creating a smaller, efficient, "bare-bones" router, we will provide developers and researchers more time for security auditing and more time to question the I2P design and specifications. -- We will provide a Forum Funding System for features/development and vulnerability disclosures. +- We focus on implementing an [I2CP](https://geti2p.net/en/docs/spec/i2cp) server for any application to connect to and use the I2P network; this includes Monero. - We will implement alternative reseeding options so users can use [Pluggable Transports](https://www.torproject.org/docs/pluggable-transports.html.en) instead of HTTPS for reseed. - We will implement extended functionality *(hidden mode + disabled inbound)* to provide anonymity for those who live in countries with extreme conditions or those firewalled by carrier-grade NAT or DS-Lite. - We will always create a welcome environment for collaboration. diff --git a/src/client/I2PTunnel/I2PTunnel.cpp b/src/client/I2PTunnel/I2PTunnel.cpp index db122dd4..9286a5e4 100644 --- a/src/client/I2PTunnel/I2PTunnel.cpp +++ b/src/client/I2PTunnel/I2PTunnel.cpp @@ -328,7 +328,7 @@ void I2PClientTunnelHandler::HandleStreamRequestComplete( } else { LogPrint(eLogError, "I2PClientTunnelHandler: ", - "I2P Client Tunnel Issue when creating the stream.", + "I2P Client Tunnel Issue when creating the stream. ", "Check the previous warnings for details."); Terminate(); } diff --git a/src/core/transport/NTCP.cpp b/src/core/transport/NTCP.cpp index 460757be..6c3ee341 100644 --- a/src/core/transport/NTCP.cpp +++ b/src/core/transport/NTCP.cpp @@ -32,6 +32,10 @@ #include "NTCP.h" +#include +#include +#include + #include "NTCPSession.h" #include "NetworkDatabase.h" #include "RouterContext.h" @@ -42,77 +46,57 @@ namespace i2p { namespace transport { -NTCPServer::NTCPServer(int) +NTCPServer::NTCPServer( + std::size_t port) : m_IsRunning(false), m_Thread(nullptr), m_Work(m_Service), + m_NTCPEndpoint(boost::asio::ip::tcp::v4(), port), + m_NTCPEndpointV6(boost::asio::ip::tcp::v6(), port), m_NTCPAcceptor(nullptr), - m_NTCPV6Acceptor(nullptr) {} + m_NTCPV6Acceptor(nullptr) { + LogPrint(eLogDebug, "NTCPServer: initializing"); +} NTCPServer::~NTCPServer() { + LogPrint(eLogDebug, "NTCPServer: destroying"); Stop(); } void NTCPServer::Start() { if (!m_IsRunning) { + LogPrint(eLogDebug, "NTCPServer: starting"); m_IsRunning = true; - m_Thread = new std::thread(std::bind(&NTCPServer::Run, this)); - // create acceptors - auto addresses = context.GetRouterInfo().GetAddresses(); - for (auto& address : addresses) { - if (address.transportStyle == - i2p::data::RouterInfo::eTransportNTCP && - address.host.is_v4()) { - m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor( - m_Service, - boost::asio::ip::tcp::endpoint( - boost::asio::ip::tcp::v4(), - address.port)); - LogPrint(eLogInfo, "NTCPServer: listening on port ", address.port); - auto conn = std::make_shared(*this); - m_NTCPAcceptor->async_accept( - conn->GetSocket(), - std::bind( - &NTCPServer::HandleAccept, + m_Thread = std::make_unique(std::bind(&NTCPServer::Run, this)); + // Create acceptors + m_NTCPAcceptor = + std::make_unique( + m_Service, + m_NTCPEndpoint); + auto conn = std::make_shared(*this); + m_NTCPAcceptor->async_accept( + conn->GetSocket(), + std::bind( + &NTCPServer::HandleAccept, + this, + conn, + std::placeholders::_1)); + // If IPv6 is enabled, create IPv6 acceptor + if (context.SupportsV6()) { + m_NTCPV6Acceptor = + std::make_unique(m_Service); + m_NTCPV6Acceptor->open(boost::asio::ip::tcp::v6()); + m_NTCPV6Acceptor->set_option(boost::asio::ip::v6_only(true)); + m_NTCPV6Acceptor->bind(m_NTCPEndpointV6); + m_NTCPV6Acceptor->listen(); + auto conn = std::make_shared(*this); + m_NTCPV6Acceptor->async_accept( + conn->GetSocket(), + std::bind( + &NTCPServer::HandleAcceptV6, this, conn, std::placeholders::_1)); - if (context.SupportsV6()) { - m_NTCPV6Acceptor = new boost::asio::ip::tcp::acceptor(m_Service); - m_NTCPV6Acceptor->open(boost::asio::ip::tcp::v6()); - m_NTCPV6Acceptor->set_option(boost::asio::ip::v6_only(true)); - m_NTCPV6Acceptor->bind(boost::asio::ip::tcp::endpoint( - boost::asio::ip::tcp::v6(), - address.port)); - m_NTCPV6Acceptor->listen(); - LogPrint(eLogInfo, "NTCPServer: listening V6 on port ", address.port); - auto conn = std::make_shared (*this); - m_NTCPV6Acceptor->async_accept( - conn->GetSocket(), - std::bind( - &NTCPServer::HandleAcceptV6, - this, - conn, - std::placeholders::_1)); - } - } - } - } -} - -void NTCPServer::Stop() { - m_NTCPSessions.clear(); - if (m_IsRunning) { - m_IsRunning = false; - delete m_NTCPAcceptor; - m_NTCPAcceptor = nullptr; - delete m_NTCPV6Acceptor; - m_NTCPV6Acceptor = nullptr; - m_Service.stop(); - if (m_Thread) { - m_Thread->join(); - delete m_Thread; - m_Thread = nullptr; } } } @@ -120,42 +104,20 @@ void NTCPServer::Stop() { void NTCPServer::Run() { while (m_IsRunning) { try { + LogPrint(eLogDebug, "NTCPServer: running ioservice"); m_Service.run(); } catch (std::exception& ex) { - LogPrint("NTCPServer: Run(): ", ex.what()); + LogPrint(eLogError, + "NTCPServer: ioservice error: '", ex.what(), "'"); } } } -void NTCPServer::AddNTCPSession( - std::shared_ptr session) { - if (session) { - std::unique_lock l(m_NTCPSessionsMutex); - m_NTCPSessions[session->GetRemoteIdentity().GetIdentHash()] = session; - } -} - -void NTCPServer::RemoveNTCPSession( - std::shared_ptr session) { - if (session) { - std::unique_lock l(m_NTCPSessionsMutex); - m_NTCPSessions.erase(session->GetRemoteIdentity().GetIdentHash()); - } -} - -std::shared_ptr NTCPServer::FindNTCPSession( - const i2p::data::IdentHash& ident) { - std::unique_lock l(m_NTCPSessionsMutex); - auto it = m_NTCPSessions.find(ident); - if (it != m_NTCPSessions.end()) - return it->second; - return nullptr; -} - void NTCPServer::HandleAccept( std::shared_ptr conn, - const boost::system::error_code& error) { - if (!error) { + const boost::system::error_code& ecode) { + if (!ecode) { + LogPrint(eLogDebug, "NTCPServer: handling accepted connection"); boost::system::error_code ec; auto ep = conn->GetSocket().remote_endpoint(ec); if (!ec) { @@ -176,25 +138,29 @@ void NTCPServer::HandleAccept( conn->ServerLogin(); } else { LogPrint(eLogError, - "NTCPServer: HandleAccept(): ", ec.message()); + "NTCPServer: HandleAccept() remote endpoint: ", ec.message()); } + } else { + LogPrint(eLogError, + "NTCPServer: HandleAccept(): '", ecode.message(), "'"); } - if (error != boost::asio::error::operation_aborted) { - conn = std::make_shared (*this); + if (ecode != boost::asio::error::operation_aborted) { + conn = std::make_shared(*this); m_NTCPAcceptor->async_accept( conn->GetSocket(), std::bind( - &NTCPServer::HandleAccept, - this, - conn, - std::placeholders::_1)); + &NTCPServer::HandleAccept, + this, + conn, + std::placeholders::_1)); } } void NTCPServer::HandleAcceptV6( std::shared_ptr conn, - const boost::system::error_code& error) { - if (!error) { + const boost::system::error_code& ecode) { + if (!ecode) { + LogPrint(eLogDebug, "NTCPServer: handling V6 accepted connection"); boost::system::error_code ec; auto ep = conn->GetSocket().remote_endpoint(ec); if (!ec) { @@ -215,46 +181,55 @@ void NTCPServer::HandleAcceptV6( if (conn) conn->ServerLogin(); } else { - LogPrint(eLogError, "NTCPServer: HandleAcceptV6(): ", ec.message()); + LogPrint(eLogError, + "NTCPServer: HandleAcceptV6() remote endpoint: ", ec.message()); } + } else { + LogPrint(eLogError, + "NTCPServer: HandleAcceptV6(): '", ecode.message(), "'"); } - if (error != boost::asio::error::operation_aborted) { - conn = std::make_shared (*this); + if (ecode != boost::asio::error::operation_aborted) { + conn = std::make_shared(*this); m_NTCPV6Acceptor->async_accept( conn->GetSocket(), std::bind( - &NTCPServer::HandleAcceptV6, - this, - conn, - std::placeholders::_1)); + &NTCPServer::HandleAcceptV6, + this, + conn, + std::placeholders::_1)); } } void NTCPServer::Connect( const boost::asio::ip::address& address, - int port, + std::size_t port, std::shared_ptr conn) { LogPrint(eLogInfo, - "NTCPServer: connecting to ", address , ":", port); + "NTCPServer: connecting to [", + context.GetRouterInfo().GetIdentHashAbbreviation(), "] ", + address , ":", port); + m_Service.post([conn, this]() { this->AddNTCPSession(conn); - }); + }); conn->GetSocket().async_connect( boost::asio::ip::tcp::endpoint( - address, - port), + address, + port), std::bind( - &NTCPServer::HandleConnect, - this, - std::placeholders::_1, - conn)); + &NTCPServer::HandleConnect, + this, + conn, + std::placeholders::_1)); } void NTCPServer::HandleConnect( - const boost::system::error_code& ecode, - std::shared_ptr conn) { + std::shared_ptr conn, + const boost::system::error_code& ecode) { if (ecode) { - LogPrint(eLogError, "NTCPServer: connect error: ", ecode.message()); + LogPrint(eLogError, + "NTCPServer: ", conn->GetSocket().remote_endpoint(), + " connect error '", ecode.message(), "'"); if (ecode != boost::asio::error::operation_aborted) i2p::data::netdb.SetUnreachable( conn->GetRemoteIdentity().GetIdentHash(), @@ -262,8 +237,8 @@ void NTCPServer::HandleConnect( conn->Terminate(); } else { LogPrint(eLogInfo, - "NTCPServer: connected to ", conn->GetSocket().remote_endpoint()); - if (conn->GetSocket().local_endpoint().protocol () == + "NTCPServer: connected to ", conn->GetSocket().remote_endpoint()); + if (conn->GetSocket().local_endpoint().protocol() == boost::asio::ip::tcp::v6()) // ipv6 context.UpdateNTCPV6Address( conn->GetSocket().local_endpoint().address()); @@ -271,13 +246,61 @@ void NTCPServer::HandleConnect( } } +void NTCPServer::AddNTCPSession( + std::shared_ptr session) { + if (session) { + LogPrint(eLogDebug, + "NTCPServer: ", session->GetSocket().remote_endpoint(), + ", adding NTCP session"); + std::unique_lock l(m_NTCPSessionsMutex); + m_NTCPSessions[session->GetRemoteIdentity().GetIdentHash()] = session; + } +} + +void NTCPServer::RemoveNTCPSession( + std::shared_ptr session) { + if (session) { + LogPrint(eLogDebug, + "NTCPServer: ", session->GetSocket().remote_endpoint(), + ", removing NTCP session"); + std::unique_lock l(m_NTCPSessionsMutex); + m_NTCPSessions.erase(session->GetRemoteIdentity().GetIdentHash()); + } +} + +std::shared_ptr NTCPServer::FindNTCPSession( + const i2p::data::IdentHash& ident) { + LogPrint(eLogDebug, "NTCPServer: finding NTCP session"); + std::unique_lock l(m_NTCPSessionsMutex); + auto it = m_NTCPSessions.find(ident); + if (it != m_NTCPSessions.end()) + return it->second; + return nullptr; +} + void NTCPServer::Ban( - const boost::asio::ip::address& addr) { + const std::shared_ptr& session) { uint32_t ts = i2p::util::GetSecondsSinceEpoch(); - m_BanList[addr] = ts + NTCP_BAN_EXPIRATION_TIMEOUT; + m_BanList[session->GetRemoteEndpoint().address()] = + ts + static_cast(NTCPTimeoutLength::ban_expiration); LogPrint(eLogInfo, - "NTCPServer: ", addr, " has been banned for ", - NTCP_BAN_EXPIRATION_TIMEOUT, " seconds"); + "NTCPServer:", session->GetFormattedSessionInfo(), "has been banned for ", + static_cast(NTCPTimeoutLength::ban_expiration), " seconds"); +} + +void NTCPServer::Stop() { + LogPrint(eLogDebug, "NTCPServer: stopping"); + m_NTCPSessions.clear(); + if (m_IsRunning) { + m_IsRunning = false; + m_NTCPAcceptor.reset(nullptr); + m_NTCPV6Acceptor.reset(nullptr); + m_Service.stop(); + if (m_Thread) { + m_Thread->join(); + m_Thread.reset(nullptr); + } + } } } // namespace transport diff --git a/src/core/transport/NTCP.h b/src/core/transport/NTCP.h index f8389f8d..546fc0c8 100644 --- a/src/core/transport/NTCP.h +++ b/src/core/transport/NTCP.h @@ -35,9 +35,11 @@ #include +#include #include #include #include +#include #include #include @@ -51,8 +53,9 @@ namespace transport { class NTCPServer { public: - NTCPServer( - int port); + explicit NTCPServer( + std::size_t port); + ~NTCPServer(); void Start(); @@ -70,7 +73,7 @@ class NTCPServer { void Connect( const boost::asio::ip::address& address, - int port, + std::size_t port, std::shared_ptr conn); boost::asio::io_service& GetService() { @@ -78,37 +81,41 @@ class NTCPServer { } void Ban( - const boost::asio::ip::address& addr); + const std::shared_ptr& session); private: void Run(); void HandleAccept( std::shared_ptr conn, - const boost::system::error_code& error); + const boost::system::error_code& ecode); void HandleAcceptV6( std::shared_ptr conn, - const boost::system::error_code& error); + const boost::system::error_code& ecode); void HandleConnect( - const boost::system::error_code& ecode, - std::shared_ptr conn); + std::shared_ptr conn, + const boost::system::error_code& ecode); private: bool m_IsRunning; - std::thread* m_Thread; + std::unique_ptr m_Thread; + boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; - boost::asio::ip::tcp::acceptor* m_NTCPAcceptor, - *m_NTCPV6Acceptor; + + boost::asio::ip::tcp::endpoint m_NTCPEndpoint, m_NTCPEndpointV6; + std::unique_ptr m_NTCPAcceptor, m_NTCPV6Acceptor; + std::mutex m_NTCPSessionsMutex; - std::map > m_NTCPSessions; + std::map> m_NTCPSessions; + // IP -> ban expiration time in seconds std::map m_BanList; public: - // for HTTP/I2PControl + // for I2PControl const decltype(m_NTCPSessions)& GetNTCPSessions() const { return m_NTCPSessions; } diff --git a/src/core/transport/NTCPSession.cpp b/src/core/transport/NTCPSession.cpp index b0cd0afb..77d9f956 100644 --- a/src/core/transport/NTCPSession.cpp +++ b/src/core/transport/NTCPSession.cpp @@ -35,6 +35,8 @@ #include #include +#include +#include #include #include "I2NPProtocol.h" @@ -66,138 +68,108 @@ NTCPSession::NTCPSession( m_ReceiveBufferOffset(0), m_NextMessage(nullptr), m_IsSending(false) { + LogPrint(eLogDebug, "NTCPSession: initializing DH Keys pair"); m_DHKeysPair = transports.GetNextDHKeysPair(); - m_Establisher = new Establisher; + LogPrint(eLogDebug, "NTCPSession: initializing establisher"); + m_Establisher = std::make_unique(); } NTCPSession::~NTCPSession() { - delete m_Establisher; + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "*** destroying session"); } -void NTCPSession::CreateAESKey( - std::uint8_t* pubKey, - i2p::crypto::AESKey& key) { - i2p::crypto::DiffieHellman dh; - std::uint8_t sharedKey[NTCP_PUBKEY_SIZE]; - if (!dh.Agree(sharedKey, m_DHKeysPair->privateKey, pubKey)) { - LogPrint(eLogError, "NTCPSession: couldn't create shared key"); - Terminate(); - return; - } - std::uint8_t* aesKey = key; - if (sharedKey[0] & 0x80) { - aesKey[0] = 0; - memcpy(aesKey + 1, sharedKey, NTCP_SESSIONKEY_SIZE - 1); - } else if (sharedKey[0]) { - memcpy(aesKey, sharedKey, NTCP_SESSIONKEY_SIZE); +// TODO(unassigned): unfinished +void NTCPSession::ServerLogin() { + auto error_code = SetRemoteEndpoint(); + if (!error_code) { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "--> Phase1, receiving"); + boost::asio::async_read( + m_Socket, + boost::asio::buffer( + &m_Establisher->phase1, + sizeof(NTCPPhase1)), + boost::asio::transfer_all(), + std::bind( + &NTCPSession::HandlePhase1Received, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2)); + ScheduleTermination(); } else { - // find first non-zero byte - std::uint8_t* nonZero = sharedKey + 1; - while (!*nonZero) { - nonZero++; - if (nonZero - sharedKey > (std::uint8_t)NTCP_SESSIONKEY_SIZE) { - LogPrint(eLogWarning, - "NTCPSession: first 32 bytes of shared key is all zeros. Ignored"); - return; - } - } - memcpy(aesKey, nonZero, NTCP_SESSIONKEY_SIZE); - } -} - -void NTCPSession::Done() { - m_Server.GetService().post( - std::bind( - &NTCPSession::Terminate, - shared_from_this())); -} - -void NTCPSession::Terminate() { - if (!m_IsTerminated) { - m_IsTerminated = true; - m_IsEstablished = false; - m_Socket.close(); - transports.PeerDisconnected(shared_from_this()); - m_Server.RemoveNTCPSession(shared_from_this()); - m_SendQueue.clear(); - m_NextMessage = nullptr; - m_TerminationTimer.cancel(); - LogPrint(eLogInfo, "NTCPSession: session terminated"); + LogPrint(eLogError, + "NTCPSession:", GetFormattedSessionInfo(), + "!!! ServerLogin(): '", error_code.message(), "'"); } } -void NTCPSession::Connected() { - m_IsEstablished = true; - delete m_Establisher; - m_Establisher = nullptr; - delete m_DHKeysPair; - m_DHKeysPair = nullptr; - SendTimeSyncMessage(); - // we tell immediately who we are - m_SendQueue.push_back(CreateDatabaseStoreMsg()); - transports.PeerConnected(shared_from_this()); -} +/** + * + * Phase1: SessionRequest + * + */ void NTCPSession::ClientLogin() { - if (!m_DHKeysPair) - m_DHKeysPair = transports.GetNextDHKeysPair(); - // send Phase1 - const std::uint8_t* x = m_DHKeysPair->publicKey; - memcpy( - m_Establisher->phase1.pubKey, - x, - NTCP_PUBKEY_SIZE); - i2p::crypto::SHA256().CalculateDigest( - m_Establisher->phase1.HXxorHI, - x, - NTCP_PUBKEY_SIZE); - const std::uint8_t* ident = m_RemoteIdentity.GetIdentHash(); - for (std::size_t i = 0; i < NTCP_HASH_SIZE; i++) - m_Establisher->phase1.HXxorHI[i] ^= ident[i]; - boost::asio::async_write( - m_Socket, - boost::asio::buffer( - &m_Establisher->phase1, - sizeof(NTCPPhase1)), - boost::asio::transfer_all(), - std::bind( - &NTCPSession::HandlePhase1Sent, - shared_from_this(), - std::placeholders::_1, - std::placeholders::_2)); - ScheduleTermination(); -} - -void NTCPSession::ServerLogin() { - boost::system::error_code ec; - auto ep = m_Socket.remote_endpoint(ec); - if (!ec) { - m_ConnectedFrom = ep.address(); - // receive Phase1 - boost::asio::async_read( + // Set shortened ident hash for logging + SetRemoteIdentHashAbbreviation(); + // Set endpoint + auto ecode = SetRemoteEndpoint(); + if (!ecode) { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "*** Phase1, preparing"); + if (!m_DHKeysPair) { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "*** Phase1, acquiring DH keys pair"); + m_DHKeysPair = transports.GetNextDHKeysPair(); + } + const std::uint8_t* x = m_DHKeysPair->public_key.data(); + memcpy( + m_Establisher->phase1.pub_key.data(), + x, + static_cast(NTCPSize::pub_key)); + i2p::crypto::SHA256().CalculateDigest( + m_Establisher->phase1.HXxorHI.data(), + x, + static_cast(NTCPSize::pub_key)); + const std::uint8_t* ident = m_RemoteIdentity.GetIdentHash(); + for (std::size_t i = 0; i < static_cast(NTCPSize::hash); i++) + m_Establisher->phase1.HXxorHI.at(i) ^= ident[i]; + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "<-- Phase1, sending"); + boost::asio::async_write( m_Socket, boost::asio::buffer( &m_Establisher->phase1, sizeof(NTCPPhase1)), boost::asio::transfer_all(), std::bind( - &NTCPSession::HandlePhase1Received, + &NTCPSession::HandlePhase1Sent, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); ScheduleTermination(); + } else { + LogPrint(eLogError, + "NTCPSession:", GetFormattedSessionInfo(), + "!!! ClientLogin(): '", ecode.message(), "'"); } } void NTCPSession::HandlePhase1Sent( const boost::system::error_code& ecode, - std::size_t) { + std::size_t /*bytes_transferred*/) { if (ecode) { LogPrint(eLogError, - "NTCPSession: couldn't send phase 1 message: ", ecode.message()); + "NTCPSession:", GetFormattedSessionInfo(), + "!!! couldn't send Phase1 '", ecode.message(), "'"); if (ecode != boost::asio::error::operation_aborted) Terminate(); } else { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "--> Phase1 sent, receiving"); boost::asio::async_read( m_Socket, boost::asio::buffer( @@ -214,58 +186,92 @@ void NTCPSession::HandlePhase1Sent( void NTCPSession::HandlePhase1Received( const boost::system::error_code& ecode, - std::size_t) { + std::size_t /*bytes_transferred*/) { if (ecode) { LogPrint(eLogError, - "NTCPSession: phase 1 read error '", ecode.message(), "'"); + "NTCPSession:", GetFormattedSessionInfo(), + "!!! Phase1 receive error '", ecode.message(), "'"); if (ecode != boost::asio::error::operation_aborted) Terminate(); } else { - // verify ident - std::uint8_t digest[NTCP_HASH_SIZE]; + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "*** Phase1 received, verifying ident"); + std::array(NTCPSize::hash)> digest; i2p::crypto::SHA256().CalculateDigest( - digest, - m_Establisher->phase1.pubKey, - NTCP_PUBKEY_SIZE); + digest.data(), + m_Establisher->phase1.pub_key.data(), + static_cast(NTCPSize::pub_key)); const std::uint8_t* ident = i2p::context.GetRouterInfo().GetIdentHash(); - for (std::size_t i = 0; i < NTCP_HASH_SIZE; i++) { - if ((m_Establisher->phase1.HXxorHI[i] ^ ident[i]) != digest[i]) { - LogPrint(eLogError, "NTCPSession: wrong ident"); + for (std::size_t i = 0; i < static_cast(NTCPSize::hash); i++) { + if ((m_Establisher->phase1.HXxorHI.at(i) ^ ident[i]) != digest.at(i)) { + LogPrint(eLogError, + "NTCPSession:", GetFormattedSessionInfo(), + "!!! HandlePhase1Received(): wrong ident"); Terminate(); return; } } + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "*** Phase1 successful, proceeding to Phase2"); SendPhase2(); } } +/** + * + * Phase2: SessionCreated + * + */ + void NTCPSession::SendPhase2() { - if (!m_DHKeysPair) + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "*** Phase2, preparing"); + if (!m_DHKeysPair) { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "*** Phase2, acquiring DH keys pair"); m_DHKeysPair = transports.GetNextDHKeysPair(); - const std::uint8_t* y = m_DHKeysPair->publicKey; - memcpy(m_Establisher->phase2.pubKey, y, NTCP_PUBKEY_SIZE); - std::uint8_t xy[NTCP_PUBKEY_SIZE * 2]; // Combined DH key size for hxy - memcpy(xy, m_Establisher->phase1.pubKey, NTCP_PUBKEY_SIZE); - memcpy(xy + NTCP_PUBKEY_SIZE, y, NTCP_PUBKEY_SIZE); + } + const std::uint8_t* y = m_DHKeysPair->public_key.data(); + memcpy( + m_Establisher->phase2.pub_key.data(), + y, + static_cast(NTCPSize::pub_key)); + // Combine DH key size for hxy + std::array(NTCPSize::pub_key) * 2> xy; + memcpy( + xy.data(), + m_Establisher->phase1.pub_key.data(), + static_cast(NTCPSize::pub_key)); + memcpy( + xy.data() + static_cast(NTCPSize::pub_key), + y, + static_cast(NTCPSize::pub_key)); i2p::crypto::SHA256().CalculateDigest( - m_Establisher->phase2.encrypted.hxy, - xy, - NTCP_PUBKEY_SIZE * 2); + m_Establisher->phase2.encrypted.hxy.data(), + xy.data(), + static_cast(NTCPSize::pub_key) * 2); std::uint32_t tsB = htobe32(i2p::util::GetSecondsSinceEpoch()); m_Establisher->phase2.encrypted.timestamp = tsB; i2p::crypto::RandBytes( - m_Establisher->phase2.encrypted.padding, - NTCP_PADDING_SIZE); + m_Establisher->phase2.encrypted.padding.data(), + static_cast(NTCPSize::padding)); i2p::crypto::AESKey aesKey; - CreateAESKey(m_Establisher->phase1.pubKey, aesKey); + CreateAESKey(m_Establisher->phase1.pub_key.data(), aesKey); m_Encryption.SetKey(aesKey); m_Encryption.SetIV(y + 240); m_Decryption.SetKey(aesKey); - m_Decryption.SetIV(m_Establisher->phase1.HXxorHI + NTCP_IV_SIZE); + m_Decryption.SetIV( + m_Establisher->phase1.HXxorHI.data() + + static_cast(NTCPSize::iv)); m_Encryption.Encrypt( reinterpret_cast(&m_Establisher->phase2.encrypted), sizeof(m_Establisher->phase2.encrypted), reinterpret_cast(&m_Establisher->phase2.encrypted)); + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "<-- Phase2, sending"); boost::asio::async_write( m_Socket, boost::asio::buffer( @@ -282,19 +288,23 @@ void NTCPSession::SendPhase2() { void NTCPSession::HandlePhase2Sent( const boost::system::error_code& ecode, - std::size_t, + std::size_t /*bytes_transferred*/, std::uint32_t tsB) { if (ecode) { LogPrint(eLogError, - "NTCPSession: couldn't send phase 2 message: ", ecode.message()); + "NTCPSession:", GetFormattedSessionInfo(), + "*** couldn't send Phase2: '", ecode.message(), "'"); if (ecode != boost::asio::error::operation_aborted) Terminate(); } else { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "--> Phase2 sent, receiving Phase3"); boost::asio::async_read( m_Socket, boost::asio::buffer( m_ReceiveBuffer, - NTCP_PHASE3_UNENCRYPTED_SIZE), + static_cast(NTCPSize::phase3_unencrypted)), boost::asio::transfer_all(), std::bind( &NTCPSession::HandlePhase3Received, @@ -307,13 +317,15 @@ void NTCPSession::HandlePhase2Sent( void NTCPSession::HandlePhase2Received( const boost::system::error_code& ecode, - std::size_t) { + std::size_t /*bytes_transferred*/) { if (ecode) { LogPrint(eLogError, - "NTCPSession: phase 2 read error '", ecode.message(), - "', wrong ident assumed"); + "NTCPSession:", GetFormattedSessionInfo(), + "!!! Phase2 read error '", ecode.message(), "'"); if (ecode != boost::asio::error::operation_aborted) { - // this RI is not valid + LogPrint(eLogError, + "NTCPSession:", GetFormattedSessionInfo(), + "!!! Phase2 error, RI is not valid"); i2p::data::netdb.SetUnreachable( GetRemoteIdentity().GetIdentHash(), true); @@ -322,62 +334,133 @@ void NTCPSession::HandlePhase2Received( Terminate(); } } else { - i2p::crypto::AESKey aesKey; - CreateAESKey(m_Establisher->phase2.pubKey, aesKey); - m_Decryption.SetKey(aesKey); - m_Decryption.SetIV(m_Establisher->phase2.pubKey + 240); - m_Encryption.SetKey(aesKey); - m_Encryption.SetIV(m_Establisher->phase1.HXxorHI + NTCP_IV_SIZE); + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "*** Phase2 received, processing"); + i2p::crypto::AESKey aes_key; + CreateAESKey(m_Establisher->phase2.pub_key.data(), aes_key); + m_Decryption.SetKey(aes_key); + // TODO(unassigned): document 240 + m_Decryption.SetIV(m_Establisher->phase2.pub_key.data() + 240); + m_Encryption.SetKey(aes_key); + m_Encryption.SetIV( + m_Establisher->phase1.HXxorHI.data() + + static_cast(NTCPSize::iv)); m_Decryption.Decrypt( reinterpret_cast(&m_Establisher->phase2.encrypted), sizeof(m_Establisher->phase2.encrypted), reinterpret_cast(&m_Establisher->phase2.encrypted)); - // verify - std::uint8_t xy[NTCP_PUBKEY_SIZE * 2]; + // Verify + std::array(NTCPSize::pub_key) * 2> xy; memcpy( - xy, - m_DHKeysPair->publicKey, - NTCP_PUBKEY_SIZE); + xy.data(), + m_DHKeysPair->public_key.data(), + static_cast(NTCPSize::pub_key)); memcpy( - xy + NTCP_PUBKEY_SIZE, - m_Establisher->phase2.pubKey, - NTCP_PUBKEY_SIZE); + xy.data() + static_cast(NTCPSize::pub_key), + m_Establisher->phase2.pub_key.data(), + static_cast(NTCPSize::pub_key)); if (!i2p::crypto::SHA256().VerifyDigest( - m_Establisher->phase2.encrypted.hxy, - xy, - NTCP_PUBKEY_SIZE * 2)) { - LogPrint(eLogError, "NTCPSession: incorrect hash"); + m_Establisher->phase2.encrypted.hxy.data(), + xy.data(), + static_cast(NTCPSize::pub_key) * 2)) { + LogPrint(eLogError, + "NTCPSession:", GetFormattedSessionInfo(), + "!!! Phase2, incorrect hash"); transports.ReuseDHKeysPair(m_DHKeysPair); m_DHKeysPair = nullptr; Terminate(); return; } + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "*** Phase2 successful, proceeding to Phase3"); SendPhase3(); } } +void NTCPSession::CreateAESKey( + std::uint8_t* pub_key, + i2p::crypto::AESKey& key) { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "*** creating shared key"); + i2p::crypto::DiffieHellman dh; + std::array(NTCPSize::pub_key)> shared_key; + if (!dh.Agree(shared_key.data(), m_DHKeysPair->private_key.data(), pub_key)) { + LogPrint(eLogError, + "NTCPSession:", GetFormattedSessionInfo(), + "!!! couldn't create shared key"); + Terminate(); + return; + } + std::uint8_t* aes_key = key; + if (shared_key.at(0) & 0x80) { + aes_key[0] = 0; + memcpy( + aes_key + 1, + shared_key.data(), + static_cast(NTCPSize::session_key) - 1); + } else if (shared_key.at(0)) { + memcpy( + aes_key, + shared_key.data(), + static_cast(NTCPSize::session_key)); + } else { + // Find first non-zero byte + std::uint8_t* non_zero = shared_key.data() + 1; + while (!*non_zero) { + non_zero++; + if (non_zero - shared_key.data() > + static_cast(NTCPSize::pub_key)) { + LogPrint(eLogWarning, + "NTCPSession:", GetFormattedSessionInfo(), + "*** first 32 bytes of shared key is all zeros. Ignored"); + return; + } + } + memcpy(aes_key, non_zero, static_cast(NTCPSize::session_key)); + } +} + +/** + * + * Phase3: SessionConfirm A + * + */ + void NTCPSession::SendPhase3() { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "*** Phase3, preparing"); auto keys = i2p::context.GetPrivateKeys(); std::uint8_t* buf = m_ReceiveBuffer; htobe16buf(buf, keys.GetPublic().GetFullLen()); - buf += NTCP_PHASE3_ALICE_RI_SIZE; - buf += i2p::context.GetIdentity().ToBuffer(buf, NTCP_BUFFER_SIZE); + buf += static_cast(NTCPSize::phase3_alice_ri); + buf += + i2p::context.GetIdentity().ToBuffer( + buf, + static_cast(NTCPSize::buffer)); std::uint32_t tsA = htobe32(i2p::util::GetSecondsSinceEpoch()); htobuf32(buf, tsA); - buf += NTCP_PHASE3_ALICE_TS_SIZE; - std::size_t signatureLen = keys.GetPublic().GetSignatureLen(); - std::size_t len = (buf - m_ReceiveBuffer) + signatureLen; - std::size_t paddingSize = len & 0x0F; // %16 - if (paddingSize > 0) { - paddingSize = NTCP_IV_SIZE - paddingSize; - i2p::crypto::RandBytes(buf, paddingSize); - buf += paddingSize; - len += paddingSize; + buf += static_cast(NTCPSize::phase3_alice_ts); + std::size_t signature_len = keys.GetPublic().GetSignatureLen(); + std::size_t len = (buf - m_ReceiveBuffer) + signature_len; + std::size_t padding_size = len & 0x0F; // %16 + if (padding_size > 0) { + padding_size = static_cast(NTCPSize::iv) - padding_size; + i2p::crypto::RandBytes(buf, padding_size); + buf += padding_size; + len += padding_size; } SignedData s; - s.Insert(m_Establisher->phase1.pubKey, NTCP_PUBKEY_SIZE); // x - s.Insert(m_Establisher->phase2.pubKey, NTCP_PUBKEY_SIZE); // y - s.Insert(m_RemoteIdentity.GetIdentHash(), NTCP_HASH_SIZE); + s.Insert( + m_Establisher->phase1.pub_key.data(), + static_cast(NTCPSize::pub_key)); // x + s.Insert( + m_Establisher->phase2.pub_key.data(), + static_cast(NTCPSize::pub_key)); // y + s.Insert( + m_RemoteIdentity.GetIdentHash(), + static_cast(NTCPSize::hash)); s.Insert(tsA); // timestamp Alice s.Insert(m_Establisher->phase2.encrypted.timestamp); // timestamp Bob s.Sign(keys, buf); @@ -385,6 +468,8 @@ void NTCPSession::SendPhase3() { m_ReceiveBuffer, len, m_ReceiveBuffer); + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "<-- Phase3, sending"); boost::asio::async_write( m_Socket, boost::asio::buffer( @@ -401,24 +486,27 @@ void NTCPSession::SendPhase3() { void NTCPSession::HandlePhase3Sent( const boost::system::error_code& ecode, - std::size_t, + std::size_t /*bytes_transferred*/, std::uint32_t tsA) { if (ecode) { LogPrint(eLogError, - "NTCPSession: couldn't send phase 3 message: ", ecode.message()); + "NTCPSession:", GetFormattedSessionInfo(), + "!!! couldn't send Phase3 '", ecode.message(), "'"); if (ecode != boost::asio::error::operation_aborted) Terminate(); } else { - // wait for phase4 - auto signatureLen = m_RemoteIdentity.GetSignatureLen(); - std::size_t paddingSize = signatureLen & 0x0F; // %16 - if (paddingSize > 0) - signatureLen += (NTCP_IV_SIZE - paddingSize); + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "--> Phase3 sent, receiving Phase4"); + auto signature_len = m_RemoteIdentity.GetSignatureLen(); + std::size_t padding_size = signature_len & 0x0F; // %16 + if (padding_size > 0) + signature_len += (static_cast(NTCPSize::iv) - padding_size); boost::asio::async_read( m_Socket, boost::asio::buffer( m_ReceiveBuffer, - signatureLen), + signature_len), boost::asio::transfer_all(), std::bind( &NTCPSession::HandlePhase4Received, @@ -435,36 +523,48 @@ void NTCPSession::HandlePhase3Received( std::uint32_t tsB) { if (ecode) { LogPrint(eLogError, - "NTCPSession: phase 3 read error '", ecode.message(), "'"); + "NTCPSession:", GetFormattedSessionInfo(), + "!!! Phase3 read error '", ecode.message(), "'"); if (ecode != boost::asio::error::operation_aborted) Terminate(); } else { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "*** Phase3 received, processing"); m_Decryption.Decrypt( m_ReceiveBuffer, bytes_transferred, m_ReceiveBuffer); std::uint8_t* buf = m_ReceiveBuffer; - uint16_t size = bufbe16toh(buf); - m_RemoteIdentity.FromBuffer(buf + NTCP_PHASE3_ALICE_RI_SIZE, size); + std::uint16_t size = bufbe16toh(buf); + m_RemoteIdentity.FromBuffer( + buf + static_cast(NTCPSize::phase3_alice_ri), + size); if (m_Server.FindNTCPSession(m_RemoteIdentity.GetIdentHash())) { - LogPrint(eLogError, "NTCPSession: session already exists"); + LogPrint(eLogError, + "NTCPSession:", GetFormattedSessionInfo(), + "!!! Phase3, session already exists"); Terminate(); } - size_t expectedSize = size + - NTCP_PHASE3_ALICE_RI_SIZE + - NTCP_PHASE3_ALICE_TS_SIZE + - m_RemoteIdentity.GetSignatureLen(); - size_t paddingLen = expectedSize & 0x0F; - if (paddingLen) - paddingLen = (16 - paddingLen); - if (expectedSize > NTCP_PHASE3_UNENCRYPTED_SIZE) { - // we need more bytes for Phase3 - expectedSize += paddingLen; + std::size_t expected_size = + size + + static_cast(NTCPSize::phase3_alice_ri) + + static_cast(NTCPSize::phase3_alice_ts) + + m_RemoteIdentity.GetSignatureLen(); + std::size_t padding_len = expected_size & 0x0F; + if (padding_len) + padding_len = (16 - padding_len); + if (expected_size > static_cast(NTCPSize::phase3_unencrypted)) { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "*** Phase3, we need more bytes, reading more"); + expected_size += padding_len; boost::asio::async_read( m_Socket, boost::asio::buffer( - m_ReceiveBuffer + NTCP_PHASE3_UNENCRYPTED_SIZE, - expectedSize), + m_ReceiveBuffer + + static_cast(NTCPSize::phase3_unencrypted), + expected_size), boost::asio::transfer_all(), std::bind( &NTCPSession::HandlePhase3ExtraReceived, @@ -472,9 +572,9 @@ void NTCPSession::HandlePhase3Received( std::placeholders::_1, std::placeholders::_2, tsB, - paddingLen)); + padding_len)); } else { - HandlePhase3(tsB, paddingLen); + HandlePhase3(tsB, padding_len); } } } @@ -483,70 +583,102 @@ void NTCPSession::HandlePhase3ExtraReceived( const boost::system::error_code& ecode, std::size_t bytes_transferred, std::uint32_t tsB, - std::size_t paddingLen) { + std::size_t padding_len) { if (ecode) { LogPrint(eLogError, - "NTCPSession: phase 3 extra read error '", ecode.message(), "'"); + "NTCPSession:", GetFormattedSessionInfo(), + "!!! Phase3, extra read error '", ecode.message(), "'"); if (ecode != boost::asio::error::operation_aborted) Terminate(); } else { m_Decryption.Decrypt( - m_ReceiveBuffer + NTCP_PHASE3_UNENCRYPTED_SIZE, + m_ReceiveBuffer + + static_cast(NTCPSize::phase3_unencrypted), bytes_transferred, - m_ReceiveBuffer+ NTCP_PHASE3_UNENCRYPTED_SIZE); - HandlePhase3(tsB, paddingLen); + m_ReceiveBuffer + + static_cast(NTCPSize::phase3_unencrypted)); + HandlePhase3(tsB, padding_len); } } void NTCPSession::HandlePhase3( std::uint32_t tsB, - std::size_t paddingLen) { + std::size_t padding_len) { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "*** Phase3, handling"); std::uint8_t* buf = m_ReceiveBuffer + m_RemoteIdentity.GetFullLen() + - NTCP_PHASE3_ALICE_RI_SIZE; + static_cast(NTCPSize::phase3_alice_ri); std::uint32_t tsA = buf32toh(buf); - buf += NTCP_PHASE3_ALICE_TS_SIZE; - buf += paddingLen; + buf += static_cast(NTCPSize::phase3_alice_ts); + buf += padding_len; SignedData s; - s.Insert(m_Establisher->phase1.pubKey, NTCP_PUBKEY_SIZE); // x - s.Insert(m_Establisher->phase2.pubKey, NTCP_PUBKEY_SIZE); // y - s.Insert(i2p::context.GetRouterInfo().GetIdentHash(), NTCP_HASH_SIZE); + s.Insert( + m_Establisher->phase1.pub_key.data(), + static_cast(NTCPSize::pub_key)); // x + s.Insert( + m_Establisher->phase2.pub_key.data(), + static_cast(NTCPSize::pub_key)); // y + s.Insert( + i2p::context.GetRouterInfo().GetIdentHash(), + static_cast(NTCPSize::hash)); s.Insert(tsA); s.Insert(tsB); if (!s.Verify(m_RemoteIdentity, buf)) { - LogPrint(eLogError, "NTCPSession: phase 3 signature verification failed"); + LogPrint(eLogError, + "NTCPSession:", GetFormattedSessionInfo(), + "!!! Phase3, signature verification failed"); Terminate(); return; } m_RemoteIdentity.DropVerifier(); + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "*** Phase3 successful, proceeding to Phase4"); SendPhase4(tsA, tsB); } +/** + * + * Phase4: SessionConfirm B + * + */ + void NTCPSession::SendPhase4( std::uint32_t tsA, std::uint32_t tsB) { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "*** Phase4, preparing"); SignedData s; - s.Insert(m_Establisher->phase1.pubKey, NTCP_PUBKEY_SIZE); // x - s.Insert(m_Establisher->phase2.pubKey, NTCP_PUBKEY_SIZE); // y - s.Insert(m_RemoteIdentity.GetIdentHash(), NTCP_HASH_SIZE); + s.Insert( + m_Establisher->phase1.pub_key.data(), + static_cast(NTCPSize::pub_key)); // x + s.Insert( + m_Establisher->phase2.pub_key.data(), + static_cast(NTCPSize::pub_key)); // y + s.Insert( + m_RemoteIdentity.GetIdentHash(), + static_cast(NTCPSize::hash)); s.Insert(tsA); s.Insert(tsB); auto keys = i2p::context.GetPrivateKeys(); - auto signatureLen = keys.GetPublic().GetSignatureLen(); + auto signature_len = keys.GetPublic().GetSignatureLen(); s.Sign(keys, m_ReceiveBuffer); - size_t paddingSize = signatureLen & 0x0F; // %16 - if (paddingSize > 0) - signatureLen += (NTCP_IV_SIZE - paddingSize); + std::size_t padding_size = signature_len & 0x0F; // %16 + if (padding_size > 0) + signature_len += (static_cast(NTCPSize::iv) - padding_size); m_Encryption.Encrypt( m_ReceiveBuffer, - signatureLen, + signature_len, m_ReceiveBuffer); + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "<-- Phase4, sending"); boost::asio::async_write( m_Socket, boost::asio::buffer( m_ReceiveBuffer, - signatureLen), + signature_len), boost::asio::transfer_all(), std::bind( &NTCPSession::HandlePhase4Sent, @@ -557,21 +689,23 @@ void NTCPSession::SendPhase4( void NTCPSession::HandlePhase4Sent( const boost::system::error_code& ecode, - std::size_t) { + std::size_t /*bytes_transferred*/) { if (ecode) { LogPrint(eLogWarning, - "NTCPSession: couldn't send phase 4 message '", ecode.message(), "'"); + "NTCPSession:", GetFormattedSessionInfo(), + "!!! couldn't send Phase4 '", ecode.message(), "'"); if (ecode != boost::asio::error::operation_aborted) Terminate(); } else { - LogPrint(eLogInfo, - "NTCPSession: server session from ", - m_Socket.remote_endpoint(), " connected"); + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "*** Phase4 sent"); m_Server.AddNTCPSession(shared_from_this()); Connected(); m_ReceiveBufferOffset = 0; m_NextMessage = nullptr; - Receive(); + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "--> Phase4, receiving"); + ReceivePayload(); } } @@ -581,166 +715,234 @@ void NTCPSession::HandlePhase4Received( std::uint32_t tsA) { if (ecode) { LogPrint(eLogError, - "NTCPSession: phase 4 read error '", ecode.message(), - "', check your clock"); + "NTCPSession:", GetFormattedSessionInfo(), + "!!! Phase4 read error '", ecode.message(), "', check your clock"); if (ecode != boost::asio::error::operation_aborted) { - // this router doesn't like us + LogPrint(eLogError, + "NTCPSession:", GetFormattedSessionInfo(), + "!!! Phase4, remote router does not like us"); i2p::data::netdb.SetUnreachable(GetRemoteIdentity().GetIdentHash(), true); Terminate(); } } else { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "*** Phase4 received, processing ", bytes_transferred, " bytes"); m_Decryption.Decrypt(m_ReceiveBuffer, bytes_transferred, m_ReceiveBuffer); - // verify signature + // Verify signature SignedData s; - s.Insert(m_Establisher->phase1.pubKey, NTCP_PUBKEY_SIZE); // x - s.Insert(m_Establisher->phase2.pubKey, NTCP_PUBKEY_SIZE); // y - s.Insert(i2p::context.GetRouterInfo().GetIdentHash(), NTCP_HASH_SIZE); - s.Insert(tsA); // timestamp Alice - s.Insert(m_Establisher->phase2.encrypted.timestamp); // timestamp Bob + s.Insert( + m_Establisher->phase1.pub_key.data(), + static_cast(NTCPSize::pub_key)); // x + s.Insert( + m_Establisher->phase2.pub_key.data(), + static_cast(NTCPSize::pub_key)); // y + s.Insert( + i2p::context.GetRouterInfo().GetIdentHash(), + static_cast(NTCPSize::hash)); + s.Insert(tsA); // Timestamp Alice + s.Insert(m_Establisher->phase2.encrypted.timestamp); // Timestamp Bob if (!s.Verify(m_RemoteIdentity, m_ReceiveBuffer)) { - LogPrint(eLogError, "NTCPSession: phase 4 signature verification failed"); + LogPrint(eLogError, + "NTCPSession:", GetFormattedSessionInfo(), + "!!! Phase4 signature verification failed"); Terminate(); return; } m_RemoteIdentity.DropVerifier(); - LogPrint(eLogInfo, - "NTCPSession: session to ", m_Socket.remote_endpoint(), " connected"); + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "*** Phase4, session connected"); Connected(); m_ReceiveBufferOffset = 0; m_NextMessage = nullptr; - Receive(); + ReceivePayload(); } } -void NTCPSession::Receive() { - m_Socket.async_read_some( +/** + * + * SessionEstablished + * + */ + +void NTCPSession::Connected() { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "*** processing connected session"); + m_IsEstablished = true; + m_Establisher.reset(nullptr); + delete m_DHKeysPair; + m_DHKeysPair = nullptr; + SendTimeSyncMessage(); + // We tell immediately who we are + m_SendQueue.push_back(CreateDatabaseStoreMsg()); + transports.PeerConnected(shared_from_this()); +} + +void NTCPSession::ReceivePayload() { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "--> receiving payload"); + boost::asio::async_read( + m_Socket, boost::asio::buffer( m_ReceiveBuffer + m_ReceiveBufferOffset, - NTCP_BUFFER_SIZE - m_ReceiveBufferOffset), + static_cast(NTCPSize::buffer) - m_ReceiveBufferOffset), + boost::asio::transfer_all(), std::bind( - &NTCPSession::HandleReceived, + &NTCPSession::HandleReceivedPayload, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } -void NTCPSession::HandleReceived( +void NTCPSession::HandleReceivedPayload( const boost::system::error_code& ecode, std::size_t bytes_transferred) { if (ecode) { - LogPrint(eLogError, "NTCPSession: HandleReceived(): ", ecode.message()); - if (!m_NumReceivedBytes) - m_Server.Ban(m_ConnectedFrom); + LogPrint(eLogError, + "NTCPSession:", GetFormattedSessionInfo(), + "!!! HandleReceived(): '", ecode.message(), "'"); + if (!m_NumReceivedBytes) { + // Ban peer + LogPrint(eLogInfo, + "NTCPSession:", GetFormattedSessionInfo(), "!!! banning"); + m_Server.Ban(shared_from_this()); + } // if (ecode != boost::asio::error::operation_aborted) Terminate(); } else { m_NumReceivedBytes += bytes_transferred; + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "--> ", bytes_transferred, " bytes transferred, ", + GetNumReceivedBytes(), " total bytes received"); i2p::transport::transports.UpdateReceivedBytes(bytes_transferred); m_ReceiveBufferOffset += bytes_transferred; - if (m_ReceiveBufferOffset >= NTCP_IV_SIZE) { - int numReloads = 0; + if (m_ReceiveBufferOffset >= static_cast(NTCPSize::iv)) { + std::size_t num_reloads = 0; do { - std::uint8_t* nextBlock = m_ReceiveBuffer; - while (m_ReceiveBufferOffset >= NTCP_IV_SIZE) { - if (!DecryptNextBlock(nextBlock)) { // 16 bytes + std::uint8_t* next_block = m_ReceiveBuffer; + while (m_ReceiveBufferOffset >= static_cast(NTCPSize::iv)) { + if (!DecryptNextBlock(next_block)) { // 16 bytes Terminate(); return; } - nextBlock += NTCP_IV_SIZE; - m_ReceiveBufferOffset -= NTCP_IV_SIZE; + next_block += static_cast(NTCPSize::iv); + m_ReceiveBufferOffset -= static_cast(NTCPSize::iv); } if (m_ReceiveBufferOffset > 0) - memcpy(m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset); - // try to read more - if (numReloads < 5) { + memcpy(m_ReceiveBuffer, next_block, m_ReceiveBufferOffset); + // Try to read more + if (num_reloads < 5) { // TODO(unassigned): document 5 boost::system::error_code ec; - std::size_t moreBytes = m_Socket.available(ec); - if (moreBytes) { - if (moreBytes > NTCP_BUFFER_SIZE - m_ReceiveBufferOffset) - moreBytes = NTCP_BUFFER_SIZE - m_ReceiveBufferOffset; - moreBytes = m_Socket.read_some( + std::size_t more_bytes = m_Socket.available(ec); + if (more_bytes) { + if (more_bytes > + static_cast(NTCPSize::buffer) - m_ReceiveBufferOffset) + more_bytes = + static_cast(NTCPSize::buffer) - m_ReceiveBufferOffset; + more_bytes = m_Socket.read_some( boost::asio::buffer( m_ReceiveBuffer + m_ReceiveBufferOffset, - moreBytes)); + more_bytes)); if (ec) { LogPrint(eLogError, - "NTCPSession: HandleReceived(): read more bytes error: ", - ec.message()); + "NTCPSession:", GetFormattedSessionInfo(), + "!!! HandleReceived(): read more bytes error '", + ec.message(), "'"); Terminate(); return; } - m_NumReceivedBytes += moreBytes; - m_ReceiveBufferOffset += moreBytes; - numReloads++; + m_NumReceivedBytes += more_bytes; + m_ReceiveBufferOffset += more_bytes; + num_reloads++; } } } - while (m_ReceiveBufferOffset >= NTCP_IV_SIZE); + while (m_ReceiveBufferOffset >= static_cast(NTCPSize::iv)); m_Handler.Flush(); } - ScheduleTermination(); // reset termination timer - Receive(); + ScheduleTermination(); // Reset termination timer + ReceivePayload(); } } bool NTCPSession::DecryptNextBlock( const std::uint8_t* encrypted) { // 16 bytes - if (!m_NextMessage) { // new message, header expected - // decrypt header and extract length - std::uint8_t buf[NTCP_IV_SIZE]; - m_Decryption.Decrypt(encrypted, buf); - uint16_t dataSize = bufbe16toh(buf); - if (dataSize) { - // new message - if (dataSize > NTCP_MAX_MESSAGE_SIZE) { + // New message, header expected + if (!m_NextMessage) { + // Decrypt header and extract length + std::array(NTCPSize::iv)> buf; + m_Decryption.Decrypt(encrypted, buf.data()); + std::uint16_t data_size = bufbe16toh(buf.data()); + if (data_size) { + // New message + if (data_size > static_cast(NTCPSize::max_message)) { LogPrint(eLogError, - "NTCPSession: data size ", dataSize, " exceeds max size"); + "NTCPSession:", GetFormattedSessionInfo(), + "!!! data block size '", data_size, "' exceeds max size"); return false; } auto msg = - dataSize <= I2NP_MAX_SHORT_MESSAGE_SIZE - NTCP_PHASE3_ALICE_RI_SIZE ? - NewI2NPShortMessage() : - NewI2NPMessage(); + data_size <= + I2NP_MAX_SHORT_MESSAGE_SIZE - + static_cast(NTCPSize::phase3_alice_ri) ? + NewI2NPShortMessage() : + NewI2NPMessage(); m_NextMessage = ToSharedI2NPMessage(msg); - memcpy(m_NextMessage->buf, buf, NTCP_IV_SIZE); - m_NextMessageOffset = NTCP_IV_SIZE; - m_NextMessage->offset = NTCP_PHASE3_ALICE_RI_SIZE; // size field - m_NextMessage->len = dataSize + NTCP_PHASE3_ALICE_RI_SIZE; + memcpy( + m_NextMessage->buf, + buf.data(), + static_cast(NTCPSize::iv)); + m_NextMessageOffset = + static_cast(NTCPSize::iv); + m_NextMessage->offset = + static_cast(NTCPSize::phase3_alice_ri); // size field + m_NextMessage->len = + data_size + static_cast(NTCPSize::phase3_alice_ri); } else { - // timestamp - LogPrint("NTCPSession: timestamp"); + // Timestamp + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "*** timestamp"); return true; } - } else { // message continues + } else { // Message continues m_Decryption.Decrypt( encrypted, m_NextMessage->buf + m_NextMessageOffset); - m_NextMessageOffset += NTCP_IV_SIZE; + m_NextMessageOffset += static_cast(NTCPSize::iv); } - if (m_NextMessageOffset >= m_NextMessage->len + NTCP_ADLER32_SIZE) { - // we have a complete I2NP message + if (m_NextMessageOffset >= + m_NextMessage->len + static_cast(NTCPSize::adler32)) { + // We have a complete I2NP message if (i2p::crypto::util::Adler32().VerifyDigest( - m_NextMessage->buf + m_NextMessageOffset - NTCP_ADLER32_SIZE, + m_NextMessage->buf + + m_NextMessageOffset - static_cast(NTCPSize::adler32), m_NextMessage->buf, - m_NextMessageOffset - NTCP_ADLER32_SIZE)) + m_NextMessageOffset - static_cast(NTCPSize::adler32))) m_Handler.PutNextMessage(m_NextMessage); else LogPrint(eLogWarning, - "NTCPSession: incorrect Adler checksum of NTCP message. Dropped"); + "NTCPSession:", GetFormattedSessionInfo(), + "!!! incorrect Adler checksum of NTCP message, dropped"); m_NextMessage = nullptr; } return true; } -void NTCPSession::Send( +void NTCPSession::SendPayload( std::shared_ptr msg) { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "<-- sending I2NP message"); m_IsSending = true; boost::asio::async_write( m_Socket, CreateMsgBuffer(msg), boost::asio::transfer_all(), std::bind( - &NTCPSession::HandleSent, + &NTCPSession::HandleSentPayload, shared_from_this(), std::placeholders::_1, std::placeholders::_2, @@ -749,41 +951,55 @@ void NTCPSession::Send( boost::asio::const_buffers_1 NTCPSession::CreateMsgBuffer( std::shared_ptr msg) { - std::uint8_t* sendBuffer; + std::uint8_t* send_buffer; int len; if (msg) { - // regular I2NP - if (msg->offset < NTCP_PHASE3_ALICE_RI_SIZE) + // Regular I2NP + if (msg->offset < static_cast(NTCPSize::phase3_alice_ri)) LogPrint(eLogError, - "NTCPSession: malformed I2NP message"); // TODO(unassigned): Error handling - sendBuffer = msg->GetBuffer() - NTCP_PHASE3_ALICE_RI_SIZE; + "NTCPSession:", GetFormattedSessionInfo(), + "!!! malformed I2NP message"); // TODO(unassigned): Error handling + send_buffer = + msg->GetBuffer() - static_cast(NTCPSize::phase3_alice_ri); len = msg->GetLength(); - htobe16buf(sendBuffer, len); + htobe16buf(send_buffer, len); } else { - // prepare timestamp - sendBuffer = m_TimeSyncBuffer; - len = NTCP_PHASE3_ALICE_TS_SIZE; - htobuf16(sendBuffer, 0); - htobe32buf(sendBuffer + NTCP_PHASE3_ALICE_TS_SIZE, time(0)); + // Prepare timestamp + send_buffer = m_TimeSyncBuffer; + len = static_cast(NTCPSize::phase3_alice_ts); + htobuf16(send_buffer, 0); + htobe32buf( + send_buffer + static_cast(NTCPSize::phase3_alice_ts), + time(0)); } int rem = (len + 6) & 0x0F; // %16 int padding = 0; if (rem > 0) { - padding = NTCP_IV_SIZE - rem; + padding = static_cast(NTCPSize::iv) - rem; i2p::crypto::RandBytes( - sendBuffer + len + NTCP_PHASE3_ALICE_TS_SIZE, + send_buffer + len + static_cast(NTCPSize::phase3_alice_ts), padding); } i2p::crypto::util::Adler32().CalculateDigest( - sendBuffer + len + NTCP_PHASE3_ALICE_RI_SIZE + padding, - sendBuffer, len + NTCP_PHASE3_ALICE_RI_SIZE + padding); + send_buffer + len + + static_cast(NTCPSize::phase3_alice_ri) + padding, + send_buffer, + len + static_cast(NTCPSize::phase3_alice_ri) + padding); int l = len + padding + 6; - m_Encryption.Encrypt(sendBuffer, l, sendBuffer); - return boost::asio::buffer ((const std::uint8_t *)sendBuffer, l); + m_Encryption.Encrypt(send_buffer, l, send_buffer); + return boost::asio::buffer(static_cast(send_buffer), l); +} + +void NTCPSession::SendTimeSyncMessage() { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "<-- sending TimeSyncMessage"); + SendPayload(nullptr); } -void NTCPSession::Send( - const std::vector >& msgs) { +void NTCPSession::SendPayload( + const std::vector>& msgs) { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "<-- sending I2NP messages"); m_IsSending = true; std::vector bufs; for (auto it : msgs) @@ -793,41 +1009,44 @@ void NTCPSession::Send( bufs, boost::asio::transfer_all(), std::bind( - &NTCPSession::HandleSent, + &NTCPSession::HandleSentPayload, shared_from_this(), std::placeholders::_1, - std::placeholders::_2, msgs)); + std::placeholders::_2, + msgs)); } -void NTCPSession::HandleSent( +void NTCPSession::HandleSentPayload( const boost::system::error_code& ecode, std::size_t bytes_transferred, - std::vector >) { + std::vector> /*msgs*/) { m_IsSending = false; if (ecode) { - LogPrint(eLogWarning, "NTCPSession: couldn't send msgs: ", ecode.message()); + LogPrint(eLogWarning, + "NTCPSession:", GetFormattedSessionInfo(), + "!!! couldn't send I2NP messages, error '", ecode.message(), "'"); // TODO(unassigned): // we shouldn't call Terminate () here, because HandleReceive takes care // 'delete this' statement in Terminate() must be eliminated later //Terminate(); } else { m_NumSentBytes += bytes_transferred; + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "<-- ", bytes_transferred, " bytes transferred, ", + GetNumSentBytes(), " total bytes sent"); i2p::transport::transports.UpdateSentBytes(bytes_transferred); if (!m_SendQueue.empty()) { - Send(m_SendQueue); + SendPayload(m_SendQueue); m_SendQueue.clear(); } else { - ScheduleTermination(); // reset termination timer + ScheduleTermination(); // Reset termination timer } } } -void NTCPSession::SendTimeSyncMessage() { - Send(nullptr); -} - void NTCPSession::SendI2NPMessages( - const std::vector >& msgs) { + const std::vector>& msgs) { m_Server.GetService().post( std::bind( &NTCPSession::PostI2NPMessages, @@ -836,21 +1055,30 @@ void NTCPSession::SendI2NPMessages( } void NTCPSession::PostI2NPMessages( - std::vector > msgs) { + std::vector> msgs) { if (m_IsTerminated) return; if (m_IsSending) { for (auto it : msgs) m_SendQueue.push_back(it); } else { - Send(msgs); + SendPayload(msgs); } } +/** + * + * SessionEnd + * + */ + void NTCPSession::ScheduleTermination() { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "*** scheduling termination"); m_TerminationTimer.cancel(); m_TerminationTimer.expires_from_now( - boost::posix_time::seconds(NTCP_TERMINATION_TIMEOUT)); + boost::posix_time::seconds( + static_cast(NTCPTimeoutLength::termination))); m_TerminationTimer.async_wait( std::bind( &NTCPSession::HandleTerminationTimer, @@ -860,13 +1088,44 @@ void NTCPSession::ScheduleTermination() { void NTCPSession::HandleTerminationTimer( const boost::system::error_code& ecode) { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), + "*** handling termination timer"); if (ecode != boost::asio::error::operation_aborted) { LogPrint(eLogError, - "NTCPSession: No activity for ", NTCP_TERMINATION_TIMEOUT, " seconds"); + "NTCPSession:", GetFormattedSessionInfo(), + "!!! no activity for '", + static_cast(NTCPTimeoutLength::termination), "' seconds"); // Terminate(); m_Socket.close(); // invoke Terminate() from HandleReceive } } +void NTCPSession::Done() { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "*** done with session"); + m_Server.GetService().post( + std::bind( + &NTCPSession::Terminate, + shared_from_this())); +} + +void NTCPSession::Terminate() { + if (!m_IsTerminated) { + LogPrint(eLogDebug, + "NTCPSession:", GetFormattedSessionInfo(), "*** terminating session"); + m_IsTerminated = true; + m_IsEstablished = false; + m_Socket.close(); + transports.PeerDisconnected(shared_from_this()); + m_Server.RemoveNTCPSession(shared_from_this()); + m_SendQueue.clear(); + m_NextMessage.reset(); + m_TerminationTimer.cancel(); + LogPrint(eLogInfo, + "NTCPSession:", GetFormattedSessionInfo(), "*** session terminated"); + } +} + } // namespace transport } // namespace i2p diff --git a/src/core/transport/NTCPSession.h b/src/core/transport/NTCPSession.h index 0bd42297..10250847 100644 --- a/src/core/transport/NTCPSession.h +++ b/src/core/transport/NTCPSession.h @@ -38,11 +38,12 @@ #include #include -#include - +#include #include #include #include +#include +#include #include #include @@ -55,55 +56,56 @@ namespace i2p { namespace transport { -const std::size_t NTCP_PUBKEY_SIZE = 256, // DH (X, Y) - NTCP_HASH_SIZE = 32, - NTCP_PADDING_SIZE = 12, - NTCP_SESSIONKEY_SIZE = 32, - NTCP_IV_SIZE = 16, - NTCP_ADLER32_SIZE = 4; +enum struct NTCPSize : const std::size_t { + pub_key = 256, // DH (X, Y) + hash = 32, + padding = 12, + session_key = 32, + iv = 16, + adler32 = 4, + // TODO(unassigned): + // Through release of java 0.9.15, the router identity was always 387 bytes, + // the signature was always a 40 byte DSA signature, and the padding was always 15 bytes. + // As of release java 0.9.16, the router identity may be longer than 387 bytes, + // and the signature type and length are implied by the type of the Signing Public Key in Alice's Router Identity. + // The padding is as necessary to a multiple of 16 bytes for the entire unencrypted contents. + phase3_alice_ri = 2, + phase3_alice_ts = 4, + phase3_padding = 15, + phase3_signature = 40, + phase3_unencrypted = + phase3_alice_ri + + i2p::data::DEFAULT_IDENTITY_SIZE + // 387 + phase3_alice_ts + + phase3_padding + + phase3_signature, // Total = 448 + max_message = 16384, + buffer = 4160, // fits 4 tunnel messages (4 * 1028) +}; + +enum struct NTCPTimeoutLength : const std::size_t { + termination = 120, // 2 minutes + ban_expiration = 70, // in seconds +}; // TODO(anonimal): is packing really necessary? // If so, should we not be consistent with other protocols? #pragma pack(1) struct NTCPPhase1 { - std::uint8_t pubKey[NTCP_PUBKEY_SIZE]; - std::uint8_t HXxorHI[NTCP_HASH_SIZE]; + std::array(NTCPSize::pub_key)> pub_key; + std::array(NTCPSize::hash)> HXxorHI; }; struct NTCPPhase2 { - std::uint8_t pubKey[NTCP_PUBKEY_SIZE]; + std::array(NTCPSize::pub_key)> pub_key; struct { - std::uint8_t hxy[NTCP_HASH_SIZE]; + std::array(NTCPSize::hash)> hxy; std::uint32_t timestamp; - std::uint8_t padding[NTCP_PADDING_SIZE]; + std::array(NTCPSize::padding)> padding; } encrypted; }; #pragma pack() -// TODO(unassigned): -// Through release of java 0.9.15, the router identity was always 387 bytes, -// the signature was always a 40 byte DSA signature, and the padding was always 15 bytes. -// As of release java 0.9.16, the router identity may be longer than 387 bytes, -// and the signature type and length are implied by the type of the Signing Public Key in Alice's Router Identity. -// The padding is as necessary to a multiple of 16 bytes for the entire unencrypted contents. -const std::size_t NTCP_PHASE3_ALICE_RI_SIZE = 2, - NTCP_PHASE3_ALICE_TS_SIZE = 4, - NTCP_PHASE3_PADDING_SIZE = 15, - NTCP_PHASE3_SIGNATURE_SIZE = 40; - -// Total = 448 -const std::size_t NTCP_PHASE3_UNENCRYPTED_SIZE = - NTCP_PHASE3_ALICE_RI_SIZE + - i2p::data::DEFAULT_IDENTITY_SIZE + // 387 - NTCP_PHASE3_ALICE_TS_SIZE + - NTCP_PHASE3_PADDING_SIZE + - NTCP_PHASE3_SIGNATURE_SIZE; - -const std::size_t NTCP_MAX_MESSAGE_SIZE = 16384, - NTCP_BUFFER_SIZE = 4160, // fits 4 tunnel messages (4 * 1028) - NTCP_TERMINATION_TIMEOUT = 120, // 2 minutes - NTCP_BAN_EXPIRATION_TIMEOUT = 70; // in seconds - class NTCPServer; class NTCPSession : public TransportSession, @@ -112,6 +114,7 @@ class NTCPSession NTCPSession( NTCPServer& server, std::shared_ptr in_RemoteRouter = nullptr); + ~NTCPSession(); void Terminate(); @@ -131,11 +134,51 @@ class NTCPSession void ServerLogin(); void SendI2NPMessages( - const std::vector >& msgs); + const std::vector>& msgs); + + std::size_t GetNumSentBytes() const { + return m_NumSentBytes; + } + + std::size_t GetNumReceivedBytes() const { + return m_NumReceivedBytes; + } + + /// @brief Sets peer abbreviated ident hash + void SetRemoteIdentHashAbbreviation() { + m_RemoteIdentHashAbbreviation = + GetRemoteRouter()->GetIdentHashAbbreviation(); + } + + /// @brief Sets peer endpoint address/port + /// @note Requires socket to be initialized before call + const boost::system::error_code SetRemoteEndpoint() { + boost::system::error_code ec; + m_RemoteEndpoint = m_Socket.remote_endpoint(ec); + return ec; + } + + /// @return Log-formatted string of session info + const std::string GetFormattedSessionInfo() { + std::ostringstream info; + info << " [" << GetRemoteIdentHashAbbreviation() + << "] " << GetRemoteEndpoint() << " "; + return info.str(); + } + + /// @return Current session's peer's ident hash + const std::string& GetRemoteIdentHashAbbreviation() { + return m_RemoteIdentHashAbbreviation; + } + + /// @return Current session's endpoint address/port + const boost::asio::ip::tcp::endpoint& GetRemoteEndpoint() { + return m_RemoteEndpoint; + } private: void PostI2NPMessages( - std::vector > msgs); + std::vector> msgs); void Connected(); @@ -150,7 +193,7 @@ class NTCPSession std::uint8_t* pubKey, i2p::crypto::AESKey& key); - // client + // Client void SendPhase3(); void HandlePhase1Sent( @@ -170,9 +213,8 @@ class NTCPSession const boost::system::error_code& ecode, std::size_t bytes_transferred, std::uint32_t tsA); - // end client - // server + // Server void SendPhase2(); void SendPhase4( @@ -197,51 +239,56 @@ class NTCPSession const boost::system::error_code& ecode, std::size_t bytes_transferred, std::uint32_t tsB, - std::size_t paddingLen); + std::size_t padding_len); void HandlePhase3( std::uint32_t tsB, - std::size_t paddingLen); + std::size_t padding_len); void HandlePhase4Sent( const boost::system::error_code& ecode, std::size_t bytes_transferred); - // end server - // common - void Receive(); + // Client/Server + void ReceivePayload(); - void HandleReceived( + void HandleReceivedPayload( const boost::system::error_code& ecode, std::size_t bytes_transferred); bool DecryptNextBlock( const std::uint8_t* encrypted); - // end common - void Send( + /// @brief Send payload (I2NP message) + /// @param msg shared pointer to payload (I2NPMessage) + void SendPayload( std::shared_ptr msg); - void Send( - const std::vector >& msgs); + + /// @brief Send payload (I2NP messages) + /// @param msg shared pointer to payload (I2NPMessages) + void SendPayload( + const std::vector>& msgs); boost::asio::const_buffers_1 CreateMsgBuffer( std::shared_ptr msg); - void HandleSent( + void HandleSentPayload( const boost::system::error_code& ecode, std::size_t bytes_transferred, - std::vector > msgs); + std::vector> msgs); - // timer + // Timer void ScheduleTermination(); void HandleTerminationTimer( const boost::system::error_code& ecode); - // end timer private: + std::string m_RemoteIdentHashAbbreviation; + NTCPServer& m_Server; boost::asio::ip::tcp::socket m_Socket; + boost::asio::ip::tcp::endpoint m_RemoteEndpoint; boost::asio::deadline_timer m_TerminationTimer; bool m_IsEstablished, m_IsTerminated; @@ -251,10 +298,17 @@ class NTCPSession struct Establisher { NTCPPhase1 phase1; NTCPPhase2 phase2; - } * m_Establisher; + }; + + std::unique_ptr m_Establisher; + + i2p::crypto::AESAlignedBuffer< + static_cast(NTCPSize::buffer) + + static_cast(NTCPSize::iv)> m_ReceiveBuffer; + + i2p::crypto::AESAlignedBuffer< + static_cast(NTCPSize::iv)> m_TimeSyncBuffer; - i2p::crypto::AESAlignedBuffer m_ReceiveBuffer; - i2p::crypto::AESAlignedBuffer m_TimeSyncBuffer; std::size_t m_ReceiveBufferOffset; std::shared_ptr m_NextMessage; @@ -262,9 +316,7 @@ class NTCPSession i2p::I2NPMessagesHandler m_Handler; bool m_IsSending; - std::vector > m_SendQueue; - - boost::asio::ip::address m_ConnectedFrom; // for ban + std::vector> m_SendQueue; }; } // namespace transport diff --git a/src/core/transport/SSU.cpp b/src/core/transport/SSU.cpp index 01c07edc..6e911db1 100644 --- a/src/core/transport/SSU.cpp +++ b/src/core/transport/SSU.cpp @@ -36,10 +36,13 @@ #include +#include #include -#include +#include #include +#include +#include "SSU.h" #include "crypto/Rand.h" #include "NetworkDatabase.h" #include "RouterContext.h" @@ -49,7 +52,8 @@ namespace i2p { namespace transport { -SSUServer::SSUServer(int port) +SSUServer::SSUServer( + std::size_t port) : m_Thread(nullptr), m_ThreadV6(nullptr), m_ReceiversThread(nullptr), @@ -62,6 +66,7 @@ SSUServer::SSUServer(int port) m_SocketV6(m_ReceiversService), m_IntroducersUpdateTimer(m_Service), m_PeerTestsCleanupTimer(m_Service) { + LogPrint(eLogDebug, "SSUServer: initializing"); m_Socket.set_option(boost::asio::socket_base::receive_buffer_size(65535)); m_Socket.set_option(boost::asio::socket_base::send_buffer_size(65535)); if (context.SupportsV6()) { @@ -73,34 +78,37 @@ SSUServer::SSUServer(int port) } } -SSUServer::~SSUServer() {} +SSUServer::~SSUServer() { + LogPrint(eLogDebug, "SSUServer: destroying"); +} void SSUServer::Start() { + LogPrint(eLogDebug, "SSUServer: starting"); m_IsRunning = true; m_ReceiversThread = - new std::thread( - std::bind( - &SSUServer::RunReceivers, - this)); + std::make_unique( + std::bind( + &SSUServer::RunReceivers, + this)); m_Thread = - new std::thread( - std::bind( - &SSUServer::Run, - this)); + std::make_unique( + std::bind( + &SSUServer::Run, + this)); m_ReceiversService.post( std::bind( - &SSUServer::Receive, - this)); + &SSUServer::Receive, + this)); if (context.SupportsV6()) { m_ThreadV6 = - new std::thread( + std::make_unique( std::bind( - &SSUServer::RunV6, - this)); + &SSUServer::RunV6, + this)); m_ReceiversService.post( std::bind( - &SSUServer::ReceiveV6, - this)); + &SSUServer::ReceiveV6, + this)); } SchedulePeerTestsCleanupTimer(); // wait for 30 seconds and decide if we need introducers @@ -108,6 +116,7 @@ void SSUServer::Start() { } void SSUServer::Stop() { + LogPrint(eLogDebug, "SSUServer: stopping"); DeleteAllSessions(); m_IsRunning = false; m_Service.stop(); @@ -117,28 +126,27 @@ void SSUServer::Stop() { m_ReceiversService.stop(); if (m_ReceiversThread) { m_ReceiversThread->join(); - delete m_ReceiversThread; - m_ReceiversThread = nullptr; + m_ReceiversThread.reset(nullptr); } if (m_Thread) { m_Thread->join(); - delete m_Thread; - m_Thread = nullptr; + m_Thread.reset(nullptr); } if (m_ThreadV6) { m_ThreadV6->join(); - delete m_ThreadV6; - m_ThreadV6 = nullptr; + m_ThreadV6.reset(nullptr); } } void SSUServer::Run() { while (m_IsRunning) { try { + LogPrint(eLogDebug, "SSUServer: running ioservice"); m_Service.run(); } catch (std::exception& ex) { - LogPrint(eLogError, "SSUServer::Run(): ", ex.what()); + LogPrint(eLogError, + "SSUServer: Run() ioservice error: '", ex.what(), "'"); } } } @@ -146,10 +154,12 @@ void SSUServer::Run() { void SSUServer::RunV6() { while (m_IsRunning) { try { + LogPrint(eLogDebug, "SSUServer: running V6 ioservice"); m_ServiceV6.run(); } catch (std::exception& ex) { - LogPrint(eLogError, "SSUServer::RunV6(): ", ex.what()); + LogPrint(eLogError, + "SSUServer: RunV6() ioservice error: '", ex.what(), "'"); } } } @@ -157,10 +167,12 @@ void SSUServer::RunV6() { void SSUServer::RunReceivers() { while (m_IsRunning) { try { + LogPrint(eLogDebug, "SSUServer: running receivers ioservice"); m_ReceiversService.run(); } catch (std::exception& ex) { - LogPrint(eLogError, "SSUServer:RunReceivers(): ", ex.what()); + LogPrint(eLogError, + "SSUServer: RunReceivers() ioservice error: '", ex.what(), "'"); } } } @@ -168,11 +180,13 @@ void SSUServer::RunReceivers() { void SSUServer::AddRelay( uint32_t tag, const boost::asio::ip::udp::endpoint& relay) { + LogPrint(eLogDebug, "SSUServer: adding relay"); m_Relays[tag] = relay; } std::shared_ptr SSUServer::FindRelaySession( uint32_t tag) { + LogPrint(eLogDebug, "SSUServer: finding relay session"); auto it = m_Relays.find(tag); if (it != m_Relays.end()) return FindSession(it->second); @@ -183,63 +197,67 @@ void SSUServer::Send( const uint8_t* buf, size_t len, const boost::asio::ip::udp::endpoint& to) { + LogPrint(eLogDebug, "SSUServer: sending data"); if (to.protocol() == boost::asio::ip::udp::v4()) { try { m_Socket.send_to( boost::asio::buffer( - buf, - len), + buf, + len), to); } catch (const std::exception& ex) { - LogPrint(eLogError, "SSUServer: send error: ", ex.what()); + LogPrint(eLogError, "SSUServer: send error: '", ex.what(), "'"); } } else { try { m_SocketV6.send_to( boost::asio::buffer( - buf, - len), + buf, + len), to); } catch (const std::exception& ex) { - LogPrint(eLogError, "SSUServer: V6 send error: ", ex.what()); + LogPrint(eLogError, "SSUServer: V6 send error: '", ex.what(), "'"); } } } void SSUServer::Receive() { + LogPrint(eLogDebug, "SSUServer: receiving data"); SSUPacket* packet = new SSUPacket(); m_Socket.async_receive_from( boost::asio::buffer( - packet->buf, - SSU_MTU_V4), + packet->buf, + SSU_MTU_V4), packet->from, std::bind( - &SSUServer::HandleReceivedFrom, - this, - std::placeholders::_1, - std::placeholders::_2, - packet)); + &SSUServer::HandleReceivedFrom, + this, + std::placeholders::_1, + std::placeholders::_2, + packet)); } void SSUServer::ReceiveV6() { + LogPrint(eLogDebug, "SSUServer: V6: receiving data"); SSUPacket* packet = new SSUPacket(); m_SocketV6.async_receive_from( boost::asio::buffer( - packet->buf, - SSU_MTU_V6), + packet->buf, + SSU_MTU_V6), packet->from, std::bind( - &SSUServer::HandleReceivedFromV6, - this, - std::placeholders::_1, - std::placeholders::_2, - packet)); + &SSUServer::HandleReceivedFromV6, + this, + std::placeholders::_1, + std::placeholders::_2, + packet)); } void SSUServer::HandleReceivedFrom( const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket* packet) { + LogPrint(eLogDebug, "SSUServer: handling received data"); if (!ecode) { packet->len = bytes_transferred; std::vector packets; @@ -250,17 +268,17 @@ void SSUServer::HandleReceivedFrom( packet = new SSUPacket(); packet->len = m_Socket.receive_from( boost::asio::buffer( - packet->buf, - SSU_MTU_V4), + packet->buf, + SSU_MTU_V4), packet->from); packets.push_back(packet); moreBytes = m_Socket.available(); } m_Service.post( std::bind( - &SSUServer::HandleReceivedPackets, - this, - packets)); + &SSUServer::HandleReceivedPackets, + this, + packets)); Receive(); } else { LogPrint("SSUServer: receive error: ", ecode.message()); @@ -272,6 +290,7 @@ void SSUServer::HandleReceivedFromV6( const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket* packet) { + LogPrint(eLogDebug, "SSUServer: V6: handling received data"); if (!ecode) { packet->len = bytes_transferred; std::vector packets; @@ -281,17 +300,17 @@ void SSUServer::HandleReceivedFromV6( packet = new SSUPacket(); packet->len = m_SocketV6.receive_from( boost::asio::buffer( - packet->buf, - SSU_MTU_V6), + packet->buf, + SSU_MTU_V6), packet->from); packets.push_back(packet); moreBytes = m_SocketV6.available(); } m_ServiceV6.post( std::bind( - &SSUServer::HandleReceivedPackets, - this, - packets)); + &SSUServer::HandleReceivedPackets, + this, + packets)); ReceiveV6(); } else { LogPrint("SSUServer: V6 receive error: ", ecode.message()); @@ -301,30 +320,33 @@ void SSUServer::HandleReceivedFromV6( void SSUServer::HandleReceivedPackets( std::vector packets) { + LogPrint(eLogDebug, "SSUServer: handling received packets"); std::shared_ptr session; - for (auto it1 : packets) { - auto packet = it1; + for (auto packets_it : packets) { + auto packet = packets_it; try { // we received packet for other session than previous if (!session || session->GetRemoteEndpoint() != packet->from) { - if (session) session->FlushData(); - auto it = m_Sessions.find(packet->from); - if (it != m_Sessions.end()) - session = it->second; + if (session) + session->FlushData(); + auto session_it = m_Sessions.find(packet->from); + if (session_it != m_Sessions.end()) + session = session_it->second; if (!session) { - session = std::make_shared (*this, packet->from); + session = std::make_shared(*this, packet->from); session->WaitForConnect(); { std::unique_lock l(m_SessionsMutex); m_Sessions[packet->from] = session; } LogPrint(eLogInfo, - "SSUServer: new SSU session from ", packet->from.address().to_string(), - ":", packet->from.port(), " created"); + "SSUServer: created new SSU session from ", + session->GetRemoteEndpoint()); } } session->ProcessNextMessage(packet->buf, packet->len, packet->from); } catch (std::exception& ex) { - LogPrint(eLogError, "SSUServer::HandleReceivedPackets(): ", ex.what()); + LogPrint(eLogError, + "SSUServer: HandleReceivedPackets(): '", ex.what(), "'"); if (session) session->FlushData(); session = nullptr; @@ -337,6 +359,7 @@ void SSUServer::HandleReceivedPackets( std::shared_ptr SSUServer::FindSession( std::shared_ptr router) const { + LogPrint(eLogDebug, "SSUServer: finding session from RI"); if (!router) return nullptr; auto address = router->GetSSUAddress(true); // v4 only @@ -344,8 +367,8 @@ std::shared_ptr SSUServer::FindSession( return nullptr; auto session = FindSession( boost::asio::ip::udp::endpoint( - address->host, - address->port)); + address->host, + address->port)); if (session || !context.SupportsV6()) return session; // try v6 @@ -354,13 +377,15 @@ std::shared_ptr SSUServer::FindSession( return nullptr; return FindSession( boost::asio::ip::udp::endpoint( - address->host, - address->port)); + address->host, + address->port)); } std::shared_ptr SSUServer::FindSession( - const boost::asio::ip::udp::endpoint& e) const { - auto it = m_Sessions.find(e); + const boost::asio::ip::udp::endpoint& ep) const { + LogPrint(eLogDebug, + "SSUServer: finding session from endpoint)"); + auto it = m_Sessions.find(ep); if (it != m_Sessions.end()) return it->second; else @@ -370,6 +395,7 @@ std::shared_ptr SSUServer::FindSession( std::shared_ptr SSUServer::GetSession( std::shared_ptr router, bool peerTest) { + LogPrint(eLogDebug, "SSUServer: getting session"); std::shared_ptr session; if (router) { auto address = router->GetSSUAddress(!context.SupportsV6()); @@ -382,7 +408,7 @@ std::shared_ptr SSUServer::GetSession( session = it->second; } else { // otherwise create new session - session = std::make_shared ( + session = std::make_shared( *this, remoteEndpoint, router, @@ -390,12 +416,12 @@ std::shared_ptr SSUServer::GetSession( std::unique_lock l(m_SessionsMutex); m_Sessions[remoteEndpoint] = session; } + session->SetRemoteIdentHashAbbreviation(); if (!router->UsesIntroducer()) { // connect directly - LogPrint("SSUServer: creating new SSU session to [", - router->GetIdentHashAbbreviation(), "] ", - remoteEndpoint.address().to_string(), ":", - remoteEndpoint.port()); + LogPrint(eLogInfo, + "SSUServer: creating new session to", + session->GetFormattedSessionInfo()); session->Connect(); } else { // connect through introducer @@ -408,22 +434,25 @@ std::shared_ptr SSUServer::GetSession( introducer = &(address->introducers[i]); it = m_Sessions.find( boost::asio::ip::udp::endpoint( - introducer->iHost, - introducer->iPort)); + introducer->iHost, + introducer->iPort)); if (it != m_Sessions.end()) { introducerSession = it->second; break; } } if (introducerSession) { // session found - LogPrint("SSUServer: session to introducer already exists"); + LogPrint(eLogInfo, + "SSUServer: ", introducer->iHost, ":", introducer->iPort, + "session to introducer already exists"); } else { // create new - LogPrint("SSUServer: creating new session to introducer"); + LogPrint(eLogInfo, + "SSUServer: creating new session to introducer"); introducer = &(address->introducers[0]); // TODO(unassigned): ??? boost::asio::ip::udp::endpoint introducerEndpoint( introducer->iHost, introducer->iPort); - introducerSession = std::make_shared ( + introducerSession = std::make_shared( *this, introducerEndpoint, router); @@ -432,7 +461,8 @@ std::shared_ptr SSUServer::GetSession( } // introduce LogPrint("SSUServer: introducing new SSU session to [", - router->GetIdentHashAbbreviation(), "] through introducer ", + router->GetIdentHashAbbreviation(), "] through introducer [", + introducerSession->GetRemoteIdentHashAbbreviation(), "] ", introducer->iHost, ":", introducer->iPort); session->WaitForIntroduction(); @@ -463,6 +493,7 @@ std::shared_ptr SSUServer::GetSession( void SSUServer::DeleteSession( std::shared_ptr session) { + LogPrint(eLogDebug, "SSUServer: deleting session"); if (session) { session->Close(); std::unique_lock l(m_SessionsMutex); @@ -471,6 +502,7 @@ void SSUServer::DeleteSession( } void SSUServer::DeleteAllSessions() { + LogPrint(eLogDebug, "SSUServer: deleting all sessions"); std::unique_lock l(m_SessionsMutex); for (auto it : m_Sessions) it.second->Close(); @@ -480,16 +512,15 @@ void SSUServer::DeleteAllSessions() { template std::shared_ptr SSUServer::GetRandomSession( Filter filter) { - std::vector > filteredSessions; + LogPrint(eLogDebug, "SSUServer: getting random session"); + std::vector> filteredSessions; for (auto s : m_Sessions) if (filter (s.second)) filteredSessions.push_back(s.second); if (filteredSessions.size() > 0) { size_t s = filteredSessions.size(); size_t ind = - i2p::crypto::RandInRange( - size_t{0}, - s - 1); + i2p::crypto::RandInRange(0, s - 1); return filteredSessions[ind]; } return nullptr; @@ -497,6 +528,7 @@ std::shared_ptr SSUServer::GetRandomSession( std::shared_ptr SSUServer::GetRandomEstablishedSession( std::shared_ptr excluded) { + LogPrint(eLogDebug, "SSUServer: getting random established session"); return GetRandomSession( [excluded](std::shared_ptr session)->bool { return session->GetState() == eSessionStateEstablished && @@ -507,6 +539,7 @@ std::shared_ptr SSUServer::GetRandomEstablishedSession( std::set SSUServer::FindIntroducers( int maxNumIntroducers) { + LogPrint(eLogDebug, "SSUServer: finding introducers"); uint32_t ts = i2p::util::GetSecondsSinceEpoch(); std::set ret; for (int i = 0; i < maxNumIntroducers; i++) { @@ -527,18 +560,21 @@ std::set SSUServer::FindIntroducers( } void SSUServer::ScheduleIntroducersUpdateTimer() { + LogPrint(eLogDebug, "SSUServer: scheduling introducers update timer"); m_IntroducersUpdateTimer.expires_from_now( boost::posix_time::seconds( - SSU_KEEP_ALIVE_INTERVAL)); + SSU_KEEP_ALIVE_INTERVAL)); m_IntroducersUpdateTimer.async_wait( std::bind( - &SSUServer::HandleIntroducersUpdateTimer, - this, - std::placeholders::_1)); + &SSUServer::HandleIntroducersUpdateTimer, + this, + std::placeholders::_1)); } void SSUServer::HandleIntroducersUpdateTimer( const boost::system::error_code& ecode) { + LogPrint(eLogDebug, + "SSUServer: handling introducers update timer"); if (ecode != boost::asio::error::operation_aborted) { // timeout expired if (i2p::context.GetStatus() == eRouterStatusTesting) { @@ -593,6 +629,7 @@ void SSUServer::NewPeerTest( uint32_t nonce, PeerTestParticipant role, std::shared_ptr session) { + LogPrint(eLogDebug, "SSUServer: new peer test"); m_PeerTests[nonce] = { i2p::util::GetMillisecondsSinceEpoch(), role, @@ -602,6 +639,7 @@ void SSUServer::NewPeerTest( PeerTestParticipant SSUServer::GetPeerTestParticipant( uint32_t nonce) { + LogPrint(eLogDebug, "SSUServer: getting PeerTest participant"); auto it = m_PeerTests.find(nonce); if (it != m_PeerTests.end()) return it->second.role; @@ -611,6 +649,7 @@ PeerTestParticipant SSUServer::GetPeerTestParticipant( std::shared_ptr SSUServer::GetPeerTestSession( uint32_t nonce) { + LogPrint(eLogDebug, "SSUServer: getting PeerTest session"); auto it = m_PeerTests.find(nonce); if (it != m_PeerTests.end()) return it->second.session; @@ -621,6 +660,7 @@ std::shared_ptr SSUServer::GetPeerTestSession( void SSUServer::UpdatePeerTest( uint32_t nonce, PeerTestParticipant role) { + LogPrint(eLogDebug, "SSUServer: updating PeerTest"); auto it = m_PeerTests.find(nonce); if (it != m_PeerTests.end()) it->second.role = role; @@ -628,22 +668,25 @@ void SSUServer::UpdatePeerTest( void SSUServer::RemovePeerTest( uint32_t nonce) { + LogPrint(eLogDebug, "SSUServer: removing PeerTest"); m_PeerTests.erase(nonce); } void SSUServer::SchedulePeerTestsCleanupTimer() { + LogPrint(eLogDebug, "SSUServer: scheduling PeerTests cleanup timer"); m_PeerTestsCleanupTimer.expires_from_now( boost::posix_time::seconds( - SSU_PEER_TEST_TIMEOUT)); + SSU_PEER_TEST_TIMEOUT)); m_PeerTestsCleanupTimer.async_wait( std::bind( - &SSUServer::HandlePeerTestsCleanupTimer, - this, - std::placeholders::_1)); + &SSUServer::HandlePeerTestsCleanupTimer, + this, + std::placeholders::_1)); } void SSUServer::HandlePeerTestsCleanupTimer( const boost::system::error_code& ecode) { + LogPrint(eLogDebug, "SSUServer: handling PeerTests cleanup timer"); if (ecode != boost::asio::error::operation_aborted) { int numDeleted = 0; uint64_t ts = i2p::util::GetMillisecondsSinceEpoch(); diff --git a/src/core/transport/SSU.h b/src/core/transport/SSU.h index 64702129..9523458a 100644 --- a/src/core/transport/SSU.h +++ b/src/core/transport/SSU.h @@ -38,8 +38,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -69,7 +71,8 @@ struct SSUPacket { class SSUServer { public: SSUServer( - int port); + std::size_t port); + ~SSUServer(); void Start(); @@ -84,7 +87,7 @@ class SSUServer { std::shared_ptr router) const; std::shared_ptr FindSession( - const boost::asio::ip::udp::endpoint& e) const; + const boost::asio::ip::udp::endpoint& ep) const; std::shared_ptr GetRandomEstablishedSession( std::shared_ptr excluded); @@ -107,7 +110,7 @@ class SSUServer { } void Send( - const uint8_t * buf, + const uint8_t* buf, size_t len, const boost::asio::ip::udp::endpoint& to); @@ -186,38 +189,22 @@ class SSUServer { bool m_IsRunning; - std::thread* m_Thread, - *m_ThreadV6, - *m_ReceiversThread; - - boost::asio::io_service - m_Service, - m_ServiceV6, - m_ReceiversService; - - boost::asio::io_service::work - m_Work, - m_WorkV6, - m_ReceiversWork; + std::unique_ptr m_Thread, m_ThreadV6, m_ReceiversThread; - boost::asio::ip::udp::endpoint - m_Endpoint, - m_EndpointV6; + boost::asio::io_service m_Service, m_ServiceV6, m_ReceiversService; + boost::asio::io_service::work m_Work, m_WorkV6, m_ReceiversWork; - boost::asio::ip::udp::socket - m_Socket, - m_SocketV6; + boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6; + boost::asio::ip::udp::socket m_Socket, m_SocketV6; - boost::asio::deadline_timer - m_IntroducersUpdateTimer, - m_PeerTestsCleanupTimer; + boost::asio::deadline_timer m_IntroducersUpdateTimer, m_PeerTestsCleanupTimer; // introducers we are connected to std::list m_Introducers; mutable std::mutex m_SessionsMutex; - std::map > m_Sessions; + std::map> m_Sessions; // we are introducer std::map m_Relays; diff --git a/src/core/transport/SSUData.cpp b/src/core/transport/SSUData.cpp index 6d00e6c6..7e667497 100644 --- a/src/core/transport/SSUData.cpp +++ b/src/core/transport/SSUData.cpp @@ -36,6 +36,9 @@ #include +#include +#include + #include "NetworkDatabase.h" #include "SSU.h" #include "util/Log.h" @@ -65,6 +68,7 @@ SSUData::SSUData( m_ResendTimer(session.GetService()), m_DecayTimer(session.GetService()), m_IncompleteMessagesCleanupTimer(session.GetService()) { + LogPrint(eLogDebug, "SSUData: initializing"); m_MaxPacketSize = session.IsV6() ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE; @@ -74,13 +78,17 @@ SSUData::SSUData( AdjustPacketSize(*remoteRouter); } -SSUData::~SSUData() {} +SSUData::~SSUData() { + LogPrint(eLogDebug, "SSUData: destroying"); +} void SSUData::Start() { + LogPrint(eLogDebug, "SSUData: starting"); ScheduleIncompleteMessagesCleanup(); } void SSUData::Stop() { + LogPrint(eLogDebug, "SSUData: stopping"); m_ResendTimer.cancel(); m_DecayTimer.cancel(); m_IncompleteMessagesCleanupTimer.cancel(); @@ -88,6 +96,8 @@ void SSUData::Stop() { void SSUData::AdjustPacketSize( const i2p::data::RouterInfo& remoteRouter) { + LogPrint(eLogDebug, + "SSUData: adjusting packet size"); auto ssuAddress = remoteRouter.GetSSUAddress(); if (ssuAddress && ssuAddress->mtu) { if (m_Session.IsV6 ()) @@ -100,7 +110,9 @@ void SSUData::AdjustPacketSize( m_PacketSize <<= 4; if (m_PacketSize > m_MaxPacketSize) m_PacketSize = m_MaxPacketSize; - LogPrint("SSUData: MTU=", ssuAddress->mtu, " packet size=", m_PacketSize); + LogPrint(eLogInfo, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "MTU=", ssuAddress->mtu, " packet size=", m_PacketSize); } else { LogPrint(eLogWarning, "SSUData: unexpected MTU ", ssuAddress->mtu); m_PacketSize = m_MaxPacketSize; @@ -110,6 +122,9 @@ void SSUData::AdjustPacketSize( void SSUData::UpdatePacketSize( const i2p::data::IdentHash& remoteIdent) { + LogPrint(eLogDebug, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "updating packet size"); auto routerInfo = i2p::data::netdb.FindRouter(remoteIdent); if (routerInfo) AdjustPacketSize(*routerInfo); @@ -117,6 +132,10 @@ void SSUData::UpdatePacketSize( void SSUData::ProcessSentMessageAck( uint32_t msgID) { + // TODO(anonimal): too spammy? keep? + //LogPrint(eLogDebug, + //"SSUData:", m_Session.GetFormattedSessionInfo(), + //"processing sent message ACK"); auto it = m_SentMessages.find(msgID); if (it != m_SentMessages.end()) { m_SentMessages.erase(it); @@ -128,6 +147,8 @@ void SSUData::ProcessSentMessageAck( void SSUData::ProcessAcks( uint8_t *& buf, uint8_t flag) { + LogPrint(eLogDebug, + "SSUData:", m_Session.GetFormattedSessionInfo(), "processing ACKs"); if (flag & DATA_FLAG_EXPLICIT_ACKS_INCLUDED) { // explicit ACKs uint8_t numAcks =*buf; @@ -172,7 +193,10 @@ void SSUData::ProcessAcks( } void SSUData::ProcessFragments( - uint8_t * buf) { + uint8_t* buf) { + LogPrint(eLogDebug, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "processing fragments"); uint8_t numFragments = *buf; // number of fragments buf++; for (int i = 0; i < numFragments; i++) { @@ -188,7 +212,8 @@ void SSUData::ProcessFragments( uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17 if (fragmentSize >= SSU_V4_MAX_PACKET_SIZE) { LogPrint(eLogError, - "SSUData: fragment size ", fragmentSize, "exceeds max SSU packet size"); + "SSUData:", m_Session.GetFormattedSessionInfo(), + "fragment size ", fragmentSize, "exceeds max SSU packet size"); return; } // find message with msgID @@ -225,19 +250,22 @@ void SSUData::ProcessFragments( } } if (isLast) - LogPrint(eLogDebug, "SSUData: message ", msgID, " is complete"); + LogPrint(eLogDebug, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "message ", msgID, " is complete"); } } else { if (fragmentNum < incompleteMessage->nextFragmentNum) { // duplicate fragment LogPrint(eLogWarning, - "SSUData: ignoring duplicate fragment ", - static_cast(fragmentNum), + "SSUData:", m_Session.GetFormattedSessionInfo(), + " ignoring duplicate fragment ", static_cast(fragmentNum), " of message ", msgID); } else { // missing fragment LogPrint(eLogWarning, - "SSUData: missing fragments from ", + "SSUData:", m_Session.GetFormattedSessionInfo(), + " missing fragments from ", static_cast(incompleteMessage->nextFragmentNum), " to ", fragmentNum - 1, " of message ", msgID); auto savedFragment = @@ -248,7 +276,8 @@ void SSUData::ProcessFragments( i2p::util::GetSecondsSinceEpoch(); else LogPrint(eLogWarning, - "SSUData: fragment ", static_cast(fragmentNum), + "SSUData:", m_Session.GetFormattedSessionInfo(), + "fragment ", static_cast(fragmentNum), " of message ", msgID, " is already saved"); } isLast = false; @@ -271,22 +300,28 @@ void SSUData::ProcessFragments( m_Handler.PutNextMessage(msg); } else { LogPrint(eLogWarning, - "SSUData: SSU message ", msgID, " already received"); + "SSUData:", m_Session.GetFormattedSessionInfo(), + "SSU message ", msgID, " already received"); } } else { auto i2np_type = msg->GetTypeID(); // we expect DeliveryStatus if (i2np_type == e_I2NPDeliveryStatus) { - LogPrint("SSUData: SSU session established"); + LogPrint(eLogInfo, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "SSU session established"); m_Session.Established(); } else if (i2np_type == e_I2NPDatabaseStore) { // we got a database store message - LogPrint("SSUData: Got DSM From SSU"); + LogPrint(eLogInfo, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "Got DSM From SSU"); m_ReceivedMessages.insert(msgID); m_Handler.PutNextMessage(msg); } else { LogPrint(eLogError, - "SSUData: SSU unexpected message ", + "SSUData:", m_Session.GetFormattedSessionInfo(), + "SSU unexpected message ", static_cast(msg->GetTypeID())); } } @@ -298,6 +333,9 @@ void SSUData::ProcessFragments( } void SSUData::FlushReceivedMessage() { + LogPrint(eLogDebug, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "flushing received message"); m_Handler.Flush(); } @@ -308,8 +346,9 @@ void SSUData::ProcessMessage( uint8_t flag = *buf; buf++; LogPrint(eLogDebug, - "SSUData: process SSU data flags=", - static_cast(flag), " len=", len); + "SSUData:", m_Session.GetFormattedSessionInfo(), + "processing message: flags=", static_cast(flag), + " len=", len); // process acks if presented if (flag & (DATA_FLAG_ACK_BITFIELDS_INCLUDED | DATA_FLAG_EXPLICIT_ACKS_INCLUDED)) ProcessAcks(buf, flag); @@ -318,7 +357,8 @@ void SSUData::ProcessMessage( uint8_t extendedDataSize = *buf; buf++; // size LogPrint(eLogDebug, - "SSUData: SSU extended data of ", + "SSUData:", m_Session.GetFormattedSessionInfo(), + "SSU extended data of ", static_cast(extendedDataSize), " bytes presented"); buf += extendedDataSize; } @@ -328,9 +368,14 @@ void SSUData::ProcessMessage( void SSUData::Send( std::shared_ptr msg) { + LogPrint(eLogDebug, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "sending message"); uint32_t msgID = msg->ToSSU(); if (m_SentMessages.count(msgID) > 0) { - LogPrint(eLogWarning, "SSUData: SSU message ", msgID, " was already sent"); + LogPrint(eLogWarning, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "message ", msgID, " was already sent"); return; } if (m_SentMessages.empty()) // schedule resend at first message only @@ -382,7 +427,9 @@ void SSUData::Send( try { m_Session.Send(buf, size); } catch (boost::system::system_error& ec) { - LogPrint(eLogError, "SSUData: can't send SSU fragment ", ec.what()); + LogPrint(eLogError, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "can't send SSU fragment: '", ec.what(), "'"); } if (!isLast) { len -= payloadSize; @@ -396,6 +443,9 @@ void SSUData::Send( void SSUData::SendMsgAck( uint32_t msgID) { + LogPrint(eLogDebug, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "sending message ACK"); // actual length is 44 = 37 + 7 but pad it to multiple of 16 uint8_t buf[48 + 18]; uint8_t * payload = buf + SSU_HEADER_SIZE_MIN; @@ -414,9 +464,13 @@ void SSUData::SendMsgAck( void SSUData::SendFragmentAck( uint32_t msgID, int fragmentNum) { + LogPrint(eLogDebug, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "sending fragment ACK"); if (fragmentNum > 64) { LogPrint(eLogWarning, - "SSUData: fragment number ", fragmentNum, " exceeds 64"); + "SSUData:", m_Session.GetFormattedSessionInfo(), + "fragment number ", fragmentNum, " exceeds 64"); return; } uint8_t buf[64 + 18]; @@ -441,6 +495,9 @@ void SSUData::SendFragmentAck( } void SSUData::ScheduleResend() { + LogPrint(eLogDebug, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "scheduling resend"); m_ResendTimer.cancel(); m_ResendTimer.expires_from_now( boost::posix_time::seconds( @@ -455,6 +512,9 @@ void SSUData::ScheduleResend() { void SSUData::HandleResendTimer( const boost::system::error_code& ecode) { + LogPrint(eLogDebug, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "handling resend timer"); if (ecode != boost::asio::error::operation_aborted) { uint32_t ts = i2p::util::GetSecondsSinceEpoch(); for (auto it = m_SentMessages.begin(); it != m_SentMessages.end();) { @@ -466,7 +526,8 @@ void SSUData::HandleResendTimer( m_Session.Send(f->buf, f->len); // resend } catch (boost::system::system_error& ec) { LogPrint(eLogError, - "SSUData: can't resend SSU fragment: ", ec.what()); + "SSUData:", m_Session.GetFormattedSessionInfo(), + "can't resend SSU fragment: '", ec.what(), "'"); } } it->second->numResends++; @@ -474,7 +535,8 @@ void SSUData::HandleResendTimer( it++; } else { LogPrint(eLogError, - "SSUData: SSU message has not been ACKed after ", + "SSUData:", m_Session.GetFormattedSessionInfo(), + "SSU message has not been ACKed after ", MAX_NUM_RESENDS, " attempts. Deleted"); it = m_SentMessages.erase(it); } @@ -487,6 +549,9 @@ void SSUData::HandleResendTimer( } void SSUData::ScheduleDecay() { + LogPrint(eLogDebug, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "scheduling decay"); m_DecayTimer.cancel(); m_DecayTimer.expires_from_now( boost::posix_time::seconds( @@ -501,11 +566,17 @@ void SSUData::ScheduleDecay() { void SSUData::HandleDecayTimer( const boost::system::error_code& ecode) { + LogPrint(eLogDebug, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "handling decay"); if (ecode != boost::asio::error::operation_aborted) m_ReceivedMessages.clear(); } void SSUData::ScheduleIncompleteMessagesCleanup() { + LogPrint(eLogDebug, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "scheduling incomplete messages cleanup"); m_IncompleteMessagesCleanupTimer.cancel(); m_IncompleteMessagesCleanupTimer.expires_from_now( boost::posix_time::seconds( @@ -520,6 +591,9 @@ void SSUData::ScheduleIncompleteMessagesCleanup() { void SSUData::HandleIncompleteMessagesCleanupTimer( const boost::system::error_code& ecode) { + LogPrint(eLogDebug, + "SSUData:", m_Session.GetFormattedSessionInfo(), + "handling incomplete messages cleanup"); if (ecode != boost::asio::error::operation_aborted) { uint32_t ts = i2p::util::GetSecondsSinceEpoch(); for (auto it = m_IncompleteMessages.begin (); @@ -527,7 +601,8 @@ void SSUData::HandleIncompleteMessagesCleanupTimer( if (ts > it->second->lastFragmentInsertTime + INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT) { LogPrint(eLogError, - "SSUData: SSU message ", it->first, " was not completed in ", + "SSUData:", m_Session.GetFormattedSessionInfo(), + "SSU message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds. Deleted"); it = m_IncompleteMessages.erase(it); } else { diff --git a/src/core/transport/SSUSession.cpp b/src/core/transport/SSUSession.cpp index f5570769..c35486c5 100644 --- a/src/core/transport/SSUSession.cpp +++ b/src/core/transport/SSUSession.cpp @@ -34,7 +34,9 @@ #include +#include #include +#include #include "RouterContext.h" #include "SSU.h" @@ -162,8 +164,8 @@ SSUSession::SSUSession( SSUSession::~SSUSession() {} boost::asio::io_service& SSUSession::GetService() { - return IsV6 () ? - m_Server.GetServiceV6 () : + return IsV6() ? + m_Server.GetServiceV6() : m_Server.GetService(); } @@ -171,8 +173,9 @@ void SSUSession::CreateAESandMacKey( const uint8_t* pubKey) { i2p::crypto::DiffieHellman dh; uint8_t sharedKey[256]; - if (!dh.Agree(sharedKey, m_DHKeysPair->privateKey, pubKey)) { - LogPrint(eLogError, "SSUSession: couldn't create shared key"); + if (!dh.Agree(sharedKey, m_DHKeysPair->private_key.data(), pubKey)) { + LogPrint(eLogError, + "SSUSession:", GetFormattedSessionInfo(), "couldn't create shared key"); return; } uint8_t* sessionKey = m_SessionKey; @@ -190,7 +193,9 @@ void SSUSession::CreateAESandMacKey( while (!*nonZero) { nonZero++; if (nonZero - sharedKey > 32) { - LogPrint("SSUSession: first 32 bytes of shared key is all zeros. Ignored"); + LogPrint(eLogWarning, + "SSUSession:", GetFormattedSessionInfo(), + "first 32 bytes of shared key is all zeros. Ignored"); return; } } @@ -216,6 +221,10 @@ void SSUSession::ProcessNextMessage( size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) { m_NumReceivedBytes += len; + LogPrint(eLogDebug, + "SSUSession:", GetFormattedSessionInfo(), + "--> ", len, " bytes transferred, ", + GetNumReceivedBytes(), " total bytes received"); i2p::transport::transports.UpdateReceivedBytes(len); if (m_State == eSessionStateIntroduced) { // HolePunch received @@ -351,7 +360,7 @@ void SSUSession::ProcessSessionRequest( return; } LogPrint(eLogDebug, "SSUSession: SessionRequest received"); - m_RemoteEndpoint = senderEndpoint; + SetRemoteEndpoint(senderEndpoint); if (!m_DHKeysPair) m_DHKeysPair = transports.GetNextDHKeysPair(); CreateAESandMacKey(pkt.bodyptr); @@ -359,27 +368,31 @@ void SSUSession::ProcessSessionRequest( } void SSUSession::SendSessionRequest() { + LogPrint(eLogError, + "SSUSession:", GetFormattedSessionInfo(), + "sending SessionRequest"); auto introKey = GetIntroKey(); if (!introKey) { LogPrint(eLogError, - "SSUSession: SendSessionRequest(): SSU is not supported"); + "SSUSession:", GetFormattedSessionInfo(), + "SendSessionRequest(): SSU is not supported"); return; } uint8_t buf[320 + 18] = {}; // 304 bytes for ipv4, 320 for ipv6, all set to 0 uint8_t* payload = buf + SSU_HEADER_SIZE_MIN; - memcpy(payload, m_DHKeysPair->publicKey, 256); // x - bool isV4 = m_RemoteEndpoint.address().is_v4(); + memcpy(payload, m_DHKeysPair->public_key.data(), 256); // x + bool isV4 = GetRemoteEndpoint().address().is_v4(); if (isV4) { payload[256] = 4; memcpy( payload + 257, - m_RemoteEndpoint.address().to_v4().to_bytes().data(), + GetRemoteEndpoint().address().to_v4().to_bytes().data(), 4); } else { payload[256] = 16; memcpy( payload + 257, - m_RemoteEndpoint.address().to_v6().to_bytes().data(), + GetRemoteEndpoint().address().to_v6().to_bytes().data(), 16); } uint8_t iv[16]; @@ -394,7 +407,7 @@ void SSUSession::SendSessionRequest() { m_Server.Send( buf, isV4 ? 304 : 320, - m_RemoteEndpoint); + GetRemoteEndpoint()); } /** @@ -406,17 +419,22 @@ void SSUSession::SendSessionRequest() { void SSUSession::ProcessSessionCreated( SSUSessionPacket& pkt) { if (!m_RemoteRouter || !m_DHKeysPair) { - LogPrint(eLogWarning, "SSUSession: unsolicited SessionCreated message"); + LogPrint(eLogWarning, + "SSUSession:", GetFormattedSessionInfo(), + "unsolicited SessionCreated message"); return; } - LogPrint(eLogDebug, "SSUSession: SessionCreated received"); + LogPrint(eLogDebug, + "SSUSession:", GetFormattedSessionInfo(), + "SessionCreated received"); m_Timer.cancel(); // connect timer // x, y, our IP, our port, remote IP, remote port, relayTag, signed on time SignedData s; uint8_t* payload = pkt.bodyptr; uint8_t* y = payload; + // TODO(unassigned): if we cannot create shared key, we should not continue CreateAESandMacKey(y); - s.Insert(m_DHKeysPair->publicKey, 256); // x + s.Insert(m_DHKeysPair->public_key.data(), 256); // x s.Insert(y, 256); // y payload += 256; uint8_t addressSize = *payload; @@ -438,17 +456,18 @@ void SSUSession::ProcessSessionCreated( s.Insert(payload, 2); // our port payload += 2; // port LogPrint(eLogInfo, - "SSUSession: ProcessSessionCreated: our external address is ", + "SSUSession:", GetFormattedSessionInfo(), + "ProcessSessionCreated(): our external address is ", ourIP.to_string(), ":", ourPort); i2p::context.UpdateAddress(ourIP); - if (m_RemoteEndpoint.address().is_v4()) { + if (GetRemoteEndpoint().address().is_v4()) { // remote IP v4 - s.Insert(m_RemoteEndpoint.address().to_v4().to_bytes().data(), 4); + s.Insert(GetRemoteEndpoint().address().to_v4().to_bytes().data(), 4); } else { // remote IP v6 - s.Insert(m_RemoteEndpoint.address().to_v6().to_bytes().data(), 16); + s.Insert(GetRemoteEndpoint().address().to_v6().to_bytes().data(), 16); } - s.Insert(htobe16(m_RemoteEndpoint.port())); // remote port + s.Insert(htobe16(GetRemoteEndpoint().port())); // remote port s.Insert(payload, 8); // relayTag and signed on time m_RelayTag = bufbe32toh(payload); payload += 4; // relayTag @@ -466,7 +485,8 @@ void SSUSession::ProcessSessionCreated( SendSessionConfirmed(y, ourAddress, addressSize + 2); } else { // invalid signature LogPrint(eLogError, - "SSUSession: SessionCreated signature verification failed"); + "SSUSession:", GetFormattedSessionInfo(), + "SessionCreated signature verification failed"); } } @@ -478,7 +498,8 @@ void SSUSession::SendSessionCreated( i2p::context.GetRouterInfo().GetSSUAddress(true); // v4 only if (!introKey || !address) { LogPrint(eLogError, - "SSUSession: SendSessionCreated(): SSU is not supported"); + "SSUSession:", GetFormattedSessionInfo(), + "SendSessionCreated(): SSU is not supported"); return; } // x,y, remote IP, remote port, our IP, our port, relayTag, signed on time @@ -486,16 +507,16 @@ void SSUSession::SendSessionCreated( s.Insert(x, 256); // x uint8_t buf[384 + 18] = {}; uint8_t* payload = buf + SSU_HEADER_SIZE_MIN; - memcpy(payload, m_DHKeysPair->publicKey, 256); + memcpy(payload, m_DHKeysPair->public_key.data(), 256); s.Insert(payload, 256); // y payload += 256; - if (m_RemoteEndpoint.address().is_v4()) { + if (GetRemoteEndpoint().address().is_v4()) { // ipv4 *payload = 4; payload++; memcpy( payload, - m_RemoteEndpoint.address().to_v4().to_bytes().data(), + GetRemoteEndpoint().address().to_v4().to_bytes().data(), 4); s.Insert(payload, 4); // remote endpoint IP V4 payload += 4; @@ -505,12 +526,12 @@ void SSUSession::SendSessionCreated( payload++; memcpy( payload, - m_RemoteEndpoint.address().to_v6().to_bytes().data(), + GetRemoteEndpoint().address().to_v6().to_bytes().data(), 16); s.Insert(payload, 16); // remote endpoint IP V6 payload += 16; } - htobe16buf(payload, m_RemoteEndpoint.port()); + htobe16buf(payload, GetRemoteEndpoint().port()); s.Insert(payload, 2); // remote port payload += 2; if (address->host.is_v4()) @@ -523,7 +544,7 @@ void SSUSession::SendSessionCreated( relayTag = i2p::crypto::Rand(); if (!relayTag) relayTag = 1; - m_Server.AddRelay(relayTag, m_RemoteEndpoint); + m_Server.AddRelay(relayTag, GetRemoteEndpoint()); } htobe32buf(payload, relayTag); payload += 4; // relay tag @@ -550,7 +571,7 @@ void SSUSession::SendSessionCreated( payload); payload += signatureLen; size_t msgLen = payload - buf; - if (msgLen <= SSU_MTU_V4 ) { + if (msgLen <= SSU_MTU_V4) { // encrypt message with intro key FillHeaderAndEncrypt( PAYLOAD_TYPE_SESSION_CREATED, @@ -571,14 +592,16 @@ void SSUSession::SendSessionCreated( */ void SSUSession::ProcessSessionConfirmed( - SSUSessionPacket & pkt) { + SSUSessionPacket& pkt) { if (m_SessionConfirmData == nullptr) { - // no session confirm data wtf? + // No session confirm data LogPrint(eLogError, - "SSUSession: unsolicited SessionConfirmed"); + "SSUSession:", GetFormattedSessionInfo(), + "unsolicited SessionConfirmed"); return; } - LogPrint(eLogDebug, "SSUSession: SessionConfirmed received"); + LogPrint(eLogDebug, + "SSUSession:", GetFormattedSessionInfo(), "SessionConfirmed received"); uint8_t* buf = pkt.dataptr; uint8_t* payload = pkt.bodyptr; payload++; // identity fragment info @@ -603,7 +626,8 @@ void SSUSession::ProcessSessionConfirmed( return; } // bad state or verification failed - LogPrint(eLogError, "SSUSession: SessionConfirmed Failed"); + LogPrint(eLogError, + "SSUSession:", GetFormattedSessionInfo(), "SessionConfirmed Failed"); } void SSUSession::SendSessionConfirmed( @@ -634,20 +658,20 @@ void SSUSession::SendSessionConfirmed( // x,y, our IP, our port, remote IP, remote port, // relayTag, our signed on time SignedData s; - s.Insert(m_DHKeysPair->publicKey, 256); // x + s.Insert(m_DHKeysPair->public_key.data(), 256); // x s.Insert(y, 256); // y s.Insert(ourAddress, ourAddressLen); // our address/port as seen by party - if (m_RemoteEndpoint.address().is_v4()) + if (GetRemoteEndpoint().address().is_v4()) // remote IP V4 s.Insert( - m_RemoteEndpoint.address().to_v4().to_bytes().data(), + GetRemoteEndpoint().address().to_v4().to_bytes().data(), 4); else // remote IP V6 s.Insert( - m_RemoteEndpoint.address().to_v6().to_bytes().data(), + GetRemoteEndpoint().address().to_v6().to_bytes().data(), 16); - s.Insert (htobe16(m_RemoteEndpoint.port())); // remote port + s.Insert (htobe16(GetRemoteEndpoint().port())); // remote port s.Insert(htobe32(m_RelayTag)); // relay tag s.Insert(htobe32(signedOnTime)); // signed on time s.Sign(i2p::context.GetPrivateKeys(), payload); // DSA signature @@ -694,7 +718,7 @@ void SSUSession::ProcessRelayRequest( nonce, from, introKey, - session->m_RemoteEndpoint); + session->GetRemoteEndpoint()); SendRelayIntro(session.get(), from); } } @@ -705,7 +729,8 @@ void SSUSession::SendRelayRequest( auto address = i2p::context.GetRouterInfo().GetSSUAddress(); if (!address) { LogPrint(eLogError, - "SSUSession: SendRelayRequest(): SSU is not supported"); + "SSUSession:", GetFormattedSessionInfo(), + "SendRelayRequest(): SSU is not supported"); return; } uint8_t buf[96 + 18] = {}; @@ -743,7 +768,7 @@ void SSUSession::SendRelayRequest( m_Server.Send( buf, 96, - m_RemoteEndpoint); + GetRemoteEndpoint()); } /** @@ -754,7 +779,8 @@ void SSUSession::SendRelayRequest( void SSUSession::ProcessRelayResponse( SSUSessionPacket& pkt) { - LogPrint(eLogDebug, "SSUSession: RelayResponse received"); + LogPrint(eLogDebug, + "SSUSession:", GetFormattedSessionInfo(), "RelayResponse received"); uint8_t* payload = pkt.bodyptr; uint8_t remoteSize = *payload; payload++; // remote size @@ -778,7 +804,8 @@ void SSUSession::ProcessRelayResponse( uint16_t ourPort = bufbe16toh(payload); payload += 2; // our port LogPrint(eLogInfo, - "SSUSession: ProcessRelayResponse: our external address is ", + "SSUSession:", GetFormattedSessionInfo(), + "ProcessRelayResponse(): our external address is ", ourIP.to_string(), ":", ourPort); i2p::context.UpdateAddress(ourIP); } @@ -793,7 +820,8 @@ void SSUSession::SendRelayResponse( // Charlie's address always v4 if (!to.address().is_v4()) { LogPrint(eLogError, - "SSUSession: SendRelayResponse: Charlie's IP must be V4"); + "SSUSession:", GetFormattedSessionInfo(), + "SendRelayResponse: Charlie's IP must be V4"); return; } *payload = 4; @@ -872,8 +900,9 @@ void SSUSession::ProcessRelayIntro( port)); } else { LogPrint(eLogWarning, - "SSUSession: ProcessRelayIntro(): address size ", - static_cast(size), " is not supported"); + "SSUSession:", GetFormattedSessionInfo(), + "ProcessRelayIntro(): address size ", + static_cast(size), " is not supported"); } } @@ -885,7 +914,8 @@ void SSUSession::SendRelayIntro( // Alice's address always v4 if (!from.address().is_v4()) { LogPrint(eLogError, - "SSUSession: SendRelayIntro(): Alice's IP must be V4"); + "SSUSession:", GetFormattedSessionInfo(), + "SendRelayIntro(): Alice's IP must be V4"); return; } uint8_t buf[48 + 18] = {}; @@ -909,8 +939,9 @@ void SSUSession::SendRelayIntro( m_Server.Send( buf, 48, - session->m_RemoteEndpoint); - LogPrint(eLogDebug, "SSUSession: RelayIntro sent"); + session->GetRemoteEndpoint()); + LogPrint(eLogDebug, + "SSUSession: ", GetFormattedSessionInfo(), "RelayIntro sent"); } /** @@ -951,8 +982,8 @@ void SSUSession::ProcessPeerTest( const uint8_t* introKey = buf + size + 7; if (port && !address) { LogPrint(eLogWarning, - "SSUSession: address of ", - static_cast(size), " bytes not supported"); + "SSUSession:", GetFormattedSessionInfo(), "address of ", + static_cast(size), " bytes not supported"); return; } switch (m_Server.GetPeerTestParticipant(nonce)) { @@ -960,12 +991,14 @@ void SSUSession::ProcessPeerTest( case ePeerTestParticipantAlice1: { if (m_State == eSessionStateEstablished) { LogPrint(eLogDebug, - "SSUSession: PeerTest from Bob. We are Alice"); + "SSUSession:", GetFormattedSessionInfo(), + "PeerTest from Bob. We are Alice"); if (i2p::context.GetStatus() == eRouterStatusTesting) // still not OK i2p::context.SetStatus(eRouterStatusFirewalled); } else { LogPrint(eLogDebug, - "SSUSession: first PeerTest from Charlie. We are Alice"); + "SSUSession:", GetFormattedSessionInfo(), + "first PeerTest from Charlie. We are Alice"); i2p::context.SetStatus(eRouterStatusOK); m_Server.UpdatePeerTest( nonce, @@ -983,11 +1016,13 @@ void SSUSession::ProcessPeerTest( case ePeerTestParticipantAlice2: { if (m_State == eSessionStateEstablished) { LogPrint(eLogDebug, - "SSUSession: PeerTest from Bob. We are Alice"); + "SSUSession:", GetFormattedSessionInfo(), + "PeerTest from Bob. We are Alice"); } else { // PeerTest successive LogPrint(eLogDebug, - "SSUSession: second PeerTest from Charlie. We are Alice"); + "SSUSession:", GetFormattedSessionInfo(), + "second PeerTest from Charlie. We are Alice"); i2p::context.SetStatus(eRouterStatusOK); m_Server.RemovePeerTest(nonce); } @@ -995,7 +1030,8 @@ void SSUSession::ProcessPeerTest( } case ePeerTestParticipantBob: { LogPrint(eLogDebug, - "SSUSession: PeerTest from Charlie. We are Bob"); + "SSUSession:", GetFormattedSessionInfo(), + "PeerTest from Charlie. We are Bob"); // session with Alice from PeerTest auto session = m_Server.GetPeerTestSession(nonce); if (session && session->m_State == eSessionStateEstablished) @@ -1008,7 +1044,8 @@ void SSUSession::ProcessPeerTest( } case ePeerTestParticipantCharlie: { LogPrint(eLogDebug, - "SSUSession: PeerTest from Alice. We are Charlie"); + "SSUSession:", GetFormattedSessionInfo(), + "PeerTest from Alice. We are Charlie"); SendPeerTest( nonce, senderEndpoint.address().to_v4().to_ulong(), @@ -1023,7 +1060,8 @@ void SSUSession::ProcessPeerTest( // new test if (port) { LogPrint(eLogDebug, - "SSUSession: PeerTest from Bob. We are Charlie"); + "SSUSession:", GetFormattedSessionInfo(), + "PeerTest from Bob. We are Charlie"); m_Server.NewPeerTest(nonce, ePeerTestParticipantCharlie); Send( // back to Bob PAYLOAD_TYPE_PEER_TEST, @@ -1036,7 +1074,8 @@ void SSUSession::ProcessPeerTest( introKey); } else { LogPrint(eLogDebug, - "SSUSession: PeerTest from Alice. We are Bob"); + "SSUSession:", GetFormattedSessionInfo(), + "PeerTest from Alice. We are Bob"); auto session = m_Server.GetRandomEstablishedSession( shared_from_this()); // Charlie @@ -1054,7 +1093,8 @@ void SSUSession::ProcessPeerTest( } } } else { - LogPrint(eLogError, "SSUSession: unexpected PeerTest"); + LogPrint(eLogError, + "SSUSession:", GetFormattedSessionInfo(), "unexpected PeerTest"); } } } @@ -1091,7 +1131,8 @@ void SSUSession::SendPeerTest( memcpy(payload, addr->key, 32); // intro key else LogPrint(eLogError, - "SSUSession: SSU is not supported, can't send PeerTest"); + "SSUSession:", GetFormattedSessionInfo(), + "SSU is not supported, can't send PeerTest"); } else { memcpy(payload, introKey, 32); // intro key } @@ -1124,11 +1165,13 @@ void SSUSession::SendPeerTest( void SSUSession::SendPeerTest() { // we are Alice - LogPrint(eLogDebug, "SSUSession: sending PeerTest"); + LogPrint(eLogDebug, + "SSUSession: <--", GetFormattedSessionInfo(), "sending PeerTest"); auto address = i2p::context.GetRouterInfo().GetSSUAddress(); if (!address) { LogPrint(eLogError, - "SSUSession: SSU is not supported, can't send PeerTest"); + "SSUSession:", GetFormattedSessionInfo(), + "SSU is not supported, can't send PeerTest"); return; } uint32_t nonce = i2p::crypto::Rand(); @@ -1160,9 +1203,11 @@ void SSUSession::SendSesionDestroyed() { Send(buf, 48); } catch(std::exception& ex) { LogPrint(eLogError, - "SSUSession: SendSesionDestroyed() exception ", ex.what()); + "SSUSession:", GetFormattedSessionInfo(), + "SendSesionDestroyed(): '", ex.what(), "'"); } - LogPrint(eLogDebug, "SSUSession: SessionDestroyed sent"); + LogPrint(eLogDebug, + "SSUSession:", GetFormattedSessionInfo(), "SessionDestroyed sent"); } } @@ -1176,7 +1221,8 @@ void SSUSession::SendKeepAlive() { // encrypt message with session key FillHeaderAndEncrypt(PAYLOAD_TYPE_DATA, buf, 48); Send(buf, 48); - LogPrint(eLogDebug, "SSUSession: keep-alive sent"); + LogPrint(eLogDebug, + "SSUSession:", GetFormattedSessionInfo(), "keep-alive sent"); ScheduleTermination(); } } @@ -1189,7 +1235,9 @@ void SSUSession::FillHeaderAndEncrypt( const uint8_t* iv, const uint8_t* macKey) { if (len < SSU_HEADER_SIZE_MIN) { - LogPrint(eLogError, "SSUSession: unexpected SSU packet length ", len); + LogPrint(eLogError, + "SSUSession:", GetFormattedSessionInfo(), + "unexpected SSU packet length ", len); return; } SSUSessionPacket pkt(buf, len); @@ -1218,7 +1266,9 @@ void SSUSession::FillHeaderAndEncrypt( uint8_t* buf, size_t len) { if (len < SSU_HEADER_SIZE_MIN) { - LogPrint(eLogError, "SSUSession: unexpected SSU packet length ", len); + LogPrint(eLogError, + "SSUSession:", GetFormattedSessionInfo(), + "unexpected SSU packet length ", len); return; } SSUSessionPacket pkt(buf, len); @@ -1248,7 +1298,8 @@ void SSUSession::Decrypt( const uint8_t* aesKey) { if (len < SSU_HEADER_SIZE_MIN) { LogPrint(eLogError, - "SSUSession: Decrypt(): unexpected SSU packet length ", len); + "SSUSession:", GetFormattedSessionInfo(), + "Decrypt(): unexpected SSU packet length ", len); return; } SSUSessionPacket pkt(buf, len); @@ -1268,7 +1319,8 @@ void SSUSession::DecryptSessionKey( size_t len) { if (len < SSU_HEADER_SIZE_MIN) { LogPrint(eLogError, - "SSUSession: DecryptSessionKey(): unexpected SSU packet length ", len); + "SSUSession:", GetFormattedSessionInfo(), + "DecryptSessionKey(): unexpected SSU packet length ", len); return; } SSUSessionPacket pkt(buf, len); @@ -1289,7 +1341,8 @@ bool SSUSession::Validate( const uint8_t* macKey) { if (len < SSU_HEADER_SIZE_MIN) { LogPrint(eLogError, - "SSUSession: Validate(): unexpected SSU packet length ", len); + "SSUSession:", GetFormattedSessionInfo(), + "Validate(): unexpected SSU packet length ", len); return false; } SSUSessionPacket pkt(buf, len); @@ -1319,7 +1372,8 @@ void SSUSession::Connect() { void SSUSession::WaitForConnect() { if (IsOutbound()) LogPrint(eLogWarning, - "SSUSession: WaitForConnect() for outgoing session"); + "SSUSession:", GetFormattedSessionInfo(), + "WaitForConnect() for outgoing session"); else ScheduleConnectTimer(); } @@ -1341,7 +1395,8 @@ void SSUSession::HandleConnectTimer( if (!ecode) { // timeout expired LogPrint(eLogError, - "SSUSession: session was not established after ", + "SSUSession:", GetFormattedSessionInfo(), + "session was not established after ", SSU_CONNECT_TIMEOUT, " seconds"); Failed(); } @@ -1394,7 +1449,7 @@ void SSUSession::Done() { void SSUSession::Established() { // clear out session confirmation data - m_SessionConfirmData = nullptr; + m_SessionConfirmData.reset(nullptr); m_State = eSessionStateEstablished; if (m_DHKeysPair) { delete m_DHKeysPair; @@ -1434,8 +1489,8 @@ void SSUSession::HandleTerminationTimer( const boost::system::error_code& ecode) { if (ecode != boost::asio::error::operation_aborted) { LogPrint(eLogError, - "SSUSession: no activity for ", - SSU_TERMINATION_TIMEOUT, " seconds"); + "SSUSession:", GetFormattedSessionInfo(), + "no activity for ", SSU_TERMINATION_TIMEOUT, " seconds"); Failed(); } } @@ -1453,7 +1508,7 @@ const uint8_t* SSUSession::GetIntroKey() const { } void SSUSession::SendI2NPMessages( - const std::vector >& msgs) { + const std::vector>& msgs) { GetService().post( std::bind( &SSUSession::PostI2NPMessages, @@ -1462,7 +1517,7 @@ void SSUSession::SendI2NPMessages( } void SSUSession::PostI2NPMessages( - std::vector > msgs) { + std::vector> msgs) { if (m_State == eSessionStateEstablished) { for (auto it : msgs) if (it) @@ -1481,7 +1536,8 @@ void SSUSession::Send( msgSize += (16 - paddingSize); if (msgSize > SSU_MTU_V4) { LogPrint(eLogWarning, - "SSUSession: payload size ", msgSize, " exceeds MTU"); + "SSUSession:", GetFormattedSessionInfo(), + "<-- payload size ", msgSize, " exceeds MTU"); return; } memcpy(buf + SSU_HEADER_SIZE_MIN, payload, len); @@ -1494,8 +1550,12 @@ void SSUSession::Send( const uint8_t* buf, size_t size) { m_NumSentBytes += size; + LogPrint(eLogDebug, + "SSUSession:", GetFormattedSessionInfo(), + "<-- ", size, " bytes transferred, ", + GetNumSentBytes(), " total bytes sent"); i2p::transport::transports.UpdateSentBytes(size); - m_Server.Send(buf, size, m_RemoteEndpoint); + m_Server.Send(buf, size, GetRemoteEndpoint()); } } // namespace transport diff --git a/src/core/transport/SSUSession.h b/src/core/transport/SSUSession.h index dadf2f87..57197f95 100644 --- a/src/core/transport/SSUSession.h +++ b/src/core/transport/SSUSession.h @@ -36,7 +36,9 @@ #include #include +#include #include +#include #include #include "I2NPProtocol.h" @@ -197,16 +199,12 @@ class SSUSession void Done(); - boost::asio::ip::udp::endpoint& GetRemoteEndpoint() { - return m_RemoteEndpoint; - } - bool IsV6() const { return m_RemoteEndpoint.address().is_v6(); } void SendI2NPMessages( - const std::vector >& msgs); + const std::vector>& msgs); void SendPeerTest(); // Alice @@ -232,6 +230,36 @@ class SSUSession return m_CreationTime; } + /// @brief Sets peer abbreviated ident hash + void SetRemoteIdentHashAbbreviation() { + m_RemoteIdentHashAbbreviation = + GetRemoteRouter()->GetIdentHashAbbreviation(); + } + + /// @brief Set current session's endpoint address/port + void SetRemoteEndpoint( + const boost::asio::ip::udp::endpoint& ep) { + m_RemoteEndpoint = ep; + } + + /// @return Log-formatted string of session info + const std::string GetFormattedSessionInfo() { + std::ostringstream info; + info << " [" << GetRemoteIdentHashAbbreviation() << "] " + << GetRemoteEndpoint() << " "; + return info.str(); + } + + /// @return Current session's peer's ident hash + const std::string& GetRemoteIdentHashAbbreviation() { + return m_RemoteIdentHashAbbreviation; + } + + /// @return Current session's endpoint address/port + const boost::asio::ip::udp::endpoint& GetRemoteEndpoint() { + return m_RemoteEndpoint; + } + void FlushData(); private: @@ -241,7 +269,7 @@ class SSUSession const uint8_t* pubKey); void PostI2NPMessages( - std::vector > msgs); + std::vector> msgs); /// @brief Call for established session void ProcessDecryptedMessage( @@ -386,6 +414,7 @@ class SSUSession private: friend class SSUData; // TODO(unassigned): change in later + std::string m_RemoteIdentHashAbbreviation; SSUServer& m_Server; boost::asio::ip::udp::endpoint m_RemoteEndpoint; boost::asio::deadline_timer m_Timer; diff --git a/src/core/transport/TransportSession.h b/src/core/transport/TransportSession.h index 05480c68..f505c917 100644 --- a/src/core/transport/TransportSession.h +++ b/src/core/transport/TransportSession.h @@ -33,10 +33,10 @@ #ifndef SRC_CORE_TRANSPORT_TRANSPORTSESSION_H_ #define SRC_CORE_TRANSPORT_TRANSPORTSESSION_H_ -#include - +#include #include #include +#include #include #include "I2NPProtocol.h" @@ -47,8 +47,8 @@ namespace i2p { namespace transport { struct DHKeysPair { // transient keys for transport sessions - uint8_t publicKey[256]; - uint8_t privateKey[256]; + std::array public_key; + std::array private_key; }; class SignedData { @@ -60,30 +60,30 @@ class SignedData { } void Insert( - const uint8_t* buf, - size_t len) { - m_Stream.write((char *)buf, len); + const std::uint8_t* buf, + std::size_t len) { + m_Stream.write(reinterpret_cast(buf), len); } template void Insert( - T t) { - m_Stream.write((char *)&t, sizeof(T)); + T type) { + m_Stream.write(reinterpret_cast(&type), sizeof(T)); } bool Verify( const i2p::data::IdentityEx& ident, - const uint8_t* signature) const { + const std::uint8_t* signature) const { return ident.Verify( - (const uint8_t *)m_Stream.str().c_str(), + (const std::uint8_t *)m_Stream.str().c_str(), m_Stream.str().size(), signature); } void Sign( const i2p::data::PrivateKeys& keys, - uint8_t* signature) const { + std::uint8_t* signature) const { keys.Sign( - (const uint8_t *)m_Stream.str().c_str(), + (const std::uint8_t *)m_Stream.str().c_str(), m_Stream.str().size(), signature); } @@ -119,11 +119,11 @@ class TransportSession { return m_RemoteIdentity; } - size_t GetNumSentBytes() const { + std::size_t GetNumSentBytes() const { return m_NumSentBytes; } - size_t GetNumReceivedBytes() const { + std::size_t GetNumReceivedBytes() const { return m_NumReceivedBytes; } @@ -138,8 +138,7 @@ class TransportSession { std::shared_ptr m_RemoteRouter; i2p::data::IdentityEx m_RemoteIdentity; DHKeysPair* m_DHKeysPair; // X - for client and Y - for server - size_t m_NumSentBytes, - m_NumReceivedBytes; + std::size_t m_NumSentBytes, m_NumReceivedBytes; bool m_IsOutbound; }; diff --git a/src/core/transport/Transports.cpp b/src/core/transport/Transports.cpp index 00c83102..04a2532b 100644 --- a/src/core/transport/Transports.cpp +++ b/src/core/transport/Transports.cpp @@ -33,6 +33,8 @@ #include "Transports.h" #include +#include +#include #include #include @@ -47,37 +49,40 @@ namespace i2p { namespace transport { DHKeysPairSupplier::DHKeysPairSupplier( - int size) + std::size_t size) : m_QueueSize(size), m_IsRunning(false), m_Thread(nullptr) {} DHKeysPairSupplier::~DHKeysPairSupplier() { + LogPrint(eLogDebug, "DHKeysPairSupplier: destroying"); Stop(); } void DHKeysPairSupplier::Start() { + LogPrint(eLogDebug, "DHKeysPairSupplier: starting"); m_IsRunning = true; m_Thread = - new std::thread( + std::make_unique( std::bind( - &DHKeysPairSupplier::Run, - this)); + &DHKeysPairSupplier::Run, + this)); } void DHKeysPairSupplier::Stop() { + LogPrint(eLogDebug, "DHKeysPairSupplier: stopping"); m_IsRunning = false; m_Acquired.notify_one(); if (m_Thread) { m_Thread->join(); - delete m_Thread; - m_Thread = 0; + m_Thread.reset(nullptr); } } void DHKeysPairSupplier::Run() { + LogPrint(eLogDebug, "DHKeysPairSupplier: running"); while (m_IsRunning) { - int num; + std::size_t num; while ((num = m_QueueSize - m_Queue.size ()) > 0) CreateDHKeysPairs(num); std::unique_lock l(m_AcquiredMutex); @@ -86,14 +91,14 @@ void DHKeysPairSupplier::Run() { } void DHKeysPairSupplier::CreateDHKeysPairs( - int num) { + std::size_t num) { + LogPrint(eLogDebug, "DHKeysPairSupplier: creating"); if (num > 0) { - for (int i = 0; i < num; i++) { - i2p::transport::DHKeysPair* pair = - new i2p::transport::DHKeysPair(); + for (std::size_t i = 0; i < num; i++) { + i2p::transport::DHKeysPair* pair = new i2p::transport::DHKeysPair(); i2p::crypto::DiffieHellman().GenerateKeyPair( - pair->privateKey, - pair->publicKey); + pair->private_key.data(), + pair->public_key.data()); std::unique_lock l(m_AcquiredMutex); m_Queue.push(pair); } @@ -101,6 +106,7 @@ void DHKeysPairSupplier::CreateDHKeysPairs( } DHKeysPair* DHKeysPairSupplier::Acquire() { + LogPrint(eLogDebug, "DHKeysPairSupplier: acquiring"); std::unique_lock l(m_AcquiredMutex); if (!m_Queue.empty()) { auto pair = m_Queue.front(); @@ -109,18 +115,18 @@ DHKeysPair* DHKeysPairSupplier::Acquire() { return pair; } l.unlock(); - // queue is empty, create new key pair DHKeysPair* pair = new DHKeysPair(); i2p::crypto::DiffieHellman().GenerateKeyPair( - pair->privateKey, - pair->publicKey); + pair->private_key.data(), + pair->public_key.data()); return pair; } void DHKeysPairSupplier::Return( DHKeysPair* pair) { - std::unique_lock l(m_AcquiredMutex); + LogPrint(eLogDebug, "DHKeysPairSupplier: returning"); + std::unique_lock l(m_AcquiredMutex); m_Queue.push(pair); } @@ -143,52 +149,57 @@ Transports::Transports() m_LastBandwidthUpdateTime(0) {} Transports::~Transports() { + LogPrint(eLogDebug, "Transports: destroying"); Stop(); } void Transports::Start() { + LogPrint(eLogDebug, "Transports: starting"); #ifdef USE_UPNP m_UPnP.Start(); LogPrint(eLogInfo, "Transports: UPnP started"); #endif m_DHKeysPairSupplier.Start(); m_IsRunning = true; - m_Thread = - new std::thread( - std::bind( - &Transports::Run, - this)); + m_Thread = std::make_unique(std::bind(&Transports::Run, this)); // create acceptors auto addresses = context.GetRouterInfo().GetAddresses(); for (auto& address : addresses) { - if (!m_NTCPServer) { - m_NTCPServer = new NTCPServer(address.port); - m_NTCPServer->Start(); + LogPrint("Transports: creating servers for address ", address.host); + if (address.transportStyle == + i2p::data::RouterInfo::eTransportNTCP && address.host.is_v4()) { + if (!m_NTCPServer) { + LogPrint(eLogInfo, "Transports: TCP listening on port ", address.port); + m_NTCPServer = std::make_unique(address.port); + m_NTCPServer->Start(); + } else { + LogPrint(eLogError, "Transports: TCP server already exists"); + } } if (address.transportStyle == - i2p::data::RouterInfo::eTransportSSU && - address.host.is_v4()) { + i2p::data::RouterInfo::eTransportSSU && address.host.is_v4()) { if (!m_SSUServer) { - m_SSUServer = new SSUServer(address.port); - LogPrint("Transports: UDP listening on port ", address.port); + LogPrint(eLogInfo, "Transports: UDP listening on port ", address.port); + m_SSUServer = std::make_unique(address.port); m_SSUServer->Start(); DetectExternalIP(); } else { - LogPrint("Transports: SSU server already exists"); + LogPrint(eLogError, "Transports: SSU server already exists"); } } } m_PeerCleanupTimer.expires_from_now( boost::posix_time::seconds( - 5 * SESSION_CREATION_TIMEOUT)); + 5 * SESSION_CREATION_TIMEOUT)); // TODO(unassigned): why 5 seconds m_PeerCleanupTimer.async_wait( std::bind( - &Transports::HandlePeerCleanupTimer, - this, - std::placeholders::_1)); + &Transports::HandlePeerCleanupTimer, + this, + std::placeholders::_1)); } void Transports::Stop() { + LogPrint(eLogDebug, "Transports: stopping"); #ifdef USE_UPNP m_UPnP.Stop(); LogPrint(eLogInfo, "Transports: UPnP stopped"); @@ -197,35 +208,34 @@ void Transports::Stop() { m_Peers.clear(); if (m_SSUServer) { m_SSUServer->Stop(); - delete m_SSUServer; - m_SSUServer = nullptr; + m_SSUServer.reset(nullptr); } if (m_NTCPServer) { m_NTCPServer->Stop(); - delete m_NTCPServer; - m_NTCPServer = nullptr; + m_NTCPServer.reset(nullptr); } m_DHKeysPairSupplier.Stop(); m_IsRunning = false; m_Service.stop(); if (m_Thread) { m_Thread->join(); - delete m_Thread; - m_Thread = nullptr; + m_Thread.reset(nullptr); } } void Transports::Run() { + LogPrint(eLogDebug, "Transports: running"); while (m_IsRunning) { try { m_Service.run(); } catch (std::exception& ex) { - LogPrint("Transports::Run(): ", ex.what()); + LogPrint("Transports: Run(): '", ex.what(), "'"); } } } void Transports::UpdateBandwidth() { + LogPrint(eLogDebug, "Transports: updating bandwidth"); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch(); if (m_LastBandwidthUpdateTime > 0) { auto delta = ts - m_LastBandwidthUpdateTime; @@ -242,57 +252,65 @@ void Transports::UpdateBandwidth() { } bool Transports::IsBandwidthExceeded() const { + if (std::max(m_InBandwidth, m_OutBandwidth) > LOW_BANDWIDTH_LIMIT) { + LogPrint(eLogDebug, "Transports: bandwidth has been exceeded"); + return true; + } if (i2p::context.GetRouterInfo().IsHighBandwidth()) - return false; - return std::max(m_InBandwidth, m_OutBandwidth) > LOW_BANDWIDTH_LIMIT; + LogPrint(eLogDebug, "Transports: bandwidth has not been exceeded"); + return false; } void Transports::SendMessage( const i2p::data::IdentHash& ident, std::shared_ptr msg) { - SendMessages(ident, std::vector > {msg}); + LogPrint(eLogDebug, "Transports: sending messages"); + SendMessages( + ident, + std::vector> {msg}); } void Transports::SendMessages( const i2p::data::IdentHash& ident, - const std::vector >& msgs) { + const std::vector>& msgs) { m_Service.post( std::bind( - &Transports::PostMessages, - this, - ident, - msgs)); + &Transports::PostMessages, + this, + ident, + msgs)); } void Transports::PostMessages( i2p::data::IdentHash ident, - std::vector > msgs) { + std::vector> msgs) { + LogPrint(eLogDebug, "Transports: posting messages"); if (ident == i2p::context.GetRouterInfo().GetIdentHash()) { // we send it to ourself - for (auto it : msgs) - i2p::HandleI2NPMessage(it); + for (auto msg : msgs) + i2p::HandleI2NPMessage(msg); return; } auto it = m_Peers.find(ident); if (it == m_Peers.end()) { bool connected = false; try { - auto r = i2p::data::netdb.FindRouter(ident); + auto router = i2p::data::netdb.FindRouter(ident); it = m_Peers.insert( std::make_pair( - ident, - Peer{ 0, r, {}, i2p::util::GetSecondsSinceEpoch(), {} })).first; + ident, + Peer{ 0, router, {}, i2p::util::GetSecondsSinceEpoch(), {} })).first; connected = ConnectToPeer(ident, it->second); } catch (std::exception& ex) { - LogPrint(eLogError, "Transports::PostMessages() ", ex.what()); + LogPrint(eLogError, "Transports: PostMessages(): '", ex.what(), "'"); } if (!connected) return; } if (!it->second.sessions.empty()) { it->second.sessions.front()->SendI2NPMessages(msgs); } else { - for (auto it1 : msgs) - it->second.delayedMessages.push_back(it1); + for (auto msg : msgs) + it->second.delayed_messages.push_back(msg); } } @@ -301,9 +319,15 @@ bool Transports::ConnectToPeer( Peer& peer) { // we have RI already if (peer.router) { + LogPrint(eLogDebug, + "Transports: connecting to peer", + GetFormattedSessionInfo(peer.router)); // NTCP - if (!peer.numAttempts) { - peer.numAttempts++; + if (!peer.num_attempts) { + LogPrint(eLogDebug, + "Transports: attempting NTCP for peer", + GetFormattedSessionInfo(peer.router)); + peer.num_attempts++; auto address = peer.router->GetNTCPAddress(!context.SupportsV6()); if (address) { #if BOOST_VERSION >= 104900 @@ -315,61 +339,69 @@ bool Transports::ConnectToPeer( #endif { if (!peer.router->UsesIntroducer() && !peer.router->IsUnreachable()) { - auto s = std::make_shared (*m_NTCPServer, peer.router); + auto s = std::make_shared(*m_NTCPServer, peer.router); m_NTCPServer->Connect(address->host, address->port, s); return true; } } else { // we don't have address if (address->addressString.length() > 0) { // trying to resolve - LogPrint(eLogInfo, "Transports: resolving ", address->addressString); + LogPrint(eLogInfo, + "Transports: NTCP resolving ", address->addressString); NTCPResolve(address->addressString, ident); return true; } } } - } else if (peer.numAttempts == 1) { // SSU - peer.numAttempts++; + } else if (peer.num_attempts == 1) { // SSU + LogPrint(eLogDebug, + "Transports: attempting SSU for peer", + GetFormattedSessionInfo(peer.router)); + peer.num_attempts++; if (m_SSUServer) { if (m_SSUServer->GetSession(peer.router)) return true; } } - LogPrint(eLogError, "Transports: no NTCP or SSU addresses available"); + LogPrint(eLogError, + "Transports:", GetFormattedSessionInfo(peer.router), + "no NTCP/SSU address available"); peer.Done(); m_Peers.erase(ident); return false; } else { // otherwise request RI - LogPrint("Transports: router not found, requesting"); + LogPrint(eLogDebug, "Transports: RI not found, requesting"); i2p::data::netdb.RequestDestination( ident, std::bind( - &Transports::RequestComplete, - this, - std::placeholders::_1, - ident)); + &Transports::RequestComplete, + this, + std::placeholders::_1, + ident)); } return true; } void Transports::RequestComplete( - std::shared_ptr r, + std::shared_ptr router, const i2p::data::IdentHash& ident) { m_Service.post( std::bind( - &Transports::HandleRequestComplete, - this, - r, - ident)); + &Transports::HandleRequestComplete, + this, + router, + ident)); } void Transports::HandleRequestComplete( - std::shared_ptr r, + std::shared_ptr router, const i2p::data::IdentHash& ident) { auto it = m_Peers.find(ident); if (it != m_Peers.end()) { - if (r) { - LogPrint("Transports: router found, trying to connect"); - it->second.router = r; + if (router) { + LogPrint(eLogInfo, + "Transports: router ", router->GetIdentHashAbbreviation(), + " found, trying to connect"); + it->second.router = router; ConnectToPeer(ident, it->second); } else { LogPrint("Transports: router not found, failed to send messages"); @@ -385,15 +417,15 @@ void Transports::NTCPResolve( std::make_shared(m_Service); resolver->async_resolve( boost::asio::ip::tcp::resolver::query( - addr, - ""), + addr, + ""), std::bind( - &Transports::HandleNTCPResolve, - this, - std::placeholders::_1, - std::placeholders::_2, - ident, - resolver)); + &Transports::HandleNTCPResolve, + this, + std::placeholders::_1, + std::placeholders::_2, + ident, + resolver)); } void Transports::HandleNTCPResolve( @@ -411,7 +443,7 @@ void Transports::HandleNTCPResolve( " has been resolved to ", address); auto addr = peer.router->GetNTCPAddress(); if (addr) { - auto s = std::make_shared (*m_NTCPServer, peer.router); + auto s = std::make_shared(*m_NTCPServer, peer.router); m_NTCPServer->Connect(address, addr->port, s); return; } @@ -426,11 +458,14 @@ void Transports::CloseSession( std::shared_ptr router) { if (!router) return; + LogPrint(eLogDebug, + "Transports: closing session for [", + router->GetIdentHashAbbreviation(), "]"); m_Service.post( std::bind( - &Transports::PostCloseSession, - this, - router)); + &Transports::PostCloseSession, + this, + router)); } void Transports::PostCloseSession( @@ -440,12 +475,15 @@ void Transports::PostCloseSession( // try SSU first if (ssuSession) { m_SSUServer->DeleteSession(ssuSession); - LogPrint("Transports: SSU session closed"); + LogPrint(eLogInfo, + "Transports: SSU session [", + router->GetIdentHashAbbreviation(), "] closed"); } // TODO(unassigned): delete NTCP } void Transports::DetectExternalIP() { + LogPrint(eLogDebug, "Transports: detecting external IP"); if (m_SSUServer) { i2p::context.SetStatus(eRouterStatusTesting); for (int i = 0; i < 5; i++) { @@ -466,41 +504,47 @@ void Transports::DetectExternalIP() { } DHKeysPair* Transports::GetNextDHKeysPair() { + LogPrint(eLogDebug, "Transports: getting next DH keys pair"); return m_DHKeysPairSupplier.Acquire(); } void Transports::ReuseDHKeysPair(DHKeysPair* pair) { + LogPrint(eLogDebug, "Transports: reusing DH keys pair"); m_DHKeysPairSupplier.Return(pair); } void Transports::PeerConnected( std::shared_ptr session) { + auto router = session->GetRemoteRouter(); + LogPrint(eLogDebug, + "Transports:", GetFormattedSessionInfo(router), "connecting"); m_Service.post([session, this]() { auto ident = session->GetRemoteIdentity().GetIdentHash(); auto it = m_Peers.find(ident); if (it != m_Peers.end()) { it->second.sessions.push_back(session); - session->SendI2NPMessages(it->second.delayedMessages); - it->second.delayedMessages.clear(); + session->SendI2NPMessages(it->second.delayed_messages); + it->second.delayed_messages.clear(); } else { // incoming connection m_Peers.insert( std::make_pair( - ident, - Peer{ 0, nullptr, { session }, - i2p::util::GetSecondsSinceEpoch(), {} })); + ident, + Peer{ 0, nullptr, { session }, + i2p::util::GetSecondsSinceEpoch(), {} })); } }); } void Transports::PeerDisconnected( std::shared_ptr session) { + LogPrint(eLogDebug, "Transports: disconnecting peer"); m_Service.post([session, this]() { auto ident = session->GetRemoteIdentity().GetIdentHash(); auto it = m_Peers.find(ident); if (it != m_Peers.end()) { it->second.sessions.remove(session); if (it->second.sessions.empty()) { // TODO(unassigned): why? - if (it->second.delayedMessages.size() > 0) + if (it->second.delayed_messages.size() > 0) ConnectToPeer(ident, it->second); else m_Peers.erase(it); @@ -511,41 +555,50 @@ void Transports::PeerDisconnected( bool Transports::IsConnected( const i2p::data::IdentHash& ident) const { + LogPrint(eLogDebug, "Transports: testing if connected"); auto it = m_Peers.find(ident); - return it != m_Peers.end(); + if (it != m_Peers.end()) { + LogPrint(eLogDebug, "Transports: we are connected"); + return true; + } + LogPrint(eLogDebug, "Transports: we are not connected"); + return false; } void Transports::HandlePeerCleanupTimer( const boost::system::error_code& ecode) { + LogPrint(eLogDebug, "Transports: handling peer cleanup timer"); if (ecode != boost::asio::error::operation_aborted) { auto ts = i2p::util::GetSecondsSinceEpoch(); for (auto it = m_Peers.begin(); it != m_Peers.end();) { - if (it->second.sessions.empty () && - ts > it->second.creationTime + SESSION_CREATION_TIMEOUT) { + if (it->second.sessions.empty() && + ts > it->second.creation_time + SESSION_CREATION_TIMEOUT) { LogPrint(eLogError, - "Transports: session to peer ", it->first.ToBase64(), - " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds"); + "Transports: session to peer", + GetFormattedSessionInfo(it->second.router), + "has not been created in ", SESSION_CREATION_TIMEOUT, " seconds"); it = m_Peers.erase(it); } else { it++; } } UpdateBandwidth(); // TODO(unassigned): use separate timer(s) for it - // if still testing, repeat peer test + // if still testing, repeat peer test if (i2p::context.GetStatus() == eRouterStatusTesting) DetectExternalIP(); m_PeerCleanupTimer.expires_from_now( boost::posix_time::seconds( - 5 * SESSION_CREATION_TIMEOUT)); + 5 * SESSION_CREATION_TIMEOUT)); m_PeerCleanupTimer.async_wait( std::bind( - &Transports::HandlePeerCleanupTimer, - this, - std::placeholders::_1)); + &Transports::HandlePeerCleanupTimer, + this, + std::placeholders::_1)); } } std::shared_ptr Transports::GetRandomPeer() const { + LogPrint(eLogDebug, "Transports: getting random peer"); if (m_Peers.empty()) // ensure m.Peers.size() >= 1 return nullptr; size_t s = m_Peers.size(); @@ -553,7 +606,6 @@ std::shared_ptr Transports::GetRandomPeer() const { std::advance( it, i2p::crypto::RandInRange(0, s - 1)); - return it->second.router; } diff --git a/src/core/transport/Transports.h b/src/core/transport/Transports.h index 54087e08..0c36c313 100644 --- a/src/core/transport/Transports.h +++ b/src/core/transport/Transports.h @@ -37,15 +37,17 @@ #include #include +#include #include +#include #include #include #include +#include #include #include #include #include -#include #include "I2NPProtocol.h" #include "Identity.h" @@ -65,7 +67,8 @@ namespace transport { class DHKeysPairSupplier { public: DHKeysPairSupplier( - int size); + std::size_t size); + ~DHKeysPairSupplier(); void Start(); @@ -81,31 +84,31 @@ class DHKeysPairSupplier { void Run(); void CreateDHKeysPairs( - int num); + std::size_t num); private: const int m_QueueSize; - std::queue m_Queue; bool m_IsRunning; - std::thread* m_Thread; + std::queue m_Queue; + std::unique_ptr m_Thread; std::condition_variable m_Acquired; std::mutex m_AcquiredMutex; }; struct Peer { - int numAttempts; + std::size_t num_attempts; std::shared_ptr router; - std::list > sessions; - uint64_t creationTime; - std::vector > delayedMessages; + std::list> sessions; + std::uint64_t creation_time; + std::vector> delayed_messages; void Done() { for (auto it : sessions) it->Done(); } }; -const size_t SESSION_CREATION_TIMEOUT = 10; // in seconds -const uint32_t LOW_BANDWIDTH_LIMIT = 32*1024; // 32KBs +const std::size_t SESSION_CREATION_TIMEOUT = 10; // in seconds +const std::uint32_t LOW_BANDWIDTH_LIMIT = 32 * 1024; // 32KBs class Transports { public: @@ -131,7 +134,7 @@ class Transports { void SendMessages( const i2p::data::IdentHash& ident, - const std::vector >& msgs); + const std::vector>& msgs); void CloseSession( std::shared_ptr router); @@ -146,55 +149,65 @@ class Transports { const i2p::data::IdentHash& ident) const; void UpdateSentBytes( - uint64_t numBytes) { + std::uint64_t numBytes) { m_TotalSentBytes += numBytes; } void UpdateReceivedBytes( - uint64_t numBytes) { + std::uint64_t numBytes) { m_TotalReceivedBytes += numBytes; } - uint64_t GetTotalSentBytes() const { + std::uint64_t GetTotalSentBytes() const { return m_TotalSentBytes; } - uint64_t GetTotalReceivedBytes() const { + std::uint64_t GetTotalReceivedBytes() const { return m_TotalReceivedBytes; } // bytes per second - uint32_t GetInBandwidth() const { + std::uint32_t GetInBandwidth() const { return m_InBandwidth; } // bytes per second - uint32_t GetOutBandwidth() const { + std::uint32_t GetOutBandwidth() const { return m_OutBandwidth; } bool IsBandwidthExceeded() const; - size_t GetNumPeers() const { + std::size_t GetNumPeers() const { return m_Peers.size(); } std::shared_ptr GetRandomPeer() const; + const std::string GetFormattedSessionInfo( + std::shared_ptr& router) { + if (router) { + std::ostringstream info; + info << " [" << router->GetIdentHashAbbreviation() << "] "; + return info.str(); + } + return "[hash unavailable]"; + } + private: void Run(); void RequestComplete( - std::shared_ptr r, + std::shared_ptr router, const i2p::data::IdentHash& ident); void HandleRequestComplete( - std::shared_ptr r, + std::shared_ptr router, const i2p::data::IdentHash& ident); void PostMessages( i2p::data::IdentHash ident, - std::vector > msgs); + std::vector> msgs); void PostCloseSession( std::shared_ptr router); @@ -221,39 +234,30 @@ class Transports { private: bool m_IsRunning; - std::thread * m_Thread; + + std::unique_ptr m_Thread; boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; boost::asio::deadline_timer m_PeerCleanupTimer; - NTCPServer* m_NTCPServer; - SSUServer* m_SSUServer; + std::unique_ptr m_NTCPServer; + std::unique_ptr m_SSUServer; + std::map m_Peers; DHKeysPairSupplier m_DHKeysPairSupplier; - std::atomic m_TotalSentBytes, - m_TotalReceivedBytes; - uint32_t m_InBandwidth, - m_OutBandwidth; + std::atomic m_TotalSentBytes, m_TotalReceivedBytes; - uint64_t m_LastInBandwidthUpdateBytes, - m_LastOutBandwidthUpdateBytes; - - uint64_t m_LastBandwidthUpdateTime; + std::uint32_t m_InBandwidth, m_OutBandwidth; + std::uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes; + std::uint64_t m_LastBandwidthUpdateTime; #ifdef USE_UPNP UPnP m_UPnP; #endif public: - // for HTTP only - const NTCPServer* GetNTCPServer() const { - return m_NTCPServer; - } - const SSUServer* GetSSUServer() const { - return m_SSUServer; - } const decltype(m_Peers)& GetPeers() const { return m_Peers; } diff --git a/src/core/transport/UPnP.cpp b/src/core/transport/UPnP.cpp index 842f85fb..ea7e2160 100644 --- a/src/core/transport/UPnP.cpp +++ b/src/core/transport/UPnP.cpp @@ -144,8 +144,7 @@ UPnP::UPnP() void UPnP::Stop() { if (m_Thread) { m_Thread->join(); - delete m_Thread; - m_Thread = nullptr; + m_Thread.reset(nullptr); } } @@ -197,10 +196,10 @@ void UPnP::Start() { } } m_Thread = - new std::thread( + std::make_unique( std::bind( - &UPnP::Run, - this)); + &UPnP::Run, + this)); } UPnP::~UPnP() {} diff --git a/src/core/transport/UPnP.h b/src/core/transport/UPnP.h index d11bb010..c6739bfa 100644 --- a/src/core/transport/UPnP.h +++ b/src/core/transport/UPnP.h @@ -42,6 +42,7 @@ #include #include +#include #include #include @@ -75,7 +76,7 @@ class UPnP { private: void Run(); - std::thread* m_Thread; + std::unique_ptr m_Thread; struct UPNPUrls m_upnpUrls; struct IGDdatas m_upnpData;