diff --git a/.travis.yml b/.travis.yml index ff2d4958..c791187d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ cache: apt: true os: - linux + - osx sudo: required dist: trusty addons: @@ -23,6 +24,11 @@ addons: - libssl-dev compiler: - gcc + - clang +before_install: + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install openssl miniupnpc ; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew unlink boost openssl && brew link boost openssl -f ; fi env: matrix: - BUILD_TYPE=Release UPNP=ON diff --git a/ClientContext.cpp b/ClientContext.cpp index ccb8e0ad..59f11f21 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -52,8 +52,12 @@ namespace client LoadPrivateKeys (keys, httpProxyKeys); localDestination = CreateNewLocalDestination (keys, false); } - m_HttpProxy = new i2p::proxy::HTTPProxy(httpProxyAddr, httpProxyPort, localDestination); - m_HttpProxy->Start(); + try { + m_HttpProxy = new i2p::proxy::HTTPProxy(httpProxyAddr, httpProxyPort, localDestination); + m_HttpProxy->Start(); + } catch (std::exception& e) { + LogPrint(eLogError, "Clients: Exception in HTTP Proxy: ", e.what()); + } } bool socksproxy; i2p::config::GetOption("socksproxy.enabled", socksproxy); @@ -70,8 +74,12 @@ namespace client LoadPrivateKeys (keys, socksProxyKeys); localDestination = CreateNewLocalDestination (keys, false); } - m_SocksProxy = new i2p::proxy::SOCKSProxy(socksProxyAddr, socksProxyPort, socksOutProxyAddr, socksOutProxyPort, localDestination); - m_SocksProxy->Start(); + try { + m_SocksProxy = new i2p::proxy::SOCKSProxy(socksProxyAddr, socksProxyPort, socksOutProxyAddr, socksOutProxyPort, localDestination); + m_SocksProxy->Start(); + } catch (std::exception& e) { + LogPrint(eLogError, "Clients: Exception in SOCKS Proxy: ", e.what()); + } } // I2P tunnels @@ -83,8 +91,12 @@ namespace client std::string samAddr; i2p::config::GetOption("sam.address", samAddr); uint16_t samPort; i2p::config::GetOption("sam.port", samPort); LogPrint(eLogInfo, "Clients: starting SAM bridge at ", samAddr, ":", samPort); - m_SamBridge = new SAMBridge (samAddr, samPort); - m_SamBridge->Start (); + try { + m_SamBridge = new SAMBridge (samAddr, samPort); + m_SamBridge->Start (); + } catch (std::exception& e) { + LogPrint(eLogError, "Clients: Exception in SAM bridge: ", e.what()); + } } // BOB @@ -93,8 +105,12 @@ namespace client std::string bobAddr; i2p::config::GetOption("bob.address", bobAddr); uint16_t bobPort; i2p::config::GetOption("bob.port", bobPort); LogPrint(eLogInfo, "Clients: starting BOB command channel at ", bobAddr, ":", bobPort); - m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort); - m_BOBCommandChannel->Start (); + try { + m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort); + m_BOBCommandChannel->Start (); + } catch (std::exception& e) { + LogPrint(eLogError, "Clients: Exception in BOB bridge: ", e.what()); + } } m_AddressBook.StartResolvers (); diff --git a/Config.cpp b/Config.cpp index 1dc1207f..8d42895a 100644 --- a/Config.cpp +++ b/Config.cpp @@ -123,11 +123,11 @@ namespace config { ("service", value()->zero_tokens()->default_value(false), "Router will use system folders like '/var/lib/i2pd'") ("notransit", value()->zero_tokens()->default_value(false), "Router will not accept transit tunnels at startup") ("floodfill", value()->zero_tokens()->default_value(false), "Router will be floodfill") - ("bandwidth", value()->default_value('-'), "Bandwidth limiting: L - 32kbps, O - 256Kbps, P - unlimited") + ("bandwidth", value()->default_value(""), "Bandwidth limit: integer in kbps or letters: L (32), O (256), P (2048), X (>9000)") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") ("insomnia", value()->zero_tokens()->default_value(false), "Prevent system from sleeping") - ("close", value()->default_value("ask"), "On close action") // minimize, exit, ask TODO: add custom validator or something + ("close", value()->default_value("ask"), "Action on close: minimize, exit, ask") // TODO: add custom validator or something #endif ; diff --git a/Daemon.cpp b/Daemon.cpp index 3adfdb71..f15fe3e3 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -142,35 +142,47 @@ namespace i2p i2p::context.SetAcceptsTunnels (!transit); bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill); - char bandwidth; i2p::config::GetOption("bandwidth", bandwidth); - - if (isFloodfill) - { + if (isFloodfill) { LogPrint(eLogInfo, "Daemon: router will be floodfill"); i2p::context.SetFloodfill (true); - } - else + } else { i2p::context.SetFloodfill (false); - if (bandwidth != '-') - { - LogPrint(eLogInfo, "Daemon: bandwidth set to ", bandwidth); - if (bandwidth > 'O') - i2p::context.SetExtraBandwidth (); - else if (bandwidth > 'L') - i2p::context.SetHighBandwidth (); - else - i2p::context.SetLowBandwidth (); } + + /* this section also honors 'floodfill' flag, if set above */ + std::string bandwidth; i2p::config::GetOption("bandwidth", bandwidth); + if (bandwidth.length () > 0) + { + if (bandwidth[0] >= 'K' && bandwidth[0] <= 'X') + { + i2p::context.SetBandwidth (bandwidth[0]); + LogPrint(eLogInfo, "Daemon: bandwidth set to ", i2p::context.GetBandwidthLimit (), "KBps"); + } + else + { + auto value = std::atoi(bandwidth.c_str()); + if (value > 0) + { + i2p::context.SetBandwidth (value); + LogPrint(eLogInfo, "Daemon: bandwidth set to ", i2p::context.GetBandwidthLimit (), " KBps"); + } + else + { + LogPrint(eLogInfo, "Daemon: unexpected bandwidth ", bandwidth, ". Set to 'low'"); + i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_LOW_BANDWIDTH2); + } + } + } else if (isFloodfill) { LogPrint(eLogInfo, "Daemon: floodfill bandwidth set to 'extra'"); - i2p::context.SetExtraBandwidth (); + i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH1); } else { LogPrint(eLogInfo, "Daemon: bandwidth set to 'low'"); - i2p::context.SetLowBandwidth (); - } + i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_LOW_BANDWIDTH2); + } std::string family; i2p::config::GetOption("family", family); i2p::context.SetFamily (family); diff --git a/Daemon.h b/Daemon.h index efbd5df4..031686f7 100644 --- a/Daemon.h +++ b/Daemon.h @@ -50,26 +50,31 @@ namespace i2p bool init(int argc, char* argv[]); bool start(); - bool stop(); + bool stop(); void run (); }; #else class DaemonLinux : public Daemon_Singleton { - public: - static DaemonLinux& Instance() - { - static DaemonLinux instance; - return instance; - } + public: + static DaemonLinux& Instance() + { + static DaemonLinux instance; + return instance; + } - bool start(); - bool stop(); -; void run (); + bool start(); + bool stop(); + void run (); + + private: + + std::string pidfile; + int pidFH; + + public: - private: - std::string pidfile; - int pidFH; + int gracefullShutdownInterval; // in seconds }; #endif diff --git a/DaemonLinux.cpp b/DaemonLinux.cpp index e760b4f5..b408fc70 100644 --- a/DaemonLinux.cpp +++ b/DaemonLinux.cpp @@ -12,19 +12,29 @@ #include "Config.h" #include "FS.h" #include "Log.h" +#include "RouterContext.h" void handle_signal(int sig) { switch (sig) { - case SIGHUP: - LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening log..."); - i2p::log::Logger().Reopen (); - break; - case SIGABRT: - case SIGTERM: - case SIGINT: - Daemon.running = 0; // Exit loop + case SIGHUP: + LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening log..."); + i2p::log::Logger().Reopen (); + break; + case SIGINT: + if (i2p::context.AcceptsTunnels () && !Daemon.gracefullShutdownInterval) + { + i2p::context.SetAcceptsTunnels (false); + Daemon.gracefullShutdownInterval = 10*60; // 10 minutes + LogPrint(eLogInfo, "Graceful shutdown after ", Daemon.gracefullShutdownInterval, " seconds"); + } + else + Daemon.running = 0; + break; + case SIGABRT: + case SIGTERM: + Daemon.running = 0; // Exit loop break; } } @@ -96,6 +106,7 @@ namespace i2p return false; } } + gracefullShutdownInterval = 0; // not specified // Signal handler struct sigaction sa; @@ -122,6 +133,15 @@ namespace i2p while (running) { std::this_thread::sleep_for (std::chrono::seconds(1)); + if (gracefullShutdownInterval) + { + gracefullShutdownInterval--; // - 1 second + if (gracefullShutdownInterval <= 0) + { + LogPrint(eLogInfo, "Graceful shutdown"); + return; + } + } } } } diff --git a/RouterContext.cpp b/RouterContext.cpp index 2157a81e..e50681d9 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -165,34 +165,49 @@ namespace i2p m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY_SIG); } } - - void RouterContext::SetHighBandwidth () - { - if (!m_RouterInfo.IsHighBandwidth () || m_RouterInfo.IsExtraBandwidth ()) + + void RouterContext::SetBandwidth (char L) { + uint16_t limit = 0; + enum { low, high, extra } type = high; + /* detect parameters */ + switch (L) { - m_RouterInfo.SetCaps ((m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eHighBandwidth) & ~i2p::data::RouterInfo::eExtraBandwidth); - UpdateRouterInfo (); + case i2p::data::CAPS_FLAG_LOW_BANDWIDTH1 : limit = 12; type = low; break; + case i2p::data::CAPS_FLAG_LOW_BANDWIDTH2 : limit = 48; type = low; break; + case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH1 : limit = 64; type = high; break; + case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH2 : limit = 128; type = high; break; + case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH3 : limit = 256; type = high; break; + case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH1 : limit = 2048; type = extra; break; + case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH2 : limit = 9999; type = extra; break; + default: + limit = 48; type = low; } - } - - void RouterContext::SetLowBandwidth () - { - if (m_RouterInfo.IsHighBandwidth () || m_RouterInfo.IsExtraBandwidth ()) + /* update caps & flags in RI */ + auto caps = m_RouterInfo.GetCaps (); + caps &= ~i2p::data::RouterInfo::eHighBandwidth; + caps &= ~i2p::data::RouterInfo::eExtraBandwidth; + switch (type) { - m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eHighBandwidth & ~i2p::data::RouterInfo::eExtraBandwidth); - UpdateRouterInfo (); + case low : /* not set */; break; + case high : caps |= i2p::data::RouterInfo::eHighBandwidth; break; + case extra : caps |= i2p::data::RouterInfo::eExtraBandwidth; break; } + m_RouterInfo.SetCaps (caps); + UpdateRouterInfo (); + m_BandwidthLimit = limit; } - void RouterContext::SetExtraBandwidth () - { - if (!m_RouterInfo.IsExtraBandwidth () || !m_RouterInfo.IsHighBandwidth ()) - { - m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eExtraBandwidth | i2p::data::RouterInfo::eHighBandwidth); - UpdateRouterInfo (); - } + void RouterContext::SetBandwidth (int limit) + { + if (limit > 2000) { SetBandwidth('X'); } + else if (limit > 256) { SetBandwidth('P'); } + else if (limit > 128) { SetBandwidth('O'); } + else if (limit > 64) { SetBandwidth('N'); } + else if (limit > 48) { SetBandwidth('M'); } + else if (limit > 12) { SetBandwidth('L'); } + else { SetBandwidth('K'); } } - + bool RouterContext::IsUnreachable () const { return m_RouterInfo.GetCaps () & i2p::data::RouterInfo::eUnreachable; diff --git a/RouterContext.h b/RouterContext.h index 0679a038..9766c66e 100644 --- a/RouterContext.h +++ b/RouterContext.h @@ -45,6 +45,7 @@ namespace i2p uint32_t GetUptime () const; uint32_t GetStartupTime () const { return m_StartupTime; }; uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; }; + uint64_t GetBandwidthLimit () const { return m_BandwidthLimit; }; RouterStatus GetStatus () const { return m_Status; }; void SetStatus (RouterStatus status); @@ -58,9 +59,8 @@ namespace i2p bool IsFloodfill () const { return m_IsFloodfill; }; void SetFloodfill (bool floodfill); void SetFamily (const std::string& family); - void SetHighBandwidth (); - void SetLowBandwidth (); - void SetExtraBandwidth (); + void SetBandwidth (int limit); /* in kilobytes */ + void SetBandwidth (char L); /* by letter */ bool AcceptsTunnels () const { return m_AcceptsTunnels; }; void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; }; bool SupportsV6 () const { return m_RouterInfo.IsV6 (); }; @@ -101,6 +101,7 @@ namespace i2p uint64_t m_LastUpdateTime; bool m_AcceptsTunnels, m_IsFloodfill; uint64_t m_StartupTime; // in seconds since epoch + uint32_t m_BandwidthLimit; // allowed bandwidth RouterStatus m_Status; std::mutex m_GarlicMutex; }; diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 22c5f2f8..dfd54059 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -77,7 +77,7 @@ namespace data bool RouterInfo::LoadFile () { - std::ifstream s(m_FullPath.c_str (), std::ifstream::binary); + std::ifstream s(m_FullPath, std::ifstream::binary); if (s.is_open ()) { s.seekg (0,std::ios::end); @@ -333,16 +333,19 @@ namespace data void RouterInfo::UpdateCapsProperty () { std::string caps; - if (m_Caps & eFloodfill) - { - if (m_Caps & eExtraBandwidth) caps += CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P' - caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O' + if (m_Caps & eFloodfill) { caps += CAPS_FLAG_FLOODFILL; // floodfill - } - else - { - if (m_Caps & eExtraBandwidth) caps += CAPS_FLAG_EXTRA_BANDWIDTH1; - caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH3 : CAPS_FLAG_LOW_BANDWIDTH2; // bandwidth + caps += (m_Caps & eExtraBandwidth) + ? CAPS_FLAG_EXTRA_BANDWIDTH1 // 'P' + : CAPS_FLAG_HIGH_BANDWIDTH3; // 'O' + } else { + if (m_Caps & eExtraBandwidth) { + caps += CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P' + } else if (m_Caps & eHighBandwidth) { + caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O' + } else { + caps += CAPS_FLAG_LOW_BANDWIDTH2; // 'L' + } } if (m_Caps & eHidden) caps += CAPS_FLAG_HIDDEN; // hidden if (m_Caps & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable diff --git a/RouterInfo.h b/RouterInfo.h index 5fa865b0..7648c6ba 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -24,13 +24,14 @@ namespace data const char CAPS_FLAG_HIDDEN = 'H'; const char CAPS_FLAG_REACHABLE = 'R'; const char CAPS_FLAG_UNREACHABLE = 'U'; - const char CAPS_FLAG_LOW_BANDWIDTH1 = 'K'; - const char CAPS_FLAG_LOW_BANDWIDTH2 = 'L'; - const char CAPS_FLAG_HIGH_BANDWIDTH1 = 'M'; - const char CAPS_FLAG_HIGH_BANDWIDTH2 = 'N'; - const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O'; - const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; - const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; + /* bandwidth flags */ + const char CAPS_FLAG_LOW_BANDWIDTH1 = 'K'; /* < 12 KBps */ + const char CAPS_FLAG_LOW_BANDWIDTH2 = 'L'; /* 12-48 KBps */ + const char CAPS_FLAG_HIGH_BANDWIDTH1 = 'M'; /* 48-64 KBps */ + const char CAPS_FLAG_HIGH_BANDWIDTH2 = 'N'; /* 64-128 KBps */ + const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O'; /* 128-256 KBps */ + const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2000 KBps */ + const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */ const char CAPS_FLAG_SSU_TESTING = 'B'; const char CAPS_FLAG_SSU_INTRODUCER = 'C'; @@ -174,7 +175,6 @@ namespace data const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity->GetStandardIdentity ().publicKey; }; bool IsDestination () const { return false; }; - private: bool LoadFile (); diff --git a/Transports.cpp b/Transports.cpp index 275c6f90..0fdfce3d 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -200,9 +200,9 @@ namespace transport bool Transports::IsBandwidthExceeded () const { - if (i2p::context.GetRouterInfo ().IsExtraBandwidth ()) return false; + auto limit = i2p::context.GetBandwidthLimit() * 1024; // convert to bytes auto bw = std::max (m_InBandwidth, m_OutBandwidth); - return bw > (i2p::context.GetRouterInfo ().IsHighBandwidth () ? HIGH_BANDWIDTH_LIMIT : LOW_BANDWIDTH_LIMIT); + return bw > limit; } void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr msg) diff --git a/Transports.h b/Transports.h index 9b603963..3bfe1f8b 100644 --- a/Transports.h +++ b/Transports.h @@ -66,8 +66,6 @@ namespace transport }; const size_t SESSION_CREATION_TIMEOUT = 10; // in seconds - const uint32_t LOW_BANDWIDTH_LIMIT = 32*1024; // 32KBs - const uint32_t HIGH_BANDWIDTH_LIMIT = 256*1024; // 256KBs class Transports { public: @@ -94,8 +92,8 @@ namespace transport void UpdateReceivedBytes (uint64_t numBytes) { m_TotalReceivedBytes += numBytes; }; uint64_t GetTotalSentBytes () const { return m_TotalSentBytes; }; uint64_t GetTotalReceivedBytes () const { return m_TotalReceivedBytes; }; - uint32_t GetInBandwidth () const { return m_InBandwidth; }; // bytes per second - uint32_t GetOutBandwidth () const { return m_OutBandwidth; }; // bytes per second + uint32_t GetInBandwidth () const { return m_InBandwidth; }; + uint32_t GetOutBandwidth () const { return m_OutBandwidth; }; bool IsBandwidthExceeded () const; size_t GetNumPeers () const { return m_Peers.size (); }; std::shared_ptr GetRandomPeer () const; @@ -138,7 +136,7 @@ namespace transport DHKeysPairSupplier m_DHKeysPairSupplier; std::atomic m_TotalSentBytes, m_TotalReceivedBytes; - uint32_t m_InBandwidth, m_OutBandwidth; + uint32_t m_InBandwidth, m_OutBandwidth; // bytes per second uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes; uint64_t m_LastBandwidthUpdateTime; diff --git a/docs/configuration.md b/docs/configuration.md index 1a45716d..f3e9f98c 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -23,9 +23,14 @@ If you are upgrading your very old router (< 2.3.0) see also [this](config_opts_ * --ipv6 - Enable communication through ipv6. false by default * --notransit - Router will not accept transit tunnels at startup. false by default * --floodfill - Router will be floodfill. false by default -* --bandwidth= - L if bandwidth is limited to 32Kbs/sec, O - to 256Kbs/sec, P - unlimited +* --bandwidth= - Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000) * --family= - Name of a family, router belongs to + +Windows-specific options: + * --svcctl= - Windows service management (--svcctl="install" or --svcctl="remove") +* --insomnia - Prevent system from sleeping +* --close= - Action on close: minimize, exit, ask All options below still possible in cmdline, but better write it in config file: diff --git a/version.h b/version.h index e7414de3..c5177d30 100644 --- a/version.h +++ b/version.h @@ -1,14 +1,14 @@ #ifndef _VERSION_H_ #define _VERSION_H_ -#define CODENAME "Purple" +#define CODENAME "Bora Bora" #define STRINGIZE(x) #x #define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c) #define I2PD_VERSION_MAJOR 2 -#define I2PD_VERSION_MINOR 5 -#define I2PD_VERSION_MICRO 1 +#define I2PD_VERSION_MINOR 6 +#define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_PATCH 0 #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) #define VERSION I2PD_VERSION