From 285328d92fc772b350ec2a0ba990b0a44945f617 Mon Sep 17 00:00:00 2001 From: jolavillette Date: Sat, 22 Aug 2026 14:18:26 +0200 Subject: [PATCH] i2p(sam3): move the session restart delay to startSession() stopSession() ended with an unconditional 10 s sleep, meant to give i2pd time to let go of a session before the next one is created ("restart" button in the settings, which posts a stop ticket immediately followed by a start ticket). A stop is not always followed by a start. On application exit p3face-config's shutdown sequence calls rsAutoProxyMonitor::stopAllRSShutdown(), which posts that same stop ticket and then waits for the service to acknowledge it; the sleep therefore delayed the whole shutdown by 10 s for nothing. Measured on a node with SAM3 enabled: 10.0 s of a 21.8 s shutdown were spent in this sleep, the monitor logging "waiting for auto proxy service(s) to shut down 0..10/15 (remaining: 1)". The "stop" button in the settings pays it too, equally uselessly. Record when the session was closed instead, and wait out what is left of the delay in startSession(), where it is actually needed. The guarantee i2pd relies on is unchanged -- a session is still never created less than 10 s after the previous one was closed -- but a stop that is not followed by a start now returns immediately. Co-Authored-By: Claude Opus 5 --- src/services/autoproxy/p3i2psam3.cpp | 33 +++++++++++++++++++++++----- src/services/autoproxy/p3i2psam3.h | 5 +++++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/services/autoproxy/p3i2psam3.cpp b/src/services/autoproxy/p3i2psam3.cpp index ca7a44575..889a5779d 100644 --- a/src/services/autoproxy/p3i2psam3.cpp +++ b/src/services/autoproxy/p3i2psam3.cpp @@ -29,6 +29,14 @@ static const std::string kConfigKeyBOBAddr = "BOB_ADDR"; static constexpr bool kDefaultSAM3Enable = false; +/* At least i2pd doesn't like to instantaniously stop and (re)start a session, so + * a new session is never created less than this long after the previous one was + * closed. The wait happens in startSession(), where it is actually needed, and + * not in stopSession(): a stop is not always followed by a start (RS shutdown, + * "stop" button in the settings) and waiting there held back the whole + * application exit by 10 seconds. */ +static constexpr auto kSessionRestartDelay = std::chrono::seconds(10); + RS_SET_CONTEXT_DEBUG_LEVEL(2) static void inline doSleep(std::chrono::duration> timeToSleepMS) { @@ -36,7 +44,9 @@ static void inline doSleep(std::chrono::duration> timeT } p3I2pSam3::p3I2pSam3(p3PeerMgr *peerMgr) : - mConfigLoaded(false), mPeerMgr(peerMgr), mPending(), mLock("p3i2p-sam3") + mConfigLoaded(false), mPeerMgr(peerMgr), mPending(), + mLastSessionClosed(std::chrono::steady_clock::time_point::min()), + mLock("p3i2p-sam3") #ifdef RS_USE_I2P_SAM3_LIBSAM3 , mLockSam3Access("p3i2p-sam3-access") #endif @@ -498,6 +508,19 @@ bool p3I2pSam3::startSession() stopSession(); } + // Give i2pd time to let go of the previous session. No lock may be held here. + std::chrono::steady_clock::time_point sessionReady; + { + RS_STACK_MUTEX(mLock); + sessionReady = mLastSessionClosed + kSessionRestartDelay; + } + const auto now = std::chrono::steady_clock::now(); + if (now < sessionReady) { + const auto wait = std::chrono::duration_cast(sessionReady - now); + RS_DBG("waiting ", wait.count(), " ms before creating a new SAM session"); + doSleep(wait); + } + auto session = (Sam3Session*)rs_malloc(sizeof (Sam3Session)); // add nick @@ -592,12 +615,10 @@ void p3I2pSam3::stopSession() mSetting.session = nullptr; mState = samStatus::samState::offline; - } - // At least i2pd doesn't like to instantaniously stop and (re)start a session, wait here just a little bit. - // Not ideal but does the trick. - // (This happens when using the "restart" button in the settings.) - doSleep(std::chrono::seconds(10)); + // startSession() waits out kSessionRestartDelay counted from here + mLastSessionClosed = std::chrono::steady_clock::now(); + } } void p3I2pSam3::stopForwarding() diff --git a/src/services/autoproxy/p3i2psam3.h b/src/services/autoproxy/p3i2psam3.h index c6b57615e..1ddc8c3cf 100644 --- a/src/services/autoproxy/p3i2psam3.h +++ b/src/services/autoproxy/p3i2psam3.h @@ -1,6 +1,7 @@ #ifndef P3I2PSAM3_H #define P3I2PSAM3_H +#include #include #include @@ -102,6 +103,10 @@ private: // used to keep track of connections, libsam3 does it internally but it can be unreliable since pointers are shared std::list mValidConnections, mInvalidConnections; + // Point in time at which the last SAM session was closed. startSession() uses + // it to honour kSessionRestartDelay. Guarded by mLock. + std::chrono::steady_clock::time_point mLastSessionClosed; + // mutex RsMutex mLock; RsMutex mLockSam3Access; // libsam3 is not thread safe! (except for key lookup)