diff --git a/ClientContext.cpp b/ClientContext.cpp index 3c4d63c0..6ef7ec60 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -276,6 +276,22 @@ namespace client return success; } + std::vector ClientContext::GetForwardInfosFor(const i2p::data::IdentHash & destination) + { + std::lock_guard lock(m_ForwardsMutex); + for(auto & c : m_ClientForwards) + { + if (c.second->IsLocalDestination(destination)) + return c.second->GetSessions(); + } + for(auto & s : m_ServerForwards) + { + if(std::get<0>(s.first) == destination) + return s.second->GetSessions(); + } + return {}; + } + std::shared_ptr ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType, const std::map * params) { diff --git a/ClientContext.h b/ClientContext.h index 87dbec0f..7faf04ca 100644 --- a/ClientContext.h +++ b/ClientContext.h @@ -66,7 +66,9 @@ namespace client AddressBook& GetAddressBook () { return m_AddressBook; }; const SAMBridge * GetSAMBridge () const { return m_SamBridge; }; - + + std::vector GetForwardInfosFor(const i2p::data::IdentHash & destination); + private: void ReadTunnels (); diff --git a/Datagram.cpp b/Datagram.cpp index 37559922..42354945 100644 --- a/Datagram.cpp +++ b/Datagram.cpp @@ -165,6 +165,16 @@ namespace datagram return session; } + std::shared_ptr DatagramDestination::GetInfoForRemote(const i2p::data::IdentHash & remote) + { + std::lock_guard lock(m_SessionsMutex); + for ( auto & item : m_Sessions) + { + if(item.first == remote) return std::make_shared(item.second->GetSessionInfo()); + } + return nullptr; + } + DatagramSession::DatagramSession(i2p::client::ClientDestination * localDestination, const i2p::data::IdentHash & remoteIdent) : m_LocalDestination(localDestination), @@ -183,6 +193,29 @@ namespace datagram m_LocalDestination->GetService().post(std::bind(&DatagramSession::HandleSend, this, msg)); } + DatagramSession::Info DatagramSession::GetSessionInfo() const + { + if(!m_RoutingSession) + return DatagramSession::Info{nullptr, nullptr, m_LastUse, m_LastSuccess}; + + auto routingPath = m_RoutingSession->GetSharedRoutingPath(); + if (!routingPath) + return DatagramSession::Info{nullptr, nullptr, m_LastUse, m_LastSuccess}; + auto lease = routingPath->remoteLease; + auto tunnel = routingPath->outboundTunnel; + if(lease) + { + if(tunnel) + return DatagramSession::Info{new i2p::data::IdentHash(lease->tunnelGateway), new i2p::data::IdentHash(tunnel->GetEndpointIdentHash()), m_LastUse, m_LastSuccess}; + else + return DatagramSession::Info{new i2p::data::IdentHash(lease->tunnelGateway), nullptr, m_LastUse, m_LastSuccess}; + } + else if(tunnel) + return DatagramSession::Info{nullptr, new i2p::data::IdentHash(tunnel->GetEndpointIdentHash()), m_LastUse, m_LastSuccess}; + else + return DatagramSession::Info{nullptr, nullptr, m_LastUse, m_LastSuccess}; + } + void DatagramSession::HandleSend(std::shared_ptr msg) { // do we have a routing session? diff --git a/Datagram.h b/Datagram.h index fd1f290d..a44133f7 100644 --- a/Datagram.h +++ b/Datagram.h @@ -44,6 +44,24 @@ namespace datagram void SendMsg(std::shared_ptr msg); /** get the last time in milliseconds for when we used this datagram session */ uint64_t LastActivity() const { return m_LastUse; } + /** get the last time in milliseconds when we successfully sent data */ + uint64_t LastSuccess() const { return m_LastSuccess; } + struct Info + { + const i2p::data::IdentHash * IBGW; + const i2p::data::IdentHash * OBEP; + const uint64_t activity; + const uint64_t success; + ~Info() + { + if(IBGW) delete IBGW; + if(OBEP) delete OBEP; + } + }; + + Info GetSessionInfo() const; + + private: /** update our routing path we are using, mark that we have changed paths */ @@ -90,6 +108,7 @@ namespace datagram public: + DatagramDestination (std::shared_ptr owner); ~DatagramDestination (); @@ -101,6 +120,8 @@ namespace datagram void SetReceiver (const Receiver& receiver, uint16_t port) { std::lock_guard lock(m_ReceiversMutex); m_ReceiversByPorts[port] = receiver; }; void ResetReceiver (uint16_t port) { std::lock_guard lock(m_ReceiversMutex); m_ReceiversByPorts.erase (port); }; + + std::shared_ptr GetInfoForRemote(const i2p::data::IdentHash & remote); private: // clean up after next tick diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 309e3f6b..56756277 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -337,7 +337,38 @@ namespace http { s << "" << it->GetWindowSize () << ""; s << "" << (int)it->GetStatus () << ""; s << "
\r\n" << std::endl; + } + s << "
\r\n"; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + s << ""; + auto forward = i2p::client::context.GetForwardInfosFor(dest->GetIdentHash()); + for (auto & info : forward) + { + s << ""; + s << ""; + s << ""; + + s << ""; + s << ""; + auto sec = std::chrono::duration >( std::chrono::milliseconds(info.idle) ); + s << ""; + s << "
\r\n"; } + s << "
Forwards
Remote DestinationIBGWOBEPUDP ConverstationIdle Time
" << info.RemoteIdent.ToBase32() << ""; + if(info.CurrentIBGW) + s << info.CurrentIBGW->ToBase64(); + else + s << "(none)"; + s << ""; + if(info.CurrentOBEP) + s << info.CurrentOBEP->ToBase64(); + else + s << "(none)"; + s << "" << info.LocalEndpoint << " ⇄ " << info.RemoteEndpoint << "" << sec.count() << " seconds
\r\n"; } } diff --git a/I2PTunnel.cpp b/I2PTunnel.cpp index 087221a3..386c0cd2 100644 --- a/I2PTunnel.cpp +++ b/I2PTunnel.cpp @@ -631,6 +631,30 @@ namespace client void I2PUDPServerTunnel::Start() { m_LocalDest->Start(); } + + std::vector I2PUDPServerTunnel::GetSessions() + { + std::vector sessions; + auto localident = m_LocalDest->GetIdentHash(); + std::lock_guard lock(m_SessionsMutex); + for ( UDPSession * s : m_Sessions ) + { + if (!s->m_Destination) continue; + auto info = s->m_Destination->GetInfoForRemote(s->Identity); + if(!info) continue; + sessions.push_back(DatagramSessionInfo{ + m_Name, + localident, + s->Identity, + info->IBGW, + info->OBEP, + s->IPSocket.local_endpoint(), + s->SendEndpoint, + info->success + }); + } + return sessions; + } I2PUDPClientTunnel::I2PUDPClientTunnel(const std::string & name, const std::string &remoteDest, boost::asio::ip::udp::endpoint localEndpoint, @@ -662,6 +686,34 @@ namespace client m_ResolveThread = new std::thread(std::bind(&I2PUDPClientTunnel::TryResolving, this)); } + std::vector I2PUDPClientTunnel::GetSessions() + { + std::vector infos; + if(m_Session && m_LocalDest) + { + auto localident = m_LocalDest->GetIdentHash(); + auto s = m_Session; + if (s->m_Destination) + { + auto info = m_Session->m_Destination->GetInfoForRemote(s->Identity); + if(!info) + { + infos.push_back(DatagramSessionInfo{ + m_Name, + localident, + s->Identity, + info->IBGW, + info->OBEP, + s->IPSocket.local_endpoint(), + s->SendEndpoint, + info->success + }); + } + } + } + return infos; + } + void I2PUDPClientTunnel::TryResolving() { LogPrint(eLogInfo, "UDP Tunnel: Trying to resolve ", m_RemoteDest); m_RemoteIdent = new i2p::data::IdentHash; diff --git a/I2PTunnel.h b/I2PTunnel.h index 76bfc36b..7fe58574 100644 --- a/I2PTunnel.h +++ b/I2PTunnel.h @@ -137,7 +137,28 @@ namespace client /** max size for i2p udp */ const size_t I2P_UDP_MAX_MTU = i2p::datagram::MAX_DATAGRAM_SIZE; - + + /** read only info about a datagram session */ + struct DatagramSessionInfo + { + /** the name of this forward */ + const std::string Name; + /** ident hash of local destination */ + const i2p::data::IdentHash LocalIdent; + /** ident hash of remote destination */ + const i2p::data::IdentHash RemoteIdent; + /** ident hash of IBGW in use currently in this session or nullptr if none is set */ + const i2p::data::IdentHash * CurrentIBGW; + /** ident hash of OBEP in use for this session or nullptr if none is set */ + const i2p::data::IdentHash * CurrentOBEP; + /** i2p router's udp endpoint */ + const boost::asio::ip::udp::endpoint LocalEndpoint; + /** client's udp endpoint */ + const boost::asio::ip::udp::endpoint RemoteEndpoint; + /** how long has this converstation been idle in ms */ + const uint64_t idle; + }; + struct UDPSession { i2p::datagram::DatagramDestination * m_Destination; @@ -174,6 +195,7 @@ namespace client void ExpireStale(const uint64_t delta=I2P_UDP_SESSION_TIMEOUT); void Start(); const char * GetName() const { return m_Name.c_str(); } + std::vector GetSessions(); private: void HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); UDPSession * ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort); @@ -196,7 +218,8 @@ namespace client ~I2PUDPClientTunnel(); void Start(); const char * GetName() const { return m_Name.c_str(); } - + std::vector GetSessions(); + bool IsLocalDestination(const i2p::data::IdentHash & destination) const { return destination == m_LocalDest->GetIdentHash(); } private: void HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void TryResolving();