[noise] Hold the refill only for connections still inside their grace period

Gating on the noise handshake alone let the refill land between the
handshake and the hello response, inside the window being optimized; a
connection now holds the slot while it is unauthenticated and younger
than a second, so a fresh client gets through its hello first and a stale
half open one stops holding the slot after that.
This commit is contained in:
J. Nick Koston
2026-09-07 00:47:55 +02:00
parent 29f7439154
commit 05dbc5ee59
3 changed files with 10 additions and 6 deletions
+6 -1
View File
@@ -316,10 +316,15 @@ class APIConnection final : public APIServerConnectionBase {
void on_noise_encryption_set_key_request(const NoiseEncryptionSetKeyRequest &msg);
#endif
static constexpr uint32_t CONNECT_GRACE_MS = 1000;
bool is_authenticated() {
return static_cast<ConnectionState>(this->flags_.connection_state) == ConnectionState::AUTHENTICATED;
}
bool is_handshake_complete() const { return this->helper_->is_handshake_complete(); }
// A connection that is still setting up within its grace period; an older
// unauthenticated one is a stale half open client and no longer counts
bool is_still_connecting(uint32_t now) {
return !this->is_authenticated() && now - this->last_traffic_ < CONNECT_GRACE_MS;
}
bool is_connection_setup() {
return static_cast<ConnectionState>(this->flags_.connection_state) == ConnectionState::CONNECTED ||
this->is_authenticated();
@@ -118,8 +118,6 @@ class APIFrameHelper {
virtual APIError loop() = 0;
virtual APIError read_packet(ReadPacketBuffer *buffer) = 0;
bool can_write_without_blocking() { return this->state_ == State::DATA && this->overflow_buf_.empty(); }
/// Transport handshake done (immediately for plaintext)
bool is_handshake_complete() const { return this->state_ == State::DATA; }
int getpeername(struct sockaddr *addr, socklen_t *addrlen) { return socket_->getpeername(addr, addrlen); }
APIError close() {
if (state_ == State::CLOSED)
+4 -3
View File
@@ -196,14 +196,15 @@ void APIServer::loop() {
}
#ifdef USE_API_NOISE
// Refill only while no api client waits on a noise handshake; an OTA
// handshake is not visible here and just pays the refill it triggered.
// Refill only while no api client is still connecting; an OTA handshake is
// not visible here and just pays the refill it triggered.
void APIServer::prepare_spare_ephemeral_() {
if (noise::has_spare_ephemeral() || !network::is_connected()) {
return;
}
const uint32_t now = App.get_loop_component_start_time();
for (auto &client : this->active_clients()) {
if (!client->is_handshake_complete()) {
if (client->is_still_connecting(now)) {
return;
}
}