diff --git a/ClientContext.cpp b/ClientContext.cpp index b89f54ba..791ab563 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -40,7 +40,11 @@ namespace client // proxies std::string proxyKeys = i2p::util::config::GetArg("-proxykeys", ""); if (proxyKeys.length () > 0) - localDestination = LoadLocalDestination (proxyKeys, false); + { + i2p::data::PrivateKeys keys; + LoadPrivateKeys (keys, proxyKeys); + localDestination = CreateNewLocalDestination (keys, false); + } LogPrint(eLogInfo, "Clients: starting HTTP Proxy"); m_HttpProxy = new i2p::proxy::HTTPProxy(i2p::util::config::GetArg("-httpproxyaddress", "127.0.0.1"), i2p::util::config::GetArg("-httpproxyport", 4446), localDestination); m_HttpProxy->Start(); @@ -122,10 +126,8 @@ namespace client m_SharedLocalDestination = nullptr; } - std::shared_ptr ClientContext::LoadLocalDestination (const std::string& filename, - bool isPublic, i2p::data::SigningKeyType sigType, const std::map * params) + void ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType) { - i2p::data::PrivateKeys keys; std::string fullPath = i2p::util::filesystem::GetFullPath (filename); std::ifstream s(fullPath.c_str (), std::ifstream::binary); if (s.is_open ()) @@ -152,22 +154,6 @@ namespace client LogPrint (eLogInfo, "Clients: New private keys file ", fullPath, " for ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created"); } - - std::shared_ptr localDestination = nullptr; - std::unique_lock l(m_DestinationsMutex); - auto it = m_Destinations.find (keys.GetPublic ()->GetIdentHash ()); - if (it != m_Destinations.end ()) - { - LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " already exists"); - localDestination = it->second; - } - else - { - localDestination = std::make_shared (keys, isPublic, params); - m_Destinations[localDestination->GetIdentHash ()] = localDestination; - localDestination->Start (); - } - return localDestination; } std::shared_ptr ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType, @@ -225,7 +211,21 @@ namespace client return nullptr; } - // should be moved in i2p::utils::fs + template + std::string ClientContext::GetI2CPOption (const Section& section, const std::string& name, const Type& value) const + { + return section.second.get (boost::property_tree::ptree::path_type (name, '/'), std::to_string (value)); + } + + template + void ClientContext::ReadI2CPOptions (const Section& section, std::map& options) const + { + options[I2CP_PARAM_INBOUND_TUNNEL_LENGTH] = GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNEL_LENGTH, DEFAULT_INBOUND_TUNNEL_LENGTH); + options[I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH] = GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, DEFAULT_OUTBOUND_TUNNEL_LENGTH); + options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, DEFAULT_INBOUND_TUNNELS_QUANTITY); + options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, DEFAULT_OUTBOUND_TUNNELS_QUANTITY); + } + void ClientContext::ReadTunnels () { boost::property_tree::ptree pt; @@ -258,15 +258,16 @@ namespace client int destinationPort = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0); i2p::data::SigningKeyType sigType = section.second.get (I2P_CLIENT_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); // I2CP - std::map options; - options[I2CP_PARAM_INBOUND_TUNNEL_LENGTH] = section.second.get (decltype (pt)::path_type (I2CP_PARAM_INBOUND_TUNNEL_LENGTH, '/'), std::to_string (DEFAULT_INBOUND_TUNNEL_LENGTH)); - options[I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH] = section.second.get (decltype (pt)::path_type (I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, '/'), std::to_string (DEFAULT_OUTBOUND_TUNNEL_LENGTH)); - options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = section.second.get (decltype (pt)::path_type (I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, '/'), std::to_string (DEFAULT_INBOUND_TUNNELS_QUANTITY)); - options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = section.second.get (decltype (pt)::path_type (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, '/'), std::to_string (DEFAULT_OUTBOUND_TUNNELS_QUANTITY)); + std::map options; + ReadI2CPOptions (section, options); std::shared_ptr localDestination = nullptr; if (keys.length () > 0) - localDestination = LoadLocalDestination (keys, false, sigType, &options); + { + i2p::data::PrivateKeys k; + LoadPrivateKeys (k, keys, sigType); + localDestination = CreateNewLocalDestination (k, false, &options); + } auto clientTunnel = new I2PClientTunnel (name, dest, address, port, localDestination, destinationPort); if (m_ClientTunnels.insert (std::make_pair (port, std::unique_ptr(clientTunnel))).second) clientTunnel->Start (); @@ -286,12 +287,11 @@ namespace client i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); // I2CP std::map options; - options[I2CP_PARAM_INBOUND_TUNNEL_LENGTH] = section.second.get (decltype (pt)::path_type (I2CP_PARAM_INBOUND_TUNNEL_LENGTH, '/'), std::to_string (DEFAULT_INBOUND_TUNNEL_LENGTH)); - options[I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH] = section.second.get (decltype (pt)::path_type (I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, '/'), std::to_string (DEFAULT_OUTBOUND_TUNNEL_LENGTH)); - options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = section.second.get (decltype (pt)::path_type (I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, '/'), std::to_string (DEFAULT_INBOUND_TUNNELS_QUANTITY)); - options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = section.second.get (decltype (pt)::path_type (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, '/'), std::to_string (DEFAULT_OUTBOUND_TUNNELS_QUANTITY)); + ReadI2CPOptions (section, options); - auto localDestination = LoadLocalDestination (keys, true, sigType, &options); + i2p::data::PrivateKeys k; + LoadPrivateKeys (k, keys, sigType); + auto localDestination = CreateNewLocalDestination (k, true, &options); I2PServerTunnel * serverTunnel = (type == I2P_TUNNELS_SECTION_TYPE_HTTP) ? new I2PServerTunnelHTTP (name, host, port, localDestination, inPort) : new I2PServerTunnel (name, host, port, localDestination, inPort); diff --git a/ClientContext.h b/ClientContext.h index 24d2910c..1750f2b5 100644 --- a/ClientContext.h +++ b/ClientContext.h @@ -50,9 +50,7 @@ namespace client const std::map * params = nullptr); void DeleteLocalDestination (std::shared_ptr destination); std::shared_ptr FindLocalDestination (const i2p::data::IdentHash& destination) const; - std::shared_ptr LoadLocalDestination (const std::string& filename, bool isPublic, - i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256, - const std::map * params = nullptr); + void LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); AddressBook& GetAddressBook () { return m_AddressBook; }; const SAMBridge * GetSAMBridge () const { return m_SamBridge; }; @@ -60,7 +58,11 @@ namespace client 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; + private: std::mutex m_DestinationsMutex; diff --git a/Transports.cpp b/Transports.cpp index e66ad864..e2578456 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -231,8 +231,11 @@ namespace transport try { auto r = netdb.FindRouter (ident); - it = m_Peers.insert (std::pair(ident, { 0, r, {}, - i2p::util::GetSecondsSinceEpoch (), {} })).first; + { + std::unique_lock l(m_PeersMutex); + it = m_Peers.insert (std::pair(ident, { 0, r, {}, + i2p::util::GetSecondsSinceEpoch (), {} })).first; + } connected = ConnectToPeer (ident, it->second); } catch (std::exception& ex) @@ -318,6 +321,7 @@ namespace transport } LogPrint (eLogError, "Transports: No NTCP or SSU addresses available"); peer.Done (); + std::unique_lock l(m_PeersMutex); m_Peers.erase (ident); return false; } @@ -349,6 +353,7 @@ namespace transport else { LogPrint (eLogError, "Transports: RouterInfo not found, Failed to send messages"); + std::unique_lock l(m_PeersMutex); m_Peers.erase (it); } } @@ -382,6 +387,7 @@ namespace transport } } LogPrint (eLogError, "Transports: Unable to resolve NTCP address: ", ecode.message ()); + std::unique_lock l(m_PeersMutex); m_Peers.erase (it1); } } @@ -413,6 +419,7 @@ namespace transport } } LogPrint (eLogError, "Transports: Unable to resolve SSU address: ", ecode.message ()); + std::unique_lock l(m_PeersMutex); m_Peers.erase (it1); } } @@ -502,7 +509,10 @@ namespace transport it->second.delayedMessages.clear (); } else // incoming connection + { + std::unique_lock l(m_PeersMutex); m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch (), {} })); + } }); } @@ -521,14 +531,18 @@ namespace transport if (it->second.delayedMessages.size () > 0) ConnectToPeer (ident, it->second); else + { + std::unique_lock l(m_PeersMutex); m_Peers.erase (it); + } } } }); } bool Transports::IsConnected (const i2p::data::IdentHash& ident) const - { + { + std::unique_lock l(m_PeersMutex); auto it = m_Peers.find (ident); return it != m_Peers.end (); } @@ -543,6 +557,7 @@ namespace transport if (it->second.sessions.empty () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT) { LogPrint (eLogWarning, "Transports: Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds"); + std::unique_lock l(m_PeersMutex); it = m_Peers.erase (it); } else @@ -559,6 +574,7 @@ namespace transport std::shared_ptr Transports::GetRandomPeer () const { if (!m_Peers.size ()) return nullptr; + std::unique_lock l(m_PeersMutex); auto it = m_Peers.begin (); std::advance (it, rand () % m_Peers.size ()); return it != m_Peers.end () ? it->second.router : nullptr; diff --git a/Transports.h b/Transports.h index 98e32679..9b603963 100644 --- a/Transports.h +++ b/Transports.h @@ -132,6 +132,7 @@ namespace transport NTCPServer * m_NTCPServer; SSUServer * m_SSUServer; + mutable std::mutex m_PeersMutex; std::map m_Peers; DHKeysPairSupplier m_DHKeysPairSupplier; diff --git a/docs/build_notes_unix.md b/docs/build_notes_unix.md index 145e1a70..882a8ece 100644 --- a/docs/build_notes_unix.md +++ b/docs/build_notes_unix.md @@ -1,46 +1,90 @@ Building on Unix systems ============================= -Common build/install process from sources: +First of all we need to make sure that all dependencies are satisfied. -* git clone https://github.com/PurpleI2P/i2pd.git -* mkdir -p 'i2pd/build/tmp' && cd 'i2pd/build/tmp' -* cmake -DCMAKE_BUILD_TYPE=Release .. -* make -* make install +This doc is trying to cover: +* [Debian/Ubuntu](#debianubuntu) (contains packaging instructions) +* [Fedora/Centos](#fedoracentos) +* [FreeBSD](#freebsd) -Available cmake options: +Make sure you have all required dependencies for your system successfully installed. -* CMAKE_BUILD_TYPE -- build profile (Debug/Release) -* WITH_AESNI -- AES-NI support (ON/OFF) -* WITH_HARDENING -- enable hardening features (ON/OFF) (gcc only) -* 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_PCH -- use pre-compiled header (experimental, speeds up build) +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 +``` + +After successfull build i2pd could be installed with: +```bash +make install +``` Debian/Ubuntu ------------- -For building from source on debian system you will need the following "-dev" packages: +You will need a compiler and other tools that could be installed with `build-essential` package: +```bash +sudo apt-get install build-essential +``` -* libboost-chrono-dev -* libboost-date-time-dev -* libboost-filesystem-dev -* libboost-program-options-dev -* libboost-regex-dev -* libboost-system-dev -* libboost-thread-dev -* libssl-dev (e.g. openssl) -* zlib1g-dev (libssl-dev already depends on it) -* libminiupnpc-dev (optional, if WITH_UPNP=ON) +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-regex-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 +``` - apt-get install build-essential fakeroot devscripts - cd i2pd - debuild --no-tgz-check # building from git repo +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* + +> *Centos 7 has CMake 2.8.11 in the official repositories that too old to build i2pd, CMake >=2.8.12 is required* +> You could build CMake for Centos manualy(WARNING there are a lot of build dependencies!): +> ```bash +> wget https://kojipkgs.fedoraproject.org/packages/cmake/2.8.12/3.fc21/src/cmake-2.8.12-3.fc21.src.rpm +> yum-builddep cmake-2.8.12-3.fc21.src.rpm +> rpmbuild --rebuild cmake-2.8.12-3.fc21.src.rpm +> yum install ~/rpmbuild/RPMS/x86_64/cmake-2.8.12-3.el7.centos.x86_64.rpm +> ``` + +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 +``` FreeBSD ------- @@ -49,17 +93,35 @@ 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 +* `devel/cmake` +* `devel/boost-libs` +* `lang/gcc47`(or later version) -To use newer compiler you should set these variables: - - export CC=/usr/local/bin/gcc47 - export CXX=/usr/local/bin/g++47 - -Replace "47" with your actual gcc 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 +``` Branch 10.X has more reliable clang version, that can finally build i2pd, -but i still recommend to use gcc, otherwise you will fight it's bugs by +but I still recommend to use gcc, otherwise you will fight it's bugs by your own. + +CMake Options +------------- + +Available CMake options(each option has a for 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 +```