initial ntcp soft/hard limits

This commit is contained in:
Jeff Becker 2017-10-30 08:27:55 -04:00
parent bc11181d5e
commit 6441c9d5d8
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05
4 changed files with 59 additions and 14 deletions

View File

@ -71,6 +71,8 @@ namespace config {
("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)") ("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)")
("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)") ("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)")
("limits.transittunnels", value<uint16_t>()->default_value(2500), "Maximum active transit sessions (default:2500)") ("limits.transittunnels", value<uint16_t>()->default_value(2500), "Maximum active transit sessions (default:2500)")
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Threshold to start probabalistic backoff with ntcp sessions (default: use system limit)")
("limits.ntcphard", value<uint16_t>()->default_value(0), "Maximum number of ntcp sessions (default: use system limit)")
; ;
options_description httpserver("HTTP Server options"); options_description httpserver("HTTP Server options");

View File

@ -791,7 +791,8 @@ namespace transport
NTCPServer::NTCPServer (): NTCPServer::NTCPServer ():
m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service),
m_TerminationTimer (m_Service), m_NTCPAcceptor (nullptr), m_NTCPV6Acceptor (nullptr), m_TerminationTimer (m_Service), m_NTCPAcceptor (nullptr), m_NTCPV6Acceptor (nullptr),
m_ProxyType(eNoProxy), m_Resolver(m_Service), m_ProxyEndpoint(nullptr) m_ProxyType(eNoProxy), m_Resolver(m_Service), m_ProxyEndpoint(nullptr),
m_SoftLimit(0), m_HardLimit(0)
{ {
} }
@ -965,6 +966,13 @@ namespace transport
auto ep = conn->GetSocket ().remote_endpoint(ec); auto ep = conn->GetSocket ().remote_endpoint(ec);
if (!ec) if (!ec)
{ {
if(ShouldLimit())
{
// hit limit, close premature
LogPrint(eLogWarning, "NTCP: limiting with backoff session from ", ep);
conn->GetSocket().close();
return;
}
LogPrint (eLogDebug, "NTCP: Connected from ", ep); LogPrint (eLogDebug, "NTCP: Connected from ", ep);
if (conn) if (conn)
{ {
@ -993,6 +1001,14 @@ namespace transport
auto ep = conn->GetSocket ().remote_endpoint(ec); auto ep = conn->GetSocket ().remote_endpoint(ec);
if (!ec) if (!ec)
{ {
if(ShouldLimit())
{
// hit limit, close premature
LogPrint(eLogWarning, "NTCP: limiting with backoff on session from ", ep);
conn->GetSocket().close();
return;
}
LogPrint (eLogDebug, "NTCP: Connected from ", ep); LogPrint (eLogDebug, "NTCP: Connected from ", ep);
if (conn) if (conn)
{ {

View File

@ -167,8 +167,19 @@ namespace transport
boost::asio::io_service& GetService () { return m_Service; }; boost::asio::io_service& GetService () { return m_Service; };
void SetSessionLimits(uint16_t softLimit, uint16_t hardLimit) { m_SoftLimit = softLimit; m_HardLimit = hardLimit; }
bool ShouldLimit() const { return ShouldHardLimit() || ShouldSoftLimit(); }
private: private:
/** @brief return true for hard limit */
bool ShouldHardLimit() const { return m_HardLimit && m_NTCPSessions.size() >= m_HardLimit; }
/** @brief return true for probabalistic soft backoff */
bool ShouldSoftLimit() const
{
auto sessions = m_NTCPSessions.size();
return sessions && m_SoftLimit && m_SoftLimit < sessions && ( rand() % sessions ) <= m_SoftLimit;
}
void Run (); void Run ();
void HandleAccept (std::shared_ptr<NTCPSession> conn, const boost::system::error_code& error); void HandleAccept (std::shared_ptr<NTCPSession> conn, const boost::system::error_code& error);
void HandleAcceptV6 (std::shared_ptr<NTCPSession> conn, const boost::system::error_code& error); void HandleAcceptV6 (std::shared_ptr<NTCPSession> conn, const boost::system::error_code& error);
@ -198,6 +209,8 @@ namespace transport
uint16_t m_ProxyPort; uint16_t m_ProxyPort;
boost::asio::ip::tcp::resolver m_Resolver; boost::asio::ip::tcp::resolver m_Resolver;
boost::asio::ip::tcp::endpoint * m_ProxyEndpoint; boost::asio::ip::tcp::endpoint * m_ProxyEndpoint;
uint16_t m_SoftLimit, m_HardLimit;
public: public:
// for HTTP/I2PControl // for HTTP/I2PControl

View File

@ -147,13 +147,20 @@ namespace transport
m_PeerTestTimer = new boost::asio::deadline_timer (*m_Service); m_PeerTestTimer = new boost::asio::deadline_timer (*m_Service);
} }
i2p::config::GetOption("nat", m_IsNAT); i2p::config::GetOption("nat", m_IsNAT);
m_DHKeysPairSupplier.Start (); m_DHKeysPairSupplier.Start ();
m_IsRunning = true; m_IsRunning = true;
m_Thread = new std::thread (std::bind (&Transports::Run, this)); m_Thread = new std::thread (std::bind (&Transports::Run, this));
std::string ntcpproxy; i2p::config::GetOption("ntcpproxy", ntcpproxy); std::string ntcpproxy; i2p::config::GetOption("ntcpproxy", ntcpproxy);
i2p::http::URL proxyurl; i2p::http::URL proxyurl;
uint16_t softLimit, hardLimit;
i2p::config::GetOption("limits.ntcpsoft", softLimit);
i2p::config::GetOption("limits.ntcphard", hardLimit);
if(softLimit >= hardLimit)
{
LogPrint(eLogError, "ntcp soft limit must be less than ntcp hard limit");
return;
}
if(ntcpproxy.size() && enableNTCP) if(ntcpproxy.size() && enableNTCP)
{ {
if(proxyurl.parse(ntcpproxy)) if(proxyurl.parse(ntcpproxy))
@ -161,12 +168,11 @@ namespace transport
if(proxyurl.schema == "socks" || proxyurl.schema == "http") if(proxyurl.schema == "socks" || proxyurl.schema == "http")
{ {
m_NTCPServer = new NTCPServer(); m_NTCPServer = new NTCPServer();
m_NTCPServer->SetSessionLimits(softLimit, hardLimit);
NTCPServer::ProxyType proxytype = NTCPServer::eSocksProxy; NTCPServer::ProxyType proxytype = NTCPServer::eSocksProxy;
if (proxyurl.schema == "http") if (proxyurl.schema == "http")
proxytype = NTCPServer::eHTTPProxy; proxytype = NTCPServer::eHTTPProxy;
m_NTCPServer->UseProxy(proxytype, proxyurl.host, proxyurl.port) ; m_NTCPServer->UseProxy(proxytype, proxyurl.host, proxyurl.port) ;
m_NTCPServer->Start(); m_NTCPServer->Start();
if(!m_NTCPServer->NetworkIsReady()) if(!m_NTCPServer->NetworkIsReady())
@ -193,6 +199,7 @@ namespace transport
if (m_NTCPServer == nullptr && enableNTCP) if (m_NTCPServer == nullptr && enableNTCP)
{ {
m_NTCPServer = new NTCPServer (); m_NTCPServer = new NTCPServer ();
m_NTCPServer->SetSessionLimits(softLimit, hardLimit);
m_NTCPServer->Start (); m_NTCPServer->Start ();
if (!(m_NTCPServer->IsBoundV6() || m_NTCPServer->IsBoundV4())) { if (!(m_NTCPServer->IsBoundV6() || m_NTCPServer->IsBoundV4())) {
/** failed to bind to NTCP */ /** failed to bind to NTCP */
@ -394,20 +401,27 @@ namespace transport
{ {
if (!peer.router->UsesIntroducer () && !peer.router->IsUnreachable ()) if (!peer.router->UsesIntroducer () && !peer.router->IsUnreachable ())
{ {
auto s = std::make_shared<NTCPSession> (*m_NTCPServer, peer.router); if(!m_NTCPServer->ShouldLimit())
if(m_NTCPServer->UsingProxy())
{ {
NTCPServer::RemoteAddressType remote = NTCPServer::eIP4Address; auto s = std::make_shared<NTCPSession> (*m_NTCPServer, peer.router);
std::string addr = address->host.to_string(); if(m_NTCPServer->UsingProxy())
{
NTCPServer::RemoteAddressType remote = NTCPServer::eIP4Address;
std::string addr = address->host.to_string();
if(address->host.is_v6()) if(address->host.is_v6())
remote = NTCPServer::eIP6Address; remote = NTCPServer::eIP6Address;
m_NTCPServer->ConnectWithProxy(addr, address->port, remote, s); m_NTCPServer->ConnectWithProxy(addr, address->port, remote, s);
}
else
m_NTCPServer->Connect (address->host, address->port, s);
return true;
} }
else else
m_NTCPServer->Connect (address->host, address->port, s); {
return true; LogPrint(eLogWarning, "Transports: NTCP Limit hit falling back to SSU");
}
} }
} }
else // we don't have address else // we don't have address