From 46f927fc1bd35bdc00b7ad61f053791f286c4a46 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 9 Nov 2016 14:51:55 -0500 Subject: [PATCH 01/40] cleanup unclaimed out-of-sequence fragments --- Tunnel.cpp | 5 +++++ Tunnel.h | 4 ++++ TunnelBase.h | 1 + TunnelEndpoint.cpp | 53 +++++++++++++++++++++++++++------------------- TunnelEndpoint.h | 5 +++-- 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/Tunnel.cpp b/Tunnel.cpp index 9552684e..faba99d3 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -714,6 +714,8 @@ namespace tunnel if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) tunnel->SetState (eTunnelStateExpiring); + else // we don't need to cleanup expiring tunnels + tunnel->Cleanup (); } it++; } @@ -763,7 +765,10 @@ namespace tunnel it = m_TransitTunnels.erase (it); } else + { + tunnel->Cleanup (); it++; + } } } diff --git a/Tunnel.h b/Tunnel.h index 54917d49..53c93e90 100644 --- a/Tunnel.h +++ b/Tunnel.h @@ -165,6 +165,10 @@ namespace tunnel virtual size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }; void Print (std::stringstream& s) const; bool IsInbound() const { return true; } + + // override TunnelBase + void Cleanup () { m_Endpoint.Cleanup (); }; + private: TunnelEndpoint m_Endpoint; diff --git a/TunnelBase.h b/TunnelBase.h index 1b4e1e1f..770badf8 100644 --- a/TunnelBase.h +++ b/TunnelBase.h @@ -37,6 +37,7 @@ namespace tunnel m_TunnelID (tunnelID), m_NextTunnelID (nextTunnelID), m_NextIdent (nextIdent), m_CreationTime (i2p::util::GetSecondsSinceEpoch ()) {}; virtual ~TunnelBase () {}; + virtual void Cleanup () {}; virtual void HandleTunnelDataMsg (std::shared_ptr tunnelMsg) = 0; virtual void SendTunnelDataMsg (std::shared_ptr msg) = 0; diff --git a/TunnelEndpoint.cpp b/TunnelEndpoint.cpp index 455254ff..23cf16f3 100644 --- a/TunnelEndpoint.cpp +++ b/TunnelEndpoint.cpp @@ -6,6 +6,7 @@ #include "I2NPProtocol.h" #include "Transports.h" #include "RouterContext.h" +#include "Timestamp.h" #include "TunnelEndpoint.h" namespace i2p @@ -192,7 +193,7 @@ namespace tunnel void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr data) { - if (!m_OutOfSequenceFragments.insert ({{msgID, fragmentNum}, {fragmentNum, isLastFragment, data}}).second) + if (!m_OutOfSequenceFragments.insert ({{msgID, fragmentNum}, {isLastFragment, data, i2p::util::GetMillisecondsSinceEpoch () }}).second) LogPrint (eLogInfo, "TunnelMessage: duplicate out-of-sequence fragment ", fragmentNum, " of message ", msgID); } @@ -213,30 +214,25 @@ namespace tunnel { auto it = m_OutOfSequenceFragments.find ({msgID, msg.nextFragmentNum}); if (it != m_OutOfSequenceFragments.end ()) - { - if (it->second.fragmentNum == msg.nextFragmentNum) + { + LogPrint (eLogDebug, "TunnelMessage: Out-of-sequence fragment ", (int)msg.nextFragmentNum, " of message ", msgID, " found"); + size_t size = it->second.data->GetLength (); + if (msg.data->len + size > msg.data->maxLen) { - LogPrint (eLogDebug, "TunnelMessage: Out-of-sequence fragment ", (int)it->second.fragmentNum, " of message ", msgID, " found"); - size_t size = it->second.data->GetLength (); - if (msg.data->len + size > msg.data->maxLen) - { - LogPrint (eLogWarning, "TunnelMessage: Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough"); - auto newMsg = NewI2NPMessage (); - *newMsg = *(msg.data); - msg.data = newMsg; - } - if (msg.data->Concat (it->second.data->GetBuffer (), size) < size) // concatenate out-of-sync fragment - LogPrint (eLogError, "TunnelMessage: Tunnel endpoint I2NP buffer overflow ", msg.data->maxLen); - if (it->second.isLastFragment) - // message complete - msg.nextFragmentNum = 0; - else - msg.nextFragmentNum++; - m_OutOfSequenceFragments.erase (it); - return true; + LogPrint (eLogWarning, "TunnelMessage: Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough"); + auto newMsg = NewI2NPMessage (); + *newMsg = *(msg.data); + msg.data = newMsg; } + if (msg.data->Concat (it->second.data->GetBuffer (), size) < size) // concatenate out-of-sync fragment + LogPrint (eLogError, "TunnelMessage: Tunnel endpoint I2NP buffer overflow ", msg.data->maxLen); + if (it->second.isLastFragment) + // message complete + msg.nextFragmentNum = 0; else - LogPrint (eLogError, "Tunnel message: next fragment ", (int)it->second.fragmentNum, " of message ", msgID, " mismatch. ", (int)msg.nextFragmentNum, " expected"); + msg.nextFragmentNum++; + m_OutOfSequenceFragments.erase (it); + return true; } return false; } @@ -275,6 +271,19 @@ namespace tunnel default: LogPrint (eLogError, "TunnelMessage: Unknown delivery type ", (int)msg.deliveryType); }; + } + + void TunnelEndpoint::Cleanup () + { + auto ts = i2p::util::GetMillisecondsSinceEpoch (); + // out-of-sequence fragments + for (auto it = m_OutOfSequenceFragments.begin (); it != m_OutOfSequenceFragments.end ();) + { + if (ts > it->second.receiveTime + i2p::I2NP_MESSAGE_EXPIRATION_TIMEOUT) + it = m_OutOfSequenceFragments.erase (it); + else + ++it; + } } } } diff --git a/TunnelEndpoint.h b/TunnelEndpoint.h index cb0056b4..60c4fc0a 100644 --- a/TunnelEndpoint.h +++ b/TunnelEndpoint.h @@ -20,9 +20,9 @@ namespace tunnel struct Fragment { - uint8_t fragmentNum; bool isLastFragment; std::shared_ptr data; + uint64_t receiveTime; // milliseconds since epoch }; public: @@ -30,7 +30,8 @@ namespace tunnel TunnelEndpoint (bool isInbound): m_IsInbound (isInbound), m_NumReceivedBytes (0) {}; ~TunnelEndpoint (); size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; - + void Cleanup (); + void HandleDecryptedTunnelDataMsg (std::shared_ptr msg); private: From a4d586b24e65bfcdd8948bbf0eaf50eac8d367a8 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 9 Nov 2016 15:59:01 -0500 Subject: [PATCH 02/40] openssl 1.1 for ECDSA --- Crypto.h | 6 ++++++ Signature.h | 13 +++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Crypto.h b/Crypto.h index efbc7165..7d9a38d7 100644 --- a/Crypto.h +++ b/Crypto.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -296,6 +297,11 @@ inline int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) { *pr = sig->r; *ps = sig->s; } +inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) + { sig->r = r; sig->s = s; return 1; } +inline void ECDSA_SIG_get0(const ECDSA_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) diff --git a/Signature.h b/Signature.h index df9d8d33..7962bc2d 100644 --- a/Signature.h +++ b/Signature.h @@ -169,8 +169,9 @@ namespace crypto uint8_t digest[Hash::hashLen]; Hash::CalculateHash (buf, len, digest); ECDSA_SIG * sig = ECDSA_SIG_new(); - sig->r = BN_bin2bn (signature, GetSignatureLen ()/2, NULL); - sig->s = BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL); + auto r = BN_bin2bn (signature, GetSignatureLen ()/2, NULL); + auto s = BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL); + ECDSA_SIG_set0(sig, r, s); // ECDSA verification int ret = ECDSA_do_verify (digest, Hash::hashLen, sig, m_PublicKey); ECDSA_SIG_free(sig); @@ -207,9 +208,11 @@ namespace crypto uint8_t digest[Hash::hashLen]; Hash::CalculateHash (buf, len, digest); ECDSA_SIG * sig = ECDSA_do_sign (digest, Hash::hashLen, m_PrivateKey); + const BIGNUM * r, * s; + ECDSA_SIG_get0 (sig, &r, &s); // signatureLen = keyLen - bn2buf (sig->r, signature, keyLen/2); - bn2buf (sig->s, signature + keyLen/2, keyLen/2); + bn2buf (r, signature, keyLen/2); + bn2buf (s, signature + keyLen/2, keyLen/2); ECDSA_SIG_free(sig); } @@ -271,7 +274,6 @@ namespace crypto RSAVerifier (const uint8_t * signingKey) { m_PublicKey = RSA_new (); - memset (m_PublicKey, 0, sizeof (RSA)); RSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, keyLen, NULL) /* n */ , BN_dup (GetRSAE ()) /* d */, NULL); } @@ -304,7 +306,6 @@ namespace crypto RSASigner (const uint8_t * signingPrivateKey) { m_PrivateKey = RSA_new (); - memset (m_PrivateKey, 0, sizeof (RSA)); RSA_set0_key (m_PrivateKey, BN_bin2bn (signingPrivateKey, keyLen, NULL), /* n */ BN_dup (GetRSAE ()) /* e */, BN_bin2bn (signingPrivateKey + keyLen, keyLen, NULL) /* d */); } From 5001cea3a3357886a8d96d630479e1ec035c55d2 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 10 Nov 2016 08:21:32 -0500 Subject: [PATCH 03/40] add dir-locals for emacs users with code standards set --- .dir-locals.el | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .dir-locals.el diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 00000000..767a2edd --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,3 @@ +((c++-mode . ((indent-tabs-mode . t) + (tab-width . 2))) + (c-mode . ((mode . c++)))) From dd259f1852fb1b4c48598410b2d4f2858f8caaea Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 10 Nov 2016 08:22:52 -0500 Subject: [PATCH 04/40] fix formatting --- .dir-locals.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.dir-locals.el b/.dir-locals.el index 767a2edd..25bf45ad 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -1,3 +1,3 @@ ((c++-mode . ((indent-tabs-mode . t) - (tab-width . 2))) + (tab-width . 2))) (c-mode . ((mode . c++)))) From e152785de99469927ac0fc7eb7fd754ee927ea78 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 10 Nov 2016 08:25:16 -0500 Subject: [PATCH 05/40] remove tab width setting in dir-locals --- .dir-locals.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.dir-locals.el b/.dir-locals.el index 25bf45ad..2ef6066c 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -1,3 +1,2 @@ -((c++-mode . ((indent-tabs-mode . t) - (tab-width . 2))) +((c++-mode . ((indent-tabs-mode . t))) (c-mode . ((mode . c++)))) From 6377631ae76f123c4adce7a8e53bfecaa1c98b8f Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 10 Nov 2016 12:51:39 -0500 Subject: [PATCH 06/40] OpenSSL 1.1 for EVP_PKEY --- Crypto.cpp | 6 ++++-- Crypto.h | 10 +++++++--- Family.cpp | 2 +- Reseed.cpp | 6 ++++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Crypto.cpp b/Crypto.cpp index 6b5fb7d6..42514857 100644 --- a/Crypto.cpp +++ b/Crypto.cpp @@ -270,8 +270,10 @@ namespace crypto { if (m_IsUpdated) { - bn2buf (m_DH->pub_key, m_PublicKey, 256); - BN_free (m_DH->pub_key); m_DH->pub_key = NULL; + const BIGNUM * priv_key, * pub_key; + DH_get0_key (m_DH, &pub_key, &priv_key); + bn2buf (pub_key, m_PublicKey, 256); + DH_set0_key (m_DH, NULL, NULL); m_IsUpdated= false; } return m_PublicKey; diff --git a/Crypto.h b/Crypto.h index 7d9a38d7..115fefda 100644 --- a/Crypto.h +++ b/Crypto.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "Base.h" @@ -281,6 +282,8 @@ namespace crypto void InitCrypto (bool precomputation); void TerminateCrypto (); +} +} // take care about openssl version #include @@ -318,9 +321,10 @@ inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) inline void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) { *pub_key = dh->pub_key; *priv_key = dh->priv_key; } +inline int EVP_PKEY_base_id(const EVP_PKEY *pkey) + { return EVP_PKEY_type(pkey->type); } +inline RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey) + { return pkey->pkey.rsa; } #endif -} -} - #endif diff --git a/Family.cpp b/Family.cpp index c1840e51..ce995a4a 100644 --- a/Family.cpp +++ b/Family.cpp @@ -40,7 +40,7 @@ namespace data if (family) family[0] = 0; } auto pkey = X509_get_pubkey (cert); - int keyType = EVP_PKEY_type(pkey->type); + int keyType = EVP_PKEY_base_id (pkey); switch (keyType) { case EVP_PKEY_DSA: diff --git a/Reseed.cpp b/Reseed.cpp index d8a265db..65de62b4 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -350,9 +350,11 @@ namespace data if (terminator) terminator[0] = 0; } // extract RSA key (we need n only, e = 65537) - RSA * key = X509_get_pubkey (cert)->pkey.rsa; + RSA * key = EVP_PKEY_get0_RSA (X509_get_pubkey (cert)); + const BIGNUM * n, * e, * d; + RSA_get0_key(key, &n, &e, &d); PublicKey value; - i2p::crypto::bn2buf (key->n, value, 512); + i2p::crypto::bn2buf (n, value, 512); if (cn) m_SigningKeys[cn] = value; else From 3bbe1e9c0cd794eac4dff2772737eb189e249be7 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 10 Nov 2016 14:59:21 -0500 Subject: [PATCH 07/40] excluded deprecated reseed --- Config.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Config.cpp b/Config.cpp index aa75b8db..d11802cc 100644 --- a/Config.cpp +++ b/Config.cpp @@ -165,7 +165,6 @@ namespace config { "https://netdb.i2p2.no/," "https://us.reseed.i2p2.no:444/," "https://uk.reseed.i2p2.no:444/," - "https://i2p.manas.ca:8443/," "https://i2p-0.manas.ca:8443/," "https://reseed.i2p.vzaws.com:8443/," "https://download.xxlspeed.com/," From 89d69a5d5a61865edeb53a6cb3691b0dce67d327 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 10 Nov 2016 18:38:29 -0500 Subject: [PATCH 08/40] rollback due the race condition --- Crypto.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Crypto.cpp b/Crypto.cpp index 42514857..c70b62ef 100644 --- a/Crypto.cpp +++ b/Crypto.cpp @@ -270,10 +270,9 @@ namespace crypto { if (m_IsUpdated) { - const BIGNUM * priv_key, * pub_key; - DH_get0_key (m_DH, &pub_key, &priv_key); - bn2buf (pub_key, m_PublicKey, 256); - DH_set0_key (m_DH, NULL, NULL); + // TODO: seems race condition here + bn2buf (m_DH->pub_key, m_PublicKey, 256); + BN_free (m_DH->pub_key); m_DH->pub_key = NULL; m_IsUpdated= false; } return m_PublicKey; From aa47e11471325056b4489e7326f857c6db9d0a95 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 10 Nov 2016 21:44:40 -0500 Subject: [PATCH 09/40] fixed race condition --- Crypto.cpp | 20 +++----------------- Crypto.h | 5 ++--- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/Crypto.cpp b/Crypto.cpp index c70b62ef..f9478646 100644 --- a/Crypto.cpp +++ b/Crypto.cpp @@ -224,7 +224,7 @@ namespace crypto // DH - DHKeys::DHKeys (): m_IsUpdated (true) + DHKeys::DHKeys () { m_DH = DH_new (); DH_set0_pqg (m_DH, BN_dup (elgp), NULL, BN_dup (elgg)); @@ -236,7 +236,7 @@ namespace crypto DH_free (m_DH); } - void DHKeys::GenerateKeys (uint8_t * priv, uint8_t * pub) + void DHKeys::GenerateKeys () { BIGNUM * priv_key = NULL, * pub_key = NULL; #if !defined(__x86_64__) // use short exponent for non x64 @@ -261,21 +261,7 @@ namespace crypto DH_get0_key (m_DH, (const BIGNUM **)&pub_key, (const BIGNUM **)&priv_key); } - if (priv) bn2buf (priv_key, priv, 256); - if (pub) bn2buf (pub_key, pub, 256); - m_IsUpdated = true; - } - - const uint8_t * DHKeys::GetPublicKey () - { - if (m_IsUpdated) - { - // TODO: seems race condition here - bn2buf (m_DH->pub_key, m_PublicKey, 256); - BN_free (m_DH->pub_key); m_DH->pub_key = NULL; - m_IsUpdated= false; - } - return m_PublicKey; + bn2buf (pub_key, m_PublicKey, 256); } void DHKeys::Agree (const uint8_t * pub, uint8_t * shared) diff --git a/Crypto.h b/Crypto.h index 115fefda..476d2a26 100644 --- a/Crypto.h +++ b/Crypto.h @@ -36,15 +36,14 @@ namespace crypto DHKeys (); ~DHKeys (); - void GenerateKeys (uint8_t * priv = nullptr, uint8_t * pub = nullptr); - const uint8_t * GetPublicKey (); + void GenerateKeys (); + const uint8_t * GetPublicKey () const { return m_PublicKey; }; void Agree (const uint8_t * pub, uint8_t * shared); private: DH * m_DH; uint8_t m_PublicKey[256]; - bool m_IsUpdated; }; // ElGamal From 74aa961561895c661bfada1859a6b58e84c8fe93 Mon Sep 17 00:00:00 2001 From: Darknet Villain Date: Fri, 11 Nov 2016 09:42:18 +0000 Subject: [PATCH 10/40] Fix RTD: Use 4 spaces, not tabs in docs --- docs/building/windows.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/building/windows.md b/docs/building/windows.md index 0aa76877..7cc09cb8 100644 --- a/docs/building/windows.md +++ b/docs/building/windows.md @@ -30,16 +30,16 @@ Where $ARCH is `i686` or `x86_64` (matching your system). - 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 + 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 From 91427264c3d97d38158b0d34fd65cf3411bfbb40 Mon Sep 17 00:00:00 2001 From: Darknet Villain Date: Fri, 11 Nov 2016 10:01:38 +0000 Subject: [PATCH 11/40] Fix link to configuration --- docs/usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage.md b/docs/usage.md index a4bcbb77..1ce9eed6 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -48,7 +48,7 @@ Enable/disable i2pd to be started on bootup: ## Configuring i2pd -See [configuration page](i2pd.readthedocs.io/page/configuration.html). +See [configuration documentation](/page/configuration.html). ## Browsing and hosting websites From 6f2357c695bc90896c2bd86a2e02da6b0c6c6f5e Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 11 Nov 2016 12:44:44 -0500 Subject: [PATCH 12/40] fixed openssl 1.1 crash --- Identity.cpp | 2 +- Signature.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Identity.cpp b/Identity.cpp index 9e07382f..f39e9bd8 100644 --- a/Identity.cpp +++ b/Identity.cpp @@ -488,7 +488,7 @@ namespace data switch (m_Public->GetSigningKeyType ()) { case SIGNING_KEY_TYPE_DSA_SHA1: - m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey)); + m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey)); break; case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: m_Signer.reset (new i2p::crypto::ECDSAP256Signer (m_SigningPrivateKey)); diff --git a/Signature.h b/Signature.h index 7962bc2d..1d90d8a3 100644 --- a/Signature.h +++ b/Signature.h @@ -77,10 +77,11 @@ namespace crypto { public: - DSASigner (const uint8_t * signingPrivateKey) + DSASigner (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey) + // openssl 1.1 always requires DSA public key even for signing { m_PrivateKey = CreateDSA (); - DSA_set0_key (m_PrivateKey, NULL, BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL)); + DSA_set0_key (m_PrivateKey, BN_bin2bn (signingPublicKey, DSA_PUBLIC_KEY_LENGTH, NULL), BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL)); } ~DSASigner () From 8676a1b4efcb7210e20767d7c30d62a636406dc0 Mon Sep 17 00:00:00 2001 From: atnaguzin Date: Sat, 12 Nov 2016 17:49:16 +0300 Subject: [PATCH 13/40] update changelog, added leaseset list to client/server tunnel pages --- ChangeLog | 4 ++++ Destination.h | 1 + HTTPServer.cpp | 11 +++++++++-- debian/changelog | 6 ++++++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 98b33e81..dd1bac57 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,10 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.10.1] - 2016-11-07 +### Fixed +- Fixed some performance issues for Windows and Android + ## [2.10.0] - 2016-10-17 ### Added - Datagram i2p tunnels diff --git a/Destination.h b/Destination.h index ba19a32a..121b7e16 100644 --- a/Destination.h +++ b/Destination.h @@ -143,6 +143,7 @@ namespace client // for HTTP only int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); }; + const decltype(m_RemoteLeaseSets)& GetLeaseSets () const { return m_RemoteLeaseSets; }; }; class ClientDestination: public LeaseSetDestination diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 99edf508..556051aa 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -225,7 +225,7 @@ namespace http { else s << numKBytesSent / 1024 / 1024 << " GiB"; s << " (" << (double) i2p::transport::transports.GetOutBandwidth () / 1024 << " KiB/s)
\r\n"; - s << "Data path: " << i2p::fs::GetDataDir() << "
\r\n
\r\n"; + s << "Data path: " << i2p::fs::GetDataDir() << "
\r\n"; s << "
\r\n\r\n

\r\n"; s << "Router Ident: " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "
\r\n"; s << "Router Family: " << i2p::context.GetRouterInfo().GetProperty("family") << "
\r\n"; @@ -253,7 +253,7 @@ namespace http { s << address->host.to_string() << ":" << address->port << "
\r\n"; } s << "

\r\n
\r\n"; - s << "
\r\nRouters: " << i2p::data::netdb.GetNumRouters () << " "; + s << "Routers: " << i2p::data::netdb.GetNumRouters () << " "; s << "Floodfills: " << i2p::data::netdb.GetNumFloodfills () << " "; s << "LeaseSets: " << i2p::data::netdb.GetNumLeaseSets () << "
\r\n"; @@ -287,6 +287,13 @@ namespace http { s << "Base64:
\r\n
\r\n
\r\n"; s << "LeaseSets: " << dest->GetNumRemoteLeaseSets () << "
\r\n"; + if(dest->GetNumRemoteLeaseSets()) + { + s << "
\r\n\r\n

\r\n"; + for(auto& it: dest->GetLeaseSets ()) + s << it.second->GetIdentHash ().ToBase32 () << "
\r\n"; + s << "

\r\n
\r\n"; + } auto pool = dest->GetTunnelPool (); if (pool) { diff --git a/debian/changelog b/debian/changelog index 1ecafa34..f71b2e4a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +i2pd (2.10.1-1) unstable; urgency=low + + * updated to version 2.10.1 + + -- orignal Mon, 7 Nov 2016 14:18:30 +0000 + i2pd (2.10.0-1) unstable; urgency=low * updated to version 2.10.0/0.9.27 From f76b014a5296d04875acac0ea59cddabcca84ac2 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 13 Nov 2016 09:14:05 -0500 Subject: [PATCH 14/40] re-run PeerTest --- Transports.cpp | 19 ++++++++++++++++--- Transports.h | 6 ++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Transports.cpp b/Transports.cpp index 358ca4c7..d41253d6 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -108,7 +108,8 @@ namespace transport Transports transports; Transports::Transports (): - m_IsOnline (true), m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), m_PeerCleanupTimer (m_Service), + m_IsOnline (true), m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), + m_PeerCleanupTimer (m_Service), m_PeerTestTimer (m_Service), m_NTCPServer (nullptr), m_SSUServer (nullptr), m_DHKeysPairSupplier (5), // 5 pre-generated keys m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_InBandwidth (0), m_OutBandwidth (0), m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0), m_LastBandwidthUpdateTime (0) @@ -168,11 +169,14 @@ namespace transport } m_PeerCleanupTimer.expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT)); m_PeerCleanupTimer.async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1)); + m_PeerTestTimer.expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL)); + m_PeerTestTimer.async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1)); } void Transports::Stop () { m_PeerCleanupTimer.cancel (); + m_PeerTestTimer.cancel (); m_Peers.clear (); if (m_SSUServer) { @@ -546,8 +550,7 @@ namespace transport { if (RoutesRestricted()) return; if (m_SSUServer) - { - + { bool statusChanged = false; for (int i = 0; i < 5; i++) { @@ -688,6 +691,16 @@ namespace transport } } + void Transports::HandlePeerTestTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + PeerTest (); + m_PeerTestTimer.expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL)); + m_PeerTestTimer.async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1)); + } + } + std::shared_ptr Transports::GetRandomPeer () const { if (m_Peers.empty ()) return nullptr; diff --git a/Transports.h b/Transports.h index 9ecfd719..1fe262a9 100644 --- a/Transports.h +++ b/Transports.h @@ -66,6 +66,7 @@ namespace transport }; const size_t SESSION_CREATION_TIMEOUT = 10; // in seconds + const int PEER_TEST_INTERVAL = 71; // in minutes const int MAX_NUM_DELAYED_MESSAGES = 50; class Transports { @@ -127,7 +128,8 @@ namespace transport void PostCloseSession (std::shared_ptr router); bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer); void HandlePeerCleanupTimer (const boost::system::error_code& ecode); - + void HandlePeerTestTimer (const boost::system::error_code& ecode); + void NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident); void HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, i2p::data::IdentHash ident, std::shared_ptr resolver); @@ -144,7 +146,7 @@ namespace transport std::thread * m_Thread; boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; - boost::asio::deadline_timer m_PeerCleanupTimer; + boost::asio::deadline_timer m_PeerCleanupTimer, m_PeerTestTimer; NTCPServer * m_NTCPServer; SSUServer * m_SSUServer; From eaa7adc88c528a4aba1f535ca0b534a86caa2700 Mon Sep 17 00:00:00 2001 From: Darknet Villain Date: Sun, 13 Nov 2016 23:04:41 +0000 Subject: [PATCH 15/40] Update usage.md --- docs/usage.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index 1ce9eed6..7cb206c1 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -23,12 +23,12 @@ To display all available options: i2pd can be controlled with signals. Process ID by default is written to file `~/.i2pd/i2pd.pid` or `/var/run/i2pd/i2pd.pid`. You can use `kill` utility to send signals like this: - kill -TERM $( cat /var/run/i2pd/i2pd.pid ) + kill -INT $( cat /var/run/i2pd/i2pd.pid ) i2pd supports the following signals: - TERM - Graceful shutdown. i2pd will wait for 10 minutes and stop. Send second TERM signal to shutdown i2pd immediately. - HUP - Reload configuration files. +* INT - Graceful shutdown. i2pd will wait for 10 minutes and stop. Send second INT signal to shutdown i2pd immediately. +* HUP - Reload configuration files. ### systemd unit From 975dab6d1daed97ad4bab66daf481bc2815cc58b Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 14 Nov 2016 08:38:25 -0500 Subject: [PATCH 16/40] add hacking.md for notes on internal structure --- docs/hacking.md | 114 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 docs/hacking.md diff --git a/docs/hacking.md b/docs/hacking.md new file mode 100644 index 00000000..163575f0 --- /dev/null +++ b/docs/hacking.md @@ -0,0 +1,114 @@ + +# Hacking on I2PD + +This document contains notes compiled from hacking on i2pd + +## prerequisites + +This guide assumes: + +* a decent understanding of c++ +* basic understanding of how i2p works at i2np level and up + +## general structure + +Notes on multithreading + +* every compontent runs in its own thread + +* each component (usually) has a public function `GetService()` which can be used to obtain the `boost::asio::io_service` that it uses. + +* when talking between components/threads, **always** use `GetService().post()` and be mindfull of stack allocated memory. + + +### NetDb + +#### NetDb.h + +The `i2p::data::netdb` is a `i2p::data::NetDb` instance processes and dispatches *inbound* i2np messages passed in from transports. + +global singleton at `i2p::data::netdb` as of 2.10.1 + +#### NetDbRequests.h + +For Pending RouterInfo/LeaseSet lookup and store requests + + +### ClientContext + +#### ClientContext.h + +`i2p::client::ClientContext` spawns all destinations used by the i2p router including the shared local destination. + +global singleton at `i2p::client::context` as of 2.10.1 + + + +### Daemon + +File: Daemon.cpp + +`i2p::util::Daemon_Singleton_Private` subclasses implement the daemon start-up and tear-down, creates Http Webui and i2p control server. + + + + +### Destinations + +#### Destination.h + +each destination runs in its own thread + +##### i2p::client::LeaseSetDestination + +Base for `i2p::client::ClientDestination` + +##### i2p::client::ClientDestination + +Destination capable of creating (tcp/i2p) streams and datagram sessions. + + +#### Streaming.h + +##### i2p::stream::StreamingDestination + +Does not implement any destination related members, the name is a bit misleading. + +Owns a `i2p::client::ClientDestination` and runs in the destination thread. + +Anyone creating or using streams outside of the destination thread **MUST** be aware of the consequences of multithreaded c++ :^) + +If you use streaming please consider running all code within the destination thread using `ClientDestination::GetService().post()` + + +#### Garlic.h + +Provides Inter-Destination routing primatives. + +##### i2p::garlic::GarlicDestination + +sublcass of `i2p::client::LeaseSetDestination` for sending messages down shared routing paths. + +##### i2p::garlic::GarlicRoutingSession + +a point to point conversation between us and 1 other destination. + +##### i2p::garlic::GarlicRoutingPath + +A routing path currently used by a routing session. specifies which outbound tunnel to use and which remote lease set to use for `OBEP` to `IBGW` inter tunnel communication. + +members: + +* outboundTunnel (OBEP) +* remoteLease (IBGW) +* rtt (round trip time) +* updatedTime (last time this path's IBGW/OBEP was updated) +* numTimesUsesd (number of times this path was used) + +### Transports + +each transport runs in its own thread + +#### Transports.h + +`i2p::transport::Transports` contains NTCP and SSU transport instances From 6b5b9b3d62b556abdc8450bf44e3b10ac79a7422 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 14 Nov 2016 12:05:44 -0500 Subject: [PATCH 17/40] add reseed from floodfill option --- Config.cpp | 3 +- NetDb.cpp | 80 ++++++++++++++++++++++++++++++++++++++++++++--- NetDb.h | 9 ++++++ NetDbRequests.cpp | 9 ++++-- Tag.h | 8 ++++- 5 files changed, 100 insertions(+), 9 deletions(-) diff --git a/Config.cpp b/Config.cpp index aa75b8db..71fcbfbd 100644 --- a/Config.cpp +++ b/Config.cpp @@ -157,7 +157,8 @@ namespace config { options_description reseed("Reseed options"); reseed.add_options() - ("reseed.verify", value()->default_value(false), "Verify .su3 signature") + ("reseed.verify", value()->default_value(false), "Verify .su3 signature") + ("reseed.floodfill", value()->default_value(""), "Path to router info of floodfill to reseed from") ("reseed.file", value()->default_value(""), "Path to .su3 file") ("reseed.urls", value()->default_value( "https://reseed.i2p-projekt.de/," diff --git a/NetDb.cpp b/NetDb.cpp index dbfa4bcb..e667dc11 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -14,6 +14,7 @@ #include "RouterContext.h" #include "Garlic.h" #include "NetDb.h" +#include "Config.h" using namespace i2p::transport; @@ -23,7 +24,7 @@ namespace data { NetDb netdb; - NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_HiddenMode(false) + NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_FloodfillBootstrap(nullptr), m_HiddenMode(false) { } @@ -140,6 +141,8 @@ namespace data LogPrint(eLogError, "NetDb: no known routers, reseed seems to be totally failed"); break; } + else // we have peers now + m_FloodfillBootstrap = nullptr; if (numRouters < 2500 || ts - lastExploratory >= 90) { numRouters = 800/numRouters; @@ -295,13 +298,62 @@ namespace data m_Reseeder = new Reseeder (); m_Reseeder->LoadCertificates (); // we need certificates for SU3 verification } - int reseedRetries = 0; + int reseedRetries = 0; + + // try reseeding from floodfill first if specified + std::string riPath; + if(i2p::config::GetOption("reseed.floodfill", riPath)) { + auto ri = std::make_shared(riPath); + if (ri->IsFloodfill()) { + const uint8_t * riData = ri->GetBuffer(); + int riLen = ri->GetBufferLen(); + if(!i2p::data::netdb.AddRouterInfo(riData, riLen)) { + // bad router info + LogPrint(eLogError, "NetDb: bad router info"); + return; + } + m_FloodfillBootstrap = ri; + ReseedFromFloodfill(*ri); + // don't try reseed servers if trying to boostrap from floodfill + return; + } + } + while (reseedRetries < 10 && !m_Reseeder->ReseedNowSU3 ()) reseedRetries++; if (reseedRetries >= 10) LogPrint (eLogWarning, "NetDb: failed to reseed after 10 attempts"); } + void NetDb::ReseedFromFloodfill(const RouterInfo & ri, int numRouters, int numFloodfills) + { + LogPrint(eLogInfo, "NetDB: reseeding from floodfill ", ri.GetIdentHashBase64()); + std::vector > requests; + + i2p::data::IdentHash ourIdent = i2p::context.GetIdentHash(); + i2p::data::IdentHash ih = ri.GetIdentHash(); + i2p::data::IdentHash randomIdent; + + // make floodfill lookups + while(numFloodfills > 0) { + randomIdent.Randomize(); + auto msg = i2p::CreateRouterInfoDatabaseLookupMsg(randomIdent, ourIdent, 0, false); + requests.push_back(msg); + numFloodfills --; + } + + // make regular router lookups + while(numRouters > 0) { + randomIdent.Randomize(); + auto msg = i2p::CreateRouterInfoDatabaseLookupMsg(randomIdent, ourIdent, 0, true); + requests.push_back(msg); + numRouters --; + } + + // send them off + i2p::transport::transports.SendMessages(ih, requests); + } + bool NetDb::LoadRouterInfo (const std::string & path) { auto r = std::make_shared(path); @@ -498,6 +550,21 @@ namespace data m_Requests.RequestComplete (destination, nullptr); } } + + void NetDb::RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete) + { + + auto dest = m_Requests.CreateRequest (destination, exploritory, requestComplete); // non-exploratory + if (!dest) + { + LogPrint (eLogWarning, "NetDb: destination ", destination.ToBase64(), " is requested already"); + return; + } + LogPrint(eLogInfo, "NetDb: destination ", destination.ToBase64(), " being requested directly from ", from.ToBase64()); + // direct + transports.SendMessage (from, dest->CreateRequestMessage (nullptr, nullptr)); + } + void NetDb::HandleDatabaseStoreMsg (std::shared_ptr m) { @@ -620,7 +687,7 @@ namespace data if (!dest->IsExploratory ()) { // reply to our destination. Try other floodfills - if (outbound && inbound ) + if (outbound && inbound) { std::vector msgs; auto count = dest->GetExcludedPeers ().size (); @@ -664,7 +731,7 @@ namespace data // no more requests for detination possible. delete it m_Requests.RequestComplete (ident, nullptr); } - else + else if(!m_FloodfillBootstrap) LogPrint (eLogWarning, "NetDb: requested destination for ", key, " not found"); // try responses @@ -681,7 +748,10 @@ namespace data { // router with ident not found or too old (1 hour) LogPrint (eLogDebug, "NetDb: found new/outdated router. Requesting RouterInfo ..."); - RequestDestination (router); + if(m_FloodfillBootstrap) + RequestDestinationFrom(router, m_FloodfillBootstrap->GetIdentHash(), true); + else + RequestDestination (router); } else LogPrint (eLogDebug, "NetDb: [:|||:]"); diff --git a/NetDb.h b/NetDb.h index d295ebbe..94c8a086 100644 --- a/NetDb.h +++ b/NetDb.h @@ -60,6 +60,7 @@ namespace data std::shared_ptr FindRouterProfile (const IdentHash& ident) const; void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr); + void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr); void HandleDatabaseStoreMsg (std::shared_ptr msg); void HandleDatabaseSearchReplyMsg (std::shared_ptr msg); @@ -98,6 +99,9 @@ namespace data void VisitRouterInfos(RouterInfoVisitor v); /** visit N random router that match using filter, then visit them with a visitor, return number of RouterInfos that were visited */ size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n); + + + private: void Load (); @@ -110,6 +114,8 @@ namespace data void ManageRequests (); void ManageLookupResponses (); + void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20); + template std::shared_ptr GetRandomRouter (Filter filter) const; @@ -135,6 +141,9 @@ namespace data friend class NetDbRequests; NetDbRequests m_Requests; + /** router info we are bootstrapping from or nullptr if we are not currently doing that*/ + std::shared_ptr m_FloodfillBootstrap; + std::map, uint64_t> > m_LookupResponses; // ident->(closest FFs, timestamp) /** true if in hidden mode */ diff --git a/NetDbRequests.cpp b/NetDbRequests.cpp index 474d3693..866bc6d9 100644 --- a/NetDbRequests.cpp +++ b/NetDbRequests.cpp @@ -11,10 +11,15 @@ namespace data std::shared_ptr RequestedDestination::CreateRequestMessage (std::shared_ptr router, std::shared_ptr replyTunnel) { - auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, + std::shared_ptr msg; + if(replyTunnel) + msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory, &m_ExcludedPeers); - m_ExcludedPeers.insert (router->GetIdentHash ()); + else + msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers); + if(router) + m_ExcludedPeers.insert (router->GetIdentHash ()); m_CreationTime = i2p::util::GetSecondsSinceEpoch (); return msg; } diff --git a/Tag.h b/Tag.h index 30dfa654..3d21183f 100644 --- a/Tag.h +++ b/Tag.h @@ -11,6 +11,7 @@ #include #include +#include #include "Base.h" namespace i2p { @@ -49,7 +50,12 @@ public: { memset(m_Buf, c, sz); } - + + void Randomize() + { + RAND_bytes(m_Buf, sz); + } + std::string ToBase64 () const { char str[sz*2]; From ea31ca5ee815ca615d3834efc99909d69b9997aa Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 14 Nov 2016 12:05:44 -0500 Subject: [PATCH 18/40] add reseed from floodfill option --- Config.cpp | 3 +- NetDb.cpp | 80 ++++++++++++++++++++++++++++++++++++++++++++--- NetDb.h | 9 ++++++ NetDbRequests.cpp | 9 ++++-- Tag.h | 8 ++++- 5 files changed, 100 insertions(+), 9 deletions(-) diff --git a/Config.cpp b/Config.cpp index d11802cc..8d932048 100644 --- a/Config.cpp +++ b/Config.cpp @@ -157,7 +157,8 @@ namespace config { options_description reseed("Reseed options"); reseed.add_options() - ("reseed.verify", value()->default_value(false), "Verify .su3 signature") + ("reseed.verify", value()->default_value(false), "Verify .su3 signature") + ("reseed.floodfill", value()->default_value(""), "Path to router info of floodfill to reseed from") ("reseed.file", value()->default_value(""), "Path to .su3 file") ("reseed.urls", value()->default_value( "https://reseed.i2p-projekt.de/," diff --git a/NetDb.cpp b/NetDb.cpp index dbfa4bcb..e667dc11 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -14,6 +14,7 @@ #include "RouterContext.h" #include "Garlic.h" #include "NetDb.h" +#include "Config.h" using namespace i2p::transport; @@ -23,7 +24,7 @@ namespace data { NetDb netdb; - NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_HiddenMode(false) + NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_FloodfillBootstrap(nullptr), m_HiddenMode(false) { } @@ -140,6 +141,8 @@ namespace data LogPrint(eLogError, "NetDb: no known routers, reseed seems to be totally failed"); break; } + else // we have peers now + m_FloodfillBootstrap = nullptr; if (numRouters < 2500 || ts - lastExploratory >= 90) { numRouters = 800/numRouters; @@ -295,13 +298,62 @@ namespace data m_Reseeder = new Reseeder (); m_Reseeder->LoadCertificates (); // we need certificates for SU3 verification } - int reseedRetries = 0; + int reseedRetries = 0; + + // try reseeding from floodfill first if specified + std::string riPath; + if(i2p::config::GetOption("reseed.floodfill", riPath)) { + auto ri = std::make_shared(riPath); + if (ri->IsFloodfill()) { + const uint8_t * riData = ri->GetBuffer(); + int riLen = ri->GetBufferLen(); + if(!i2p::data::netdb.AddRouterInfo(riData, riLen)) { + // bad router info + LogPrint(eLogError, "NetDb: bad router info"); + return; + } + m_FloodfillBootstrap = ri; + ReseedFromFloodfill(*ri); + // don't try reseed servers if trying to boostrap from floodfill + return; + } + } + while (reseedRetries < 10 && !m_Reseeder->ReseedNowSU3 ()) reseedRetries++; if (reseedRetries >= 10) LogPrint (eLogWarning, "NetDb: failed to reseed after 10 attempts"); } + void NetDb::ReseedFromFloodfill(const RouterInfo & ri, int numRouters, int numFloodfills) + { + LogPrint(eLogInfo, "NetDB: reseeding from floodfill ", ri.GetIdentHashBase64()); + std::vector > requests; + + i2p::data::IdentHash ourIdent = i2p::context.GetIdentHash(); + i2p::data::IdentHash ih = ri.GetIdentHash(); + i2p::data::IdentHash randomIdent; + + // make floodfill lookups + while(numFloodfills > 0) { + randomIdent.Randomize(); + auto msg = i2p::CreateRouterInfoDatabaseLookupMsg(randomIdent, ourIdent, 0, false); + requests.push_back(msg); + numFloodfills --; + } + + // make regular router lookups + while(numRouters > 0) { + randomIdent.Randomize(); + auto msg = i2p::CreateRouterInfoDatabaseLookupMsg(randomIdent, ourIdent, 0, true); + requests.push_back(msg); + numRouters --; + } + + // send them off + i2p::transport::transports.SendMessages(ih, requests); + } + bool NetDb::LoadRouterInfo (const std::string & path) { auto r = std::make_shared(path); @@ -498,6 +550,21 @@ namespace data m_Requests.RequestComplete (destination, nullptr); } } + + void NetDb::RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete) + { + + auto dest = m_Requests.CreateRequest (destination, exploritory, requestComplete); // non-exploratory + if (!dest) + { + LogPrint (eLogWarning, "NetDb: destination ", destination.ToBase64(), " is requested already"); + return; + } + LogPrint(eLogInfo, "NetDb: destination ", destination.ToBase64(), " being requested directly from ", from.ToBase64()); + // direct + transports.SendMessage (from, dest->CreateRequestMessage (nullptr, nullptr)); + } + void NetDb::HandleDatabaseStoreMsg (std::shared_ptr m) { @@ -620,7 +687,7 @@ namespace data if (!dest->IsExploratory ()) { // reply to our destination. Try other floodfills - if (outbound && inbound ) + if (outbound && inbound) { std::vector msgs; auto count = dest->GetExcludedPeers ().size (); @@ -664,7 +731,7 @@ namespace data // no more requests for detination possible. delete it m_Requests.RequestComplete (ident, nullptr); } - else + else if(!m_FloodfillBootstrap) LogPrint (eLogWarning, "NetDb: requested destination for ", key, " not found"); // try responses @@ -681,7 +748,10 @@ namespace data { // router with ident not found or too old (1 hour) LogPrint (eLogDebug, "NetDb: found new/outdated router. Requesting RouterInfo ..."); - RequestDestination (router); + if(m_FloodfillBootstrap) + RequestDestinationFrom(router, m_FloodfillBootstrap->GetIdentHash(), true); + else + RequestDestination (router); } else LogPrint (eLogDebug, "NetDb: [:|||:]"); diff --git a/NetDb.h b/NetDb.h index d295ebbe..94c8a086 100644 --- a/NetDb.h +++ b/NetDb.h @@ -60,6 +60,7 @@ namespace data std::shared_ptr FindRouterProfile (const IdentHash& ident) const; void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr); + void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr); void HandleDatabaseStoreMsg (std::shared_ptr msg); void HandleDatabaseSearchReplyMsg (std::shared_ptr msg); @@ -98,6 +99,9 @@ namespace data void VisitRouterInfos(RouterInfoVisitor v); /** visit N random router that match using filter, then visit them with a visitor, return number of RouterInfos that were visited */ size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n); + + + private: void Load (); @@ -110,6 +114,8 @@ namespace data void ManageRequests (); void ManageLookupResponses (); + void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20); + template std::shared_ptr GetRandomRouter (Filter filter) const; @@ -135,6 +141,9 @@ namespace data friend class NetDbRequests; NetDbRequests m_Requests; + /** router info we are bootstrapping from or nullptr if we are not currently doing that*/ + std::shared_ptr m_FloodfillBootstrap; + std::map, uint64_t> > m_LookupResponses; // ident->(closest FFs, timestamp) /** true if in hidden mode */ diff --git a/NetDbRequests.cpp b/NetDbRequests.cpp index 474d3693..866bc6d9 100644 --- a/NetDbRequests.cpp +++ b/NetDbRequests.cpp @@ -11,10 +11,15 @@ namespace data std::shared_ptr RequestedDestination::CreateRequestMessage (std::shared_ptr router, std::shared_ptr replyTunnel) { - auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, + std::shared_ptr msg; + if(replyTunnel) + msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory, &m_ExcludedPeers); - m_ExcludedPeers.insert (router->GetIdentHash ()); + else + msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers); + if(router) + m_ExcludedPeers.insert (router->GetIdentHash ()); m_CreationTime = i2p::util::GetSecondsSinceEpoch (); return msg; } diff --git a/Tag.h b/Tag.h index 30dfa654..3d21183f 100644 --- a/Tag.h +++ b/Tag.h @@ -11,6 +11,7 @@ #include #include +#include #include "Base.h" namespace i2p { @@ -49,7 +50,12 @@ public: { memset(m_Buf, c, sz); } - + + void Randomize() + { + RAND_bytes(m_Buf, sz); + } + std::string ToBase64 () const { char str[sz*2]; From 98484d54c0fbf877917797d9f63a8c86285c8180 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 14 Nov 2016 13:13:57 -0500 Subject: [PATCH 19/40] check for outdated routers in reseed --- Reseed.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Reseed.cpp b/Reseed.cpp index 65de62b4..427e839d 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -305,6 +305,22 @@ namespace data if (end - contentPos >= contentLength) break; // we are beyond contentLength } + if (numFiles) // check if routers are not outdated + { + auto ts = i2p::util::GetMillisecondsSinceEpoch (); + int numOutdated = 0; + i2p::data::netdb.VisitRouterInfos ( + [&numOutdated, ts](std::shared_ptr r) + { + if (r && ts > r->GetTimestamp () + i2p::data::NETDB_MAX_EXPIRATION_TIMEOUT*1000LL) + { + LogPrint (eLogError, "Reseed: router ", r->GetIdentHash().ToBase64 (), " is outdated by ", (ts - r->GetTimestamp ())/1000LL/3600LL, " hours"); + numOutdated++; + } + }); + if (numOutdated > numFiles/2) // more than half + LogPrint (eLogError, "Reseed: mammoth's shit"); + } return numFiles; } From 89b624308e636544a3a062e37815517643bafa4c Mon Sep 17 00:00:00 2001 From: MXPLRS | Kirill Date: Mon, 14 Nov 2016 21:40:03 +0300 Subject: [PATCH 20/40] added ASCII art --- Reseed.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Reseed.cpp b/Reseed.cpp index 427e839d..f6656872 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -320,6 +320,14 @@ namespace data }); if (numOutdated > numFiles/2) // more than half LogPrint (eLogError, "Reseed: mammoth's shit"); + LogPrint (eLogError, " *_____*", + std::endl, " *_*****_*", + std::endl, " *_(O)_(O)_*", + std::endl, "**____V____**", + std::endl, "**_________**", + std::endl, "**_________**", + std::endl, " *_________*", + std::endl, " ***___***"); } return numFiles; } From ea191afd9db67cab77d633890e20e1f0d2228741 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 14 Nov 2016 13:48:34 -0500 Subject: [PATCH 21/40] fixed build error --- Reseed.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Reseed.cpp b/Reseed.cpp index f6656872..214f5bdf 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -319,15 +319,17 @@ namespace data } }); if (numOutdated > numFiles/2) // more than half + { LogPrint (eLogError, "Reseed: mammoth's shit"); - LogPrint (eLogError, " *_____*", + /*LogPrint (eLogError, " *_____*", std::endl, " *_*****_*", std::endl, " *_(O)_(O)_*", std::endl, "**____V____**", std::endl, "**_________**", std::endl, "**_________**", std::endl, " *_________*", - std::endl, " ***___***"); + std::endl, " ***___***");*/ + } } return numFiles; } From 87fd0e6f29206f9aa67d682c3b622b81bf27db1c Mon Sep 17 00:00:00 2001 From: MXPLRS | Kirill Date: Mon, 14 Nov 2016 22:38:35 +0300 Subject: [PATCH 22/40] recommit fixed ASCII art --- Reseed.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/Reseed.cpp b/Reseed.cpp index 214f5bdf..9356222a 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -319,17 +319,15 @@ namespace data } }); if (numOutdated > numFiles/2) // more than half - { - LogPrint (eLogError, "Reseed: mammoth's shit"); - /*LogPrint (eLogError, " *_____*", - std::endl, " *_*****_*", - std::endl, " *_(O)_(O)_*", - std::endl, "**____V____**", - std::endl, "**_________**", - std::endl, "**_________**", - std::endl, " *_________*", - std::endl, " ***___***");*/ - } + LogPrint (eLogError, "Reseed: mammoth's shit\n" + " *_____*\n" + " *_*****_*\n" + " *_(O)_(O)_*\n" + " **____V____**\n" + " **_________**\n" + " **_________**\n" + " *_________*\n" + " ***___***"); } return numFiles; } From 2eea85b7864e754c11a844b5864a40d7f84f0246 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 14 Nov 2016 15:04:40 -0500 Subject: [PATCH 23/40] increase reseed expiration time to 81 hours --- Reseed.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Reseed.cpp b/Reseed.cpp index 9356222a..8c8cc881 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -312,13 +312,14 @@ namespace data i2p::data::netdb.VisitRouterInfos ( [&numOutdated, ts](std::shared_ptr r) { - if (r && ts > r->GetTimestamp () + i2p::data::NETDB_MAX_EXPIRATION_TIMEOUT*1000LL) + if (r && ts > r->GetTimestamp () + 3*i2p::data::NETDB_MAX_EXPIRATION_TIMEOUT*1000LL) // 81 hours { LogPrint (eLogError, "Reseed: router ", r->GetIdentHash().ToBase64 (), " is outdated by ", (ts - r->GetTimestamp ())/1000LL/3600LL, " hours"); numOutdated++; } }); if (numOutdated > numFiles/2) // more than half + { LogPrint (eLogError, "Reseed: mammoth's shit\n" " *_____*\n" " *_*****_*\n" @@ -328,6 +329,8 @@ namespace data " **_________**\n" " *_________*\n" " ***___***"); + numFiles = numFiles > numOutdated ? numFiles - numOutdated : 0; + } } return numFiles; } From ecdb60b44e4827aa1973124e94cd2cc5f31a02d6 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 14 Nov 2016 16:23:42 -0500 Subject: [PATCH 24/40] cleanup netdb after failed reseed --- NetDb.h | 2 +- Reseed.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/NetDb.h b/NetDb.h index 94c8a086..f6d64309 100644 --- a/NetDb.h +++ b/NetDb.h @@ -99,7 +99,7 @@ namespace data void VisitRouterInfos(RouterInfoVisitor v); /** visit N random router that match using filter, then visit them with a visitor, return number of RouterInfos that were visited */ size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n); - + void ClearRouterInfos () { m_RouterInfos.clear (); }; private: diff --git a/Reseed.cpp b/Reseed.cpp index 8c8cc881..3ea69eff 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -312,7 +312,7 @@ namespace data i2p::data::netdb.VisitRouterInfos ( [&numOutdated, ts](std::shared_ptr r) { - if (r && ts > r->GetTimestamp () + 3*i2p::data::NETDB_MAX_EXPIRATION_TIMEOUT*1000LL) // 81 hours + if (r && ts > r->GetTimestamp () + 10*i2p::data::NETDB_MAX_EXPIRATION_TIMEOUT*1000LL) // 270 hours { LogPrint (eLogError, "Reseed: router ", r->GetIdentHash().ToBase64 (), " is outdated by ", (ts - r->GetTimestamp ())/1000LL/3600LL, " hours"); numOutdated++; @@ -329,7 +329,8 @@ namespace data " **_________**\n" " *_________*\n" " ***___***"); - numFiles = numFiles > numOutdated ? numFiles - numOutdated : 0; + i2p::data::netdb.ClearRouterInfos (); + numFiles = 0; } } return numFiles; From 7d7bbf15bfd820a4662f3ad19f1702f1ed759ec9 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 15 Nov 2016 10:10:13 -0500 Subject: [PATCH 25/40] use DSA for http and socks proxy by defualt --- ClientContext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ClientContext.cpp b/ClientContext.cpp index 4639ec05..7ec699cb 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -52,7 +52,7 @@ namespace client if (httpProxyKeys.length () > 0) { i2p::data::PrivateKeys keys; - if(LoadPrivateKeys (keys, httpProxyKeys)) + if(LoadPrivateKeys (keys, httpProxyKeys, i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)) { std::map params; ReadI2CPOptionsFromConfig ("httpproxy.", params); @@ -82,7 +82,7 @@ namespace client if (socksProxyKeys.length () > 0) { i2p::data::PrivateKeys keys; - if (LoadPrivateKeys (keys, socksProxyKeys)) + if (LoadPrivateKeys (keys, socksProxyKeys, i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)) { std::map params; ReadI2CPOptionsFromConfig ("socksproxy.", params); From fc94e846a6a30eccdc811c83c81ad21eef7f8c27 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 15 Nov 2016 10:20:09 -0500 Subject: [PATCH 26/40] add latency requirement option --- ClientContext.cpp | 8 +++++++- Config.cpp | 8 ++++++-- Destination.cpp | 16 ++++++++++++++++ Destination.h | 6 ++++++ Tunnel.cpp | 23 +++++++++++++++++++++++ Tunnel.h | 25 +++++++++++++++++++++++++ TunnelPool.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++-- TunnelPool.h | 15 +++++++++++++++ 8 files changed, 141 insertions(+), 5 deletions(-) diff --git a/ClientContext.cpp b/ClientContext.cpp index 4639ec05..52423a23 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -372,6 +372,8 @@ namespace client 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); options[I2CP_PARAM_TAGS_TO_SEND] = GetI2CPOption (section, I2CP_PARAM_TAGS_TO_SEND, DEFAULT_TAGS_TO_SEND); + options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MIN_TUNNEL_LATENCY, DEFAULT_MIN_TUNNEL_LATENCY); + options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY); } void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, std::map& options) const @@ -384,7 +386,11 @@ namespace client 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; + options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = value; + if (i2p::config::GetOption(prefix + I2CP_PARAM_MIN_TUNNEL_LATENCY, value)) + options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = value; + if (i2p::config::GetOption(prefix + I2CP_PARAM_MAX_TUNNEL_LATENCY, value)) + options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = value; } void ClientContext::ReadTunnels () diff --git a/Config.cpp b/Config.cpp index 8d932048..ed22c561 100644 --- a/Config.cpp +++ b/Config.cpp @@ -86,7 +86,9 @@ namespace config { ("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") + ("httpproxy.outbound.quantity", value()->default_value("5"), "HTTP proxy outbound tunnels quantity") + ("httpproxy.latency.min", value()->default_value(0), "HTTP proxy min latency for tunnels") + ("httpproxy.latency.max", value()->default_value(0), "HTTP proxy max latency for tunnels") ; options_description socksproxy("SOCKS Proxy options"); @@ -98,7 +100,9 @@ namespace config { ("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.outbound.quantity", value()->default_value("5"), "SOCKS proxy outbound tunnels quantity") + ("socksproxy.latency.min", value()->default_value(0), "SOCKS proxy min latency for tunnels") + ("socksproxy.latency.max", value()->default_value(0), "SOCKS proxy max latency for tunnels") ("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") ; diff --git a/Destination.cpp b/Destination.cpp index 9df3b438..f0bc52cb 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -63,6 +63,22 @@ namespace client m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inLen, outLen, inQty, outQty); if (explicitPeers) m_Pool->SetExplicitPeers (explicitPeers); + if(params) + { + auto itr = params->find(I2CP_PARAM_MAX_TUNNEL_LATENCY); + if (itr != params->end()) { + auto maxlatency = std::stoi(itr->second); + itr = params->find(I2CP_PARAM_MIN_TUNNEL_LATENCY); + if (itr != params->end()) { + auto minlatency = std::stoi(itr->second); + if ( minlatency > 0 && maxlatency > 0 ) { + // set tunnel pool latency + LogPrint(eLogInfo, "Destination: requiring tunnel latency [", minlatency, "ms, ", maxlatency, "ms]"); + m_Pool->RequireLatency(minlatency, maxlatency); + } + } + } + } } LeaseSetDestination::~LeaseSetDestination () diff --git a/Destination.h b/Destination.h index 121b7e16..0d3b3b4a 100644 --- a/Destination.h +++ b/Destination.h @@ -50,6 +50,12 @@ namespace client const char I2CP_PARAM_TAGS_TO_SEND[] = "crypto.tagsToSend"; const int DEFAULT_TAGS_TO_SEND = 40; + // latency + const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min"; + const int DEFAULT_MIN_TUNNEL_LATENCY = 0; + const char I2CP_PARAM_MAX_TUNNEL_LATENCY[] = "latency.max"; + const int DEFAULT_MAX_TUNNEL_LATENCY = 0; + typedef std::function stream)> StreamRequestComplete; class LeaseSetDestination: public i2p::garlic::GarlicDestination, diff --git a/Tunnel.cpp b/Tunnel.cpp index faba99d3..2d55547c 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -21,6 +21,23 @@ namespace i2p namespace tunnel { + void TunnelLatency::AddSample(Sample s) + { + m_samples ++; + m_latency += s / m_samples; + } + + bool TunnelLatency::HasSamples() const + { + return m_samples > 0; + } + + TunnelLatency::Latency TunnelLatency::GetMeanLatency() const + { + return m_latency; + } + + Tunnel::Tunnel (std::shared_ptr config): TunnelBase (config->GetTunnelID (), config->GetNextTunnelID (), config->GetNextIdentHash ()), m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false) @@ -162,6 +179,12 @@ namespace tunnel return established; } + bool Tunnel::LatencyFitsRange(uint64_t lower, uint64_t upper) const + { + auto latency = GetMeanLatency(); + return latency >= lower && latency <= upper; + } + void Tunnel::EncryptTunnelMsg (std::shared_ptr in, std::shared_ptr out) { const uint8_t * inPayload = in->GetPayload () + 4; diff --git a/Tunnel.h b/Tunnel.h index 53c93e90..8712f56d 100644 --- a/Tunnel.h +++ b/Tunnel.h @@ -79,6 +79,22 @@ namespace tunnel eTunnelStateExpiring }; + /** @brief for storing latency history */ + struct TunnelLatency + { + typedef uint64_t Sample; + typedef uint64_t Latency; + + + void AddSample(Sample s); + bool HasSamples() const; + Latency GetMeanLatency() const; + + Latency m_latency = 0; + std::size_t m_samples = 0; + + }; + class OutboundTunnel; class InboundTunnel; class Tunnel: public TunnelBase @@ -118,6 +134,14 @@ namespace tunnel void SendTunnelDataMsg (std::shared_ptr msg); void EncryptTunnelMsg (std::shared_ptr in, std::shared_ptr out); + /** @brief add latency sample */ + void AddLatencySample(const uint64_t ms) { m_Latency.AddSample(ms); } + /** @brief get this tunnel's estimated latency */ + uint64_t GetMeanLatency() const { return m_Latency.GetMeanLatency(); } + /** @breif return true if this tunnel's latency fits in range [lowerbound, upperbound] */ + bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const; + + bool LatencyIsKnown() const { return m_Latency.HasSamples(); } protected: void PrintHops (std::stringstream& s) const; @@ -129,6 +153,7 @@ namespace tunnel std::shared_ptr m_Pool; // pool, tunnel belongs to, or null TunnelState m_State; bool m_IsRecreated; + TunnelLatency m_Latency; }; class OutboundTunnel: public Tunnel diff --git a/TunnelPool.cpp b/TunnelPool.cpp index 56d72bfb..625c7d11 100644 --- a/TunnelPool.cpp +++ b/TunnelPool.cpp @@ -147,12 +147,16 @@ namespace tunnel std::shared_ptr TunnelPool::GetNextOutboundTunnel (std::shared_ptr excluded) const { - std::unique_lock l(m_OutboundTunnelsMutex); + if (HasLatencyRequriement()) + return GetLowestLatencyOutboundTunnel(excluded); + std::unique_lock l(m_OutboundTunnelsMutex); return GetNextTunnel (m_OutboundTunnels, excluded); } std::shared_ptr TunnelPool::GetNextInboundTunnel (std::shared_ptr excluded) const { + if (HasLatencyRequriement()) + return GetLowestLatencyInboundTunnel(excluded); std::unique_lock l(m_InboundTunnelsMutex); return GetNextTunnel (m_InboundTunnels, excluded); } @@ -322,7 +326,12 @@ namespace tunnel test.first->SetState (eTunnelStateEstablished); if (test.second->GetState () == eTunnelStateTestFailed) test.second->SetState (eTunnelStateEstablished); - LogPrint (eLogDebug, "Tunnels: test of ", msgID, " successful. ", i2p::util::GetMillisecondsSinceEpoch () - timestamp, " milliseconds"); + uint64_t dlt = i2p::util::GetMillisecondsSinceEpoch () - timestamp; + LogPrint (eLogDebug, "Tunnels: test of ", msgID, " successful. ", dlt, " milliseconds"); + // update latency + uint64_t latency = dlt / 2; + test.first->AddLatencySample(latency); + test.second->AddLatencySample(latency); } else { @@ -523,5 +532,37 @@ namespace tunnel std::lock_guard lock(m_CustomPeerSelectorMutex); return m_CustomPeerSelector != nullptr; } + + std::shared_ptr TunnelPool::GetLowestLatencyInboundTunnel(std::shared_ptr exclude) const + { + std::shared_ptr tun = nullptr; + std::unique_lock lock(m_InboundTunnelsMutex); + uint64_t min = 1000000; + for (const auto & itr : m_InboundTunnels) { + if(!itr->LatencyIsKnown()) continue; + auto l = itr->GetMeanLatency(); + if (l >= min) continue; + tun = itr; + if(tun == exclude) continue; + min = l; + } + return tun; + } + + std::shared_ptr TunnelPool::GetLowestLatencyOutboundTunnel(std::shared_ptr exclude) const + { + std::shared_ptr tun = nullptr; + std::unique_lock lock(m_OutboundTunnelsMutex); + uint64_t min = 1000000; + for (const auto & itr : m_OutboundTunnels) { + if(!itr->LatencyIsKnown()) continue; + auto l = itr->GetMeanLatency(); + if (l >= min) continue; + tun = itr; + if(tun == exclude) continue; + min = l; + } + return tun; + } } } diff --git a/TunnelPool.h b/TunnelPool.h index d5bcf18f..ce20be6b 100644 --- a/TunnelPool.h +++ b/TunnelPool.h @@ -69,6 +69,17 @@ namespace tunnel void SetCustomPeerSelector(TunnelPeerSelector selector); void UnsetCustomPeerSelector(); bool HasCustomPeerSelector(); + + /** @brief make this tunnel pool yield tunnels that fit latency range [min, max] */ + void RequireLatency(uint64_t min, uint64_t max) { m_MinLatency = min; m_MaxLatency = max; } + + /** @brief return true if this tunnel pool has a latency requirement */ + bool HasLatencyRequriement() const { return m_MinLatency > 0 && m_MaxLatency > 0; } + + /** @brief get the lowest latency tunnel in this tunnel pool regardless of latency requirements */ + std::shared_ptr GetLowestLatencyInboundTunnel(std::shared_ptr exclude=nullptr) const; + std::shared_ptr GetLowestLatencyOutboundTunnel(std::shared_ptr exclude=nullptr) const; + private: void CreateInboundTunnel (); @@ -94,6 +105,10 @@ namespace tunnel bool m_IsActive; std::mutex m_CustomPeerSelectorMutex; TunnelPeerSelector m_CustomPeerSelector; + + uint64_t m_MinLatency=0; // if > 0 this tunnel pool will try building tunnels with minimum latency by ms + uint64_t m_MaxLatency=0; // if > 0 this tunnel pool will try building tunnels with maximum latency by ms + public: // for HTTP only From 7fef5f5654df6065c3129c23f6a2111d3cc76b84 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 15 Nov 2016 10:37:58 -0500 Subject: [PATCH 27/40] when selecting tunnels if we can't find a low latency tunnel fall back to regular selection algorithm --- TunnelPool.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/TunnelPool.cpp b/TunnelPool.cpp index 625c7d11..2680e8b9 100644 --- a/TunnelPool.cpp +++ b/TunnelPool.cpp @@ -147,18 +147,26 @@ namespace tunnel std::shared_ptr TunnelPool::GetNextOutboundTunnel (std::shared_ptr excluded) const { + std::shared_ptr tun = nullptr; if (HasLatencyRequriement()) - return GetLowestLatencyOutboundTunnel(excluded); - std::unique_lock l(m_OutboundTunnelsMutex); - return GetNextTunnel (m_OutboundTunnels, excluded); + tun = GetLowestLatencyOutboundTunnel(excluded); + if (! tun) { + std::unique_lock l(m_OutboundTunnelsMutex); + tun = GetNextTunnel (m_OutboundTunnels, excluded); + } + return tun; } std::shared_ptr TunnelPool::GetNextInboundTunnel (std::shared_ptr excluded) const { + std::shared_ptr tun = nullptr; if (HasLatencyRequriement()) - return GetLowestLatencyInboundTunnel(excluded); - std::unique_lock l(m_InboundTunnelsMutex); - return GetNextTunnel (m_InboundTunnels, excluded); + tun = GetLowestLatencyInboundTunnel(excluded); + if (! tun) { + std::unique_lock l(m_InboundTunnelsMutex); + tun = GetNextTunnel (m_InboundTunnels, excluded); + } + return tun; } template From 5425e9aee35fc364adf88dba187b77086cb38a14 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 15 Nov 2016 10:46:58 -0500 Subject: [PATCH 28/40] select tunnels correctly --- TunnelPool.cpp | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/TunnelPool.cpp b/TunnelPool.cpp index 2680e8b9..e0a3e99e 100644 --- a/TunnelPool.cpp +++ b/TunnelPool.cpp @@ -147,26 +147,14 @@ namespace tunnel std::shared_ptr TunnelPool::GetNextOutboundTunnel (std::shared_ptr excluded) const { - std::shared_ptr tun = nullptr; - if (HasLatencyRequriement()) - tun = GetLowestLatencyOutboundTunnel(excluded); - if (! tun) { - std::unique_lock l(m_OutboundTunnelsMutex); - tun = GetNextTunnel (m_OutboundTunnels, excluded); - } - return tun; + std::unique_lock l(m_OutboundTunnelsMutex); + return GetNextTunnel (m_OutboundTunnels, excluded); } std::shared_ptr TunnelPool::GetNextInboundTunnel (std::shared_ptr excluded) const { - std::shared_ptr tun = nullptr; - if (HasLatencyRequriement()) - tun = GetLowestLatencyInboundTunnel(excluded); - if (! tun) { - std::unique_lock l(m_InboundTunnelsMutex); - tun = GetNextTunnel (m_InboundTunnels, excluded); - } - return tun; + std::unique_lock l(m_InboundTunnelsMutex); + return GetNextTunnel (m_InboundTunnels, excluded); } template @@ -179,6 +167,10 @@ namespace tunnel { if (it->IsEstablished () && it != excluded) { + if(HasLatencyRequirement() && !it->LatencyFitsRange(m_MinLatency, m_MaxLatency)) { + i ++; + continue; + } tunnel = it; i++; } From 98a55c061394b7ed67efb1caad7bbb0a1f9be221 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 15 Nov 2016 10:48:33 -0500 Subject: [PATCH 29/40] make it compile --- TunnelPool.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TunnelPool.h b/TunnelPool.h index ce20be6b..6a73bd67 100644 --- a/TunnelPool.h +++ b/TunnelPool.h @@ -74,7 +74,7 @@ namespace tunnel void RequireLatency(uint64_t min, uint64_t max) { m_MinLatency = min; m_MaxLatency = max; } /** @brief return true if this tunnel pool has a latency requirement */ - bool HasLatencyRequriement() const { return m_MinLatency > 0 && m_MaxLatency > 0; } + bool HasLatencyRequirement() const { return m_MinLatency > 0 && m_MaxLatency > 0; } /** @brief get the lowest latency tunnel in this tunnel pool regardless of latency requirements */ std::shared_ptr GetLowestLatencyInboundTunnel(std::shared_ptr exclude=nullptr) const; From 69888e148e2d2056504387a17fa9889af991e31d Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 15 Nov 2016 11:15:48 -0500 Subject: [PATCH 30/40] use correct latency computation --- Tunnel.cpp | 13 +++++++++---- Tunnel.h | 5 ++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Tunnel.cpp b/Tunnel.cpp index 2d55547c..3e9bfc6b 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -23,18 +23,23 @@ namespace tunnel void TunnelLatency::AddSample(Sample s) { - m_samples ++; - m_latency += s / m_samples; + std::unique_lock l(m_access); + m_samples.push_back(s); } bool TunnelLatency::HasSamples() const { - return m_samples > 0; + std::unique_lock l(m_access); + return m_samples.size() > 0; } TunnelLatency::Latency TunnelLatency::GetMeanLatency() const { - return m_latency; + std::unique_lock l(m_access); + Latency l = 0; + for(auto s : m_samples) + l += s; + return l / m_samples.size(); } diff --git a/Tunnel.h b/Tunnel.h index 8712f56d..85590f58 100644 --- a/Tunnel.h +++ b/Tunnel.h @@ -90,9 +90,8 @@ namespace tunnel bool HasSamples() const; Latency GetMeanLatency() const; - Latency m_latency = 0; - std::size_t m_samples = 0; - + std::vector m_samples; + std::mutex m_access; }; class OutboundTunnel; From 34afb54c21fee0cd95107896626385e65dde795f Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 15 Nov 2016 11:16:32 -0500 Subject: [PATCH 31/40] make it compile --- Tunnel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tunnel.h b/Tunnel.h index 85590f58..f3c31461 100644 --- a/Tunnel.h +++ b/Tunnel.h @@ -91,7 +91,7 @@ namespace tunnel Latency GetMeanLatency() const; std::vector m_samples; - std::mutex m_access; + mutable std::mutex m_access; }; class OutboundTunnel; From db63bb4495669ecf0f40bd1688ee36f17e623919 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 15 Nov 2016 11:18:12 -0500 Subject: [PATCH 32/40] make it compile for real --- Tunnel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tunnel.cpp b/Tunnel.cpp index 3e9bfc6b..7bfec218 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -35,7 +35,7 @@ namespace tunnel TunnelLatency::Latency TunnelLatency::GetMeanLatency() const { - std::unique_lock l(m_access); + std::unique_lock lock(m_access); Latency l = 0; for(auto s : m_samples) l += s; From 0c5ca28a14766763e8a24eda9c30f5dd12b83f57 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 15 Nov 2016 11:27:00 -0500 Subject: [PATCH 33/40] fall back on regular tunnel algorithm --- TunnelPool.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/TunnelPool.cpp b/TunnelPool.cpp index e0a3e99e..0c3db211 100644 --- a/TunnelPool.cpp +++ b/TunnelPool.cpp @@ -176,6 +176,18 @@ namespace tunnel } if (i > ind && tunnel) break; } + if(HasLatencyRequirement() && !tunnel) { + ind = rand () % (tunnels.size ()/2 + 1), i = 0; + for (const auto& it: tunnels) + { + if (it->IsEstablished () && it != excluded) + { + tunnel = it; + i++; + } + if (i > ind && tunnel) break; + } + } if (!tunnel && excluded && excluded->IsEstablished ()) tunnel = excluded; return tunnel; } From 76c9b66db48764839fd744587cd0cc69099271ae Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 15 Nov 2016 11:31:15 -0500 Subject: [PATCH 34/40] don't blow up --- Tunnel.cpp | 11 +++++++---- TunnelPool.cpp | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Tunnel.cpp b/Tunnel.cpp index 7bfec218..e1f5c035 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -36,10 +36,13 @@ namespace tunnel TunnelLatency::Latency TunnelLatency::GetMeanLatency() const { std::unique_lock lock(m_access); - Latency l = 0; - for(auto s : m_samples) - l += s; - return l / m_samples.size(); + if (m_samples.size() > 0) { + Latency l = 0; + for(auto s : m_samples) + l += s; + return l / m_samples.size(); + } + return 0; } diff --git a/TunnelPool.cpp b/TunnelPool.cpp index 0c3db211..ccd4c12c 100644 --- a/TunnelPool.cpp +++ b/TunnelPool.cpp @@ -167,7 +167,7 @@ namespace tunnel { if (it->IsEstablished () && it != excluded) { - if(HasLatencyRequirement() && !it->LatencyFitsRange(m_MinLatency, m_MaxLatency)) { + if(HasLatencyRequirement() && it->LatencyIsKnown() && !it->LatencyFitsRange(m_MinLatency, m_MaxLatency)) { i ++; continue; } From 336cd6092021de60c8303272781b279cd02aa829 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 15 Nov 2016 12:17:21 -0500 Subject: [PATCH 35/40] don't insert same floodfill twice --- NetDb.cpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index e667dc11..5a622441 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -188,23 +188,34 @@ namespace data // TODO: check if floodfill has been changed } else + { LogPrint (eLogDebug, "NetDb: RouterInfo is older: ", ident.ToBase64()); - + updated = false; + } } else { r = std::make_shared (buf, len); if (!r->IsUnreachable ()) { - LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64()); + bool inserted = false; { std::unique_lock l(m_RouterInfosMutex); - m_RouterInfos[r->GetIdentHash ()] = r; + inserted = m_RouterInfos.insert ({r->GetIdentHash (), r}).second; } - if (r->IsFloodfill () && r->IsReachable ()) // floodfill must be reachable + if (inserted) + { + LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64()); + if (r->IsFloodfill () && r->IsReachable ()) // floodfill must be reachable + { + std::unique_lock l(m_FloodfillsMutex); + m_Floodfills.push_back (r); + } + } + else { - std::unique_lock l(m_FloodfillsMutex); - m_Floodfills.push_back (r); + LogPrint (eLogWarning, "NetDb: Duplicated RouterInfo ", ident.ToBase64()); + updated = false; } } else From 6bacf94a62874e051f82fd7b99edd3fb8873bf7f Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 15 Nov 2016 14:11:55 -0500 Subject: [PATCH 36/40] handle all loopback messages --- Transports.cpp | 3 ++- Transports.h | 14 ++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Transports.cpp b/Transports.cpp index d41253d6..d06d8670 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -260,7 +260,8 @@ namespace transport { // we send it to ourself for (auto& it: msgs) - i2p::HandleI2NPMessage (it); + m_LoopbackHandler.PutNextMessage (it); + m_LoopbackHandler.Flush (); return; } if(RoutesRestricted() && ! IsRestrictedPeer(ident)) return; diff --git a/Transports.h b/Transports.h index 1fe262a9..d83c0370 100644 --- a/Transports.h +++ b/Transports.h @@ -160,13 +160,15 @@ namespace transport uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes; uint64_t m_LastBandwidthUpdateTime; - /** which router families to trust for first hops */ - std::vector m_TrustedFamilies; - mutable std::mutex m_FamilyMutex; + /** 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; + /** which routers for first hop to trust */ + std::vector m_TrustedRouters; + mutable std::mutex m_TrustedRoutersMutex; + + i2p::I2NPMessagesHandler m_LoopbackHandler; public: From 752e74d33cdefd2bcbe9ab8218d29db1321fced3 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 15 Nov 2016 14:42:18 -0500 Subject: [PATCH 37/40] show latency of tunnels in web ui --- HTTPServer.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 556051aa..bf0a3159 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -300,12 +300,16 @@ namespace http { s << "Inbound tunnels:
\r\n"; for (auto & it : pool->GetInboundTunnels ()) { it->Print(s); + if(it->LatencyIsKnown()) + s << " ( " << it->GetMeanLatency() << "ms )"; ShowTunnelDetails(s, it->GetState (), it->GetNumReceivedBytes ()); } s << "
\r\n"; s << "Outbound tunnels:
\r\n"; for (auto & it : pool->GetOutboundTunnels ()) { it->Print(s); + if(it->LatencyIsKnown()) + s << " ( " << it->GetMeanLatency() << "ms )"; ShowTunnelDetails(s, it->GetState (), it->GetNumSentBytes ()); } } @@ -401,12 +405,16 @@ namespace http { s << "Inbound tunnels:
\r\n"; for (auto & it : i2p::tunnel::tunnels.GetInboundTunnels ()) { it->Print(s); + if(it->LatencyIsKnown()) + s << " ( " << it->GetMeanLatency() << "ms )"; ShowTunnelDetails(s, it->GetState (), it->GetNumReceivedBytes ()); } s << "
\r\n"; s << "Outbound tunnels:
\r\n"; for (auto & it : i2p::tunnel::tunnels.GetOutboundTunnels ()) { it->Print(s); + if(it->LatencyIsKnown()) + s << " ( " << it->GetMeanLatency() << "ms )"; ShowTunnelDetails(s, it->GetState (), it->GetNumSentBytes ()); } s << "
\r\n"; From f6721a2ced11468d5ce37d71fed66ebbf14758fc Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 15 Nov 2016 17:45:37 -0500 Subject: [PATCH 38/40] fixed startup crash --- Config.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Config.cpp b/Config.cpp index ed22c561..fb587e61 100644 --- a/Config.cpp +++ b/Config.cpp @@ -87,8 +87,8 @@ namespace config { ("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") - ("httpproxy.latency.min", value()->default_value(0), "HTTP proxy min latency for tunnels") - ("httpproxy.latency.max", value()->default_value(0), "HTTP proxy max latency for tunnels") + ("httpproxy.latency.min", value()->default_value("0"), "HTTP proxy min latency for tunnels") + ("httpproxy.latency.max", value()->default_value("0"), "HTTP proxy max latency for tunnels") ; options_description socksproxy("SOCKS Proxy options"); @@ -101,8 +101,8 @@ namespace config { ("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.latency.min", value()->default_value(0), "SOCKS proxy min latency for tunnels") - ("socksproxy.latency.max", value()->default_value(0), "SOCKS proxy max latency for tunnels") + ("socksproxy.latency.min", value()->default_value("0"), "SOCKS proxy min latency for tunnels") + ("socksproxy.latency.max", value()->default_value("0"), "SOCKS proxy max latency for tunnels") ("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") ; From e0e50faa477d7443d3b3ce432e25aceb3989491b Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Nov 2016 10:59:11 -0500 Subject: [PATCH 39/40] publish 0-hops leaseset --- TunnelPool.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/TunnelPool.cpp b/TunnelPool.cpp index ccd4c12c..ea7928eb 100644 --- a/TunnelPool.cpp +++ b/TunnelPool.cpp @@ -215,15 +215,6 @@ namespace tunnel void TunnelPool::CreateTunnels () { int num = 0; - { - std::unique_lock l(m_InboundTunnelsMutex); - for (const auto& it : m_InboundTunnels) - if (it->IsEstablished ()) num++; - } - for (int i = num; i < m_NumInboundTunnels; i++) - CreateInboundTunnel (); - - num = 0; { std::unique_lock l(m_OutboundTunnelsMutex); for (const auto& it : m_OutboundTunnels) @@ -231,6 +222,18 @@ namespace tunnel } for (int i = num; i < m_NumOutboundTunnels; i++) CreateOutboundTunnel (); + + num = 0; + { + std::unique_lock l(m_InboundTunnelsMutex); + for (const auto& it : m_InboundTunnels) + if (it->IsEstablished ()) num++; + } + for (int i = num; i < m_NumInboundTunnels; i++) + CreateInboundTunnel (); + + if (num > 0 && m_NumInboundHops <= 0 && m_LocalDestination) // zero hops IB + m_LocalDestination->SetLeaseSetUpdated (); // update LeaseSet immediately } void TunnelPool::TestTunnels () From 5d0852c1e2d940aaae5caa44df230f140fc88887 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Nov 2016 12:10:13 -0500 Subject: [PATCH 40/40] fixed memory leak --- Garlic.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Garlic.cpp b/Garlic.cpp index 1cd1676e..b7d44d5e 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -277,6 +277,7 @@ namespace garlic { newTags->msgID = msgID; m_UnconfirmedTagsMsgs.emplace_back (newTags); + newTags = nullptr; // got acquired } m_Owner->DeliveryStatusSent (shared_from_this (), msgID); } @@ -300,13 +301,14 @@ namespace garlic size += CreateGarlicClove (payload + size, msg, m_Destination ? m_Destination->IsDestination () : false); (*numCloves)++; } - memset (payload + size, 0, 3); // certificate of message size += 3; htobe32buf (payload + size, msgID); // MessageID size += 4; htobe64buf (payload + size, ts + 8000); // Expiration of message, 8 sec size += 8; + + if (newTags) delete newTags; // not acquired, delete return size; }