Compare commits

...

17 Commits

Author SHA1 Message Date
r4sas
1293e122bc [deb] update patch
Signed-off-by: r4sas <r4sas@i2pmail.org>
2024-12-30 21:48:57 +00:00
orignal
24bcc651e0 Fixed typo 2024-12-29 17:44:32 -05:00
orignal
8713974f40 2.55.0 2024-12-29 17:25:54 -05:00
orignal
d48bf33fc5 request time in milliseconds. shorter intervals. interval variance 2024-12-23 17:52:14 -05:00
orignal
0f14f9a302 LeaseSet request timeout in milliseconds 2024-12-23 13:47:38 -05:00
orignal
55708d2a6d reduced LeaseSet lookup timeout 2024-12-22 16:09:58 -05:00
orignal
3bdfa5562b don't send same message twice 2024-12-20 19:42:25 -05:00
orignal
3995448014 fixed possible crash at shutdown 2024-12-19 14:24:26 -05:00
orignal
7497741846 fixed possible crash at shutdown 2024-12-18 14:22:05 -05:00
orignal
36939898fe send tunnel endpoint data to transport session to gateway directly 2024-12-17 20:50:54 -05:00
orignal
b4bcd9914a show next peer and connectivity on transit tunnels page 2024-12-16 19:49:14 -05:00
orignal
833e0a936e fixed build with boost 1.87 2024-12-15 18:27:24 -05:00
orignal
bdc5eaa824 fixed build with boost 1.87 2024-12-15 18:15:21 -05:00
orignal
e76d09e1a1 send tunnel participant data to transport session directly. Implemented TunnelTransportSender 2024-12-15 18:03:31 -05:00
orignal
3264704a23 Handle choked, new RTO and window size calculation 2024-12-14 17:59:51 -05:00
orignal
cec68a2447 rollback 2024-12-11 21:33:16 -05:00
orignal
73ba1afc20 don't create EVP_CIPHER_CTX for each AEAD/Chacha20/Poly1305 message 2024-12-11 18:55:30 -05:00
39 changed files with 460 additions and 165 deletions

View File

@@ -1,6 +1,47 @@
# for this file format description, # for this file format description,
# see https://github.com/olivierlacan/keep-a-changelog # see https://github.com/olivierlacan/keep-a-changelog
## [2.55.0] - 2024-12-30
### Added
- Support boost 1.87
- "i2p.streaming.maxConcurrentStreams" tunnel's param to limit number of simultaneous streams
- Separate thread for tunnel build requests
- Show next peer and connectivity on "Transit tunnels" page
- Tunnel name for local destination thread
- Throttle incoming ECIESx25519 sessions
- Send tunnel data to transport session directly if possible
- Publish 'R' cap for yggdrasil-only routers, and 'U' cap for routers through proxy
- Random tunnel rejection when medium congestion
- Save unreachable router's endpoint to use it next time without introducers
- Recognize symmetric NAT from peer test message 7
- Resend HolePunch and RelayResponse messages
### Changed
- Removed own implementation of AESNI and always use one from openssl
- Renamed main thread to i2pd-daemon
- Set i2p.streaming.profile=2 for shared local destination
- Reduced LeaseSet and RouterInfo lookup timeouts
- Cleanup ECIES sessions and tags more often
- Check LeaseSet expiration time
- Handle NTCP2 session handshakes in separate thread
- Limit last decline time by 1.5 hours in router's profile
- Don't handle RelayRequest and RelayIntro with same nonce twice
- Increased hole punch expiration interval
- Send peer test message 6 with delay if message 4 was received before message 5
- Pre-calculate more x25519 keys for transports in runtime
- Don't request LeaseSet for incoming stream
- Terminate incoming stream right away if no remote LeaseSet
- Handle choked, new RTO and window size calculation and resetting algorithm for streams
### Fixed
- Empty string in addressbook subscriptions
- ECIESx25519 sessions without destination
- Missing RouterInfo buffer in NetDb
- Invalid I2PControl certificate
- Routers disappear from NetDb when offline
- Peer test message 6 sent to unknown endpoint
- Race condition with LeaseSet update
- Excessive CPU usage by streams
- Crash on shutdown
## [2.54.0] - 2024-10-06 ## [2.54.0] - 2024-10-06
### Added ### Added
- Maintain recently connected routers list to avoid false-positive peer test - Maintain recently connected routers list to avoid false-positive peer test

View File

@@ -2,13 +2,13 @@ Description: Enable UPnP usage in package
Author: r4sas <r4sas@i2pmail.org> Author: r4sas <r4sas@i2pmail.org>
Reviewed-By: r4sas <r4sas@i2pmail.org> Reviewed-By: r4sas <r4sas@i2pmail.org>
Last-Update: 2022-03-23 Last-Update: 2024-12-30
--- i2pd.orig/Makefile --- i2pd.orig/Makefile
+++ i2pd/Makefile +++ i2pd/Makefile
@@ -31,7 +31,7 @@ include filelist.mk @@ -31,7 +31,7 @@ # import source files lists
include filelist.mk
USE_AESNI := $(or $(USE_AESNI),yes)
USE_STATIC := $(or $(USE_STATIC),no) USE_STATIC := $(or $(USE_STATIC),no)
-USE_UPNP := $(or $(USE_UPNP),no) -USE_UPNP := $(or $(USE_UPNP),no)
+USE_UPNP := $(or $(USE_UPNP),yes) +USE_UPNP := $(or $(USE_UPNP),yes)

View File

@@ -2,13 +2,13 @@ Description: Enable UPnP usage in package
Author: r4sas <r4sas@i2pmail.org> Author: r4sas <r4sas@i2pmail.org>
Reviewed-By: r4sas <r4sas@i2pmail.org> Reviewed-By: r4sas <r4sas@i2pmail.org>
Last-Update: 2022-03-23 Last-Update: 2024-12-30
--- i2pd.orig/Makefile --- i2pd.orig/Makefile
+++ i2pd/Makefile +++ i2pd/Makefile
@@ -31,7 +31,7 @@ include filelist.mk @@ -31,7 +31,7 @@ # import source files lists
include filelist.mk
USE_AESNI := $(or $(USE_AESNI),yes)
USE_STATIC := $(or $(USE_STATIC),no) USE_STATIC := $(or $(USE_STATIC),no)
-USE_UPNP := $(or $(USE_UPNP),no) -USE_UPNP := $(or $(USE_UPNP),no)
+USE_UPNP := $(or $(USE_UPNP),yes) +USE_UPNP := $(or $(USE_UPNP),yes)

View File

@@ -1,7 +1,7 @@
%define git_hash %(git rev-parse HEAD | cut -c -7) %define git_hash %(git rev-parse HEAD | cut -c -7)
Name: i2pd-git Name: i2pd-git
Version: 2.54.0 Version: 2.55.0
Release: git%{git_hash}%{?dist} Release: git%{git_hash}%{?dist}
Summary: I2P router written in C++ Summary: I2P router written in C++
Conflicts: i2pd Conflicts: i2pd
@@ -148,6 +148,9 @@ getent passwd i2pd >/dev/null || \
%changelog %changelog
* Mon Dec 30 2024 orignal <orignal@i2pmail.org> - 2.55.0
- update to 2.55.0
* Sun Oct 6 2024 orignal <orignal@i2pmail.org> - 2.54.0 * Sun Oct 6 2024 orignal <orignal@i2pmail.org> - 2.54.0
- update to 2.54.0 - update to 2.54.0

View File

@@ -1,5 +1,5 @@
Name: i2pd Name: i2pd
Version: 2.54.0 Version: 2.55.0
Release: 1%{?dist} Release: 1%{?dist}
Summary: I2P router written in C++ Summary: I2P router written in C++
Conflicts: i2pd-git Conflicts: i2pd-git
@@ -146,6 +146,9 @@ getent passwd i2pd >/dev/null || \
%changelog %changelog
* Mon Dec 30 2024 orignal <orignal@i2pmail.org> - 2.55.0
- update to 2.55.0
* Sun Oct 6 2024 orignal <orignal@i2pmail.org> - 2.54.0 * Sun Oct 6 2024 orignal <orignal@i2pmail.org> - 2.54.0
- update to 2.54.0 - update to 2.54.0

View File

@@ -826,7 +826,7 @@ namespace http {
if (i2p::tunnel::tunnels.CountTransitTunnels()) if (i2p::tunnel::tunnels.CountTransitTunnels())
{ {
s << "<b>" << tr("Transit Tunnels") << ":</b><br>\r\n"; s << "<b>" << tr("Transit Tunnels") << ":</b><br>\r\n";
s << "<table><thead><th>&#8658;</th><th>ID</th><th>&#8658;</th><th>" << tr("Amount") << "</th></thead><tbody class=\"tableitem\">"; s << "<table><thead><th>&#8658;</th><th>ID</th><th>&#8658;</th><th>" << tr("Amount") << "</th><th>" << tr("Next") << "</th></thead><tbody class=\"tableitem\">";
for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ()) for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ())
{ {
if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelGateway>(it)) if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelGateway>(it))
@@ -836,7 +836,7 @@ namespace http {
else else
s << "<tr><td>&#8658;</td><td>" << it->GetTunnelID () << "</td><td>&#8658;</td><td>"; s << "<tr><td>&#8658;</td><td>" << it->GetTunnelID () << "</td><td>&#8658;</td><td>";
ShowTraffic(s, it->GetNumTransmittedBytes ()); ShowTraffic(s, it->GetNumTransmittedBytes ());
s << "</td></tr>\r\n"; s << "</td><td>" << it->GetNextPeerName () << "</td></tr>\r\n";
} }
s << "</tbody></table>\r\n"; s << "</tbody></table>\r\n";
} }

View File

@@ -52,7 +52,7 @@ namespace transport
{ {
m_IsRunning = true; m_IsRunning = true;
LogPrint(eLogInfo, "UPnP: Starting"); LogPrint(eLogInfo, "UPnP: Starting");
m_Service.post (std::bind (&UPnP::Discover, this)); boost::asio::post (m_Service, std::bind (&UPnP::Discover, this));
std::unique_lock<std::mutex> l(m_StartedMutex); std::unique_lock<std::mutex> l(m_StartedMutex);
m_Thread.reset (new std::thread (std::bind (&UPnP::Run, this))); m_Thread.reset (new std::thread (std::bind (&UPnP::Run, this)));
m_Started.wait_for (l, std::chrono::seconds (5)); // 5 seconds maximum m_Started.wait_for (l, std::chrono::seconds (5)); // 5 seconds maximum
@@ -150,7 +150,7 @@ namespace transport
// UPnP discovered // UPnP discovered
LogPrint (eLogDebug, "UPnP: ExternalIPAddress is ", m_externalIPAddress); LogPrint (eLogDebug, "UPnP: ExternalIPAddress is ", m_externalIPAddress);
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (m_externalIPAddress)); i2p::context.UpdateAddress (boost::asio::ip::make_address (m_externalIPAddress));
// port mapping // port mapping
PortMapping (); PortMapping ();
} }

6
debian/changelog vendored
View File

@@ -1,3 +1,9 @@
i2pd (2.55.0-1) unstable; urgency=medium
* updated to version 2.55.0
-- orignal <orignal@i2pmail.org> Mon, 30 Dec 2024 16:00:00 +0000
i2pd (2.54.0-1) unstable; urgency=medium i2pd (2.54.0-1) unstable; urgency=medium
* updated to version 2.54.0/0.9.64 * updated to version 2.54.0/0.9.64

View File

@@ -2,13 +2,13 @@ Description: Enable UPnP usage in package
Author: r4sas <r4sas@i2pmail.org> Author: r4sas <r4sas@i2pmail.org>
Reviewed-By: r4sas <r4sas@i2pmail.org> Reviewed-By: r4sas <r4sas@i2pmail.org>
Last-Update: 2022-03-23 Last-Update: 2024-12-30
--- i2pd.orig/Makefile --- i2pd.orig/Makefile
+++ i2pd/Makefile +++ i2pd/Makefile
@@ -31,7 +31,7 @@ include filelist.mk @@ -31,7 +31,7 @@ # import source files lists
include filelist.mk
USE_AESNI := $(or $(USE_AESNI),yes)
USE_STATIC := $(or $(USE_STATIC),no) USE_STATIC := $(or $(USE_STATIC),no)
-USE_UPNP := $(or $(USE_UPNP),no) -USE_UPNP := $(or $(USE_UPNP),no)
+USE_UPNP := $(or $(USE_UPNP),yes) +USE_UPNP := $(or $(USE_UPNP),yes)

View File

@@ -833,7 +833,7 @@ namespace client
request->requestedBlindedKey = requestedBlindedKey; // for encrypted LeaseSet2 request->requestedBlindedKey = requestedBlindedKey; // for encrypted LeaseSet2
if (requestComplete) if (requestComplete)
request->requestComplete.push_back (requestComplete); request->requestComplete.push_back (requestComplete);
auto ts = i2p::util::GetSecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
auto ret = m_LeaseSetRequests.insert (std::pair<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> >(dest,request)); auto ret = m_LeaseSetRequests.insert (std::pair<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> >(dest,request));
if (ret.second) // inserted if (ret.second) // inserted
{ {
@@ -916,7 +916,7 @@ namespace client
nextFloodfill->GetIdentHash (), 0, msg nextFloodfill->GetIdentHash (), 0, msg
} }
}); });
request->requestTimeoutTimer.expires_from_now (boost::posix_time::seconds(LEASESET_REQUEST_TIMEOUT)); request->requestTimeoutTimer.expires_from_now (boost::posix_time::milliseconds(LEASESET_REQUEST_TIMEOUT));
request->requestTimeoutTimer.async_wait (std::bind (&LeaseSetDestination::HandleRequestTimoutTimer, request->requestTimeoutTimer.async_wait (std::bind (&LeaseSetDestination::HandleRequestTimoutTimer,
shared_from_this (), std::placeholders::_1, dest)); shared_from_this (), std::placeholders::_1, dest));
} }
@@ -933,7 +933,7 @@ namespace client
if (it != m_LeaseSetRequests.end ()) if (it != m_LeaseSetRequests.end ())
{ {
bool done = false; bool done = false;
uint64_t ts = i2p::util::GetSecondsSinceEpoch (); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
if (ts < it->second->requestTime + MAX_LEASESET_REQUEST_TIMEOUT) if (ts < it->second->requestTime + MAX_LEASESET_REQUEST_TIMEOUT)
{ {
auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, it->second->excluded); auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, it->second->excluded);

View File

@@ -40,8 +40,8 @@ namespace client
const int PUBLISH_VERIFICATION_TIMEOUT = 10; // in seconds after successful publish const int PUBLISH_VERIFICATION_TIMEOUT = 10; // in seconds after successful publish
const int PUBLISH_MIN_INTERVAL = 20; // in seconds const int PUBLISH_MIN_INTERVAL = 20; // in seconds
const int PUBLISH_REGULAR_VERIFICATION_INTERNAL = 100; // in seconds periodically const int PUBLISH_REGULAR_VERIFICATION_INTERNAL = 100; // in seconds periodically
const int LEASESET_REQUEST_TIMEOUT = 5; // in seconds const int LEASESET_REQUEST_TIMEOUT = 1600; // in milliseconds
const int MAX_LEASESET_REQUEST_TIMEOUT = 40; // in seconds const int MAX_LEASESET_REQUEST_TIMEOUT = 12000; // in milliseconds
const int DESTINATION_CLEANUP_TIMEOUT = 44; // in seconds const int DESTINATION_CLEANUP_TIMEOUT = 44; // in seconds
const int DESTINATION_CLEANUP_TIMEOUT_VARIANCE = 30; // in seconds const int DESTINATION_CLEANUP_TIMEOUT_VARIANCE = 30; // in seconds
const unsigned int MAX_NUM_FLOODFILLS_PER_REQUEST = 7; const unsigned int MAX_NUM_FLOODFILLS_PER_REQUEST = 7;

View File

@@ -725,6 +725,8 @@ namespace garlic
bool ECIESX25519AEADRatchetSession::NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) bool ECIESX25519AEADRatchetSession::NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
{ {
auto owner = GetOwner ();
if (!owner) return false;
uint8_t nonce[12]; uint8_t nonce[12];
auto index = m_SendTagset->GetNextIndex (); auto index = m_SendTagset->GetNextIndex ();
CreateNonce (index, nonce); // tag's index CreateNonce (index, nonce); // tag's index
@@ -732,8 +734,7 @@ namespace garlic
if (!tag) if (!tag)
{ {
LogPrint (eLogError, "Garlic: Can't create new ECIES-X25519-AEAD-Ratchet tag for send tagset"); LogPrint (eLogError, "Garlic: Can't create new ECIES-X25519-AEAD-Ratchet tag for send tagset");
if (GetOwner ()) owner->RemoveECIESx25519Session (m_RemoteStaticKey);
GetOwner ()->RemoveECIESx25519Session (m_RemoteStaticKey);
return false; return false;
} }
memcpy (out, &tag, 8); memcpy (out, &tag, 8);
@@ -741,7 +742,7 @@ namespace garlic
// ciphertext = ENCRYPT(k, n, payload, ad) // ciphertext = ENCRYPT(k, n, payload, ad)
uint8_t key[32]; uint8_t key[32];
m_SendTagset->GetSymmKey (index, key); m_SendTagset->GetSymmKey (index, key);
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, out, 8, key, nonce, out + 8, outLen - 8, true)) // encrypt if (!owner->AEADChaCha20Poly1305Encrypt (payload, len, out, 8, key, nonce, out + 8, outLen - 8))
{ {
LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed"); LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed");
return false; return false;
@@ -760,34 +761,35 @@ namespace garlic
uint8_t * payload = buf + 8; uint8_t * payload = buf + 8;
uint8_t key[32]; uint8_t key[32];
receiveTagset->GetSymmKey (index, key); receiveTagset->GetSymmKey (index, key);
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 16, buf, 8, key, nonce, payload, len - 16, false)) // decrypt auto owner = GetOwner ();
if (!owner) return true; // drop message
if (!owner->AEADChaCha20Poly1305Decrypt (payload, len - 16, buf, 8, key, nonce, payload, len - 16))
{ {
LogPrint (eLogWarning, "Garlic: Payload section AEAD decryption failed"); LogPrint (eLogWarning, "Garlic: Payload section AEAD decryption failed");
return false; return false;
} }
HandlePayload (payload, len - 16, receiveTagset, index); HandlePayload (payload, len - 16, receiveTagset, index);
if (GetOwner ())
int moreTags = 0;
if (owner->GetNumRatchetInboundTags () > 0) // override in settings?
{ {
int moreTags = 0; if (receiveTagset->GetNextIndex () - index < owner->GetNumRatchetInboundTags ()/2)
if (GetOwner ()->GetNumRatchetInboundTags () > 0) // override in settings? moreTags = owner->GetNumRatchetInboundTags ();
{ index -= owner->GetNumRatchetInboundTags (); // trim behind
if (receiveTagset->GetNextIndex () - index < GetOwner ()->GetNumRatchetInboundTags ()/2)
moreTags = GetOwner ()->GetNumRatchetInboundTags ();
index -= GetOwner ()->GetNumRatchetInboundTags (); // trim behind
}
else
{
moreTags = (receiveTagset->GetTagSetID () > 0) ? ECIESX25519_MAX_NUM_GENERATED_TAGS : // for non first tagset
(ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 1)); // N/2
if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS;
moreTags -= (receiveTagset->GetNextIndex () - index);
index -= ECIESX25519_MAX_NUM_GENERATED_TAGS; // trim behind
}
if (moreTags > 0)
GenerateMoreReceiveTags (receiveTagset, moreTags);
if (index > 0)
receiveTagset->SetTrimBehind (index);
} }
else
{
moreTags = (receiveTagset->GetTagSetID () > 0) ? ECIESX25519_MAX_NUM_GENERATED_TAGS : // for non first tagset
(ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 1)); // N/2
if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS;
moreTags -= (receiveTagset->GetNextIndex () - index);
index -= ECIESX25519_MAX_NUM_GENERATED_TAGS; // trim behind
}
if (moreTags > 0)
GenerateMoreReceiveTags (receiveTagset, moreTags);
if (index > 0)
receiveTagset->SetTrimBehind (index);
return true; return true;
} }

View File

@@ -1103,5 +1103,17 @@ namespace garlic
m_PayloadBuffer = new uint8_t[I2NP_MAX_MESSAGE_SIZE]; m_PayloadBuffer = new uint8_t[I2NP_MAX_MESSAGE_SIZE];
return m_PayloadBuffer; return m_PayloadBuffer;
} }
bool GarlicDestination::AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len)
{
return m_Encryptor.Encrypt (msg, msgLen, ad, adLen, key, nonce, buf, len);
}
bool GarlicDestination::AEADChaCha20Poly1305Decrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len)
{
return m_Decryptor.Decrypt (msg, msgLen, ad, adLen, key, nonce, buf, len);
}
} }
} }

View File

@@ -242,6 +242,11 @@ namespace garlic
void RemoveDeliveryStatusSession (uint32_t msgID); void RemoveDeliveryStatusSession (uint32_t msgID);
std::shared_ptr<I2NPMessage> WrapMessageForRouter (std::shared_ptr<const i2p::data::RouterInfo> router, std::shared_ptr<I2NPMessage> WrapMessageForRouter (std::shared_ptr<const i2p::data::RouterInfo> router,
std::shared_ptr<I2NPMessage> msg); std::shared_ptr<I2NPMessage> msg);
bool AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len);
bool AEADChaCha20Poly1305Decrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len);
void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag
void AddECIESx25519Key (const uint8_t * key, uint64_t tag); // one tag void AddECIESx25519Key (const uint8_t * key, uint64_t tag); // one tag
@@ -295,7 +300,10 @@ namespace garlic
// DeliveryStatus // DeliveryStatus
std::mutex m_DeliveryStatusSessionsMutex; std::mutex m_DeliveryStatusSessionsMutex;
std::unordered_map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session std::unordered_map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session
// encryption
i2p::crypto::AEADChaCha20Poly1305Encryptor m_Encryptor;
i2p::crypto::AEADChaCha20Poly1305Decryptor m_Decryptor;
public: public:
// for HTTP only // for HTTP only

View File

@@ -1435,6 +1435,12 @@ namespace transport
boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ())); boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ()));
} }
i2p::data::RouterInfo::SupportedTransports NTCP2Session::GetTransportType () const
{
if (m_RemoteEndpoint.address ().is_v4 ()) return i2p::data::RouterInfo::eNTCP2V4;
return i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? i2p::data::RouterInfo::eNTCP2V6Mesh : i2p::data::RouterInfo::eNTCP2V6;
}
NTCP2Server::NTCP2Server (): NTCP2Server::NTCP2Server ():
RunnableServiceWithWork ("NTCP2"), m_TerminationTimer (GetService ()), RunnableServiceWithWork ("NTCP2"), m_TerminationTimer (GetService ()),
m_ProxyType(eNoProxy), m_Resolver(GetService ()), m_ProxyType(eNoProxy), m_Resolver(GetService ()),
@@ -1544,6 +1550,7 @@ namespace transport
void NTCP2Server::Stop () void NTCP2Server::Stop ()
{ {
m_EstablisherService.Stop ();
{ {
// we have to copy it because Terminate changes m_NTCP2Sessions // we have to copy it because Terminate changes m_NTCP2Sessions
auto ntcpSessions = m_NTCP2Sessions; auto ntcpSessions = m_NTCP2Sessions;
@@ -1559,7 +1566,6 @@ namespace transport
m_TerminationTimer.cancel (); m_TerminationTimer.cancel ();
m_ProxyEndpoint = nullptr; m_ProxyEndpoint = nullptr;
} }
m_EstablisherService.Stop ();
StopIOService (); StopIOService ();
} }

View File

@@ -147,6 +147,7 @@ namespace transport
void SetRemoteEndpoint (const boost::asio::ip::tcp::endpoint& ep) { m_RemoteEndpoint = ep; }; void SetRemoteEndpoint (const boost::asio::ip::tcp::endpoint& ep) { m_RemoteEndpoint = ep; };
bool IsEstablished () const override { return m_IsEstablished; }; bool IsEstablished () const override { return m_IsEstablished; };
i2p::data::RouterInfo::SupportedTransports GetTransportType () const override;
bool IsTerminated () const { return m_IsTerminated; }; bool IsTerminated () const { return m_IsTerminated; };
void ClientLogin (); // Alice void ClientLogin (); // Alice

View File

@@ -502,7 +502,7 @@ namespace data
} }
// send them off // send them off
i2p::transport::transports.SendMessages(ih, requests); i2p::transport::transports.SendMessages(ih, std::move (requests));
} }
bool NetDb::LoadRouterInfo (const std::string& path, uint64_t ts) bool NetDb::LoadRouterInfo (const std::string& path, uint64_t ts)

View File

@@ -21,7 +21,7 @@ namespace data
{ {
RequestedDestination::RequestedDestination (const IdentHash& destination, bool isExploratory, bool direct): RequestedDestination::RequestedDestination (const IdentHash& destination, bool isExploratory, bool direct):
m_Destination (destination), m_IsExploratory (isExploratory), m_IsDirect (direct), m_IsActive (true), m_Destination (destination), m_IsExploratory (isExploratory), m_IsDirect (direct), m_IsActive (true),
m_CreationTime (i2p::util::GetSecondsSinceEpoch ()), m_LastRequestTime (0), m_NumAttempts (0) m_CreationTime (i2p::util::GetMillisecondsSinceEpoch ()), m_LastRequestTime (0), m_NumAttempts (0)
{ {
if (i2p::context.IsFloodfill ()) if (i2p::context.IsFloodfill ())
m_ExcludedPeers.insert (i2p::context.GetIdentHash ()); // exclude self if floodfill m_ExcludedPeers.insert (i2p::context.GetIdentHash ()); // exclude self if floodfill
@@ -44,7 +44,7 @@ namespace data
msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers); msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers);
if(router) if(router)
m_ExcludedPeers.insert (router->GetIdentHash ()); m_ExcludedPeers.insert (router->GetIdentHash ());
m_LastRequestTime = i2p::util::GetSecondsSinceEpoch (); m_LastRequestTime = i2p::util::GetMillisecondsSinceEpoch ();
m_NumAttempts++; m_NumAttempts++;
return msg; return msg;
} }
@@ -55,7 +55,7 @@ namespace data
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers); i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
m_ExcludedPeers.insert (floodfill); m_ExcludedPeers.insert (floodfill);
m_NumAttempts++; m_NumAttempts++;
m_LastRequestTime = i2p::util::GetSecondsSinceEpoch (); m_LastRequestTime = i2p::util::GetMillisecondsSinceEpoch ();
return msg; return msg;
} }
@@ -210,7 +210,7 @@ namespace data
void NetDbRequests::ManageRequests () void NetDbRequests::ManageRequests ()
{ {
uint64_t ts = i2p::util::GetSecondsSinceEpoch (); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();) for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();)
{ {
auto& dest = it->second; auto& dest = it->second;
@@ -328,7 +328,8 @@ namespace data
void NetDbRequests::ScheduleManageRequests () void NetDbRequests::ScheduleManageRequests ()
{ {
m_ManageRequestsTimer.expires_from_now (boost::posix_time::seconds(MANAGE_REQUESTS_INTERVAL)); m_ManageRequestsTimer.expires_from_now (boost::posix_time::milliseconds(MANAGE_REQUESTS_INTERVAL +
m_Rng () % MANAGE_REQUESTS_INTERVAL_VARIANCE));
m_ManageRequestsTimer.async_wait (std::bind (&NetDbRequests::HandleManageRequestsTimer, m_ManageRequestsTimer.async_wait (std::bind (&NetDbRequests::HandleManageRequestsTimer,
this, std::placeholders::_1)); this, std::placeholders::_1));
} }

View File

@@ -24,15 +24,16 @@ namespace i2p
namespace data namespace data
{ {
const int MAX_NUM_REQUEST_ATTEMPTS = 5; const int MAX_NUM_REQUEST_ATTEMPTS = 5;
const uint64_t MANAGE_REQUESTS_INTERVAL = 1; // in seconds const uint64_t MANAGE_REQUESTS_INTERVAL = 400; // in milliseconds
const uint64_t MIN_REQUEST_TIME = 5; // in seconds const uint64_t MANAGE_REQUESTS_INTERVAL_VARIANCE = 300; // in milliseconds
const uint64_t MAX_REQUEST_TIME = MAX_NUM_REQUEST_ATTEMPTS * (MIN_REQUEST_TIME + MANAGE_REQUESTS_INTERVAL); const uint64_t MIN_REQUEST_TIME = 1200; // in milliseconds
const uint64_t MAX_REQUEST_TIME = MAX_NUM_REQUEST_ATTEMPTS * (MIN_REQUEST_TIME + MANAGE_REQUESTS_INTERVAL + MANAGE_REQUESTS_INTERVAL_VARIANCE);
const uint64_t EXPLORATORY_REQUEST_INTERVAL = 55; // in seconds const uint64_t EXPLORATORY_REQUEST_INTERVAL = 55; // in seconds
const uint64_t EXPLORATORY_REQUEST_INTERVAL_VARIANCE = 170; // in seconds const uint64_t EXPLORATORY_REQUEST_INTERVAL_VARIANCE = 170; // in seconds
const uint64_t DISCOVERED_REQUEST_INTERVAL = 360; // in milliseconds const uint64_t DISCOVERED_REQUEST_INTERVAL = 360; // in milliseconds
const uint64_t DISCOVERED_REQUEST_INTERVAL_VARIANCE = 540; // in milliseconds const uint64_t DISCOVERED_REQUEST_INTERVAL_VARIANCE = 540; // in milliseconds
const uint64_t MAX_EXPLORATORY_REQUEST_TIME = 30; // in seconds const uint64_t MAX_EXPLORATORY_REQUEST_TIME = 30000; // in milliseconds
const uint64_t REQUEST_CACHE_TIME = MAX_REQUEST_TIME + 40; // in seconds const uint64_t REQUEST_CACHE_TIME = MAX_REQUEST_TIME + 40000; // in milliseconds
const uint64_t REQUESTED_DESTINATIONS_POOL_CLEANUP_INTERVAL = 191; // in seconds const uint64_t REQUESTED_DESTINATIONS_POOL_CLEANUP_INTERVAL = 191; // in seconds
class RequestedDestination class RequestedDestination
@@ -71,7 +72,7 @@ namespace data
IdentHash m_Destination; IdentHash m_Destination;
bool m_IsExploratory, m_IsDirect, m_IsActive; bool m_IsExploratory, m_IsDirect, m_IsActive;
std::unordered_set<IdentHash> m_ExcludedPeers; std::unordered_set<IdentHash> m_ExcludedPeers;
uint64_t m_CreationTime, m_LastRequestTime; // in seconds uint64_t m_CreationTime, m_LastRequestTime; // in milliseconds
std::list<RequestComplete> m_RequestComplete; std::list<RequestComplete> m_RequestComplete;
int m_NumAttempts; int m_NumAttempts;
}; };
@@ -115,9 +116,9 @@ namespace data
private: private:
i2p::util::MemoryPoolMt<RequestedDestination> m_RequestedDestinationsPool;
std::unordered_map<IdentHash, std::shared_ptr<RequestedDestination> > m_RequestedDestinations; std::unordered_map<IdentHash, std::shared_ptr<RequestedDestination> > m_RequestedDestinations;
std::list<IdentHash> m_DiscoveredRouterHashes; std::list<IdentHash> m_DiscoveredRouterHashes;
i2p::util::MemoryPoolMt<RequestedDestination> m_RequestedDestinationsPool;
boost::asio::deadline_timer m_ManageRequestsTimer, m_ExploratoryTimer, boost::asio::deadline_timer m_ManageRequestsTimer, m_ExploratoryTimer,
m_CleanupTimer, m_DiscoveredRoutersTimer; m_CleanupTimer, m_DiscoveredRoutersTimer;
std::mt19937 m_Rng; std::mt19937 m_Rng;

View File

@@ -1195,6 +1195,19 @@ namespace data
return false; return false;
} }
} }
std::string RouterInfo::GetTransportName (SupportedTransports tr)
{
switch (tr)
{
case eNTCP2V4: return "NTCP2V4";
case eNTCP2V6: return "NTCP2V6";
case eSSU2V4: return "SSU2V4";
case eSSU2V6: return "SSU2V6";
case eNTCP2V6Mesh: return "Mesh";
default: return "";
}
}
void LocalRouterInfo::CreateBuffer (const PrivateKeys& privateKeys) void LocalRouterInfo::CreateBuffer (const PrivateKeys& privateKeys)
{ {

View File

@@ -363,6 +363,10 @@ namespace data
int m_Version; int m_Version;
Congestion m_Congestion; Congestion m_Congestion;
mutable std::shared_ptr<RouterProfile> m_Profile; mutable std::shared_ptr<RouterProfile> m_Profile;
public:
static std::string GetTransportName (SupportedTransports tr);
}; };
class LocalRouterInfo: public RouterInfo class LocalRouterInfo: public RouterInfo

View File

@@ -3114,5 +3114,10 @@ namespace transport
else if (!sent && !m_SentPackets.empty ()) // if only acks received, nothing sent and we still have something to resend else if (!sent && !m_SentPackets.empty ()) // if only acks received, nothing sent and we still have something to resend
Resend (i2p::util::GetMillisecondsSinceEpoch ()); // than right time to resend Resend (i2p::util::GetMillisecondsSinceEpoch ()); // than right time to resend
} }
i2p::data::RouterInfo::SupportedTransports SSU2Session::GetTransportType () const
{
return m_RemoteEndpoint.address ().is_v4 () ? i2p::data::RouterInfo::eSSU2V4 : i2p::data::RouterInfo::eSSU2V6;
}
} }
} }

View File

@@ -267,6 +267,7 @@ namespace transport
size_t Resend (uint64_t ts); // return number of resent packets size_t Resend (uint64_t ts); // return number of resent packets
uint64_t GetLastResendTime () const { return m_LastResendTime; }; uint64_t GetLastResendTime () const { return m_LastResendTime; };
bool IsEstablished () const override { return m_State == eSSU2SessionStateEstablished; }; bool IsEstablished () const override { return m_State == eSSU2SessionStateEstablished; };
i2p::data::RouterInfo::SupportedTransports GetTransportType () const override;
uint64_t GetConnID () const { return m_SourceConnID; }; uint64_t GetConnID () const { return m_SourceConnID; };
SSU2SessionState GetState () const { return m_State; }; SSU2SessionState GetState () const { return m_State; };
void SetState (SSU2SessionState state) { m_State = state; }; void SetState (SSU2SessionState state) { m_State = state; };

View File

@@ -72,7 +72,7 @@ namespace stream
m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1), m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1),
m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed
m_Status (eStreamStatusNew), m_IsIncoming (false), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), m_Status (eStreamStatusNew), m_IsIncoming (false), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false),
m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), m_IsClientChoked (false),
m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_DoubleWinIncCounter (false), m_LocalDestination (local), m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_DoubleWinIncCounter (false), m_LocalDestination (local),
m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service),
m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port),
@@ -99,8 +99,8 @@ namespace stream
m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (0), m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_DropWindowDelaySequenceNumber (0),
m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1), m_TunnelsChangeSequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_PreviousReceivedSequenceNumber (-1),
m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed m_LastConfirmedReceivedSequenceNumber (0), // for limit inbound speed
m_Status (eStreamStatusNew), m_IsIncoming (true), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false), m_Status (eStreamStatusNew), m_IsIncoming (true), m_IsAckSendScheduled (false), m_IsNAcked (false), m_IsFirstACK (false),
m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), m_IsClientChoked (false),
m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_DoubleWinIncCounter (false), m_LocalDestination (local), m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_IsRemoteLeaseChangeInProgress (false), m_DoubleWinIncCounter (false), m_LocalDestination (local),
m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service),
m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT),
@@ -364,13 +364,14 @@ namespace stream
} }
if (delayRequested >= DELAY_CHOKING) if (delayRequested >= DELAY_CHOKING)
{ {
if (!m_IsWinDropped) if (!m_IsClientChoked)
{ {
LogPrint (eLogDebug, "Streaming: Client choked, set min. window size"); LogPrint (eLogDebug, "Streaming: Client choked, set min. window size");
m_WindowDropTargetSize = MIN_WINDOW_SIZE; m_WindowDropTargetSize = MIN_WINDOW_SIZE;
m_LastWindowDropSize = 0; m_LastWindowDropSize = 0;
m_WindowIncCounter = 0; m_WindowIncCounter = 0;
m_IsWinDropped = true; // don't drop window twice m_IsClientChoked = true;
m_IsWinDropped = false;
m_DropWindowDelaySequenceNumber = m_SequenceNumber; m_DropWindowDelaySequenceNumber = m_SequenceNumber;
UpdatePacingTime (); UpdatePacingTime ();
} }
@@ -598,7 +599,7 @@ namespace stream
m_WindowIncCounter = m_WindowIncCounter + incCounter; m_WindowIncCounter = m_WindowIncCounter + incCounter;
// //
// delay-based CC // delay-based CC
if ((m_SlowRTT2 > m_SlowRTT + m_Jitter && rttSample > m_SlowRTT2 && rttSample > m_PrevRTTSample) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection if ((m_SlowRTT2 > m_SlowRTT + m_Jitter && rttSample > m_SlowRTT2 && rttSample > m_PrevRTTSample) && !m_IsWinDropped && !m_IsClientChoked) // Drop window if RTT grows too fast, late detection
{ {
LogPrint (eLogDebug, "Streaming: Congestion detected, reduce window size"); LogPrint (eLogDebug, "Streaming: Congestion detected, reduce window size");
ProcessWindowDrop (); ProcessWindowDrop ();
@@ -612,6 +613,10 @@ namespace stream
if (wasInitial) if (wasInitial)
ScheduleResend (); ScheduleResend ();
} }
if (m_IsClientChoked && ackThrough > m_DropWindowDelaySequenceNumber)
{
m_IsClientChoked = false;
}
if (m_IsWinDropped && ackThrough > m_DropWindowDelaySequenceNumber) if (m_IsWinDropped && ackThrough > m_DropWindowDelaySequenceNumber)
{ {
m_IsFirstRttSample = true; m_IsFirstRttSample = true;
@@ -1166,7 +1171,7 @@ namespace stream
LogPrint (eLogDebug, "Streaming: RemoteLease changed, set initial window size"); LogPrint (eLogDebug, "Streaming: RemoteLease changed, set initial window size");
CancelRemoteLeaseChange (); CancelRemoteLeaseChange ();
m_CurrentRemoteLease = m_NextRemoteLease; m_CurrentRemoteLease = m_NextRemoteLease;
HalveWindowSize (); ResetWindowSize ();
} }
auto currentRemoteLease = m_CurrentRemoteLease; auto currentRemoteLease = m_CurrentRemoteLease;
if (!m_IsRemoteLeaseChangeInProgress && m_RemoteLeaseSet && m_CurrentRemoteLease && ts >= m_CurrentRemoteLease->endDate - i2p::data::LEASE_ENDDATE_THRESHOLD) if (!m_IsRemoteLeaseChangeInProgress && m_RemoteLeaseSet && m_CurrentRemoteLease && ts >= m_CurrentRemoteLease->endDate - i2p::data::LEASE_ENDDATE_THRESHOLD)
@@ -1201,7 +1206,8 @@ namespace stream
} }
if (freshTunnel) if (freshTunnel)
{ {
m_RTO = INITIAL_RTO; LogPrint (eLogDebug, "Streaming: OutboundTunnel changed, set initial window size");
ResetWindowSize ();
// m_TunnelsChangeSequenceNumber = m_SequenceNumber; // should be determined more precisely // m_TunnelsChangeSequenceNumber = m_SequenceNumber; // should be determined more precisely
} }
@@ -1291,20 +1297,34 @@ namespace stream
m_NumPacketsToSend = 1; m_PacingTimeRem = 0; m_NumPacketsToSend = 1; m_PacingTimeRem = 0;
} }
m_IsSendTime = true; m_IsSendTime = true;
if (m_WindowIncCounter && m_WindowSize < MAX_WINDOW_SIZE && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime) if (m_WindowIncCounter && (m_WindowSize < MAX_WINDOW_SIZE || m_WindowDropTargetSize) && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime)
{ {
for (int i = 0; i < m_NumPacketsToSend; i++) for (int i = 0; i < m_NumPacketsToSend; i++)
{ {
if (m_WindowIncCounter) if (m_WindowIncCounter)
{ {
if (m_LastWindowDropSize && (m_LastWindowDropSize >= m_WindowSize)) if (m_WindowDropTargetSize)
m_WindowSize += 1 - (1 / ((m_LastWindowDropSize + PREV_SPEED_KEEP_TIME_COEFF) / m_WindowSize)); // some magic here {
else if (m_LastWindowDropSize && (m_LastWindowDropSize < m_WindowSize)) if (m_LastWindowDropSize && (m_LastWindowDropSize >= m_WindowDropTargetSize))
m_WindowSize += (m_WindowSize - (m_LastWindowDropSize - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowSize; // some magic here m_WindowDropTargetSize += 1 - (1 / ((m_LastWindowDropSize + PREV_SPEED_KEEP_TIME_COEFF) / m_WindowDropTargetSize)); // some magic here
else if (m_LastWindowDropSize && (m_LastWindowDropSize < m_WindowSize))
m_WindowDropTargetSize += (m_WindowDropTargetSize - (m_LastWindowDropSize - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowDropTargetSize; // some magic here
else
m_WindowDropTargetSize += (m_WindowDropTargetSize - (1 - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowDropTargetSize;
if (m_WindowDropTargetSize > MAX_WINDOW_SIZE) m_WindowDropTargetSize = MAX_WINDOW_SIZE;
m_WindowIncCounter--;
}
else else
m_WindowSize += (m_WindowSize - (1 - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowSize; {
if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE; if (m_LastWindowDropSize && (m_LastWindowDropSize >= m_WindowSize))
m_WindowIncCounter--; m_WindowSize += 1 - (1 / ((m_LastWindowDropSize + PREV_SPEED_KEEP_TIME_COEFF) / m_WindowSize)); // some magic here
else if (m_LastWindowDropSize && (m_LastWindowDropSize < m_WindowSize))
m_WindowSize += (m_WindowSize - (m_LastWindowDropSize - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowSize; // some magic here
else
m_WindowSize += (m_WindowSize - (1 - PREV_SPEED_KEEP_TIME_COEFF)) / m_WindowSize;
if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE;
m_WindowIncCounter--;
}
} }
else else
break; break;
@@ -1316,11 +1336,8 @@ namespace stream
m_WindowSizeTail = m_WindowSizeTail + m_WindowIncCounter; m_WindowSizeTail = m_WindowSizeTail + m_WindowIncCounter;
if (m_WindowSizeTail > MAX_WINDOW_SIZE) m_WindowSizeTail = MAX_WINDOW_SIZE; if (m_WindowSizeTail > MAX_WINDOW_SIZE) m_WindowSizeTail = MAX_WINDOW_SIZE;
} }
if (m_IsNAcked) if (m_IsNAcked || m_IsResendNeeded || m_IsClientChoked) // resend packets
ResendPacket (); ResendPacket ();
else if (m_IsResendNeeded) // resend packets
ResendPacket ();
// delay-based CC
else if (m_WindowSize > int(m_SentPackets.size ())) // send packets else if (m_WindowSize > int(m_SentPackets.size ())) // send packets
SendBuffer (); SendBuffer ();
} }
@@ -1419,7 +1436,7 @@ namespace stream
if (m_NumResendAttempts == 1 && m_RTO != INITIAL_RTO) if (m_NumResendAttempts == 1 && m_RTO != INITIAL_RTO)
{ {
// loss-based CC // loss-based CC
if (!m_IsWinDropped && LOSS_BASED_CONTROL_ENABLED) if (!m_IsWinDropped && LOSS_BASED_CONTROL_ENABLED && !m_IsClientChoked)
{ {
LogPrint (eLogDebug, "Streaming: Packet loss, reduce window size"); LogPrint (eLogDebug, "Streaming: Packet loss, reduce window size");
ProcessWindowDrop (); ProcessWindowDrop ();
@@ -1458,11 +1475,12 @@ namespace stream
SendPackets (packets); SendPackets (packets);
m_LastSendTime = ts; m_LastSendTime = ts;
m_IsSendTime = false; m_IsSendTime = false;
if (m_IsNAcked || m_IsResendNeeded) ScheduleSend (); if (m_IsNAcked || m_IsResendNeeded || m_IsClientChoked) ScheduleSend ();
} }
else else if (!m_IsClientChoked)
SendBuffer (); SendBuffer ();
if (!m_IsNAcked && !m_IsResendNeeded) ScheduleResend (); if (!m_IsNAcked && !m_IsResendNeeded) ScheduleResend ();
if (m_IsClientChoked) ScheduleSend ();
} }
void Stream::ScheduleAck (int timeout) void Stream::ScheduleAck (int timeout)
@@ -1602,7 +1620,7 @@ namespace stream
if (isLeaseChanged && !m_IsRemoteLeaseChangeInProgress) if (isLeaseChanged && !m_IsRemoteLeaseChangeInProgress)
{ {
LogPrint (eLogDebug, "Streaming: RemoteLease changed, set initial window size"); LogPrint (eLogDebug, "Streaming: RemoteLease changed, set initial window size");
HalveWindowSize (); ResetWindowSize ();
} }
} }
@@ -1646,16 +1664,19 @@ namespace stream
UpdatePacingTime (); UpdatePacingTime ();
} }
void Stream::HalveWindowSize () void Stream::ResetWindowSize ()
{ {
m_RTO = INITIAL_RTO; m_RTO = INITIAL_RTO;
if (m_WindowSize > INITIAL_WINDOW_SIZE) if (!m_IsClientChoked)
{ {
m_WindowDropTargetSize = std::max (m_WindowSize/2, (float)INITIAL_WINDOW_SIZE); if (m_WindowSize > INITIAL_WINDOW_SIZE)
m_IsWinDropped = true; {
m_WindowDropTargetSize = (float)INITIAL_WINDOW_SIZE;
m_IsWinDropped = true;
}
else
m_WindowSize = INITIAL_WINDOW_SIZE;
} }
else
m_WindowSize = INITIAL_WINDOW_SIZE;
m_LastWindowDropSize = 0; m_LastWindowDropSize = 0;
m_WindowIncCounter = 0; m_WindowIncCounter = 0;
m_IsFirstRttSample = true; m_IsFirstRttSample = true;

View File

@@ -251,7 +251,7 @@ namespace stream
void UpdatePacingTime (); void UpdatePacingTime ();
void ProcessWindowDrop (); void ProcessWindowDrop ();
void HalveWindowSize (); void ResetWindowSize ();
void CancelRemoteLeaseChange (); void CancelRemoteLeaseChange ();
private: private:
@@ -272,6 +272,7 @@ namespace stream
bool m_IsFirstRttSample; bool m_IsFirstRttSample;
bool m_IsSendTime; bool m_IsSendTime;
bool m_IsWinDropped; bool m_IsWinDropped;
bool m_IsClientChoked;
bool m_IsTimeOutResend; bool m_IsTimeOutResend;
bool m_IsImmediateAckRequested; bool m_IsImmediateAckRequested;
bool m_IsRemoteLeaseChangeInProgress; bool m_IsRemoteLeaseChangeInProgress;

View File

@@ -10,6 +10,8 @@
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Crypto.h" #include "Crypto.h"
#include "Log.h" #include "Log.h"
#include "Identity.h"
#include "RouterInfo.h"
#include "RouterContext.h" #include "RouterContext.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "Garlic.h" #include "Garlic.h"
@@ -41,6 +43,21 @@ namespace tunnel
i2p::transport::transports.UpdateTotalTransitTransmittedBytes (TUNNEL_DATA_MSG_SIZE); i2p::transport::transports.UpdateTotalTransitTransmittedBytes (TUNNEL_DATA_MSG_SIZE);
} }
std::string TransitTunnel::GetNextPeerName () const
{
return i2p::data::GetIdentHashAbbreviation (GetNextIdentHash ());
}
void TransitTunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
{
LogPrint (eLogError, "TransitTunnel: We are not a gateway for ", GetTunnelID ());
}
void TransitTunnel::HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg)
{
LogPrint (eLogError, "TransitTunnel: Incoming tunnel message is not supported ", GetTunnelID ());
}
TransitTunnelParticipant::~TransitTunnelParticipant () TransitTunnelParticipant::~TransitTunnelParticipant ()
{ {
} }
@@ -62,20 +79,23 @@ namespace tunnel
auto num = m_TunnelDataMsgs.size (); auto num = m_TunnelDataMsgs.size ();
if (num > 1) if (num > 1)
LogPrint (eLogDebug, "TransitTunnel: ", GetTunnelID (), "->", GetNextTunnelID (), " ", num); LogPrint (eLogDebug, "TransitTunnel: ", GetTunnelID (), "->", GetNextTunnelID (), " ", num);
i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs); // send and clear if (!m_Sender) m_Sender = std::make_unique<TunnelTransportSender>();
m_Sender->SendMessagesTo (GetNextIdentHash (), m_TunnelDataMsgs); // send and clear
} }
} }
void TransitTunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) std::string TransitTunnelParticipant::GetNextPeerName () const
{ {
LogPrint (eLogError, "TransitTunnel: We are not a gateway for ", GetTunnelID ()); if (m_Sender)
} {
auto transport = m_Sender->GetCurrentTransport ();
void TransitTunnel::HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) if (transport)
{ return TransitTunnel::GetNextPeerName () + "-" +
LogPrint (eLogError, "TransitTunnel: Incoming tunnel message is not supported ", GetTunnelID ()); i2p::data::RouterInfo::GetTransportName (transport->GetTransportType ());
} }
return TransitTunnel::GetNextPeerName ();
}
void TransitTunnelGateway::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) void TransitTunnelGateway::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
{ {
TunnelMessageBlock block; TunnelMessageBlock block;
@@ -91,6 +111,19 @@ namespace tunnel
m_Gateway.SendBuffer (); m_Gateway.SendBuffer ();
} }
std::string TransitTunnelGateway::GetNextPeerName () const
{
const auto& sender = m_Gateway.GetSender ();
if (sender)
{
auto transport = sender->GetCurrentTransport ();
if (transport)
return TransitTunnel::GetNextPeerName () + "-" +
i2p::data::RouterInfo::GetTransportName (transport->GetTransportType ());
}
return TransitTunnel::GetNextPeerName ();
}
void TransitTunnelEndpoint::HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) void TransitTunnelEndpoint::HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg)
{ {
auto newMsg = CreateEmptyTunnelDataMsg (true); auto newMsg = CreateEmptyTunnelDataMsg (true);
@@ -100,6 +133,30 @@ namespace tunnel
m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg); m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);
} }
void TransitTunnelEndpoint::FlushTunnelDataMsgs ()
{
m_Endpoint.FlushI2NPMsgs ();
}
std::string TransitTunnelEndpoint::GetNextPeerName () const
{
auto hash = m_Endpoint.GetCurrentHash ();
if (hash)
{
const auto& sender = m_Endpoint.GetSender ();
if (sender)
{
auto transport = sender->GetCurrentTransport ();
if (transport)
return i2p::data::GetIdentHashAbbreviation (*hash) + "-" +
i2p::data::RouterInfo::GetTransportName (transport->GetTransportType ());
else
return i2p::data::GetIdentHashAbbreviation (*hash);
}
}
return "";
}
std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID, std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID,
const i2p::data::IdentHash& nextIdent, uint32_t nextTunnelID, const i2p::data::IdentHash& nextIdent, uint32_t nextTunnelID,
const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey, const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey,

View File

@@ -33,11 +33,13 @@ namespace tunnel
const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey); const i2p::crypto::AESKey& layerKey, const i2p::crypto::AESKey& ivKey);
virtual size_t GetNumTransmittedBytes () const { return 0; }; virtual size_t GetNumTransmittedBytes () const { return 0; };
virtual std::string GetNextPeerName () const;
// implements TunnelBase // implements TunnelBase
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override; void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override;
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override; void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override;
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out) override; void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out) override;
private: private:
i2p::crypto::AESKey m_LayerKey, m_IVKey; i2p::crypto::AESKey m_LayerKey, m_IVKey;
@@ -56,6 +58,7 @@ namespace tunnel
~TransitTunnelParticipant (); ~TransitTunnelParticipant ();
size_t GetNumTransmittedBytes () const override { return m_NumTransmittedBytes; }; size_t GetNumTransmittedBytes () const override { return m_NumTransmittedBytes; };
std::string GetNextPeerName () const override;
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override; void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override;
void FlushTunnelDataMsgs () override; void FlushTunnelDataMsgs () override;
@@ -63,6 +66,7 @@ namespace tunnel
size_t m_NumTransmittedBytes; size_t m_NumTransmittedBytes;
std::list<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs; std::list<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs;
std::unique_ptr<TunnelTransportSender> m_Sender;
}; };
class TransitTunnelGateway: public TransitTunnel class TransitTunnelGateway: public TransitTunnel
@@ -78,7 +82,8 @@ namespace tunnel
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override; void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override;
void FlushTunnelDataMsgs () override; void FlushTunnelDataMsgs () override;
size_t GetNumTransmittedBytes () const override { return m_Gateway.GetNumSentBytes (); }; size_t GetNumTransmittedBytes () const override { return m_Gateway.GetNumSentBytes (); };
std::string GetNextPeerName () const override;
private: private:
std::mutex m_SendMutex; std::mutex m_SendMutex;
@@ -96,10 +101,12 @@ namespace tunnel
m_Endpoint (false) {}; // transit endpoint is always outbound m_Endpoint (false) {}; // transit endpoint is always outbound
void Cleanup () override { m_Endpoint.Cleanup (); } void Cleanup () override { m_Endpoint.Cleanup (); }
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override; void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override;
void FlushTunnelDataMsgs () override;
size_t GetNumTransmittedBytes () const override { return m_Endpoint.GetNumReceivedBytes (); } size_t GetNumTransmittedBytes () const override { return m_Endpoint.GetNumReceivedBytes (); }
std::string GetNextPeerName () const override;
private: private:
TunnelEndpoint m_Endpoint; TunnelEndpoint m_Endpoint;

View File

@@ -151,6 +151,7 @@ namespace transport
}; };
virtual void SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs) = 0; virtual void SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs) = 0;
virtual bool IsEstablished () const = 0; virtual bool IsEstablished () const = 0;
virtual i2p::data::RouterInfo::SupportedTransports GetTransportType () const = 0;
private: private:

View File

@@ -55,6 +55,13 @@ namespace transport
m_Thread->join (); m_Thread->join ();
m_Thread = nullptr; m_Thread = nullptr;
} }
if (!m_Queue.empty ())
{
// clean up queue
std::queue<std::shared_ptr<Keys> > tmp;
std::swap (m_Queue, tmp);
}
m_KeysPool.CleanUpMt ();
} }
template<typename Keys> template<typename Keys>
@@ -454,13 +461,6 @@ namespace transport
return {}; // invalid future return {}; // invalid future
} }
std::future<std::shared_ptr<TransportSession> > Transports::SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs)
{
std::list<std::shared_ptr<i2p::I2NPMessage> > msgs1;
msgs.swap (msgs1);
return SendMessages (ident, std::move (msgs1));
}
std::future<std::shared_ptr<TransportSession> > Transports::SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >&& msgs) std::future<std::shared_ptr<TransportSession> > Transports::SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >&& msgs)
{ {
return boost::asio::post (*m_Service, boost::asio::use_future ([this, ident, msgs = std::move(msgs)] () mutable return boost::asio::post (*m_Service, boost::asio::use_future ([this, ident, msgs = std::move(msgs)] () mutable

View File

@@ -54,8 +54,8 @@ namespace transport
private: private:
const int m_QueueSize; const int m_QueueSize;
std::queue<std::shared_ptr<Keys> > m_Queue;
i2p::util::MemoryPoolMt<Keys> m_KeysPool; i2p::util::MemoryPoolMt<Keys> m_KeysPool;
std::queue<std::shared_ptr<Keys> > m_Queue;
bool m_IsRunning; bool m_IsRunning;
std::unique_ptr<std::thread> m_Thread; std::unique_ptr<std::thread> m_Thread;
@@ -145,7 +145,6 @@ namespace transport
void ReuseX25519KeysPair (std::shared_ptr<i2p::crypto::X25519Keys> pair); void ReuseX25519KeysPair (std::shared_ptr<i2p::crypto::X25519Keys> pair);
std::future<std::shared_ptr<TransportSession> > SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg); std::future<std::shared_ptr<TransportSession> > SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg);
std::future<std::shared_ptr<TransportSession> > SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >& msgs);
std::future<std::shared_ptr<TransportSession> > SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >&& msgs); std::future<std::shared_ptr<TransportSession> > SendMessages (const i2p::data::IdentHash& ident, std::list<std::shared_ptr<i2p::I2NPMessage> >&& msgs);
void PeerConnected (std::shared_ptr<TransportSession> session); void PeerConnected (std::shared_ptr<TransportSession> session);

View File

@@ -296,6 +296,8 @@ namespace tunnel
bool m_IsRunning; bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_ENPOINT_MESSAGE_SIZE> > m_I2NPTunnelEndpointMessagesMemoryPool;
i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_MESSAGE_SIZE> > m_I2NPTunnelMessagesMemoryPool;
std::map<uint32_t, std::shared_ptr<InboundTunnel> > m_PendingInboundTunnels; // by replyMsgID std::map<uint32_t, std::shared_ptr<InboundTunnel> > m_PendingInboundTunnels; // by replyMsgID
std::map<uint32_t, std::shared_ptr<OutboundTunnel> > m_PendingOutboundTunnels; // by replyMsgID std::map<uint32_t, std::shared_ptr<OutboundTunnel> > m_PendingOutboundTunnels; // by replyMsgID
std::list<std::shared_ptr<InboundTunnel> > m_InboundTunnels; std::list<std::shared_ptr<InboundTunnel> > m_InboundTunnels;
@@ -306,8 +308,6 @@ namespace tunnel
std::list<std::shared_ptr<TunnelPool>> m_Pools; std::list<std::shared_ptr<TunnelPool>> m_Pools;
std::shared_ptr<TunnelPool> m_ExploratoryPool; std::shared_ptr<TunnelPool> m_ExploratoryPool;
i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue; i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue;
i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_ENPOINT_MESSAGE_SIZE> > m_I2NPTunnelEndpointMessagesMemoryPool;
i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_MESSAGE_SIZE> > m_I2NPTunnelMessagesMemoryPool;
uint32_t m_MaxNumTransitTunnels; uint32_t m_MaxNumTransitTunnels;
// count of tunnels for total TCSR algorithm // count of tunnels for total TCSR algorithm
int m_TotalNumSuccesiveTunnelCreations, m_TotalNumFailedTunnelCreations; int m_TotalNumSuccesiveTunnelCreations, m_TotalNumFailedTunnelCreations;

71
libi2pd/TunnelBase.cpp Normal file
View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2024, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*
*/
#include "Transports.h"
#include "TunnelBase.h"
namespace i2p
{
namespace tunnel
{
void TunnelTransportSender::SendMessagesTo (const i2p::data::IdentHash& to,
std::list<std::shared_ptr<I2NPMessage> >&& msgs)
{
if (msgs.empty ()) return;
auto currentTransport = m_CurrentTransport.lock ();
if (!currentTransport)
{
// try to obtain transport from pending request or send thought transport is not complete
if (m_PendingTransport.valid ()) // pending request?
{
if (m_PendingTransport.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
{
// pending request complete
currentTransport = m_PendingTransport.get (); // take transports used in pending request
if (currentTransport)
{
if (currentTransport->IsEstablished ())
m_CurrentTransport = currentTransport;
else
currentTransport = nullptr;
}
}
else // still pending
{
// send through transports, but don't update pending transport
i2p::transport::transports.SendMessages (to, std::move (msgs));
return;
}
}
}
if (currentTransport) // session is good
// send to session directly
currentTransport->SendI2NPMessages (msgs);
else // no session yet
// send through transports
m_PendingTransport = i2p::transport::transports.SendMessages (to, std::move (msgs));
}
void TunnelTransportSender::SendMessagesTo (const i2p::data::IdentHash& to,
std::list<std::shared_ptr<I2NPMessage> >& msgs)
{
std::list<std::shared_ptr<i2p::I2NPMessage> > msgs1;
msgs.swap (msgs1);
SendMessagesTo (to, std::move (msgs1));
}
void TunnelTransportSender::Reset ()
{
m_CurrentTransport.reset ();
if (m_PendingTransport.valid ())
m_PendingTransport = std::future<std::shared_ptr<i2p::transport::TransportSession> >();
}
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2022, The PurpleI2P Project * Copyright (c) 2013-2024, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@@ -11,12 +11,19 @@
#include <inttypes.h> #include <inttypes.h>
#include <memory> #include <memory>
#include <future>
#include <list>
#include "Timestamp.h" #include "Timestamp.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "Identity.h" #include "Identity.h"
namespace i2p namespace i2p
{ {
namespace transport
{
class TransportSession;
}
namespace tunnel namespace tunnel
{ {
const size_t TUNNEL_DATA_MSG_SIZE = 1028; const size_t TUNNEL_DATA_MSG_SIZE = 1028;
@@ -76,6 +83,25 @@ namespace tunnel
return t1 < t2; return t1 < t2;
} }
}; };
class TunnelTransportSender final
{
public:
TunnelTransportSender () = default;
~TunnelTransportSender () = default;
void SendMessagesTo (const i2p::data::IdentHash& to, std::list<std::shared_ptr<I2NPMessage> >&& msgs);
void SendMessagesTo (const i2p::data::IdentHash& to, std::list<std::shared_ptr<I2NPMessage> >& msgs); // send and clear
std::shared_ptr<const i2p::transport::TransportSession> GetCurrentTransport () const { return m_CurrentTransport.lock (); }
void Reset ();
private:
std::weak_ptr<i2p::transport::TransportSession> m_CurrentTransport;
std::future<std::shared_ptr<i2p::transport::TransportSession> > m_PendingTransport;
};
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, The PurpleI2P Project * Copyright (c) 2013-2024, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@@ -21,10 +21,7 @@ namespace i2p
{ {
namespace tunnel namespace tunnel
{ {
TunnelEndpoint::~TunnelEndpoint ()
{
}
void TunnelEndpoint::HandleDecryptedTunnelDataMsg (std::shared_ptr<I2NPMessage> msg) void TunnelEndpoint::HandleDecryptedTunnelDataMsg (std::shared_ptr<I2NPMessage> msg)
{ {
m_NumReceivedBytes += TUNNEL_DATA_MSG_SIZE; m_NumReceivedBytes += TUNNEL_DATA_MSG_SIZE;
@@ -331,13 +328,13 @@ namespace tunnel
break; break;
case eDeliveryTypeTunnel: case eDeliveryTypeTunnel:
if (!m_IsInbound) // outbound transit tunnel if (!m_IsInbound) // outbound transit tunnel
i2p::transport::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data)); SendMessageTo (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data));
else else
LogPrint (eLogError, "TunnelMessage: Delivery type 'tunnel' arrived from an inbound tunnel, dropped"); LogPrint (eLogError, "TunnelMessage: Delivery type 'tunnel' arrived from an inbound tunnel, dropped");
break; break;
case eDeliveryTypeRouter: case eDeliveryTypeRouter:
if (!m_IsInbound) // outbound transit tunnel if (!m_IsInbound) // outbound transit tunnel
i2p::transport::transports.SendMessage (msg.hash, msg.data); i2p::transport::transports.SendMessage (msg.hash, msg.data); // send right away, because most likely it's single message
else // we shouldn't send this message. possible leakage else // we shouldn't send this message. possible leakage
LogPrint (eLogError, "TunnelMessage: Delivery type 'router' arrived from an inbound tunnel, dropped"); LogPrint (eLogError, "TunnelMessage: Delivery type 'router' arrived from an inbound tunnel, dropped");
break; break;
@@ -366,5 +363,35 @@ namespace tunnel
++it; ++it;
} }
} }
void TunnelEndpoint::SendMessageTo (const i2p::data::IdentHash& to, std::shared_ptr<i2p::I2NPMessage> msg)
{
if (msg)
{
if (!m_Sender && m_I2NPMsgs.empty ()) // first message
m_CurrentHash = to;
else if (m_CurrentHash != to) // new target router
{
FlushI2NPMsgs (); // flush message to previous
if (m_Sender) m_Sender->Reset (); // reset sender
m_CurrentHash = to; // set new target router
} // otherwise add msg to the list for current target router
m_I2NPMsgs.push_back (msg);
}
}
void TunnelEndpoint::FlushI2NPMsgs ()
{
if (!m_I2NPMsgs.empty ())
{
if (!m_Sender) m_Sender = std::make_unique<TunnelTransportSender>();
m_Sender->SendMessagesTo (m_CurrentHash, m_I2NPMsgs); // send and clear
}
}
const i2p::data::IdentHash * TunnelEndpoint::GetCurrentHash () const
{
return (m_Sender || !m_I2NPMsgs.empty ()) ? &m_CurrentHash : nullptr;
}
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2021, The PurpleI2P Project * Copyright (c) 2013-2024, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@@ -11,8 +11,10 @@
#include <inttypes.h> #include <inttypes.h>
#include <vector> #include <vector>
#include <list>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <memory>
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "TunnelBase.h" #include "TunnelBase.h"
@@ -20,7 +22,7 @@ namespace i2p
{ {
namespace tunnel namespace tunnel
{ {
class TunnelEndpoint class TunnelEndpoint final
{ {
struct TunnelMessageBlockEx: public TunnelMessageBlock struct TunnelMessageBlockEx: public TunnelMessageBlock
{ {
@@ -39,18 +41,23 @@ namespace tunnel
public: public:
TunnelEndpoint (bool isInbound): m_IsInbound (isInbound), m_NumReceivedBytes (0), m_CurrentMsgID (0) {}; TunnelEndpoint (bool isInbound): m_IsInbound (isInbound), m_NumReceivedBytes (0), m_CurrentMsgID (0) {};
~TunnelEndpoint (); ~TunnelEndpoint () = default;
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
void Cleanup (); void Cleanup ();
void HandleDecryptedTunnelDataMsg (std::shared_ptr<I2NPMessage> msg); void HandleDecryptedTunnelDataMsg (std::shared_ptr<I2NPMessage> msg);
void FlushI2NPMsgs ();
const i2p::data::IdentHash * GetCurrentHash () const; // return null if not avaiable
const std::unique_ptr<TunnelTransportSender>& GetSender () const { return m_Sender; };
private: private:
void HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, uint8_t fragmentNum, const uint8_t * fragment, size_t size); void HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, uint8_t fragmentNum, const uint8_t * fragment, size_t size);
bool ConcatFollowOnFragment (TunnelMessageBlockEx& msg, const uint8_t * fragment, size_t size) const; // true if success bool ConcatFollowOnFragment (TunnelMessageBlockEx& msg, const uint8_t * fragment, size_t size) const; // true if success
void HandleCurrenMessageFollowOnFragment (const uint8_t * fragment, size_t size, bool isLastFragment); void HandleCurrenMessageFollowOnFragment (const uint8_t * fragment, size_t size, bool isLastFragment);
void HandleNextMessage (const TunnelMessageBlock& msg); void HandleNextMessage (const TunnelMessageBlock& msg);
void SendMessageTo (const i2p::data::IdentHash& to, std::shared_ptr<i2p::I2NPMessage> msg);
void AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, const uint8_t * fragment, size_t size); void AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, const uint8_t * fragment, size_t size);
bool ConcatNextOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg); // true if something added bool ConcatNextOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg); // true if something added
@@ -65,6 +72,10 @@ namespace tunnel
size_t m_NumReceivedBytes; size_t m_NumReceivedBytes;
TunnelMessageBlockEx m_CurrentMessage; TunnelMessageBlockEx m_CurrentMessage;
uint32_t m_CurrentMsgID; uint32_t m_CurrentMsgID;
// I2NP messages to send
std::list<std::shared_ptr<i2p::I2NPMessage> > m_I2NPMsgs; // to send
i2p::data::IdentHash m_CurrentHash; // send msgs to
std::unique_ptr<TunnelTransportSender> m_Sender;
}; };
} }
} }

View File

@@ -235,40 +235,9 @@ namespace tunnel
m_NumSentBytes += TUNNEL_DATA_MSG_SIZE; m_NumSentBytes += TUNNEL_DATA_MSG_SIZE;
} }
m_Buffer.ClearTunnelDataMsgs (); m_Buffer.ClearTunnelDataMsgs ();
// send // send
auto currentTransport = m_CurrentTransport.lock (); if (!m_Sender) m_Sender = std::make_unique<TunnelTransportSender>();
if (!currentTransport) m_Sender->SendMessagesTo (m_Tunnel.GetNextIdentHash (), std::move (newTunnelMsgs));
{
// try to obtain transport from pending request or send thought transport is not complete
if (m_PendingTransport.valid ()) // pending request?
{
if (m_PendingTransport.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
{
// pending request complete
currentTransport = m_PendingTransport.get (); // take transports used in pending request
if (currentTransport)
{
if (currentTransport->IsEstablished ())
m_CurrentTransport = currentTransport;
else
currentTransport = nullptr;
}
}
else // still pending
{
// send through transports, but don't update pending transport
i2p::transport::transports.SendMessages (m_Tunnel.GetNextIdentHash (), std::move (newTunnelMsgs));
return;
}
}
}
if (currentTransport) // session is good
// send to session directly
currentTransport->SendI2NPMessages (newTunnelMsgs);
else // no session yet
// send through transports
m_PendingTransport = i2p::transport::transports.SendMessages (m_Tunnel.GetNextIdentHash (), std::move (newTunnelMsgs));
} }
} }
} }

View File

@@ -12,9 +12,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <future>
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "TransportSession.h"
#include "TunnelBase.h" #include "TunnelBase.h"
namespace i2p namespace i2p
@@ -53,14 +51,14 @@ namespace tunnel
void PutTunnelDataMsg (const TunnelMessageBlock& block); void PutTunnelDataMsg (const TunnelMessageBlock& block);
void SendBuffer (); void SendBuffer ();
size_t GetNumSentBytes () const { return m_NumSentBytes; }; size_t GetNumSentBytes () const { return m_NumSentBytes; };
const std::unique_ptr<TunnelTransportSender>& GetSender () const { return m_Sender; };
private: private:
TunnelBase& m_Tunnel; TunnelBase& m_Tunnel;
TunnelGatewayBuffer m_Buffer; TunnelGatewayBuffer m_Buffer;
size_t m_NumSentBytes; size_t m_NumSentBytes;
std::weak_ptr<i2p::transport::TransportSession> m_CurrentTransport; std::unique_ptr<TunnelTransportSender> m_Sender;
std::future<std::shared_ptr<i2p::transport::TransportSession> > m_PendingTransport;
}; };
} }
} }

View File

@@ -454,9 +454,9 @@ namespace net
#ifdef _WIN32 #ifdef _WIN32
LogPrint(eLogError, "NetIface: Cannot get address by interface name, not implemented on WIN32"); LogPrint(eLogError, "NetIface: Cannot get address by interface name, not implemented on WIN32");
if (ipv6) if (ipv6)
return boost::asio::ip::address::from_string("::1"); return boost::asio::ip::make_address("::1");
else else
return boost::asio::ip::address::from_string("127.0.0.1"); return boost::asio::ip::make_address("127.0.0.1");
#else #else
int af = (ipv6 ? AF_INET6 : AF_INET); int af = (ipv6 ? AF_INET6 : AF_INET);
ifaddrs *addrs; ifaddrs *addrs;

View File

@@ -18,7 +18,7 @@
#define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c) #define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c)
#define I2PD_VERSION_MAJOR 2 #define I2PD_VERSION_MAJOR 2
#define I2PD_VERSION_MINOR 54 #define I2PD_VERSION_MINOR 55
#define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_MICRO 0
#define I2PD_VERSION_PATCH 0 #define I2PD_VERSION_PATCH 0
#ifdef GITVER #ifdef GITVER