diff --git a/BOB.cpp b/BOB.cpp index d68c798f..15b7066b 100644 --- a/BOB.cpp +++ b/BOB.cpp @@ -1,7 +1,7 @@ #include -#include #include "Log.h" #include "ClientContext.h" +#include "util.h" #include "BOB.h" namespace i2p @@ -459,7 +459,7 @@ namespace client void BOBCommandSession::OutportCommandHandler (const char * operand, size_t len) { LogPrint (eLogDebug, "BOB: outport ", operand); - m_OutPort = boost::lexical_cast(operand); + m_OutPort = std::stoi(operand); if (m_OutPort >= 0) SendReplyOK ("outbound port set"); else @@ -476,7 +476,7 @@ namespace client void BOBCommandSession::InportCommandHandler (const char * operand, size_t len) { LogPrint (eLogDebug, "BOB: inport ", operand); - m_InPort = boost::lexical_cast(operand); + m_InPort = std::stoi(operand); if (m_InPort >= 0) SendReplyOK ("inbound port set"); else diff --git a/ChangeLog b/ChangeLog index 2fdc0082..98b33e81 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,21 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.10.0] - 2016-10-17 +### Added +- Datagram i2p tunnels +- Unique local addresses for server tunnels +- Configurable list of reseed servers and initial addressbook +- Configurable netid +- Initial iOS support + +### Changed +- Reduced file descriptiors usage +- Strict reseed checks enabled by default + +## Fixed +- Multiple fixes in I2CP and BOB implementations + ## [2.9.0] - 2016-08-12 ### Changed - Proxy refactoring & speedup diff --git a/ClientContext.cpp b/ClientContext.cpp index b7300ad2..4639ec05 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -53,7 +53,11 @@ namespace client { i2p::data::PrivateKeys keys; if(LoadPrivateKeys (keys, httpProxyKeys)) - localDestination = CreateNewLocalDestination (keys, false); + { + std::map params; + ReadI2CPOptionsFromConfig ("httpproxy.", params); + localDestination = CreateNewLocalDestination (keys, false, ¶ms); + } else LogPrint(eLogError, "Clients: failed to load HTTP Proxy key"); } @@ -65,8 +69,10 @@ namespace client } } + localDestination = nullptr; bool socksproxy; i2p::config::GetOption("socksproxy.enabled", socksproxy); - if (socksproxy) { + if (socksproxy) + { std::string socksProxyKeys; i2p::config::GetOption("socksproxy.keys", socksProxyKeys); std::string socksProxyAddr; i2p::config::GetOption("socksproxy.address", socksProxyAddr); uint16_t socksProxyPort; i2p::config::GetOption("socksproxy.port", socksProxyPort); @@ -76,8 +82,14 @@ namespace client if (socksProxyKeys.length () > 0) { i2p::data::PrivateKeys keys; - LoadPrivateKeys (keys, socksProxyKeys); - localDestination = CreateNewLocalDestination (keys, false); + if (LoadPrivateKeys (keys, socksProxyKeys)) + { + std::map params; + ReadI2CPOptionsFromConfig ("socksproxy.", params); + localDestination = CreateNewLocalDestination (keys, false, ¶ms); + } + else + LogPrint(eLogError, "Clients: failed to load SOCKS Proxy key"); } try { m_SocksProxy = new i2p::proxy::SOCKSProxy(socksProxyAddr, socksProxyPort, socksOutProxyAddr, socksOutProxyPort, localDestination); @@ -290,7 +302,7 @@ namespace client } return infos; } - + std::shared_ptr ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType, const std::map * params) { @@ -362,6 +374,19 @@ namespace client options[I2CP_PARAM_TAGS_TO_SEND] = GetI2CPOption (section, I2CP_PARAM_TAGS_TO_SEND, DEFAULT_TAGS_TO_SEND); } + void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, std::map& options) const + { + std::string value; + if (i2p::config::GetOption(prefix + I2CP_PARAM_INBOUND_TUNNEL_LENGTH, value)) + options[I2CP_PARAM_INBOUND_TUNNEL_LENGTH] = value; + if (i2p::config::GetOption(prefix + I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, value)) + options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = value; + if (i2p::config::GetOption(prefix + I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, value)) + options[I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH] = value; + if (i2p::config::GetOption(prefix + I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, value)) + options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = value; + } + void ClientContext::ReadTunnels () { boost::property_tree::ptree pt; diff --git a/ClientContext.h b/ClientContext.h index 1a41acfc..73001934 100644 --- a/ClientContext.h +++ b/ClientContext.h @@ -68,14 +68,15 @@ namespace client const SAMBridge * GetSAMBridge () const { return m_SamBridge; }; std::vector > GetForwardInfosFor(const i2p::data::IdentHash & destination); - + private: void ReadTunnels (); template std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const; template - void ReadI2CPOptions (const Section& section, std::map& options) const; + void ReadI2CPOptions (const Section& section, std::map& options) const; + void ReadI2CPOptionsFromConfig (const std::string& prefix, std::map& options) const; void CleanupUDP(const boost::system::error_code & ecode); void ScheduleCleanupUDP(); @@ -110,6 +111,7 @@ namespace client const decltype(m_ServerTunnels)& GetServerTunnels () const { return m_ServerTunnels; }; const decltype(m_ClientForwards)& GetClientForwards () const { return m_ClientForwards; } const decltype(m_ServerForwards)& GetServerForwards () const { return m_ServerForwards; } + const i2p::proxy::HTTPProxy * GetHttpProxy () const { return m_HttpProxy; } }; extern ClientContext context; diff --git a/Config.cpp b/Config.cpp index 924f244b..aa75b8db 100644 --- a/Config.cpp +++ b/Config.cpp @@ -27,10 +27,6 @@ namespace config { variables_map m_Options; void Init() { - bool nat = true; -#ifdef MESHNET - nat = false; -#endif options_description general("General options"); general.add_options() @@ -44,8 +40,8 @@ namespace config { ("family", value()->default_value(""), "Specify a family, router belongs to") ("datadir", value()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") ("host", value()->default_value("0.0.0.0"), "External IP") - ("ifname", value()->default_value(""), "network interface to bind to") - ("nat", value()->zero_tokens()->default_value(nat), "should we assume we are behind NAT?") + ("ifname", value()->default_value(""), "Network interface to bind to") + ("nat", value()->zero_tokens()->default_value(true), "Should we assume we are behind NAT?") ("port", value()->default_value(0), "Port to listen for incoming connections (default: auto)") ("ipv4", value()->zero_tokens()->default_value(true), "Enable communication through ipv4") ("ipv6", value()->zero_tokens()->default_value(false), "Enable communication through ipv6") @@ -55,8 +51,8 @@ namespace config { ("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 limit: integer in kbps or letters: L (32), O (256), P (2048), X (>9000)") - ("ntcp", value()->zero_tokens()->default_value(true), "enable ntcp transport") - ("ssu", value()->zero_tokens()->default_value(true), "enable ssu transport") + ("ntcp", value()->zero_tokens()->default_value(true), "Enable NTCP transport") + ("ssu", value()->zero_tokens()->default_value(true), "Enable SSU transport") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") ("insomnia", value()->zero_tokens()->default_value(false), "Prevent system from sleeping") @@ -66,6 +62,8 @@ namespace config { options_description limits("Limits options"); limits.add_options() + ("limits.coresize", value()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)") + ("limits.openfiles", value()->default_value(0), "Maximum number of open files (0 - use system default)") ("limits.transittunnels", value()->default_value(2500), "Maximum active transit sessions (default:2500)") ; @@ -85,6 +83,10 @@ namespace config { ("httpproxy.address", value()->default_value("127.0.0.1"), "HTTP Proxy listen address") ("httpproxy.port", value()->default_value(4444), "HTTP Proxy listen port") ("httpproxy.keys", value()->default_value(""), "File to persist HTTP Proxy keys") + ("httpproxy.inbound.length", value()->default_value("3"), "HTTP proxy inbound tunnel length") + ("httpproxy.outbound.length", value()->default_value("3"), "HTTP proxy outbound tunnel length") + ("httpproxy.inbound.quantity", value()->default_value("5"), "HTTP proxy inbound tunnels quantity") + ("httpproxy.outbound.quantity", value()->default_value("5"), "HTTP proxy outbound tunnels quantity") ; options_description socksproxy("SOCKS Proxy options"); @@ -93,7 +95,11 @@ namespace config { ("socksproxy.address", value()->default_value("127.0.0.1"), "SOCKS Proxy listen address") ("socksproxy.port", value()->default_value(4447), "SOCKS Proxy listen port") ("socksproxy.keys", value()->default_value(""), "File to persist SOCKS Proxy keys") - ("socksproxy.outproxy", value()->default_value("127.0.0.1"), "Upstream outproxy address for SOCKS Proxy") + ("socksproxy.inbound.length", value()->default_value("3"), "SOCKS proxy inbound tunnel length") + ("socksproxy.outbound.length", value()->default_value("3"), "SOCKS proxy outbound tunnel length") + ("socksproxy.inbound.quantity", value()->default_value("5"), "SOCKS proxy inbound tunnels quantity") + ("socksproxy.outbound.quantity", value()->default_value("5"), "SOCKS proxy outbound tunnels quantity") + ("socksproxy.outproxy", value()->default_value("127.0.0.1"), "Upstream outproxy address for SOCKS Proxy") ("socksproxy.outproxyport", value()->default_value(9050), "Upstream outproxy port for SOCKS Proxy") ; @@ -153,9 +159,6 @@ namespace config { reseed.add_options() ("reseed.verify", value()->default_value(false), "Verify .su3 signature") ("reseed.file", value()->default_value(""), "Path to .su3 file") -#ifdef MESHNET - ("reseed.urls", value()->default_value("https://reseed.i2p.rocks:8443/"), "Reseed URLs, separated by comma") -#else ("reseed.urls", value()->default_value( "https://reseed.i2p-projekt.de/," "https://i2p.mooo.com/netDb/," @@ -169,7 +172,6 @@ namespace config { "https://reseed-ru.lngserv.ru/," "https://reseed.atomike.ninja/" ), "Reseed URLs, separated by comma") -#endif ; options_description addressbook("AddressBook options"); @@ -182,10 +184,17 @@ namespace config { options_description trust("Trust options"); trust.add_options() - ("trust.enabled", value()->default_value(false), "enable explicit trust options") + ("trust.enabled", value()->default_value(false), "Enable explicit trust options") ("trust.family", value()->default_value(""), "Router Familiy to trust for first hops") - ("trust.hidden", value()->default_value(false), "should we hide our router from other routers?"); + ("trust.routers", value()->default_value(""), "Only Connect to these routers") + ("trust.hidden", value()->default_value(false), "Should we hide our router from other routers?"); + options_description websocket("Websocket Options"); + websocket.add_options() + ("websockets.enabled", value()->default_value(false), "enable websocket server") + ("websockets.address", value()->default_value("127.0.0.1"), "address to bind websocket server on") + ("websockets.port", value()->default_value(7666), "port to bind websocket server on"); + m_OptionsDesc .add(general) .add(limits) @@ -200,7 +209,8 @@ namespace config { .add(precomputation) .add(reseed) .add(addressbook) - .add(trust) + .add(trust) + .add(websocket) ; } diff --git a/Config.h b/Config.h index 6b2af717..595331cd 100644 --- a/Config.h +++ b/Config.h @@ -78,6 +78,12 @@ namespace config { return true; } + template + bool GetOption(const std::string& name, T& value) + { + return GetOption (name.c_str (), value); + } + /** * @brief Set value of given parameter * @param name Name of settable parameter @@ -93,7 +99,7 @@ namespace config { m_Options.at(name).value() = value; notify(m_Options); return true; - } + } /** * @brief Check is value explicitly given or default diff --git a/Crypto.h b/Crypto.h index 4408a193..1644e147 100644 --- a/Crypto.h +++ b/Crypto.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -284,8 +285,21 @@ namespace crypto #include #if (OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER) // 1.1.0 or LibreSSL // define getters and setters introduced in 1.1.0 -inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) { d->p = p; d->q = q; d->g = g; return 1; } -inline int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) { d->pub_key = pub_key; d->priv_key = priv_key; return 1; } +inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) + { d->p = p; d->q = q; d->g = g; return 1; } +inline int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) + { d->pub_key = pub_key; d->priv_key = priv_key; return 1; } +inline void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key) + { *pub_key = d->pub_key; *priv_key = d->priv_key; } +inline int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) + { sig->r = r; sig->s = s; return 1; } +inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) + { *pr = sig->r; *ps = sig->s; } + +inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) + { r->n = n; r->e = e; r->d = d; return 1; } +inline void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) + { *n = r->n; *e = r->e; *d = r->d; } #endif diff --git a/Daemon.cpp b/Daemon.cpp index 7dec30a9..9c0d15f8 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -25,6 +25,9 @@ #include "UPnP.h" #include "util.h" +#include "Event.h" +#include "Websocket.h" + namespace i2p { namespace util @@ -38,6 +41,9 @@ namespace i2p std::unique_ptr httpServer; std::unique_ptr m_I2PControlService; std::unique_ptr UPnP; +#ifdef WITH_EVENTS + std::unique_ptr m_WebsocketServer; +#endif }; Daemon_Singleton::Daemon_Singleton() : isDaemon(false), running(true), d(*new Daemon_Singleton_Private()) {} @@ -115,6 +121,9 @@ namespace i2p bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation); i2p::crypto::InitCrypto (precomputation); + + int netID; i2p::config::GetOption("netid", netID); + i2p::context.SetNetID (netID); i2p::context.Init (); bool ipv6; i2p::config::GetOption("ipv6", ipv6); @@ -191,12 +200,40 @@ namespace i2p { LogPrint(eLogInfo, "Daemon: explicit trust enabled"); std::string fam; i2p::config::GetOption("trust.family", fam); + std::string routers; i2p::config::GetOption("trust.routers", routers); + bool restricted = false; if (fam.length() > 0) { - LogPrint(eLogInfo, "Daemon: setting restricted routes to use family ", fam); - i2p::transport::transports.RestrictRoutes({fam}); - } else - LogPrint(eLogError, "Daemon: no family specified for restricted routes"); + std::set fams; + size_t pos = 0, comma; + do + { + comma = fam.find (',', pos); + fams.insert (fam.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos)); + pos = comma + 1; + } + while (comma != std::string::npos); + i2p::transport::transports.RestrictRoutesToFamilies(fams); + restricted = fams.size() > 0; + } + if (routers.length() > 0) { + std::set idents; + size_t pos = 0, comma; + do + { + comma = routers.find (',', pos); + i2p::data::IdentHash ident; + ident.FromBase64 (routers.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos)); + idents.insert (ident); + pos = comma + 1; + } + while (comma != std::string::npos); + LogPrint(eLogInfo, "Daemon: setting restricted routes to use ", idents.size(), " trusted routesrs"); + i2p::transport::transports.RestrictRoutesToRouters(idents); + restricted = idents.size() > 0; + } + if(!restricted) + LogPrint(eLogError, "Daemon: no trusted routers of families specififed"); } bool hidden; i2p::config::GetOption("trust.hidden", hidden); if (hidden) @@ -259,12 +296,27 @@ namespace i2p d.m_I2PControlService = std::unique_ptr(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort)); d.m_I2PControlService->Start (); } +#ifdef WITH_EVENTS + bool websocket; i2p::config::GetOption("websockets.enabled", websocket); + if(websocket) { + std::string websocketAddr; i2p::config::GetOption("websockets.address", websocketAddr); + uint16_t websocketPort; i2p::config::GetOption("websockets.port", websocketPort); + LogPrint(eLogInfo, "Daemon: starting Websocket server at ", websocketAddr, ":", websocketPort); + d.m_WebsocketServer = std::unique_ptr(new i2p::event::WebsocketServer (websocketAddr, websocketPort)); + d.m_WebsocketServer->Start(); + i2p::event::core.SetListener(d.m_WebsocketServer->ToListener()); + } + +#endif return true; } bool Daemon_Singleton::stop() { +#ifdef WITH_EVENTS + i2p::event::core.SetListener(nullptr); +#endif LogPrint(eLogInfo, "Daemon: shutting down"); LogPrint(eLogInfo, "Daemon: stopping Client"); i2p::client::context.Stop(); @@ -290,10 +342,17 @@ namespace i2p LogPrint(eLogInfo, "Daemon: stopping I2PControl"); d.m_I2PControlService->Stop (); d.m_I2PControlService = nullptr; - } + } +#ifdef WITH_EVENTS + if (d.m_WebsocketServer) { + LogPrint(eLogInfo, "Daemon: stopping Websocket server"); + d.m_WebsocketServer->Stop(); + d.m_WebsocketServer = nullptr; + } +#endif i2p::crypto::TerminateCrypto (); return true; } - } +} } diff --git a/Daemon.h b/Daemon.h index 85b31240..2bc05462 100644 --- a/Daemon.h +++ b/Daemon.h @@ -97,7 +97,7 @@ namespace i2p public: - int gracefullShutdownInterval; // in seconds + int gracefulShutdownInterval; // in seconds }; #endif diff --git a/DaemonLinux.cpp b/DaemonLinux.cpp index 87e50a72..edd15f07 100644 --- a/DaemonLinux.cpp +++ b/DaemonLinux.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "Config.h" #include "FS.h" @@ -25,11 +26,11 @@ void handle_signal(int sig) i2p::client::context.ReloadConfig(); break; case SIGINT: - if (i2p::context.AcceptsTunnels () && !Daemon.gracefullShutdownInterval) + if (i2p::context.AcceptsTunnels () && !Daemon.gracefulShutdownInterval) { i2p::context.SetAcceptsTunnels (false); - Daemon.gracefullShutdownInterval = 10*60; // 10 minutes - LogPrint(eLogInfo, "Graceful shutdown after ", Daemon.gracefullShutdownInterval, " seconds"); + Daemon.gracefulShutdownInterval = 10*60; // 10 minutes + LogPrint(eLogInfo, "Graceful shutdown after ", Daemon.gracefulShutdownInterval, " seconds"); } else Daemon.running = 0; @@ -83,6 +84,42 @@ namespace i2p #endif } + // set proc limits + struct rlimit limit; + uint16_t nfiles; i2p::config::GetOption("limits.openfiles", nfiles); + getrlimit(RLIMIT_NOFILE, &limit); + if (nfiles == 0) { + LogPrint(eLogInfo, "Daemon: using system limit in ", limit.rlim_cur, " max open files"); + } else if (nfiles <= limit.rlim_max) { + limit.rlim_cur = nfiles; + if (setrlimit(RLIMIT_NOFILE, &limit) == 0) { + LogPrint(eLogInfo, "Daemon: set max number of open files to ", + nfiles, " (system limit is ", limit.rlim_max, ")"); + } else { + LogPrint(eLogError, "Daemon: can't set max number of open files: ", strerror(errno)); + } + } else { + LogPrint(eLogError, "Daemon: limits.openfiles exceeds system limit: ", limit.rlim_max); + } + uint32_t cfsize; i2p::config::GetOption("limits.coresize", cfsize); + if (cfsize) // core file size set + { + cfsize *= 1024; + getrlimit(RLIMIT_CORE, &limit); + if (cfsize <= limit.rlim_max) { + limit.rlim_cur = cfsize; + if (setrlimit(RLIMIT_CORE, &limit) != 0) { + LogPrint(eLogError, "Daemon: can't set max size of coredump: ", strerror(errno)); + } else if (cfsize == 0) { + LogPrint(eLogInfo, "Daemon: coredumps disabled"); + } else { + LogPrint(eLogInfo, "Daemon: set max size of core files to ", cfsize / 1024, "Kb"); + } + } else { + LogPrint(eLogError, "Daemon: limits.coresize exceeds system limit: ", limit.rlim_max); + } + } + // Pidfile // this code is c-styled and a bit ugly, but we need fd for locking pidfile std::string pidfile; i2p::config::GetOption("pidfile", pidfile); @@ -110,7 +147,7 @@ namespace i2p return false; } } - gracefullShutdownInterval = 0; // not specified + gracefulShutdownInterval = 0; // not specified // Signal handler struct sigaction sa; @@ -137,10 +174,10 @@ namespace i2p while (running) { std::this_thread::sleep_for (std::chrono::seconds(1)); - if (gracefullShutdownInterval) + if (gracefulShutdownInterval) { - gracefullShutdownInterval--; // - 1 second - if (gracefullShutdownInterval <= 0) + gracefulShutdownInterval--; // - 1 second + if (gracefulShutdownInterval <= 0) { LogPrint(eLogInfo, "Graceful shutdown"); return; diff --git a/Destination.cpp b/Destination.cpp index d020d96e..c8384ff9 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -1,6 +1,5 @@ #include #include -#include #include "Crypto.h" #include "Log.h" #include "FS.h" @@ -18,83 +17,50 @@ namespace client m_PublishReplyToken (0), m_PublishConfirmationTimer (m_Service), m_PublishVerificationTimer (m_Service), m_CleanupTimer (m_Service) { - int inboundTunnelLen = DEFAULT_INBOUND_TUNNEL_LENGTH; - int outboundTunnelLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH; - int inboundTunnelsQuantity = DEFAULT_INBOUND_TUNNELS_QUANTITY; - int outboundTunnelsQuantity = DEFAULT_OUTBOUND_TUNNELS_QUANTITY; + int inLen = DEFAULT_INBOUND_TUNNEL_LENGTH; + int inQty = DEFAULT_INBOUND_TUNNELS_QUANTITY; + int outLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH; + int outQty = DEFAULT_OUTBOUND_TUNNELS_QUANTITY; int numTags = DEFAULT_TAGS_TO_SEND; std::shared_ptr > explicitPeers; - if (params) - { - auto it = params->find (I2CP_PARAM_INBOUND_TUNNEL_LENGTH); - if (it != params->end ()) - { - - int len = i2p::util::lexical_cast(it->second, inboundTunnelLen); - if (len >= 0) - { - inboundTunnelLen = len; - } - LogPrint (eLogInfo, "Destination: Inbound tunnel length set to ", inboundTunnelLen); - } - it = params->find (I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH); - if (it != params->end ()) - { - - int len = i2p::util::lexical_cast(it->second, outboundTunnelLen); - if (len >= 0) - { - outboundTunnelLen = len; - } - LogPrint (eLogInfo, "Destination: Outbound tunnel length set to ", outboundTunnelLen); - } - it = params->find (I2CP_PARAM_INBOUND_TUNNELS_QUANTITY); - if (it != params->end ()) - { - int quantity = i2p::util::lexical_cast(it->second, inboundTunnelsQuantity); - if (quantity > 0) - { - inboundTunnelsQuantity = quantity; - LogPrint (eLogInfo, "Destination: Inbound tunnels quantity set to ", quantity); - } - } - it = params->find (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY); - if (it != params->end ()) - { - int quantity = i2p::util::lexical_cast(it->second, outboundTunnelsQuantity); - if (quantity > 0) - { - outboundTunnelsQuantity = quantity; - LogPrint (eLogInfo, "Destination: Outbound tunnels quantity set to ", quantity); - } - } - it = params->find (I2CP_PARAM_TAGS_TO_SEND); - if (it != params->end ()) - { - int tagsToSend = i2p::util::lexical_cast(it->second, numTags); - if (tagsToSend > 0) - { - numTags = tagsToSend; - LogPrint (eLogInfo, "Destination: Tags to send set to ", tagsToSend); - } - } - it = params->find (I2CP_PARAM_EXPLICIT_PEERS); - if (it != params->end ()) - { - explicitPeers = std::make_shared >(); - std::stringstream ss(it->second); - std::string b64; - while (std::getline (ss, b64, ',')) + try { + if (params) { + auto it = params->find (I2CP_PARAM_INBOUND_TUNNEL_LENGTH); + if (it != params->end ()) + inLen = std::stoi(it->second); + it = params->find (I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH); + if (it != params->end ()) + outLen = std::stoi(it->second); + it = params->find (I2CP_PARAM_INBOUND_TUNNELS_QUANTITY); + if (it != params->end ()) + inQty = std::stoi(it->second); + it = params->find (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY); + if (it != params->end ()) + outQty = std::stoi(it->second); + it = params->find (I2CP_PARAM_TAGS_TO_SEND); + if (it != params->end ()) + numTags = std::stoi(it->second); + LogPrint (eLogInfo, "Destination: parameters for tunnel set to: ", inQty, " inbound (", inLen, " hops), ", outQty, " outbound (", outLen, " hops), ", numTags, " tags"); + it = params->find (I2CP_PARAM_EXPLICIT_PEERS); + if (it != params->end ()) { - i2p::data::IdentHash ident; - ident.FromBase64 (b64); - explicitPeers->push_back (ident); + explicitPeers = std::make_shared >(); + std::stringstream ss(it->second); + std::string b64; + while (std::getline (ss, b64, ',')) + { + i2p::data::IdentHash ident; + ident.FromBase64 (b64); + explicitPeers->push_back (ident); + LogPrint (eLogInfo, "Destination: Added to explicit peers list: ", b64); + } } - LogPrint (eLogInfo, "Destination: Explicit peers set to ", it->second); } - } + } catch (std::exception & ex) { + LogPrint(eLogError, "Destination: unable to parse parameters for destination: ", ex.what()); + } SetNumTags (numTags); - m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inboundTunnelLen, outboundTunnelLen, inboundTunnelsQuantity, outboundTunnelsQuantity); + m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inLen, outLen, inQty, outQty); if (explicitPeers) m_Pool->SetExplicitPeers (explicitPeers); } @@ -202,7 +168,12 @@ namespace client return remoteLS; } else + { LogPrint (eLogWarning, "Destination: remote LeaseSet expired"); + std::lock_guard lock(m_RemoteLeaseSetsMutex); + m_RemoteLeaseSets.erase (ident); + return nullptr; + } } else { @@ -223,12 +194,16 @@ namespace client if (!m_Pool) return nullptr; if (!m_LeaseSet) UpdateLeaseSet (); + std::lock_guard l(m_LeaseSetMutex); return m_LeaseSet; } void LeaseSetDestination::SetLeaseSet (i2p::data::LocalLeaseSet * newLeaseSet) { - m_LeaseSet.reset (newLeaseSet); + { + std::lock_guard l(m_LeaseSetMutex); + m_LeaseSet.reset (newLeaseSet); + } i2p::garlic::GarlicDestination::SetLeaseSetUpdated (); if (m_IsPublic) { @@ -305,7 +280,7 @@ namespace client std::shared_ptr leaseSet; if (buf[DATABASE_STORE_TYPE_OFFSET] == 1) // LeaseSet { - LogPrint (eLogDebug, "Remote LeaseSet"); + LogPrint (eLogDebug, "Destination: Remote LeaseSet"); std::lock_guard lock(m_RemoteLeaseSetsMutex); auto it = m_RemoteLeaseSets.find (buf + DATABASE_STORE_KEY_OFFSET); if (it != m_RemoteLeaseSets.end ()) @@ -315,16 +290,16 @@ namespace client { leaseSet->Update (buf + offset, len - offset); if (leaseSet->IsValid ()) - LogPrint (eLogDebug, "Remote LeaseSet updated"); + LogPrint (eLogDebug, "Destination: Remote LeaseSet updated"); else { - LogPrint (eLogDebug, "Remote LeaseSet update failed"); + LogPrint (eLogDebug, "Destination: Remote LeaseSet update failed"); m_RemoteLeaseSets.erase (it); leaseSet = nullptr; } } else - LogPrint (eLogDebug, "Remote LeaseSet is older. Not updated"); + LogPrint (eLogDebug, "Destination: Remote LeaseSet is older. Not updated"); } else { @@ -333,15 +308,15 @@ namespace client { if (leaseSet->GetIdentHash () != GetIdentHash ()) { - LogPrint (eLogDebug, "New remote LeaseSet added"); + LogPrint (eLogDebug, "Destination: New remote LeaseSet added"); m_RemoteLeaseSets[buf + DATABASE_STORE_KEY_OFFSET] = leaseSet; } else - LogPrint (eLogDebug, "Own remote LeaseSet dropped"); + LogPrint (eLogDebug, "Destination: Own remote LeaseSet dropped"); } else { - LogPrint (eLogError, "New remote LeaseSet failed"); + LogPrint (eLogError, "Destination: New remote LeaseSet failed"); leaseSet = nullptr; } } @@ -371,14 +346,14 @@ namespace client if (request->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST) { for (int i = 0; i < num; i++) + { + i2p::data::IdentHash peerHash (buf + 33 + i*32); + if (!request->excluded.count (peerHash) && !i2p::data::netdb.FindRouter (peerHash)) { - i2p::data::IdentHash peerHash (buf + 33 + i*32); - if (!request->excluded.count (peerHash) && !i2p::data::netdb.FindRouter (peerHash)) - { - LogPrint (eLogInfo, "Destination: Found new floodfill, request it"); // TODO: recheck this message - i2p::data::netdb.RequestDestination (peerHash); - } - } + LogPrint (eLogInfo, "Destination: Found new floodfill, request it"); // TODO: recheck this message + i2p::data::netdb.RequestDestination (peerHash); + } + } auto floodfill = i2p::data::netdb.GetClosestFloodfill (key, request->excluded); if (floodfill) diff --git a/Destination.h b/Destination.h index e2d532e8..ba19a32a 100644 --- a/Destination.h +++ b/Destination.h @@ -131,6 +131,7 @@ namespace client std::map > m_LeaseSetRequests; std::shared_ptr m_Pool; + std::mutex m_LeaseSetMutex; std::shared_ptr m_LeaseSet; bool m_IsPublic; uint32_t m_PublishReplyToken; diff --git a/Event.cpp b/Event.cpp new file mode 100644 index 00000000..e148538e --- /dev/null +++ b/Event.cpp @@ -0,0 +1,32 @@ +#include "Event.h" +#include "Log.h" + +namespace i2p +{ + namespace event + { +#ifdef WITH_EVENTS + EventCore core; +#endif + + void EventCore::SetListener(EventListener * l) + { + m_listener = l; + LogPrint(eLogInfo, "Event: listener set"); + } + + void EventCore::QueueEvent(const EventType & ev) + { + if(m_listener) + m_listener->HandleEvent(ev); + } + } +} + +void EmitEvent(const EventType & e) +{ +#ifdef WITH_EVENTS + i2p::event::core.QueueEvent(e); +#endif +} + diff --git a/Event.h b/Event.h new file mode 100644 index 00000000..1ab37847 --- /dev/null +++ b/Event.h @@ -0,0 +1,37 @@ +#ifndef EVENT_H__ +#define EVENT_H__ +#include +#include +#include + +#include + +typedef std::map EventType; + +namespace i2p +{ + namespace event + { + class EventListener { + public: + virtual ~EventListener() {}; + virtual void HandleEvent(const EventType & ev) = 0; + }; + + class EventCore + { + public: + void QueueEvent(const EventType & ev); + void SetListener(EventListener * l); + + private: + EventListener * m_listener = nullptr; + }; +#ifdef WITH_EVENTS + extern EventCore core; +#endif + } +} +void EmitEvent(const EventType & ev); + +#endif diff --git a/FS.cpp b/FS.cpp index 84b30f21..64484b15 100644 --- a/FS.cpp +++ b/FS.cpp @@ -45,18 +45,18 @@ namespace fs { return; } #if defined(WIN32) || defined(_WIN32) - char localAppData[MAX_PATH]; - // check executable directory first - GetModuleFileName (NULL, localAppData, MAX_PATH); - auto execPath = boost::filesystem::path(localAppData).parent_path(); - // if config file exists in .exe's folder use it - if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string - dataDir = execPath.string (); - else - { - // otherwise %appdata% - SHGetFolderPath(NULL, CSIDL_APPDATA, 0, NULL, localAppData); - dataDir = std::string(localAppData) + "\\" + appName; + char localAppData[MAX_PATH]; + // check executable directory first + GetModuleFileName (NULL, localAppData, MAX_PATH); + auto execPath = boost::filesystem::path(localAppData).parent_path(); + // if config file exists in .exe's folder use it + if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string + dataDir = execPath.string (); + else + { + // otherwise %appdata% + SHGetFolderPath(NULL, CSIDL_APPDATA, 0, NULL, localAppData); + dataDir = std::string(localAppData) + "\\" + appName; } return; #elif defined(MAC_OSX) @@ -66,9 +66,11 @@ namespace fs { return; #else /* other unix */ #if defined(ANDROID) - if (boost::filesystem::exists("/sdcard")) + const char * ext = getenv("EXTERNAL_STORAGE"); + if (!ext) ext = "/sdcard"; + if (boost::filesystem::exists(ext)) { - dataDir = "/sdcard/" + appName; + dataDir = std::string (ext) + "/" + appName; return; } // otherwise use /data/files diff --git a/Garlic.h b/Garlic.h index 76d8eaf3..a3ab7d92 100644 --- a/Garlic.h +++ b/Garlic.h @@ -105,7 +105,9 @@ namespace garlic if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated; }; bool IsLeaseSetNonConfirmed () const { return m_LeaseSetUpdateStatus == eLeaseSetSubmitted; }; - + bool IsLeaseSetUpdated () const { return m_LeaseSetUpdateStatus == eLeaseSetUpdated; }; + uint64_t GetLeaseSetSubmissionTime () const { return m_LeaseSetSubmissionTime; } + std::shared_ptr GetSharedRoutingPath (); void SetSharedRoutingPath (std::shared_ptr path); diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 487e9c83..99edf508 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -196,7 +196,7 @@ namespace http { } s << "
\r\n"; #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) - if (auto remains = Daemon.gracefullShutdownInterval) { + if (auto remains = Daemon.gracefulShutdownInterval) { s << "Stopping in: "; s << remains << " seconds"; s << "
\r\n"; @@ -416,13 +416,13 @@ namespace http { else s << " Accept transit tunnels
\r\n"; #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) - if (Daemon.gracefullShutdownInterval) - s << " Cancel gracefull shutdown
"; + if (Daemon.gracefulShutdownInterval) + s << " Cancel graceful shutdown
"; else - s << " Start gracefull shutdown
\r\n"; + s << " Start graceful shutdown
\r\n"; #endif #ifdef WIN32_APP - s << " Gracefull shutdown
\r\n"; + s << " Graceful shutdown
\r\n"; #endif s << " Force shutdown
\r\n"; } @@ -549,6 +549,15 @@ namespace http { s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; } + auto httpProxy = i2p::client::context.GetHttpProxy (); + if (httpProxy) + { + auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash(); + s << ""; + s << "HTTP Proxy" << " ⇐ "; + s << i2p::client::context.GetAddressBook ().ToAddress(ident); + s << "
\r\n"<< std::endl; + } s << "
\r\nServer Tunnels:
\r\n
\r\n"; for (auto& it: i2p::client::context.GetServerTunnels ()) { @@ -755,7 +764,7 @@ namespace http { else if (cmd == HTTP_COMMAND_SHUTDOWN_START) { i2p::context.SetAcceptsTunnels (false); #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) - Daemon.gracefullShutdownInterval = 10*60; + Daemon.gracefulShutdownInterval = 10*60; #endif #ifdef WIN32_APP i2p::win32::GracefulShutdown (); @@ -763,7 +772,7 @@ namespace http { } else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) { i2p::context.SetAcceptsTunnels (true); #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) - Daemon.gracefullShutdownInterval = 0; + Daemon.gracefulShutdownInterval = 0; #endif } else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW) { Daemon.running = false; diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index cdc4fb9b..96b30cb6 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -547,7 +547,6 @@ namespace i2p uint8_t typeID = msg[I2NP_HEADER_TYPEID_OFFSET]; uint32_t msgID = bufbe32toh (msg + I2NP_HEADER_MSGID_OFFSET); LogPrint (eLogDebug, "I2NP: msg received len=", len,", type=", (int)typeID, ", msgID=", (unsigned int)msgID); - uint8_t * buf = msg + I2NP_HEADER_SIZE; int size = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET); switch (typeID) diff --git a/I2PService.h b/I2PService.h index 2df11909..59746a6f 100644 --- a/I2PService.h +++ b/I2PService.h @@ -38,6 +38,7 @@ namespace client } inline std::shared_ptr GetLocalDestination () { return m_LocalDestination; } + inline std::shared_ptr GetLocalDestination () const { return m_LocalDestination; } inline void SetLocalDestination (std::shared_ptr dest) { m_LocalDestination = dest; } void CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port = 0); diff --git a/I2PTunnel.cpp b/I2PTunnel.cpp index 0ce9a7e3..93bcff0c 100644 --- a/I2PTunnel.cpp +++ b/I2PTunnel.cpp @@ -238,8 +238,8 @@ namespace client if (line == "\r") endOfHeader = true; else { - if (line.find ("Host:") != std::string::npos) - m_OutHeader << "Host: " << m_Host << "\r\n"; + if (m_Host.length () > 0 && line.find ("Host:") != std::string::npos) + m_OutHeader << "Host: " << m_Host << "\r\n"; // override host else m_OutHeader << line << "\n"; } @@ -275,26 +275,24 @@ namespace client void I2PTunnelConnectionIRC::Write (const uint8_t * buf, size_t len) { - if (m_NeedsWebIrc) { + m_OutPacket.str (""); + if (m_NeedsWebIrc) + { m_NeedsWebIrc = false; - m_OutPacket.str (""); - m_OutPacket << "WEBIRC " << this->m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) << " 127.0.0.1\n"; - I2PTunnelConnection::Write ((uint8_t *)m_OutPacket.str ().c_str (), m_OutPacket.str ().length ()); + m_OutPacket << "WEBIRC " << m_WebircPass << " cgiirc " << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()) << " 127.0.0.1\n"; } - std::string line; - m_OutPacket.str (""); m_InPacket.clear (); m_InPacket.write ((const char *)buf, len); while (!m_InPacket.eof () && !m_InPacket.fail ()) { + std::string line; std::getline (m_InPacket, line); - if (line.length () == 0 && m_InPacket.eof ()) { + if (line.length () == 0 && m_InPacket.eof ()) m_InPacket.str (""); - } auto pos = line.find ("USER"); - if (pos != std::string::npos && pos == 0) + if (!pos) // start of line { pos = line.find (" "); pos++; @@ -304,9 +302,9 @@ namespace client m_OutPacket << line.substr (0, pos); m_OutPacket << context.GetAddressBook ().ToAddress (m_From->GetIdentHash ()); m_OutPacket << line.substr (nextpos) << '\n'; - } else { + } + else m_OutPacket << line << '\n'; - } } I2PTunnelConnection::Write ((uint8_t *)m_OutPacket.str ().c_str (), m_OutPacket.str ().length ()); } @@ -503,7 +501,7 @@ namespace client int port, std::shared_ptr localDestination, const std::string& host, int inport, bool gzip): I2PServerTunnel (name, address, port, localDestination, inport, gzip), - m_Host (host.length () > 0 ? host : address) + m_Host (host) { } diff --git a/Identity.cpp b/Identity.cpp index 30051914..9e07382f 100644 --- a/Identity.cpp +++ b/Identity.cpp @@ -385,7 +385,14 @@ namespace data else { delete verifier; - while (!m_Verifier) ; // spin lock + int count = 0; + while (!m_Verifier && count < 500) // 5 seconds + { + std::this_thread::sleep_for (std::chrono::milliseconds(10)); + count++; + } + if (!m_Verifier) + LogPrint (eLogError, "Identity: couldn't get verifier in 5 seconds"); } } else diff --git a/Log.cpp b/Log.cpp index 5660821f..268e9667 100644 --- a/Log.cpp +++ b/Log.cpp @@ -22,6 +22,22 @@ namespace log { "debug" // eLogDebug }; + /** + * @brief Colorize log output -- array of terminal control sequences + * @note Using ISO 6429 (ANSI) color sequences + */ +#ifdef _WIN32 + static const char *LogMsgColors[] = { "", "", "", "", "" }; +#else /* UNIX */ + static const char *LogMsgColors[] = { + [eLogError] = "\033[1;31m", /* red */ + [eLogWarning] = "\033[1;33m", /* yellow */ + [eLogInfo] = "\033[1;36m", /* cyan */ + [eLogDebug] = "\033[1;34m", /* blue */ + [eNumLogLevels] = "\033[0m", /* reset */ + }; +#endif + #ifndef _WIN32 /** * @brief Maps our log levels to syslog one @@ -42,7 +58,7 @@ namespace log { Log::Log(): m_Destination(eLogStdout), m_MinLevel(eLogInfo), - m_LogStream (nullptr), m_Logfile(""), m_IsReady(false) + m_LogStream (nullptr), m_Logfile(""), m_IsReady(false), m_HasColors(true) { } @@ -117,7 +133,7 @@ namespace log { default: std::cout << TimeAsString(msg->timestamp) << "@" << short_tid - << "/" << g_LogLevelStr[msg->level] + << "/" << LogMsgColors[msg->level] << g_LogLevelStr[msg->level] << LogMsgColors[eNumLogLevels] << " - " << msg->text << std::endl; break; } // switch @@ -138,6 +154,7 @@ namespace log { auto os = std::make_shared (path, flags); if (os->is_open ()) { + m_HasColors = false; m_Logfile = path; m_Destination = eLogFile; m_LogStream = os; @@ -147,12 +164,14 @@ namespace log { } void Log::SendTo (std::shared_ptr os) { + m_HasColors = false; m_Destination = eLogStream; m_LogStream = os; } #ifndef _WIN32 void Log::SendTo(const char *name, int facility) { + m_HasColors = false; m_Destination = eLogSyslog; m_LogStream = nullptr; openlog(name, LOG_CONS | LOG_PID, facility); diff --git a/Log.h b/Log.h index 79bbeb3f..a6fc2222 100644 --- a/Log.h +++ b/Log.h @@ -40,17 +40,6 @@ enum LogType { #endif }; -#ifdef _WIN32 - const char LOG_COLOR_ERROR[] = ""; - const char LOG_COLOR_WARNING[] = ""; - const char LOG_COLOR_RESET[] = ""; -#else - const char LOG_COLOR_ERROR[] = "\033[1;31m"; - const char LOG_COLOR_WARNING[] = "\033[1;33m"; - const char LOG_COLOR_RESET[] = "\033[0m"; -#endif - - namespace i2p { namespace log { @@ -68,6 +57,7 @@ namespace log { char m_LastDateTime[64]; i2p::util::Queue > m_Queue; volatile bool m_IsReady; + bool m_HasColors; mutable std::mutex m_OutputLock; private: @@ -152,13 +142,13 @@ namespace log { std::string text; /**< message text as single string */ LogLevel level; /**< message level */ std::thread::id tid; /**< id of thread that generated message */ - + LogMsg (LogLevel lvl, std::time_t ts, const std::string & txt): timestamp(ts), text(txt), level(lvl) {}; }; Log & Logger(); } // log -} // i2p +} /** internal usage only -- folding args array to single string */ template @@ -190,15 +180,8 @@ void LogPrint (LogLevel level, TArgs&&... args) noexcept // fold message to single string std::stringstream ss(""); - if(level == eLogError) // if log level is ERROR color log message red - ss << LOG_COLOR_ERROR; - else if (level == eLogWarning) // if log level is WARN color log message yellow - ss << LOG_COLOR_WARNING; LogPrint (ss, std::forward(args)...); - // reset color - ss << LOG_COLOR_RESET; - auto msg = std::make_shared(level, std::time(nullptr), ss.str()); msg->tid = std::this_thread::get_id(); log.Append(msg); diff --git a/Makefile b/Makefile index 5cb32004..7dcecb26 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ ARLIB := libi2pd.a SHLIB_CLIENT := libi2pdclient.so ARLIB_CLIENT := libi2pdclient.a I2PD := i2pd -GREP := fgrep +GREP := grep DEPS := obj/make.dep include filelist.mk @@ -14,6 +14,11 @@ USE_STATIC := no USE_MESHNET := no USE_UPNP := no +ifeq ($(WEBSOCKETS),1) + NEEDED_CXXFLAGS += -DWITH_EVENTS + DAEMON_SRC += Websocket.cpp +endif + ifeq ($(UNAME),Darwin) DAEMON_SRC += DaemonLinux.cpp ifeq ($(HOMEBREW),1) @@ -89,10 +94,15 @@ strip: $(I2PD) $(SHLIB_CLIENT) $(SHLIB) strip $^ LATEST_TAG=$(shell git describe --tags --abbrev=0 openssl) +BRANCH=$(shell git branch --no-color | cut -c 3-) dist: git archive --format=tar.gz -9 --worktree-attributes \ --prefix=i2pd_$(LATEST_TAG)/ $(LATEST_TAG) -o i2pd_$(LATEST_TAG).tar.gz +last-dist: + git archive --format=tar.gz -9 --worktree-attributes \ + --prefix=i2pd_$(LATEST_TAG)/ $(BRANCH) -o ../i2pd_$(LATEST_TAG).orig.tar.gz + doxygen: doxygen -s docs/Doxyfile diff --git a/Makefile.linux b/Makefile.linux index ddff76a7..28081c81 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -39,7 +39,7 @@ ifeq ($(USE_STATIC),yes) LDLIBS += $(LIBDIR)/libssl.a LDLIBS += $(LIBDIR)/libcrypto.a LDLIBS += $(LIBDIR)/libz.a - LDLIBS += -lpthread -static-libstdc++ -static-libgcc -lrt + LDLIBS += -lpthread -static-libstdc++ -static-libgcc -lrt -ldl USE_AESNI := no else LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread @@ -55,7 +55,7 @@ IS_64 := $(shell $(CXX) -dumpmachine 2>&1 | $(GREP) -c "64") ifeq ($(USE_AESNI),yes) ifeq ($(IS_64),1) #check if AES-NI is supported by CPU -ifneq ($(shell grep -c aes /proc/cpuinfo),0) +ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0) CPU_FLAGS = -maes -DAESNI endif endif diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 20dc9ab0..f9116e3d 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -11,6 +11,9 @@ #include "Transports.h" #include "NetDb.h" #include "NTCPSession.h" +#ifdef WITH_EVENTS +#include "Event.h" +#endif using namespace i2p::crypto; @@ -604,7 +607,12 @@ namespace transport if (!memcmp (m_NextMessage->buf + m_NextMessageOffset - 4, checksum, 4)) { if (!m_NextMessage->IsExpired ()) + { +#ifdef WITH_EVENTS + EmitEvent({{"type", "transport.recvmsg"} , {"ident", GetIdentHashBase64()}, {"number", "1"}}); +#endif m_Handler.PutNextMessage (m_NextMessage); + } else LogPrint (eLogInfo, "NTCP: message expired"); } diff --git a/NetDb.cpp b/NetDb.cpp index 2c9c4395..dbfa4bcb 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -126,10 +126,8 @@ namespace data i2p::context.CleanupDestination (); lastDestinationCleanup = ts; } - // if we're in hidden mode don't publish or explore - // if (m_HiddenMode) continue; - - if (ts - lastPublish >= NETDB_PUBLISH_INTERVAL) // publish + + if (ts - lastPublish >= NETDB_PUBLISH_INTERVAL && !m_HiddenMode) // publish { Publish (); lastPublish = ts; @@ -147,8 +145,9 @@ namespace data numRouters = 800/numRouters; if (numRouters < 1) numRouters = 1; if (numRouters > 9) numRouters = 9; - m_Requests.ManageRequests (); - Explore (numRouters); + m_Requests.ManageRequests (); + if(!m_HiddenMode) + Explore (numRouters); lastExploratory = ts; } } diff --git a/RouterContext.cpp b/RouterContext.cpp index b4bbefb6..6e0057fe 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -1,5 +1,4 @@ #include -#include #include "Config.h" #include "Crypto.h" #include "Timestamp.h" @@ -77,7 +76,6 @@ namespace i2p } routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC - i2p::config::GetOption("netid", m_NetID); routerInfo.SetProperty ("netId", std::to_string (m_NetID)); routerInfo.SetProperty ("router.version", I2P_VERSION); routerInfo.CreateBuffer (m_Keys); @@ -358,8 +356,8 @@ namespace i2p if (m_IsFloodfill) { // update routers and leasesets - m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_LEASESETS, boost::lexical_cast(i2p::data::netdb.GetNumLeaseSets ())); - m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_ROUTERS, boost::lexical_cast(i2p::data::netdb.GetNumRouters ())); + m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_LEASESETS, std::to_string(i2p::data::netdb.GetNumLeaseSets ())); + m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_ROUTERS, std::to_string(i2p::data::netdb.GetNumRouters ())); UpdateRouterInfo (); } } diff --git a/SAM.cpp b/SAM.cpp index 2864cd6f..84f8dbf6 100644 --- a/SAM.cpp +++ b/SAM.cpp @@ -3,12 +3,12 @@ #ifdef _MSC_VER #include #endif -#include #include "Base.h" #include "Identity.h" #include "Log.h" #include "Destination.h" #include "ClientContext.h" +#include "util.h" #include "SAM.h" namespace i2p @@ -420,7 +420,7 @@ namespace client LogPrint (eLogDebug, "SAM: datagram send: ", buf, " ", len); std::map params; ExtractParams (buf, params); - size_t size = boost::lexical_cast(params[SAM_PARAM_SIZE]), offset = data - buf; + size_t size = std::stoi(params[SAM_PARAM_SIZE]), offset = data - buf; if (offset + size <= len) { if (m_Session) @@ -587,10 +587,28 @@ namespace client void SAMSocket::I2PReceive () { if (m_Stream) - m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE), - std::bind (&SAMSocket::HandleI2PReceive, shared_from_this (), - std::placeholders::_1, std::placeholders::_2), - SAM_SOCKET_CONNECTION_MAX_IDLE); + { + if (m_Stream->GetStatus () == i2p::stream::eStreamStatusNew || + m_Stream->GetStatus () == i2p::stream::eStreamStatusOpen) // regular + { + m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE), + std::bind (&SAMSocket::HandleI2PReceive, shared_from_this (), + std::placeholders::_1, std::placeholders::_2), + SAM_SOCKET_CONNECTION_MAX_IDLE); + } + else // closed by peer + { + // get remaning data + auto len = m_Stream->ReadSome (m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE); + if (len > 0) // still some data + { + boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, len), + std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1)); + } + else // no more data + Terminate (); + } + } } void SAMSocket::HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -599,6 +617,14 @@ namespace client { LogPrint (eLogError, "SAM: stream read error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) + { + if (bytes_transferred > 0) + boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred), + std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1)); // postpone termination + else + Terminate (); + } + else Terminate (); } else @@ -793,7 +819,7 @@ namespace client auto it = params->find (SAM_PARAM_SIGNATURE_TYPE); if (it != params->end ()) // TODO: extract string values - signatureType = boost::lexical_cast (it->second); + signatureType = std::stoi(it->second); } localDestination = i2p::client::context.CreateNewLocalDestination (true, signatureType, params); } diff --git a/SOCKS.cpp b/SOCKS.cpp index 9d85963b..ef6bd73f 100644 --- a/SOCKS.cpp +++ b/SOCKS.cpp @@ -10,6 +10,7 @@ #include "I2PEndian.h" #include "I2PTunnel.h" #include "I2PService.h" +#include "util.h" namespace i2p { @@ -638,7 +639,7 @@ namespace proxy { LogPrint(eLogInfo, "SOCKS: forwarding to upstream"); EnterState(UPSTREAM_RESOLVE); - boost::asio::ip::tcp::resolver::query q(m_UpstreamProxyAddress,boost::lexical_cast(m_UpstreamProxyPort) ); + boost::asio::ip::tcp::resolver::query q(m_UpstreamProxyAddress, std::to_string(m_UpstreamProxyPort)); m_proxy_resolver.async_resolve(q, std::bind(&SOCKSHandler::HandleUpstreamResolved, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } diff --git a/SSUData.cpp b/SSUData.cpp index e5abfd54..ad38cf25 100644 --- a/SSUData.cpp +++ b/SSUData.cpp @@ -5,6 +5,9 @@ #include "NetDb.h" #include "SSU.h" #include "SSUData.h" +#ifdef WITH_EVENTS +#include "Event.h" +#endif namespace i2p { @@ -234,8 +237,13 @@ namespace transport { m_ReceivedMessages.insert (msgID); m_LastMessageReceivedTime = i2p::util::GetSecondsSinceEpoch (); - if (!msg->IsExpired ()) + if (!msg->IsExpired ()) + { +#ifdef WITH_EVENTS + EmitEvent({{"type", "transport.recvmsg"} , {"ident", m_Session.GetIdentHashBase64()}, {"number", "1"}}); +#endif m_Handler.PutNextMessage (msg); + } else LogPrint (eLogDebug, "SSU: message expired"); } diff --git a/SSUSession.cpp b/SSUSession.cpp index 5cd59164..9f855241 100644 --- a/SSUSession.cpp +++ b/SSUSession.cpp @@ -944,7 +944,7 @@ namespace transport // existing test case ePeerTestParticipantAlice1: { - if (m_State == eSessionStateEstablished) + if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob { LogPrint (eLogDebug, "SSU: peer test from Bob. We are Alice"); if (i2p::context.GetStatus () == eRouterStatusTesting) // still not OK @@ -953,6 +953,8 @@ namespace transport else { LogPrint (eLogDebug, "SSU: first peer test from Charlie. We are Alice"); + if (m_State == eSessionStateEstablished) + LogPrint (eLogWarning, "SSU: first peer test from Charlie through established session. We are Alice"); i2p::context.SetStatus (eRouterStatusOK); m_Server.UpdatePeerTest (nonce, ePeerTestParticipantAlice2); SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, true, false); // to Charlie @@ -961,7 +963,7 @@ namespace transport } case ePeerTestParticipantAlice2: { - if (m_State == eSessionStateEstablished) + if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob LogPrint (eLogDebug, "SSU: peer test from Bob. We are Alice"); else { diff --git a/Signature.h b/Signature.h index 5934f8d2..df9d8d33 100644 --- a/Signature.h +++ b/Signature.h @@ -43,7 +43,7 @@ namespace crypto DSAVerifier (const uint8_t * signingKey) { m_PublicKey = CreateDSA (); - m_PublicKey->pub_key = BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL); + DSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL), NULL); } ~DSAVerifier () @@ -58,8 +58,7 @@ namespace crypto SHA1 (buf, len, digest); // signature DSA_SIG * sig = DSA_SIG_new(); - sig->r = BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL); - sig->s = BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL); + DSA_SIG_set0 (sig, BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL), BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL)); // DSA verification int ret = DSA_do_verify (digest, 20, sig, m_PublicKey); DSA_SIG_free(sig); @@ -81,7 +80,7 @@ namespace crypto DSASigner (const uint8_t * signingPrivateKey) { m_PrivateKey = CreateDSA (); - m_PrivateKey->priv_key = BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL); + DSA_set0_key (m_PrivateKey, NULL, BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL)); } ~DSASigner () @@ -94,8 +93,10 @@ namespace crypto uint8_t digest[20]; SHA1 (buf, len, digest); DSA_SIG * sig = DSA_do_sign (digest, 20, m_PrivateKey); - bn2buf (sig->r, signature, DSA_SIGNATURE_LENGTH/2); - bn2buf (sig->s, signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2); + const BIGNUM * r, * s; + DSA_SIG_get0 (sig, &r, &s); + bn2buf (r, signature, DSA_SIGNATURE_LENGTH/2); + bn2buf (s, signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2); DSA_SIG_free(sig); } @@ -108,10 +109,11 @@ namespace crypto { DSA * dsa = CreateDSA (); DSA_generate_key (dsa); - bn2buf (dsa->priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH); - bn2buf (dsa->pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH); - DSA_free (dsa); - + const BIGNUM * pub_key, * priv_key; + DSA_get0_key(dsa, &pub_key, &priv_key); + bn2buf (priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH); + bn2buf (pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH); + DSA_free (dsa); } struct SHA256Hash @@ -270,8 +272,7 @@ namespace crypto { m_PublicKey = RSA_new (); memset (m_PublicKey, 0, sizeof (RSA)); - m_PublicKey->e = BN_dup (GetRSAE ()); - m_PublicKey->n = BN_bin2bn (signingKey, keyLen, NULL); + RSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, keyLen, NULL) /* n */ , BN_dup (GetRSAE ()) /* d */, NULL); } ~RSAVerifier () @@ -304,9 +305,8 @@ namespace crypto { m_PrivateKey = RSA_new (); memset (m_PrivateKey, 0, sizeof (RSA)); - m_PrivateKey->e = BN_dup (GetRSAE ()); - m_PrivateKey->n = BN_bin2bn (signingPrivateKey, keyLen, NULL); - m_PrivateKey->d = BN_bin2bn (signingPrivateKey + keyLen, keyLen, NULL); + RSA_set0_key (m_PrivateKey, BN_bin2bn (signingPrivateKey, keyLen, NULL), /* n */ + BN_dup (GetRSAE ()) /* e */, BN_bin2bn (signingPrivateKey + keyLen, keyLen, NULL) /* d */); } ~RSASigner () @@ -332,9 +332,11 @@ namespace crypto RSA * rsa = RSA_new (); BIGNUM * e = BN_dup (GetRSAE ()); // make it non-const RSA_generate_key_ex (rsa, publicKeyLen*8, e, NULL); - bn2buf (rsa->n, signingPrivateKey, publicKeyLen); - bn2buf (rsa->d, signingPrivateKey + publicKeyLen, publicKeyLen); - bn2buf (rsa->n, signingPublicKey, publicKeyLen); + const BIGNUM * n, * d, * e1; + RSA_get0_key (rsa, &n, &e1, &d); + bn2buf (n, signingPrivateKey, publicKeyLen); + bn2buf (d, signingPrivateKey + publicKeyLen, publicKeyLen); + bn2buf (n, signingPublicKey, publicKeyLen); BN_free (e); // this e is not assigned to rsa->e RSA_free (rsa); } diff --git a/Streaming.cpp b/Streaming.cpp index 02e738c8..97cfad0a 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -637,7 +637,8 @@ namespace stream } auto ts = i2p::util::GetMillisecondsSinceEpoch (); - if (!m_CurrentRemoteLease || ts >= m_CurrentRemoteLease->endDate - i2p::data::LEASE_ENDDATE_THRESHOLD) + if (!m_CurrentRemoteLease || !m_CurrentRemoteLease->endDate || // excluded from LeaseSet + ts >= m_CurrentRemoteLease->endDate - i2p::data::LEASE_ENDDATE_THRESHOLD) UpdateCurrentRemoteLease (true); if (m_CurrentRemoteLease && ts < m_CurrentRemoteLease->endDate + i2p::data::LEASE_ENDDATE_THRESHOLD) { @@ -656,16 +657,43 @@ namespace stream m_CurrentOutboundTunnel->SendTunnelDataMsg (msgs); } else - LogPrint (eLogWarning, "Streaming: All leases are expired, sSID=", m_SendStreamID); + { + LogPrint (eLogWarning, "Streaming: Remote lease is not available, sSID=", m_SendStreamID); + if (m_RoutingSession) + m_RoutingSession->SetSharedRoutingPath (nullptr); // invalidate routing path + } } + void Stream::SendUpdatedLeaseSet () + { + if (m_RoutingSession) + { + if (m_RoutingSession->IsLeaseSetNonConfirmed ()) + { + auto ts = i2p::util::GetMillisecondsSinceEpoch (); + if (ts > m_RoutingSession->GetLeaseSetSubmissionTime () + i2p::garlic::LEASET_CONFIRMATION_TIMEOUT) + { + // LeaseSet was not confirmed, should try other tunnels + LogPrint (eLogWarning, "Streaming: LeaseSet was not confrimed in ", i2p::garlic::LEASET_CONFIRMATION_TIMEOUT, " milliseconds. Trying to resubmit"); + m_RoutingSession->SetSharedRoutingPath (nullptr); + m_CurrentOutboundTunnel = nullptr; + m_CurrentRemoteLease = nullptr; + SendQuickAck (); + } + } + else if (m_RoutingSession->IsLeaseSetUpdated ()) + { + LogPrint (eLogDebug, "Streaming: sending updated LeaseSet"); + SendQuickAck (); + } + } + } void Stream::ScheduleResend () { m_ResendTimer.cancel (); // check for invalid value - if (m_RTO <= 0) - m_RTO = 1; + if (m_RTO <= 0) m_RTO = INITIAL_RTO; m_ResendTimer.expires_from_now (boost::posix_time::milliseconds(m_RTO)); m_ResendTimer.async_wait (std::bind (&Stream::HandleResendTimer, shared_from_this (), std::placeholders::_1)); @@ -760,7 +788,10 @@ namespace stream { m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ()); if (!m_RemoteLeaseSet) + { LogPrint (eLogWarning, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " not found"); + m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // try to request for a next attempt + } } if (m_RemoteLeaseSet) { @@ -797,17 +828,22 @@ namespace stream } else { + LogPrint (eLogWarning, "Streaming: All remote leases are expired"); m_RemoteLeaseSet = nullptr; m_CurrentRemoteLease = nullptr; // we have requested expired before, no need to do it twice } } else + { + LogPrint (eLogWarning, "Streaming: Remote LeaseSet not found"); m_CurrentRemoteLease = nullptr; + } } StreamingDestination::StreamingDestination (std::shared_ptr owner, uint16_t localPort, bool gzip): m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip), + m_LastIncomingReceiveStreamID (0), m_PendingIncomingTimer (m_Owner->GetService ()), m_ConnTrackTimer(m_Owner->GetService()), m_ConnsPerMinute(DEFAULT_MAX_CONNS_PER_MIN), @@ -863,8 +899,15 @@ namespace stream { if (packet->IsSYN () && !packet->GetSeqn ()) // new incoming stream { - auto incomingStream = CreateNewIncomingStream (); uint32_t receiveStreamID = packet->GetReceiveStreamID (); + /* if (receiveStreamID == m_LastIncomingReceiveStreamID) + { + // already pending + LogPrint(eLogWarning, "Streaming: Incoming streaming with rSID=", receiveStreamID, " already exists"); + delete packet; // drop it, because previous should be connected + return; + } */ + auto incomingStream = CreateNewIncomingStream (); incomingStream->HandleNextPacket (packet); // SYN auto ident = incomingStream->GetRemoteIdentity(); if(ident) @@ -878,6 +921,8 @@ namespace stream return; } } + m_LastIncomingReceiveStreamID = receiveStreamID; + // handle saved packets if any { auto it = m_SavedPackets.find (receiveStreamID); diff --git a/Streaming.h b/Streaming.h index efa4d69e..e4a1562c 100644 --- a/Streaming.h +++ b/Streaming.h @@ -51,6 +51,7 @@ namespace stream const int INITIAL_RTO = 9000; // in milliseconds const size_t MAX_PENDING_INCOMING_BACKLOG = 128; const int PENDING_INCOMING_TIMEOUT = 10; // in seconds + const int MAX_RECEIVE_TIMEOUT = 30; // in seconds /** i2cp option for limiting inbound stremaing connections */ const char I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN[] = "maxconns"; @@ -161,6 +162,7 @@ namespace stream void SendClose (); bool SendPacket (Packet * packet); void SendPackets (const std::vector& packets); + void SendUpdatedLeaseSet (); void SavePacket (Packet * packet); void ProcessPacket (Packet * packet); @@ -170,7 +172,7 @@ namespace stream void UpdateCurrentRemoteLease (bool expired = false); template - void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler); + void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler, int remainingTimeout); void ScheduleResend (); void HandleResendTimer (const boost::system::error_code& ecode); @@ -251,6 +253,7 @@ namespace stream std::mutex m_StreamsMutex; std::map > m_Streams; // sendStreamID->stream Acceptor m_Acceptor; + uint32_t m_LastIncomingReceiveStreamID; std::list > m_PendingIncomingStreams; boost::asio::deadline_timer m_PendingIncomingTimer; std::map > m_SavedPackets; // receiveStreamID->packets, arrived before SYN @@ -282,18 +285,19 @@ namespace stream m_Service.post ([=](void) { if (!m_ReceiveQueue.empty () || m_Status == eStreamStatusReset) - s->HandleReceiveTimer (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), buffer, handler); + s->HandleReceiveTimer (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), buffer, handler, 0); else { - s->m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(timeout)); + int t = (timeout > MAX_RECEIVE_TIMEOUT) ? MAX_RECEIVE_TIMEOUT : timeout; + s->m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(t)); s->m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode) - { s->HandleReceiveTimer (ecode, buffer, handler); }); + { s->HandleReceiveTimer (ecode, buffer, handler, timeout - t); }); } }); } template - void Stream::HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler) + void Stream::HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler, int remainingTimeout) { size_t received = ConcatenatePackets (boost::asio::buffer_cast(buffer), boost::asio::buffer_size(buffer)); if (received > 0) @@ -307,8 +311,17 @@ namespace stream handler (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), 0); } else + { // timeout expired - handler (boost::asio::error::make_error_code (boost::asio::error::timed_out), received); + if (remainingTimeout <= 0) + handler (boost::asio::error::make_error_code (boost::asio::error::timed_out), received); + else + { + // itermediate iterrupt + SendUpdatedLeaseSet (); // send our leaseset if applicable + AsyncReceive (buffer, handler, remainingTimeout); + } + } } } } diff --git a/Timestamp.cpp b/Timestamp.cpp index fbe51ea1..6079c881 100644 --- a/Timestamp.cpp +++ b/Timestamp.cpp @@ -1,6 +1,7 @@ #include #include #include +#include "Log.h" #include "I2PEndian.h" #include "Timestamp.h" @@ -8,7 +9,7 @@ namespace i2p { namespace util { - std::chrono::system_clock::duration g_TimeOffset = std::chrono::system_clock::duration::zero (); + static int64_t g_TimeOffset = 0; // in seconds void SyncTimeWithNTP (const std::string& address) { @@ -23,25 +24,34 @@ namespace util socket.open (boost::asio::ip::udp::v4 (), ec); if (!ec) { - uint8_t request[48];// 48 bytes NTP request - memset (request, 0, 48); - request[0] = 0x80; // client mode, version 0 - uint8_t * response = new uint8_t[1500]; // MTU + uint8_t buf[48];// 48 bytes NTP request/response + memset (buf, 0, 48); + htobe32buf (buf, (3 << 27) | (3 << 24)); // RFC 4330 size_t len = 0; try { - socket.send_to (boost::asio::buffer (request, 48), ep); - len = socket.receive_from (boost::asio::buffer (response, 1500), ep); + socket.send_to (boost::asio::buffer (buf, 48), ep); + int i = 0; + while (!socket.available() && i < 10) // 10 seconds max + { + std::this_thread::sleep_for (std::chrono::seconds(1)); + i++; + } + if (socket.available ()) + len = socket.receive_from (boost::asio::buffer (buf, 48), ep); } catch (std::exception& e) { + LogPrint (eLogError, "NTP error: ", e.what ()); } if (len >= 8) { - uint32_t ts = bufbe32toh (response + 4); + auto ourTs = GetSecondsSinceEpoch (); + uint32_t ts = bufbe32toh (buf + 32); if (ts > 2208988800U) ts -= 2208988800U; // 1/1/1970 from 1/1/1900 + g_TimeOffset = ts - ourTs; + LogPrint (eLogInfo, address, " time offset from system time is ", g_TimeOffset, " seconds"); } - delete[] response; } } } diff --git a/Timestamp.h b/Timestamp.h index 2e61d856..d48cb164 100644 --- a/Timestamp.h +++ b/Timestamp.h @@ -8,8 +8,6 @@ namespace i2p { namespace util { - extern std::chrono::system_clock::duration g_TimeOffset; - inline uint64_t GetMillisecondsSinceEpoch () { return std::chrono::duration_cast( diff --git a/TransportSession.h b/TransportSession.h index 9c97d02e..5950fb06 100644 --- a/TransportSession.h +++ b/TransportSession.h @@ -64,6 +64,8 @@ namespace transport virtual ~TransportSession () {}; virtual void Done () = 0; + + std::string GetIdentHashBase64() const { return m_RemoteIdentity ? m_RemoteIdentity->GetIdentHash().ToBase64() : ""; } std::shared_ptr GetRemoteIdentity () { return m_RemoteIdentity; }; void SetRemoteIdentity (std::shared_ptr ident) { m_RemoteIdentity = ident; }; diff --git a/Transports.cpp b/Transports.cpp index a29cac15..913106ae 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -4,6 +4,11 @@ #include "I2NPProtocol.h" #include "NetDb.h" #include "Transports.h" +#include "Config.h" +#ifdef WITH_EVENTS +#include "Event.h" +#include "util.h" +#endif using namespace i2p::data; @@ -229,6 +234,9 @@ namespace transport void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector >& msgs) { +#ifdef WITH_EVENTS + EmitEvent({{"type" , "transport.sendmsg"}, {"ident", ident.ToBase64()}, {"number", std::to_string(msgs.size())}}); +#endif m_Service.post (std::bind (&Transports::PostMessages, this, ident, msgs)); } @@ -240,7 +248,8 @@ namespace transport for (auto& it: msgs) i2p::HandleI2NPMessage (it); return; - } + } + if(RoutesRestricted() && ! IsRestrictedPeer(ident)) return; auto it = m_Peers.find (ident); if (it == m_Peers.end ()) { @@ -494,12 +503,17 @@ namespace transport void Transports::DetectExternalIP () { + if (RoutesRestricted()) + { + LogPrint(eLogInfo, "Transports: restricted routes enabled, not detecting ip"); + i2p::context.SetStatus (eRouterStatusOK); + return; + } if (m_SSUServer) { -#ifndef MESHNET - i2p::context.SetStatus (eRouterStatusTesting); -#endif - + bool nat; i2p::config::GetOption("nat", nat); + if (nat) + i2p::context.SetStatus (eRouterStatusTesting); for (int i = 0; i < 5; i++) { auto router = i2p::data::netdb.GetRandomPeerTestRouter (); @@ -520,8 +534,10 @@ namespace transport void Transports::PeerTest () { + if (RoutesRestricted()) return; if (m_SSUServer) { + bool statusChanged = false; for (int i = 0; i < 5; i++) { @@ -559,6 +575,9 @@ namespace transport auto it = m_Peers.find (ident); if (it != m_Peers.end ()) { +#ifdef WITH_EVENTS + EmitEvent({{"type" , "transport.connected"}, {"ident", ident.ToBase64()}, {"inbound", "false"}}); +#endif bool sendDatabaseStore = true; if (it->second.delayedMessages.size () > 0) { @@ -578,20 +597,32 @@ namespace transport } else // incoming connection { + if(RoutesRestricted() && ! IsRestrictedPeer(ident)) { + // not trusted + LogPrint(eLogWarning, "Transports: closing untrusted inbound connection from ", ident.ToBase64()); + session->Done(); + return; + } +#ifdef WITH_EVENTS + EmitEvent({{"type" , "transport.connected"}, {"ident", ident.ToBase64()}, {"inbound", "true"}}); +#endif session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore std::unique_lock l(m_PeersMutex); m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch (), {} })); } - }); + }); } void Transports::PeerDisconnected (std::shared_ptr session) { m_Service.post([session, this]() - { + { auto remoteIdentity = session->GetRemoteIdentity (); if (!remoteIdentity) return; auto ident = remoteIdentity->GetIdentHash (); +#ifdef WITH_EVENTS + EmitEvent({{"type" , "transport.disconnected"}, {"ident", ident.ToBase64()}}); +#endif auto it = m_Peers.find (ident); if (it != m_Peers.end ()) { @@ -655,30 +686,79 @@ namespace transport std::advance (it, rand () % m_Peers.size ()); return it != m_Peers.end () ? it->second.router : nullptr; } - void Transports::RestrictRoutes(std::vector families) - { - std::lock_guard lock(m_FamilyMutex); - m_TrustedFamilies.clear(); - for ( const auto& fam : families ) - m_TrustedFamilies.push_back(fam); - } - - bool Transports::RoutesRestricted() const { - std::lock_guard lock(m_FamilyMutex); - return m_TrustedFamilies.size() > 0; - } - - /** XXX: if routes are not restricted this dies */ - std::shared_ptr Transports::GetRestrictedPeer() const { - std::string fam; - { - std::lock_guard lock(m_FamilyMutex); - // TODO: random family (?) - fam = m_TrustedFamilies[0]; - } - boost::to_lower(fam); - return i2p::data::netdb.GetRandomRouterInFamily(fam); - } + void Transports::RestrictRoutesToFamilies(std::set families) + { + std::lock_guard lock(m_FamilyMutex); + m_TrustedFamilies.clear(); + for ( const auto& fam : families ) + m_TrustedFamilies.push_back(fam); + } + + void Transports::RestrictRoutesToRouters(std::set routers) + { + std::unique_lock lock(m_TrustedRoutersMutex); + m_TrustedRouters.clear(); + for (const auto & ri : routers ) + m_TrustedRouters.push_back(ri); + } + + bool Transports::RoutesRestricted() const { + std::unique_lock famlock(m_FamilyMutex); + std::unique_lock routerslock(m_TrustedRoutersMutex); + return m_TrustedFamilies.size() > 0 || m_TrustedRouters.size() > 0; + } + + /** XXX: if routes are not restricted this dies */ + std::shared_ptr Transports::GetRestrictedPeer() const + { + { + std::lock_guard l(m_FamilyMutex); + std::string fam; + auto sz = m_TrustedFamilies.size(); + if(sz > 1) + { + auto it = m_TrustedFamilies.begin (); + std::advance(it, rand() % sz); + fam = *it; + boost::to_lower(fam); + } + else if (sz == 1) + { + fam = m_TrustedFamilies[0]; + } + if (fam.size()) + return i2p::data::netdb.GetRandomRouterInFamily(fam); + } + { + std::unique_lock l(m_TrustedRoutersMutex); + auto sz = m_TrustedRouters.size(); + if (sz) + { + if(sz == 1) + return i2p::data::netdb.FindRouter(m_TrustedRouters[0]); + auto it = m_TrustedRouters.begin(); + std::advance(it, rand() % sz); + return i2p::data::netdb.FindRouter(*it); + } + } + return nullptr; + } + + bool Transports::IsRestrictedPeer(const i2p::data::IdentHash & ih) const + { + { + std::unique_lock l(m_TrustedRoutersMutex); + for (const auto & r : m_TrustedRouters ) + if ( r == ih ) return true; + } + { + std::unique_lock l(m_FamilyMutex); + auto ri = i2p::data::netdb.FindRouter(ih); + for (const auto & fam : m_TrustedFamilies) + if(ri->IsFamily(fam)) return true; + } + return false; + } } } diff --git a/Transports.h b/Transports.h index 81063916..9ecfd719 100644 --- a/Transports.h +++ b/Transports.h @@ -110,7 +110,11 @@ namespace transport /** do we want to use restricted routes? */ bool RoutesRestricted() const; /** restrict routes to use only these router families for first hops */ - void RestrictRoutes(std::vector families); + void RestrictRoutesToFamilies(std::set families); + /** restrict routes to use only these routers for first hops */ + void RestrictRoutesToRouters(std::set routers); + + bool IsRestrictedPeer(const i2p::data::IdentHash & ident) const; void PeerTest (); @@ -157,6 +161,10 @@ namespace transport /** which router families to trust for first hops */ std::vector m_TrustedFamilies; mutable std::mutex m_FamilyMutex; + + /** which routers for first hop to trust */ + std::vector m_TrustedRouters; + mutable std::mutex m_TrustedRoutersMutex; public: diff --git a/Tunnel.cpp b/Tunnel.cpp index 7d2e6735..9552684e 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -11,6 +11,10 @@ #include "Transports.h" #include "NetDb.h" #include "Tunnel.h" +#include "TunnelPool.h" +#ifdef WITH_EVENTS +#include "Event.h" +#endif namespace i2p { @@ -29,12 +33,14 @@ namespace tunnel void Tunnel::Build (uint32_t replyMsgID, std::shared_ptr outboundTunnel) { +#ifdef WITH_EVENTS + std::string peers = i2p::context.GetIdentity()->GetIdentHash().ToBase64(); +#endif auto numHops = m_Config->GetNumHops (); int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : numHops; auto msg = NewI2NPShortMessage (); *msg->GetPayload () = numRecords; msg->len += numRecords*TUNNEL_BUILD_RECORD_SIZE + 1; - // shuffle records std::vector recordIndicies; for (int i = 0; i < numRecords; i++) recordIndicies.push_back(i); @@ -55,8 +61,14 @@ namespace tunnel hop->CreateBuildRequestRecord (records + idx*TUNNEL_BUILD_RECORD_SIZE, msgID); hop->recordIndex = idx; i++; +#ifdef WITH_EVENTS + peers += ":" + hop->ident->GetIdentHash().ToBase64(); +#endif hop = hop->next; } +#ifdef WITH_EVENTS + EmitTunnelEvent("tunnel.build", this, peers); +#endif // fill up fake records with random data for (int i = numHops; i < numRecords; i++) { @@ -182,12 +194,22 @@ namespace tunnel return ret; } + void Tunnel::SetState(TunnelState state) + { + m_State = state; +#ifdef WITH_EVENTS + EmitTunnelEvent("tunnel.state", this, state); +#endif + } + + void Tunnel::PrintHops (std::stringstream& s) const { - for (auto& it: m_Hops) + // hops are in inverted order, we must print in direct order + for (auto it = m_Hops.rbegin (); it != m_Hops.rend (); it++) { s << " ⇒ "; - s << i2p::data::GetIdentHashAbbreviation (it->ident->GetIdentHash ()); + s << i2p::data::GetIdentHashAbbreviation ((*it)->ident->GetIdentHash ()); } } @@ -581,6 +603,9 @@ namespace tunnel hop = hop->next; } } +#ifdef WITH_EVENTS + EmitTunnelEvent("tunnel.state", tunnel.get(), eTunnelStateBuildFailed); +#endif // delete it = pendingTunnels.erase (it); m_NumFailedTunnelCreations++; @@ -590,6 +615,9 @@ namespace tunnel break; case eTunnelStateBuildFailed: LogPrint (eLogDebug, "Tunnel: pending build request ", it->first, " failed, deleted"); +#ifdef WITH_EVENTS + EmitTunnelEvent("tunnel.state", tunnel.get(), eTunnelStateBuildFailed); +#endif it = pendingTunnels.erase (it); m_NumFailedTunnelCreations++; break; @@ -640,11 +668,13 @@ namespace tunnel } } - if (m_OutboundTunnels.size () < 5) + if (m_OutboundTunnels.size () < 3) { // trying to create one more oubound tunnel auto inboundTunnel = GetNextInboundTunnel (); - auto router = i2p::data::netdb.GetRandomRouter (); + auto router = i2p::transport::transports.RoutesRestricted() ? + i2p::transport::transports.GetRestrictedPeer() : + i2p::data::netdb.GetRandomRouter (); if (!inboundTunnel || !router) return; LogPrint (eLogDebug, "Tunnel: creating one hop outbound tunnel"); CreateTunnel ( @@ -697,16 +727,18 @@ namespace tunnel CreateZeroHopsOutboundTunnel (); if (!m_ExploratoryPool) { - m_ExploratoryPool = CreateTunnelPool (2, 2, 5, 5); // 2-hop exploratory, 5 tunnels + m_ExploratoryPool = CreateTunnelPool (2, 2, 3, 3); // 2-hop exploratory, 3 tunnels m_ExploratoryPool->SetLocalDestination (i2p::context.GetSharedDestination ()); } return; } - if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 5) + if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 3) { // trying to create one more inbound tunnel - auto router = i2p::data::netdb.GetRandomRouter (); + auto router = i2p::transport::transports.RoutesRestricted() ? + i2p::transport::transports.GetRestrictedPeer() : + i2p::data::netdb.GetRandomRouter (); if (!router) { LogPrint (eLogWarning, "Tunnel: can't find any router, skip creating tunnel"); return; @@ -771,7 +803,7 @@ namespace tunnel std::shared_ptr Tunnels::CreateInboundTunnel (std::shared_ptr config, std::shared_ptr outboundTunnel) { - if (config) + if (config) return CreateTunnel(config, outboundTunnel); else return CreateZeroHopsInboundTunnel (); diff --git a/Tunnel.h b/Tunnel.h index 5bc8b195..54917d49 100644 --- a/Tunnel.h +++ b/Tunnel.h @@ -19,11 +19,49 @@ #include "TunnelGateway.h" #include "TunnelBase.h" #include "I2NPProtocol.h" +#include "Event.h" namespace i2p { namespace tunnel -{ +{ + + template + static void EmitTunnelEvent(const std::string & ev, const TunnelT & t) + { +#ifdef WITH_EVENTS + EmitEvent({{"type", ev}, {"tid", std::to_string(t->GetTunnelID())}}); +#else + (void) ev; + (void) t; +#endif + } + + template + static void EmitTunnelEvent(const std::string & ev, TunnelT * t, const T & val) + { +#ifdef WITH_EVENTS + EmitEvent({{"type", ev}, {"tid", std::to_string(t->GetTunnelID())}, {"value", std::to_string(val)}, {"inbound", std::to_string(t->IsInbound())}}); +#else + (void) ev; + (void) t; + (void) val; +#endif + } + + template + static void EmitTunnelEvent(const std::string & ev, TunnelT * t, const std::string & val) + { +#ifdef WITH_EVENTS + EmitEvent({{"type", ev}, {"tid", std::to_string(t->GetTunnelID())}, {"value", val}, {"inbound", std::to_string(t->IsInbound())}}); +#else + (void) ev; + (void) t; + (void) val; +#endif + } + + const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute const int TUNNEL_RECREATION_THRESHOLD = 90; // 1.5 minutes @@ -40,7 +78,7 @@ namespace tunnel eTunnelStateFailed, eTunnelStateExpiring }; - + class OutboundTunnel; class InboundTunnel; class Tunnel: public TunnelBase @@ -62,12 +100,13 @@ namespace tunnel std::vector > GetPeers () const; std::vector > GetInvertedPeers () const; TunnelState GetState () const { return m_State; }; - void SetState (TunnelState state) { m_State = state; }; + void SetState (TunnelState state); bool IsEstablished () const { return m_State == eTunnelStateEstablished; }; bool IsFailed () const { return m_State == eTunnelStateFailed; }; bool IsRecreated () const { return m_IsRecreated; }; void SetIsRecreated () { m_IsRecreated = true; }; - + virtual bool IsInbound() const = 0; + std::shared_ptr GetTunnelPool () const { return m_Pool; }; void SetTunnelPool (std::shared_ptr pool) { m_Pool = pool; }; @@ -107,6 +146,8 @@ namespace tunnel // implements TunnelBase void HandleTunnelDataMsg (std::shared_ptr tunnelMsg); + + bool IsInbound() const { return false; } private: @@ -123,7 +164,7 @@ namespace tunnel void HandleTunnelDataMsg (std::shared_ptr msg); virtual size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }; void Print (std::stringstream& s) const; - + bool IsInbound() const { return true; } private: TunnelEndpoint m_Endpoint; diff --git a/TunnelBase.h b/TunnelBase.h index bec06400..1b4e1e1f 100644 --- a/TunnelBase.h +++ b/TunnelBase.h @@ -48,7 +48,7 @@ namespace tunnel uint32_t GetCreationTime () const { return m_CreationTime; }; void SetCreationTime (uint32_t t) { m_CreationTime = t; }; - + private: uint32_t m_TunnelID, m_NextTunnelID; diff --git a/TunnelPool.cpp b/TunnelPool.cpp index 35272f2c..56d72bfb 100644 --- a/TunnelPool.cpp +++ b/TunnelPool.cpp @@ -7,12 +7,18 @@ #include "Garlic.h" #include "Transports.h" #include "Log.h" +#include "Tunnel.h" #include "TunnelPool.h" +#include "Destination.h" +#ifdef WITH_EVENTS +#include "Event.h" +#endif namespace i2p { namespace tunnel { + TunnelPool::TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels): m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops), m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_IsActive (true), @@ -67,6 +73,9 @@ namespace tunnel { if (!m_IsActive) return; { +#ifdef WITH_EVENTS + EmitTunnelEvent("tunnels.created", createdTunnel); +#endif std::unique_lock l(m_InboundTunnelsMutex); m_InboundTunnels.insert (createdTunnel); } @@ -77,7 +86,10 @@ namespace tunnel void TunnelPool::TunnelExpired (std::shared_ptr expiredTunnel) { if (expiredTunnel) - { + { +#ifdef WITH_EVENTS + EmitTunnelEvent("tunnels.expired", expiredTunnel); +#endif expiredTunnel->SetTunnelPool (nullptr); for (auto& it: m_Tests) if (it.second.second == expiredTunnel) it.second.second = nullptr; @@ -91,6 +103,9 @@ namespace tunnel { if (!m_IsActive) return; { +#ifdef WITH_EVENTS + EmitTunnelEvent("tunnels.created", createdTunnel); +#endif std::unique_lock l(m_OutboundTunnelsMutex); m_OutboundTunnels.insert (createdTunnel); } @@ -101,6 +116,9 @@ namespace tunnel { if (expiredTunnel) { +#ifdef WITH_EVENTS + EmitTunnelEvent("tunnels.expired", expiredTunnel); +#endif expiredTunnel->SetTunnelPool (nullptr); for (auto& it: m_Tests) if (it.second.first == expiredTunnel) it.second.first = nullptr; diff --git a/Websocket.cpp b/Websocket.cpp new file mode 100644 index 00000000..0de44efe --- /dev/null +++ b/Websocket.cpp @@ -0,0 +1,137 @@ +#include "Websocket.h" +#include "Log.h" + +#include + +#include +#include +#include +#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) +#if !GCC47_BOOST149 +#include +#endif + +#include + +namespace i2p +{ + namespace event + { + + typedef websocketpp::server ServerImpl; + typedef websocketpp::connection_hdl ServerConn; + + class WebsocketServerImpl : public EventListener + { + private: + typedef ServerImpl::message_ptr MessagePtr; + public: + + WebsocketServerImpl(const std::string & addr, int port) : m_run(false), m_thread(nullptr) + { + m_server.init_asio(); + m_server.set_open_handler(std::bind(&WebsocketServerImpl::ConnOpened, this, std::placeholders::_1)); + m_server.set_close_handler(std::bind(&WebsocketServerImpl::ConnClosed, this, std::placeholders::_1)); + m_server.set_message_handler(std::bind(&WebsocketServerImpl::OnConnMessage, this, std::placeholders::_1, std::placeholders::_2)); + + m_server.listen(boost::asio::ip::address::from_string(addr), port); + } + + ~WebsocketServerImpl() + { + } + + void Start() { + m_run = true; + m_server.start_accept(); + m_thread = new std::thread([&] () { + while(m_run) { + try { + m_server.run(); + } catch (std::exception & e ) { + LogPrint(eLogError, "Websocket server: ", e.what()); + } + } + }); + } + + void Stop() { + m_run = false; + m_server.stop(); + if(m_thread) { + m_thread->join(); + delete m_thread; + } + m_thread = nullptr; + } + + void ConnOpened(ServerConn c) + { + std::lock_guard lock(m_connsMutex); + m_conns.insert(c); + } + + void ConnClosed(ServerConn c) + { + std::lock_guard lock(m_connsMutex); + m_conns.erase(c); + } + + void OnConnMessage(ServerConn conn, ServerImpl::message_ptr msg) + { + (void) conn; + (void) msg; + } + + void HandleEvent(const EventType & ev) + { + std::lock_guard lock(m_connsMutex); + LogPrint(eLogDebug, "websocket event"); + boost::property_tree::ptree event; + for (const auto & item : ev) { + event.put(item.first, item.second); + } + std::ostringstream ss; + write_json(ss, event); + std::string s = ss.str(); + + ConnList::iterator it; + for (it = m_conns.begin(); it != m_conns.end(); ++it) { + ServerImpl::connection_ptr con = m_server.get_con_from_hdl(*it); + con->send(s); + } + } + + private: + typedef std::set > ConnList; + bool m_run; + std::thread * m_thread; + std::mutex m_connsMutex; + ConnList m_conns; + ServerImpl m_server; + }; + + + WebsocketServer::WebsocketServer(const std::string & addr, int port) : m_impl(new WebsocketServerImpl(addr, port)) {} + WebsocketServer::~WebsocketServer() + { + delete m_impl; + } + + + void WebsocketServer::Start() + { + m_impl->Start(); + } + + void WebsocketServer::Stop() + { + m_impl->Stop(); + } + + EventListener * WebsocketServer::ToListener() + { + return m_impl; + } + } +} diff --git a/Websocket.h b/Websocket.h new file mode 100644 index 00000000..2ddca38f --- /dev/null +++ b/Websocket.h @@ -0,0 +1,28 @@ +#ifndef WEBSOCKET_H__ +#define WEBSOCKET_H__ +#include "Event.h" +namespace i2p +{ + namespace event + { + + class WebsocketServerImpl; + + class WebsocketServer + { + public: + WebsocketServer(const std::string & addr, int port); + ~WebsocketServer(); + + void Start(); + void Stop(); + + EventListener * ToListener(); + + private: + WebsocketServerImpl * m_impl; + }; + + } +} +#endif diff --git a/android/jni/Android.mk b/android/jni/Android.mk index a31fcfb2..a3d58ce6 100755 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -58,6 +58,7 @@ LOCAL_SRC_FILES := DaemonAndroid.cpp i2pd_android.cpp \ ../../TunnelGateway.cpp \ ../../TunnelPool.cpp \ ../../Timestamp.cpp \ + ../../Event.cpp \ ../../util.cpp \ ../../i2pd.cpp ../../UPnP.cpp diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 00048942..5291a82f 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -18,6 +18,8 @@ option(WITH_GUI "Include GUI (currently MS Windows only)" ON) option(WITH_MESHNET "Build for cjdns test network" OFF) option(WITH_ADDRSANITIZER "Build with address sanitizer unix only" OFF) option(WITH_THREADSANITIZER "Build with thread sanitizer unix only" OFF) +option(WITH_I2LUA "Build for i2lua" OFF) +option(WITH_WEBSOCKETS "Build with websocket ui" OFF) # paths set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" ) @@ -58,12 +60,22 @@ set (LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/Signature.cpp" "${CMAKE_SOURCE_DIR}/Timestamp.cpp" "${CMAKE_SOURCE_DIR}/api.cpp" + "${CMAKE_SOURCE_DIR}/Event.cpp" ) +if (WITH_WEBSOCKETS) + add_definitions(-DWITH_EVENTS) + find_package(websocketpp REQUIRED) +endif () + if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR MSYS) list (APPEND LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp") endif () +if (WITH_I2LUA) + add_definitions(-DI2LUA) +endif() + add_library(libi2pd ${LIBI2PD_SRC}) set_target_properties(libi2pd PROPERTIES PREFIX "") install(TARGETS libi2pd @@ -87,6 +99,9 @@ set (CLIENT_SRC "${CMAKE_SOURCE_DIR}/I2CP.cpp" ) +if(WITH_WEBSOCKETS) + list (APPEND CLIENT_SRC "${CMAKE_SOURCE_DIR}/Websocket.cpp") +endif () add_library(i2pdclient ${CLIENT_SRC}) set (DAEMON_SRC @@ -361,6 +376,8 @@ message(STATUS " PCH : ${WITH_PCH}") message(STATUS " MESHNET : ${WITH_MESHNET}") message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}") message(STATUS " THEADSANITIZER : ${WITH_THREADSANITIZER}") +message(STATUS " I2LUA : ${WITH_I2LUA}") +message(STATUS " WEBSOCKETS : ${WITH_WEBSOCKETS}") message(STATUS "---------------------------------------") #Handle paths nicely diff --git a/contrib/debian/README b/contrib/debian/README new file mode 100644 index 00000000..077d7b96 --- /dev/null +++ b/contrib/debian/README @@ -0,0 +1,2 @@ +This forder contain systemd unit files. +To use systemd daemon control, place files from this directory to debian folder. diff --git a/contrib/debian/i2pd.service b/contrib/debian/i2pd.service new file mode 100644 index 00000000..a83b1396 --- /dev/null +++ b/contrib/debian/i2pd.service @@ -0,0 +1,25 @@ +[Unit] +Description=I2P Router written in C++ +After=network.target + +[Service] +User=i2pd +Group=i2pd +Type=forking +ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service +ExecReload=/bin/kill -HUP $MAINPID +PIDFile=/var/run/i2pd/i2pd.pid +### Uncomment, if auto restart needed +#Restart=on-failure + +### Use SIGINT for gracefull stop daemon. +# i2pd stops accepting new tunnels and waits ~10 min while old ones do not die. +KillSignal=SIGINT +TimeoutStopSec=10m + +# If you have problems with hunging i2pd, you can try enable this +#LimitNOFILE=4096 +PrivateDevices=yes + +[Install] +WantedBy=multi-user.target diff --git a/contrib/debian/i2pd.tmpfile b/contrib/debian/i2pd.tmpfile new file mode 100644 index 00000000..6cd19112 --- /dev/null +++ b/contrib/debian/i2pd.tmpfile @@ -0,0 +1,2 @@ +d /var/run/i2pd 0755 i2pd i2pd - - +d /var/log/i2pd 0755 i2pd i2pd - - diff --git a/debian/.gitignore b/debian/.gitignore new file mode 100644 index 00000000..6bc6bcf2 --- /dev/null +++ b/debian/.gitignore @@ -0,0 +1,9 @@ +files +i2pd-dbg.substvars +i2pd-dbg/ +i2pd.postinst.debhelper +i2pd.postrm.debhelper +i2pd.prerm.debhelper +i2pd.substvars +i2pd/ + diff --git a/debian/i2pd.default b/debian/i2pd.default index 1e5d5c2e..c45eff9d 100644 --- a/debian/i2pd.default +++ b/debian/i2pd.default @@ -6,3 +6,6 @@ I2PD_ENABLED="yes" # Additional options that are passed to the Daemon. # see possible switches in /usr/share/doc/i2pd/configuration.md.gz DAEMON_OPTS="" + +# If you have problems with hunging i2pd, you can try enable this +#ulimit -n 4096 diff --git a/debian/i2pd.init b/debian/i2pd.init index 32c181bb..ca403598 100644 --- a/debian/i2pd.init +++ b/debian/i2pd.init @@ -15,10 +15,10 @@ DESC=i2pd # Introduce a short description here NAME=i2pd # Introduce the short server's name here DAEMON=/usr/sbin/$NAME # Introduce the server's location here DAEMON_OPTS="" # Arguments to run the daemon with -PIDFILE=/var/run/$NAME.pid +PIDFILE=/var/run/$NAME/$NAME.pid I2PCONF=/etc/$NAME/i2pd.conf TUNCONF=/etc/$NAME/tunnels.conf -LOGFILE=/var/log/$NAME.log +LOGFILE=/var/log/$NAME/$NAME.log USER="i2pd" # Exit if the package is not installed @@ -41,9 +41,11 @@ do_start() return 2 fi + test -e /var/run/i2pd || install -m 755 -o i2pd -g i2pd -d /var/run/i2pd touch "$PIDFILE" chown -f $USER:adm "$PIDFILE" + test -e /var/log/i2pd || install -m 755 -o i2pd -g i2pd -d /var/log/i2pd touch "$LOGFILE" chown -f $USER:adm "$LOGFILE" @@ -99,7 +101,7 @@ case "$1" in status) status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? ;; - reload) + reload|force-reload) log_daemon_msg "Reloading $DESC" "$NAME" do_reload log_end_msg $? diff --git a/debian/i2pd.openrc b/debian/i2pd.openrc index 6253cfa6..2ad10bc5 100644 --- a/debian/i2pd.openrc +++ b/debian/i2pd.openrc @@ -1,7 +1,7 @@ #!/sbin/openrc-run -pidfile="/var/run/i2pd.pid" -logfile="/var/log/i2pd.log" +pidfile="/var/run/i2pd/i2pd.pid" +logfile="/var/log/i2pd/i2pd.log" mainconf="/etc/i2pd/i2pd.conf" tunconf="/etc/i2pd/tunnels.conf" @@ -32,9 +32,6 @@ start_pre() { checkpath -f -o i2pd:adm $logfile checkpath -f -o i2pd:adm $pidfile - if [ -n "$I2PD_PORT" -a "$I2PD_PORT" -gt 0 ]; then - command_args="$command_args --port=$I2PD_PORT" - fi if [ -n "$DAEMON_OPTS" ]; then command_args="$command_args $DAEMON_OPTS" fi diff --git a/debian/i2pd.upstart b/debian/i2pd.upstart index cfa80e8d..19b58958 100644 --- a/debian/i2pd.upstart +++ b/debian/i2pd.upstart @@ -4,7 +4,7 @@ start on runlevel [2345] stop on runlevel [016] or unmounting-filesystem # these can be overridden in /etc/init/i2pd.override -env LOGFILE="/var/log/i2pd.log" +env LOGFILE="/var/log/i2pd/i2pd.log" expect fork diff --git a/debian/logrotate b/debian/logrotate index 3462c696..63c44270 100644 --- a/debian/logrotate +++ b/debian/logrotate @@ -1,4 +1,4 @@ -/var/log/i2pd.log { +/var/log/i2pd/i2pd.log { rotate 6 daily missingok diff --git a/debian/patches/01-tune-build-opts.patch b/debian/patches/01-tune-build-opts.patch index 2a09b07b..fba12f4e 100644 --- a/debian/patches/01-tune-build-opts.patch +++ b/debian/patches/01-tune-build-opts.patch @@ -1,5 +1,5 @@ diff --git a/Makefile b/Makefile -index 7d04ba0..33ee184 100644 +index b6fc795..abc3ace 100644 --- a/Makefile +++ b/Makefile @@ -9,10 +9,10 @@ DEPS := obj/make.dep @@ -10,8 +10,7 @@ index 7d04ba0..33ee184 100644 +USE_AESNI := no USE_STATIC := no USE_MESHNET := no --USE_UPNP := no -+USE_UPNP := yes - - ifeq ($(UNAME),Darwin) - DAEMON_SRC += DaemonLinux.cpp + USE_UPNP := no + + ifeq ($(WEBSOCKETS),1) + NEEDED_CXXFLAGS += -DWITH_EVENTS diff --git a/debian/postinst b/debian/postinst index 1de58c1e..9c9e74ae 100755 --- a/debian/postinst +++ b/debian/postinst @@ -1,7 +1,7 @@ #!/bin/sh set -e -LOGFILE='/var/log/i2pd.log' +LOGFILE='/var/log/i2pd/i2pd.log' I2PDHOME='/var/lib/i2pd' I2PDUSER='i2pd' @@ -17,6 +17,8 @@ case "$1" in adduser --system --quiet --group --home $I2PDHOME $I2PDUSER fi + mkdir -p -m0750 /var/log/i2pd + chown -f ${I2PDUSER}:adm /var/log/i2pd touch $LOGFILE chmod 640 $LOGFILE chown -f ${I2PDUSER}:adm $LOGFILE diff --git a/debian/postrm b/debian/postrm index a188b52c..53ab15e7 100755 --- a/debian/postrm +++ b/debian/postrm @@ -2,9 +2,11 @@ set -e if [ "$1" = "purge" ]; then - rm -f /etc/default/i2pd /var/log/i2pd.log + rm -f /etc/default/i2pd rm -rf /etc/i2pd rm -rf /var/lib/i2pd + rm -rf /var/log/i2pd + rm -rf /var/run/i2pd fi #DEBHELPER# diff --git a/debian/rules b/debian/rules index 1e3535da..171a5269 100755 --- a/debian/rules +++ b/debian/rules @@ -15,3 +15,6 @@ PREFIX=/usr override_dh_strip: dh_strip --dbg-package=i2pd-dbg + +override_dh_shlibdeps: + dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info diff --git a/docs/build_notes_android.md b/docs/build_notes_android.md deleted file mode 100644 index 93b8b77e..00000000 --- a/docs/build_notes_android.md +++ /dev/null @@ -1,57 +0,0 @@ -Building on Android -=================== - -There are two versions: with QT and without QT. - -Pre-requesties --------------- - -You need to install Android SDK, NDK and QT with android support. - -- [SDK](https://developer.android.com/studio/index.html) (choose command line tools only) -- [NDK](https://developer.android.com/ndk/downloads/index.html) -- [QT](https://www.qt.io/download-open-source/)(for QT only). Choose one for your platform for android. For example QT 5.6 under Linux would be [this file](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-linux-x64-android-5.6.1-1.run ) - -You also need Java JDK and Ant. - -QT-Creator (for QT only) ------------------------- -Open QT-creator that should be installed with QT. -Go to Settings/Anndroid and specify correct paths to SDK and NDK. -If everything is correct you will see two set avaiable: -Android for armeabi-v7a (gcc, qt) and Android for x86 (gcc, qt). - -Dependencies --------------- -Take following pre-compiled binaries from PurpleI2P's repositories. -```bash -git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git -git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git -git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git -git clone https://github.com/PurpleI2P/android-ifaddrs.git -``` - - -Building the app with QT ------------------------- -- Open qt/i2pd_qt/i2pd_qt.pro in the QT-creator -- Change line MAIN_PATH = /path/to/libraries to an actual path where you put the dependancies to -- Select appropriate project (usually armeabi-v7a) and build -- You will find an .apk file in android-build/bin folder - -Building the app without QT ---------------------------- -- Change line I2PD_LIBS_PATH in android/jni/Application.mk to an actual path where you put the dependancies to -- Run 'ndk-build -j4' from andorid folder -- Create or edit file 'local.properties'. Place 'sdk.dir=' and 'ndk.dir=' -- Run 'ant clean debug' - -Creating release .apk ----------------------- -In order to create release .apk you must obtain a Java keystore file(.jks). Either you have in already, or you can generate it yourself using keytool, or from one of you existing well-know ceritificates. For example, i2pd release are signed with this [certificate](https://github.com/PurpleI2P/i2pd/blob/openssl/contrib/certificates/router/orignal_at_mail.i2p.crt). -Create file 'ant.propeties' -key.store='path to keystore file' -key.alias='alias name' -key.store.password='keystore password' -key.alias.password='alias password' -Run 'ant clean release' diff --git a/docs/build_notes_cross.md b/docs/build_notes_cross.md deleted file mode 100644 index 78d60e6a..00000000 --- a/docs/build_notes_cross.md +++ /dev/null @@ -1,75 +0,0 @@ -Cross compilation notes -======================= - -Static 64 bit windows binary on Ubuntu 15.10 (Wily Werewolf) ---------------------------------------------------------------------- - -Install cross compiler and friends -```sh -sudo apt-get install g++-mingw-w64-x86-64 -``` -Default is to use Win32 threading model which lacks std::mutex and such. So we change defaults -```sh -sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix -``` -From now on we assume we have everything in `~/dev/`. Get Boost sources unpacked into `~/dev/boost_1_60_0/` -and change directory to it. -Now add out cross compiler configuration. Warning: the following will wipe out whatever you had in there. -```sh -echo "using gcc : mingw : x86_64-w64-mingw32-g++ ;" > ~/user-config.jam -``` -Proceed with building Boost normal way, but let's define dedicated staging directory -```sh -./bootstrap.sh -./b2 toolset=gcc-mingw target-os=windows variant=release link=static runtime-link=static address-model=64 \ - --build-type=minimal --with-filesystem --with-program_options --with-date_time \ - --stagedir=stage-mingw-64 -cd .. -``` -Now we get & build OpenSSL -```sh -git clone https://github.com/openssl/openssl -cd openssl -git checkout OpenSSL_1_0_2g -./Configure mingw64 no-rc2 no-rc4 no-rc5 no-idea no-bf no-cast no-whirlpool no-md2 no-md4 no-ripemd no-mdc2 \ - no-camellia no-seed no-comp no-krb5 no-gmp no-rfc3779 no-ec2m no-ssl2 no-jpake no-srp no-sctp no-srtp \ - --prefix=~/dev/stage --cross-compile-prefix=x86_64-w64-mingw32- -make depend -make -make install -cd .. -``` -and Zlib -```sh -git clone https://github.com/madler/zlib -cd zlib -git checkout v1.2.8 -CC=x86_64-w64-mingw32-gcc CFLAGS=-O3 ./configure --static --64 --prefix=~/dev/stage -make -make install -cd .. -``` -Now we prepare cross toolchain hint file for CMake, let's name it `~/dev/toolchain-mingw.cmake` -```cmake -SET(CMAKE_SYSTEM_NAME Windows) -SET(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) -SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) -SET(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) -SET(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32) -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -``` -Download miniupnpc, unpack, and symlink it into `~/dev/miniupnpc/`. -Finally, we can build i2pd with all that goodness -```sh -git clone https://github.com/PurpleI2P/i2pd -mkdir i2pd-mingw-64-build -cd i2pd-mingw-64-build -BOOST_ROOT=~/dev/boost_1_60_0 cmake -G 'Unix Makefiles' ~/dev/i2pd/build -DBUILD_TYPE=Release \ - -DCMAKE_TOOLCHAIN_FILE=~/dev/toolchain-mingw.cmake -DWITH_AESNI=ON -DWITH_UPNP=ON -DWITH_STATIC=ON \ - -DWITH_HARDENING=ON -DCMAKE_INSTALL_PREFIX:PATH=~/dev/i2pd-mingw-64-static \ - -DZLIB_ROOT=~/dev/stage -DBOOST_LIBRARYDIR:PATH=~/dev/boost_1_60_0/stage-mingw-64/lib \ - -DOPENSSL_ROOT_DIR:PATH=~/dev/stage -make -x86_64-w64-mingw32-strip i2pd.exe -``` -By now, you should have a release build with stripped symbols. diff --git a/docs/build_notes_unix.md b/docs/build_notes_unix.md deleted file mode 100644 index b1cc4148..00000000 --- a/docs/build_notes_unix.md +++ /dev/null @@ -1,148 +0,0 @@ -Building on Unix systems -============================= - -First of all we need to make sure that all dependencies are satisfied. - -This doc is trying to cover: -* [Debian/Ubuntu](#debian-ubuntu) (contains packaging instructions) -* [Fedora/Centos](#fedora-centos) -* [Fedora/Centos](#mac-os-x) -* [FreeBSD](#freebsd) - -Make sure you have all required dependencies for your system successfully installed. - -If so then we are ready to go! -Let's clone the repository and start building the i2pd: -```bash -git clone https://github.com/PurpleI2P/i2pd.git -cd i2pd/build -cmake -DCMAKE_BUILD_TYPE=Release # more options could be passed, see "CMake Options" -make # you may add VERBOSE=1 to cmdline for debugging -``` - -After successfull build i2pd could be installed with: -```bash -make install -``` -or you can just use 'make' once you have all dependencies (boost and openssl) installed - -```bash -git clone https://github.com/PurpleI2P/i2pd.git -cd i2pd -make -``` - -Debian/Ubuntu -------------- - -You will need a compiler and other tools that could be installed with `build-essential` package: -```bash -sudo apt-get install build-essential -``` - -Also you will need a bunch of development libraries: -```bash -sudo apt-get install \ - libboost-chrono-dev \ - libboost-date-time-dev \ - libboost-filesystem-dev \ - libboost-program-options-dev \ - libboost-system-dev \ - libboost-thread-dev \ - libssl-dev -``` - -If you need UPnP support (don't forget to run CMake with `WITH_UPNP=ON`) miniupnpc development library should be installed: -```bash -sudo apt-get install libminiupnpc-dev -``` - -You may also build deb-package with the following: -```bash -sudo apt-get install fakeroot devscripts -cd i2pd -debuild --no-tgz-check -``` - -Fedora/Centos -------------- - -You will need a compiler and other tools to perform a build: -```bash -sudo yum install make cmake gcc gcc-c++ -``` - -*Latest Fedora system using [DNF](https://en.wikipedia.org/wiki/DNF_(software)) instead of YUM by default, you may prefer to use DNF, but YUM should be ok* - -Also you will need a bunch of development libraries -```bash -sudo yum install boost-devel openssl-devel -``` - -If you need UPnP support (don't forget to run CMake with `WITH_UPNP=ON`) miniupnpc development library should be installed: -```bash -miniupnpc-devel -``` -> *Centos 7 has CMake 2.8.11 in the official repositories that too old to build i2pd, CMake >=2.8.12 is required.* -> -> But you can use cmake3 from the epel repository: -> ```bash -> yum install epel-release -y -> yum install make cmake3 gcc gcc-c++ miniupnpc-devel boost-devel openssl-devel -y -> cmake3 -DWITH_LIBRARY=OFF -DWITH_UPNP=ON -DWITH_HARDENING=ON -DBUILD_SHARED_LIBS:BOOL=OFF -> make -> ``` - -MAC OS X --------- - -Requires [homebrew](http://brew.sh/) - -```bash -brew install libressl boost -``` - -Then build: -```bash -make HOMEBREW=1 -``` - - -FreeBSD -------- - -For 10.X use clang. You would also need boost and openssl ports. -Type gmake, it invokes Makefile.bsd, make necessary changes there is required. - -Branch 9.X has gcc v4.2, that knows nothing about required c++11 standart. - -Required ports: - -* `devel/cmake` -* `devel/boost-libs` -* `lang/gcc47`(or later version) - -To use newer compiler you should set these variables(replace "47" with your actual gcc version): -```bash -export CC=/usr/local/bin/gcc47 -export CXX=/usr/local/bin/g++47 -``` - -CMake Options -------------- - -Available CMake options(each option has a form of `=`, for more information see `man 1 cmake`): - -* `CMAKE_BUILD_TYPE` build profile (Debug/Release) -* `WITH_BINARY` build i2pd itself -* `WITH_LIBRARY` build libi2pd -* `WITH_STATIC` build static versions of library and i2pd binary -* `WITH_UPNP` build with UPnP support (requires libupnp) -* `WITH_AESNI` build with AES-NI support (ON/OFF) -* `WITH_HARDENING` enable hardening features (ON/OFF) (gcc only) -* `WITH_PCH` use pre-compiled header (experimental, speeds up build) - -Also there is `-L` flag for CMake that could be used to list current cached options: -```bash -cmake -L -``` diff --git a/docs/build_requirements.md b/docs/build_requirements.md deleted file mode 100644 index 3e0dfea9..00000000 --- a/docs/build_requirements.md +++ /dev/null @@ -1,15 +0,0 @@ -Build requirements -============ - -Linux/FreeBSD/OSX ------------------ - -GCC 4.7 or newer, Boost 1.49 or newer, openssl, zlib. Clang can be used instead of GCC. - -Windows -------- - -VS2013 (known to work with 12.0.21005.1 or newer), Boost 1.46 or newer, -crypto++ 5.62. See Win32/README-Build.txt for instructions on how to build i2pd -and its dependencies. - diff --git a/docs/building/android.md b/docs/building/android.md new file mode 100644 index 00000000..3e9ab089 --- /dev/null +++ b/docs/building/android.md @@ -0,0 +1,65 @@ +Building on Android +=================== + +There are two versions: with QT and without QT. + +Pre-requesties +-------------- + +You need to install Android SDK, NDK and QT with android support. + +- [SDK](https://developer.android.com/studio/index.html) (choose command line tools only) +- [NDK](https://developer.android.com/ndk/downloads/index.html) +- [QT](https://www.qt.io/download-open-source/)(for QT only). + Choose one for your platform for android. For example QT 5.6 under Linux would be [this file](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-linux-x64-android-5.6.1-1.run) + +You also need Java JDK and Ant. + +QT-Creator (for QT only) +------------------------ + +Open QT-creator that should be installed with QT. +Go to Settings/Anndroid and specify correct paths to SDK and NDK. +If everything is correct you will see two set avaiable: +Android for armeabi-v7a (gcc, qt) and Android for x86 (gcc, qt). + +Dependencies +-------------- + +Take following pre-compiled binaries from PurpleI2P's repositories. + + git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git + git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git + git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git + git clone https://github.com/PurpleI2P/android-ifaddrs.git + +Building the app with QT +------------------------ + +- Open `qt/i2pd_qt/i2pd_qt.pro` in the QT-creator +- Change line `MAIN_PATH = /path/to/libraries` to an actual path where you put the dependancies to +- Select appropriate project (usually armeabi-v7a) and build +- You will find an .apk file in `android-build/bin` folder + +Building the app without QT +--------------------------- + +- Change line `I2PD_LIBS_PATH` in `android/jni/Application.mk` to an actual path where you put the dependancies to +- Run `ndk-build -j4` from andorid folder +- Create or edit file 'local.properties'. Place 'sdk.dir=' and 'ndk.dir=' +- Run `ant clean debug` + +Creating release .apk +---------------------- + +In order to create release .apk you must obtain a Java keystore file(.jks). Either you have in already, or you can generate it yourself using keytool, or from one of you existing well-know ceritificates. +For example, i2pd release are signed with this [certificate](https://github.com/PurpleI2P/i2pd/blob/openssl/contrib/certificates/router/orignal_at_mail.i2p.crt). + +Create file 'ant.propeties': + + key.store='path to keystore file' + key.alias='alias name' + key.store.password='keystore password' + key.alias.password='alias password' + +Run `ant clean release` diff --git a/docs/building/cross.md b/docs/building/cross.md new file mode 100644 index 00000000..fc884cad --- /dev/null +++ b/docs/building/cross.md @@ -0,0 +1,74 @@ +Cross compilation notes +======================= + +Static 64 bit windows binary on Ubuntu 15.10 (Wily Werewolf) +------------------------------------------------------------ + +Install cross compiler and friends + + sudo apt-get install g++-mingw-w64-x86-64 + +Default is to use Win32 threading model which lacks std::mutex and such. So we change defaults + + sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix + +From now on we assume we have everything in `~/dev/`. Get Boost sources unpacked into `~/dev/boost_1_60_0/` and change directory to it. +Now add out cross compiler configuration. Warning: the following will wipe out whatever you had in there. + + echo "using gcc : mingw : x86_64-w64-mingw32-g++ ;" > ~/user-config.jam + +Proceed with building Boost normal way, but let's define dedicated staging directory + + ./bootstrap.sh + ./b2 toolset=gcc-mingw target-os=windows variant=release link=static runtime-link=static address-model=64 \ + --build-type=minimal --with-filesystem --with-program_options --with-date_time \ + --stagedir=stage-mingw-64 + cd .. + +Now we get & build OpenSSL + + git clone https://github.com/openssl/openssl + cd openssl + git checkout OpenSSL_1_0_2g + ./Configure mingw64 no-rc2 no-rc4 no-rc5 no-idea no-bf no-cast no-whirlpool no-md2 no-md4 no-ripemd no-mdc2 \ + no-camellia no-seed no-comp no-krb5 no-gmp no-rfc3779 no-ec2m no-ssl2 no-jpake no-srp no-sctp no-srtp \ + --prefix=~/dev/stage --cross-compile-prefix=x86_64-w64-mingw32- + make depend + make + make install + cd .. + +...and zlib + + git clone https://github.com/madler/zlib + cd zlib + git checkout v1.2.8 + CC=x86_64-w64-mingw32-gcc CFLAGS=-O3 ./configure --static --64 --prefix=~/dev/stage + make + make install + cd .. + +Now we prepare cross toolchain hint file for CMake, let's name it `~/dev/toolchain-mingw.cmake` + + set(CMAKE_SYSTEM_NAME Windows) + set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) + set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) + set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) + set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + +Download miniupnpc, unpack and symlink it into `~/dev/miniupnpc/`. +Finally, we can build i2pd with all that goodness + + git clone https://github.com/PurpleI2P/i2pd + mkdir i2pd-mingw-64-build + cd i2pd-mingw-64-build + BOOST_ROOT=~/dev/boost_1_60_0 cmake -G 'Unix Makefiles' ~/dev/i2pd/build -DBUILD_TYPE=Release \ + -DCMAKE_TOOLCHAIN_FILE=~/dev/toolchain-mingw.cmake -DWITH_AESNI=ON -DWITH_UPNP=ON -DWITH_STATIC=ON \ + -DWITH_HARDENING=ON -DCMAKE_INSTALL_PREFIX:PATH=~/dev/i2pd-mingw-64-static \ + -DZLIB_ROOT=~/dev/stage -DBOOST_LIBRARYDIR:PATH=~/dev/boost_1_60_0/stage-mingw-64/lib \ + -DOPENSSL_ROOT_DIR:PATH=~/dev/stage + make + x86_64-w64-mingw32-strip i2pd.exe + +By now, you should have a release build with stripped symbols. diff --git a/docs/build_notes_ios.md b/docs/building/ios.md similarity index 72% rename from docs/build_notes_ios.md rename to docs/building/ios.md index 26688d21..c1753569 100644 --- a/docs/build_notes_ios.md +++ b/docs/building/ios.md @@ -9,31 +9,30 @@ Prerequisites XCode7+, cmake 3.2+ Dependencies --------------- +------------ + - precompiled openssl - precompiled boost with modules `filesystem`, `program_options`, `date_time` and `system` -- ios-cmake toolchain from https://github.com/vovasty/ios-cmake.git +- ios-cmake toolchain from `https://github.com/vovasty/ios-cmake.git` Building ------------------------- -Assume you have folder structure +-------- -``` -lib - libboost_date_time.a - libboost_filesystem.a - libboost_program_options.a - libboost_system.a - libboost.a - libcrypto.a - libssl.a -include - boost - openssl -ios-cmake -i2pd -``` +Assume you have folder structure + lib/ + libboost_date_time.a + libboost_filesystem.a + libboost_program_options.a + libboost_system.a + libboost.a + libcrypto.a + libssl.a + include/ + boost/ + openssl/ + ios-cmake/ + i2pd/ ```bash mkdir -p build/simulator/lib build/ios/lib include/i2pd @@ -77,9 +76,10 @@ cp i2pd/*.h include/i2pd ``` Include into project ---------------------------- -1. add all libraries in `lib` folder to `Project linked frameworks`. -2. add `libc++` and `libz` libraries from system libraries to `Project linked frameworks`. -3. add path to i2p headers to your `Headers search paths` +-------------------- + +- add all libraries in `lib` folder to `Project linked frameworks`. +- add `libc++` and `libz` libraries from system libraries to `Project linked frameworks`. +- add path to i2p headers to your `Headers search paths` -Alternatively you may use swift wrapper https://github.com/vovasty/SwiftyI2P.git \ No newline at end of file +Alternatively you may use swift wrapper `https://github.com/vovasty/SwiftyI2P.git` diff --git a/docs/building/requirements.md b/docs/building/requirements.md new file mode 100644 index 00000000..1bb163e1 --- /dev/null +++ b/docs/building/requirements.md @@ -0,0 +1,15 @@ +Build requirements +================== + +In general, for building i2pd you need several things: + +* compiler with c++11 support (for example: gcc >= 4.7, clang) +* boost >= 1.49 +* openssl library +* zlib library (openssl already depends on it) + +Optional tools: + +* cmake >= 2.8 (or 3.3+ if you want to use precompiled headers on windows) +* miniupnp library (for upnp support) +* [websocketpp](https://github.com/zaphoyd/websocketpp/) (for websocket ui) diff --git a/docs/building/unix.md b/docs/building/unix.md new file mode 100644 index 00000000..17623159 --- /dev/null +++ b/docs/building/unix.md @@ -0,0 +1,138 @@ +Building on Unix systems +============================= + +First of all we need to make sure that all dependencies are satisfied. + +This doc is trying to cover: + +* [Debian/Ubuntu](#debian-ubuntu) (contains packaging instructions) +* [Fedora/Centos](#fedora-centos) +* [Fedora/Centos](#mac-os-x) +* [FreeBSD](#freebsd) + +Make sure you have all required dependencies for your system successfully installed. +See [this](requirements.md) page for common requirements. + +If so then we are ready to go! +Let's clone the repository and start building the i2pd: + + git clone https://github.com/PurpleI2P/i2pd.git + +Generic build process looks like this (with cmake): + + cd i2pd/build + cmake . # see "CMake Options" section below + make # you may add VERBOSE=1 to cmdline for debugging + +..or with quick-and-dirty way with just make: + + cd i2pd/ + make + +After successfull build i2pd could be installed with: + + make install + +CMake Options +------------- + +Available CMake options(each option has a form of `=`, for more information see `man 1 cmake`): + +* `CMAKE_BUILD_TYPE` build profile (Debug/Release) +* `WITH_BINARY` build i2pd itself +* `WITH_LIBRARY` build libi2pd +* `WITH_STATIC` build static versions of library and i2pd binary +* `WITH_UPNP` build with UPnP support (requires libminiupnp) +* `WITH_AESNI` build with AES-NI support (ON/OFF) +* `WITH_HARDENING` enable hardening features (ON/OFF) (gcc only) +* `WITH_PCH` use pre-compiled header (experimental, speeds up build) +* `WITH_I2LUA` used when building i2lua +* `WITH_WEBSOCKETS` enable websocket server + + +Also there is `-L` flag for CMake that could be used to list current cached options: + + cmake -L + +Debian/Ubuntu +------------- + +You will need a compiler and other tools that could be installed with `build-essential` package: + + sudo apt-get install build-essential + +Also you will need a bunch of development libraries: + + sudo apt-get install \ + libboost-chrono-dev \ + libboost-date-time-dev \ + libboost-filesystem-dev \ + libboost-program-options-dev \ + libboost-system-dev \ + libboost-thread-dev \ + libssl-dev + +If you need UPnP support miniupnpc development library should be installed (don't forget to rerun CMake with needed option): + + sudo apt-get install libminiupnpc-dev + +You may also build deb-package with the following: + + sudo apt-get install fakeroot devscripts + cd i2pd + debuild --no-tgz-check + +Fedora/Centos +------------- + +You will need a compiler and other tools to perform a build: + + sudo yum install make cmake gcc gcc-c++ + +Also you will need a bunch of development libraries + + sudo yum install boost-devel openssl-devel + +If you need UPnP support miniupnpc development library should be installed (don't forget to rerun CMake with needed option): + + sudo yum install miniupnpc-devel + +Latest Fedora systems using [DNF](https://en.wikipedia.org/wiki/DNF_(software)) instead of YUM by default, you may prefer to use DNF, but YUM should be ok + +Centos 7 has CMake 2.8.11 in the official repositories that too old to build i2pd, CMake >=2.8.12 is required. +But you can use cmake3 from the epel repository: + + yum install epel-release -y + yum install make cmake3 gcc gcc-c++ miniupnpc-devel boost-devel openssl-devel -y + +...and then use 'cmake3' instead 'cmake'. + +MAC OS X +-------- + +Requires [homebrew](http://brew.sh) + + brew install boost libressl + +Then build: + + make HOMEBREW=1 + +FreeBSD +------- + +For 10.X use clang. You would also need devel/boost-libs, security/openssl and devel/gmake ports. +Type gmake, it invokes Makefile.bsd, make necessary changes there is required. + +Branch 9.X has gcc v4.2, that is too old (not supports -std=c++11) + +Required ports: + +* `devel/cmake` +* `devel/boost-libs` +* `lang/gcc47`(or later version) + +To use newer compiler you should set these variables(replace "47" with your actual gcc version): + + export CC=/usr/local/bin/gcc47 + export CXX=/usr/local/bin/g++47 diff --git a/docs/build_notes_windows.md b/docs/building/windows.md similarity index 50% rename from docs/build_notes_windows.md rename to docs/building/windows.md index 2b4b96b6..0aa76877 100644 --- a/docs/build_notes_windows.md +++ b/docs/building/windows.md @@ -3,7 +3,7 @@ Building on Windows There are two approaches available to build i2pd on Windows. The best one depends on your needs and personal preferences. One is to use -msys2 and [unix alike infrastructure](build_notes_unix.md). Another +msys2 and [unix alike infrastructure](unix.md). Another one is to use Visual Studio. While there might be no difference for end users of i2pd daemon, developers, however, shall be wary of differences in C++ name mangling between the two compilers when making @@ -20,86 +20,58 @@ development location for the sake of convenience. Adjust paths accordingly if it is not the case. Note that msys uses unix-alike paths like /c/dev/ for C:\dev\. - - msys2 ----- -### x86 (32-bit architecture) - -Get install file msys2-i686-*.exe from https://msys2.github.io. -open MSYS2 Shell (from Start menu). -Install all prerequisites and download i2pd source: - -```bash -pacman -S mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-gcc git make -mkdir -p /c/dev/i2pd -cd /c/dev/i2pd -git clone https://github.com/PurpleI2P/i2pd.git -cd i2pd -export PATH=/mingw32/bin:/usr/bin # we need compiler on PATH which is usually heavily cluttered on Windows -make -``` +Get install file `msys2-$ARCH-*.exe` from `https://msys2.github.io` +Where $ARCH is `i686` or `x86_64` (matching your system). -### x64 (64-bit architecture) - -Get install file msys2-x86_64-*.exe from https://msys2.github.io. -open MSYS2 Shell (from Start menu). -Install all prerequisites and download i2pd source: - -```bash -pacman -S mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-gcc git make -mkdir -p /c/dev/i2pd -cd /c/dev/i2pd -git clone https://github.com/PurpleI2P/i2pd.git -cd i2pd -export PATH=/mingw64/bin:/usr/bin # we need compiler on PATH which is usually heavily cluttered on Windows -make -``` +- Open MSYS2 Shell (from Start menu). +- Install all prerequisites and download i2pd source: + export ARCH='i686' # or 'x86_64' + export MINGW='mingw32' # or 'mingw64' + pacman -S mingw-w64-$ARCH-boost mingw-w64-$ARCH-openssl mingw-w64-$ARCH-gcc git make + mkdir -p /c/dev/i2pd + cd /c/dev/i2pd + git clone https://github.com/PurpleI2P/i2pd.git + cd i2pd + # we need compiler on PATH which is usually heavily cluttered on Windows + export PATH=/$MINGW/bin:/usr/bin + make ### Caveats -It is important to restrict PATH as described above. If you have -Strawberry Perl and/or Mercurial installed, it will pick up gcc & -openssl from the wrong places. - -If you do use precompiled headers to speed up compilation -(recommended), things can go wrong if compiler options have changed -for whatever reason. Just delete `stdafx.h.gch` found in your build -folder, note the file extension. +It is important to restrict PATH as described above. +If you have Strawberry Perl and/or Mercurial installed, +it will pick up gcc & openssl from the wrong places. -If you are an Arch Linux user, refrain from updating system with -`pacman -Syu`. Always update runtime separately as described on the -home page, otherwise you might end up with DLLs incompatibility -problems. +If you do use precompiled headers to speed up compilation (recommended), +things can go wrong if compiler options have changed for whatever reason. +Just delete `stdafx.h.gch` found in your build folder, note the file extension. +If you are an Arch Linux user, refrain from updating system with `pacman -Syu`. +Always update runtime separately as described on the home page, +otherwise you might end up with DLLs incompatibility problems. ### AES-NI -If your processor has -[AES instruction set](https://en.wikipedia.org/wiki/AES_instruction_set), -you use `make USE_AESNI=1`. No check is done however, it -will compile, but it might crash with `Illegal instruction` if not supported. +If your processor has [AES instruction set](https://en.wikipedia.org/wiki/AES_instruction_set), +use `make USE_AESNI=1` instead just `make`. No check is done however, it will compile, +but it might crash with `Illegal instruction` if this feature is not supported by your processor. -You should be able to run ./i2pd . If you need to start from the new -shell, consider starting *MinGW-w64 Win32 Shell* instead of *MSYS2 Shell* as -it adds`/minw32/bin` to the PATH. +You should be able to run ./i2pd . If you need to start from the new shell, +consider starting *MinGW-w64 Win32 Shell* instead of *MSYS2 Shell* +as it adds `/minw32/bin` to the PATH. ### UPnP -You can install it through the MSYS2 -and build with USE_UPNP key. - -```bash -pacman -S mingw-w64-i686-miniupnpc -make USE_UPNP=yes -``` -or -```bash -pacman -S mingw-w64-x86_64-miniupnpc -make USE_UPNP=yes -``` + +You can install it through the MSYS2 and build with `USE_UPNP` key. + + export ARCH='i686' # or 'x86_64' + pacman -S mingw-w64-$ARCH-miniupnpc + make USE_UPNP=yes Using Visual Studio ------------------- @@ -114,7 +86,6 @@ Requirements for building: * [Netwide assembler](http://www.nasm.us/) * Strawberry Perl or ActiveState Perl, do NOT try msys2 perl, it won't work - ### Building Boost Open a Command Prompt (there is no need to start Visual Studio command @@ -131,11 +102,9 @@ If you are on 64-bit Windows and you want to build 64-bit version as well After Boost is compiled, set the environment variable `BOOST_ROOT` to the directory Boost was unpacked to, e.g., C:\dev\boost. -If you are planning on building only particular variant, e.g. Debug -only and static linking, and/or you are out of space/time, you might -consider `--build-type=minimal`. Take a look at -[appveyor.yml](../appveyor.yml) for details on how test builds are done. - +If you are planning on building only particular variant, e.g. Debug only and static linking, +and/or you are out of space/time, you might consider `--build-type=minimal`. +Take a look at [appveyor.yml](../appveyor.yml) for details on how test builds are done. ### Building OpenSSL @@ -155,23 +124,19 @@ Now open Visual Studio command prompt and change directory to that with OpenSSL You should have it installed into C:\OpenSSL-Win32 by now. -Note that you might consider providing `-DOPENSSL_ROOT_DIR` to CMake -and/or create a symlink (with mklink /J) to C:\OpenSSL if you plan on -maintaining multiple versions, e.g. 64 bit and/or -static/shared. Consult `C:\Program Files -(x86)\CMake\share\cmake-3.3\Modules\FindOpenSSL.cmake` for details. - +Note that you might consider providing `-DOPENSSL_ROOT_DIR` to CMake and/or +create a symlink (with mklink /J) to C:\OpenSSL if you plan on maintain +multiple versions, e.g. 64 bit and/or static/shared. +See `C:\Program Files (x86)\CMake\share\cmake-3.3\Modules\FindOpenSSL.cmake` for details. ### Get miniupnpc -If you are behind a UPnP enabled router and don't feel like manually -configuring port forwarding, you should consider using -[MiniUPnP](http://miniupnp.free.fr) client. I2pd can be built capable -of using miniupnpc shared library (DLL) to open up necessary -port. You'd want to have include headers around to build i2pd with -support for this. Unpack client source code in a sibling folder, -e.g. C:\dev\miniupnpc . You may want to remove version number from -folder name included in downloaded archive. +If you are behind a UPnP enabled router and don't feel like manually configuring port forwarding, +you should consider using [MiniUPnP](http://miniupnp.free.fr) client. +I2pd can be built capable of using miniupnpc shared library (DLL) to open up necessary port. +You'd want to have include headers around to build i2pd with support for this. +Unpack client source code to subdir, e.g. `C:\dev\miniupnpc`. +You may want to remove version number from folder name included in downloaded archive. ### Creating Visual Studio project @@ -179,19 +144,16 @@ Start CMake GUI, navigate to i2pd directory, choose building directory, e.g. ./ Alternatively, if you feel adventurous, try that from the command line -``` -cd -mkdir out -cd out -cmake ..\build -G "Visual Studio 12 2013" -DWITH_UPNP=ON -DWITH_PCH=ON -DCMAKE_INSTALL_PREFIX:PATH=C:\dev\Debug_Win32_stage -``` - -WITH_UPNP will stay off, if necessary files are not found. + mkdir i2pd\out + cd i2pd\out + cmake ..\build -G "Visual Studio 12 2013" -DWITH_UPNP=ON -DWITH_PCH=ON -DCMAKE_INSTALL_PREFIX:PATH=C:\dev\Debug_Win32_stage +If necessary files are not found `WITH_UPNP` will stay off. ### Building i2pd -You can open generated solution/project with Visual Studio and build -from there, alternatively you can use `cmake --build . --config Release --target install` or +You can open generated solution/project with Visual Studio and build from there, +alternatively you can use `cmake --build . --config Release --target install` or [MSBuild tool](https://msdn.microsoft.com/en-us/library/dd293626.aspx) -`msbuild i2pd.sln /p:Configuration=Release`. + + msbuild i2pd.sln /p:Configuration=Release diff --git a/docs/configuration.md b/docs/configuration.md index 49d8c98d..b04be9fb 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -41,17 +41,25 @@ All options below still possible in cmdline, but better write it in config file: * --http.user= - Username for basic auth (default: i2pd) * --http.pass= - Password for basic auth (default: random, see logs) -* --httpproxy.address= - The address to listen on (HTTP Proxy) -* --httpproxy.port= - The port to listen on (HTTP Proxy) 4444 by default -* --httpproxy.keys= - optional keys file for proxy local destination (both HTTP and SOCKS) -* --httpproxy.enabled= - If HTTP proxy is enabled. true by default - -* --socksproxy.address= - The address to listen on (SOCKS Proxy) -* --socksproxy.port= - The port to listen on (SOCKS Proxy). 4447 by default -* --socksproxy.keys= - optional keys file for proxy local destination (both HTTP and SOCKS) -* --socksproxy.enabled= - If SOCKS proxy is enabled. true by default -* --socksproxy.outproxy= - Address of outproxy. requests outside i2p will go there -* --socksproxy.outproxyport= - Outproxy remote port +* --httpproxy.enabled= - If HTTP proxy is enabled. true by default +* --httpproxy.address= - The address to listen on (HTTP Proxy) +* --httpproxy.port= - The port to listen on (HTTP Proxy) 4444 by default +* --httpproxy.keys= - optional keys file for HTTP proxy local destination +* --httpproxy.inbound.length= - Inbound tunnels length if keys is set. 3 by default +* --httpproxy.inbound.quantity= - Inbound tunnels quantity if keys is set. 5 by default +* --httpproxy.outbound.length= - Outbound tunnels length if keys is set. 3 by default +* --httpproxy.outbound.quantity= - Outbound tunnels quantity if keys is set. 5 by default + +* --socksproxy.enabled= - If SOCKS proxy is enabled. true by default +* --socksproxy.address= - The address to listen on (SOCKS Proxy) +* --socksproxy.port= - The port to listen on (SOCKS Proxy). 4447 by default +* --socksproxy.keys= - optional keys file for SOCKS proxy local destination +* --socksproxy.inbound.length= - Inbound tunnels length if keys is set. 3 by default +* --socksproxy.inbound.quantity= - Inbound tunnels quantity if keys is set. 5 by default +* --socksproxy.outbound.length= - Outbound tunnels length if keys is set. 3 by default +* --socksproxy.outbound.quantity= - Outbound tunnels quantity if keys is set. 5 by default +* --socksproxy.outproxy= - Address of outproxy. requests outside i2p will go there +* --socksproxy.outproxyport= - Outproxy remote port * --sam.address= - The address to listen on (SAM bridge) * --sam.port= - Port of SAM bridge. Usually 7656. SAM is off if not specified @@ -80,6 +88,8 @@ All options below still possible in cmdline, but better write it in config file: * --addressbook.subscriptions= - AddressBook subscriptions URLs, separated by comma * --limits.transittunnels= - Override maximum number of transit tunnels. 2500 by default +* --limits.openfiles= - Maximum size of corefile in Kb (0 - use system limit) +* --limits.coresize= - Maximum size of corefile in Kb (0 - use system limit) Config files ------------ diff --git a/docs/index.rst b/docs/index.rst index 8cfddb24..c1061171 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -29,14 +29,13 @@ Contents: .. toctree:: :maxdepth: 2 - build_requirements - build_notes_unix - build_notes_windows - build_notes_cross - build_notes_android - build_notes_ios + building/requirements + building/unix + building/windows + building/cross + building/android + building/ios configuration family usage - diff --git a/filelist.mk b/filelist.mk index cb1263e3..94ce2f22 100644 --- a/filelist.mk +++ b/filelist.mk @@ -5,7 +5,7 @@ LIB_SRC = \ SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \ Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp TunnelGateway.cpp \ Destination.cpp Base.cpp I2PEndian.cpp FS.cpp Config.cpp Family.cpp \ - Config.cpp HTTP.cpp Timestamp.cpp util.cpp api.cpp + Config.cpp HTTP.cpp Timestamp.cpp util.cpp api.cpp Event.cpp LIB_CLIENT_SRC = \ AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp \ diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 0972f65c..143c7b8d 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -36,7 +36,7 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \ ../../SSUData.cpp ../../SSUSession.cpp ../../Streaming.cpp ../../TransitTunnel.cpp \ ../../Transports.cpp ../../Tunnel.cpp ../../TunnelEndpoint.cpp ../../TunnelGateway.cpp \ ../../TunnelPool.cpp ../../UPnP.cpp ../../Gzip.cpp ../../Timestamp.cpp ../../util.cpp \ - ../../i2pd.cpp + ../../Event.cpp ../../i2pd.cpp HEADERS += DaemonQT.h mainwindow.h \ ../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.h \ @@ -50,7 +50,7 @@ HEADERS += DaemonQT.h mainwindow.h \ ../../Streaming.h ../../Timestamp.h ../../TransitTunnel.h ../../Transports.h \ ../../TransportSession.h ../../Tunnel.h ../../TunnelBase.h ../../TunnelConfig.h \ ../../TunnelEndpoint.h ../../TunnelGateway.h ../../TunnelPool.h ../../UPnP.h \ - ../../util.h ../../version.h ../../Gzip.h ../../Tag.h + ../../util.h ../../version.h ../../Gzip.h ../../Tag.h ../../Event.h FORMS += mainwindow.ui diff --git a/util.h b/util.h index 77b94995..b8de8b5a 100644 --- a/util.h +++ b/util.h @@ -5,9 +5,9 @@ #include #include #include -#include #ifdef ANDROID +#include namespace std { template @@ -15,6 +15,11 @@ std::string to_string(T value) { return boost::lexical_cast(value); } + +inline int stoi(const std::string& str) +{ + return boost::lexical_cast(str); +} } #endif @@ -22,18 +27,6 @@ namespace i2p { namespace util { - /** - wrapper arround boost::lexical_cast that "never" fails - */ - template - T lexical_cast(const std::string & str, const T fallback) { - try { - return boost::lexical_cast(str); - } catch ( ... ) { - return fallback; - } - } - namespace net { int GetMTU (const boost::asio::ip::address& localAddress);