Inline empty() fast path, out-of-line drain+error handling

Keep the cheap overflow_buf_.empty() check inline at all call sites.
Move try_drain + HELPER_LOG + error handling into a single out-of-line
drain_overflow_and_handle_errors_() used by both write_raw_ and the
subclass loop() methods. Eliminates the duplicated drain logic.
This commit is contained in:
J. Nick Koston
2026-03-16 12:43:17 -10:00
parent ad427e1635
commit 9f774b3827
4 changed files with 27 additions and 22 deletions
+12 -5
View File
@@ -100,6 +100,15 @@ const LogString *api_error_to_logstr(APIError err) {
return LOG_STR("UNKNOWN");
}
APIError APIFrameHelper::drain_overflow_and_handle_errors_() {
if (this->overflow_buf_.try_drain(this->socket_.get()) == -1) {
HELPER_LOG("Socket write failed with errno %d", errno);
if (this->check_socket_write_err_(errno) != APIError::WOULD_BLOCK)
return APIError::SOCKET_WRITE_FAILED;
}
return APIError::OK;
}
// Write data to socket, overflow to backlog buffer if LWIP TCP send buffer is full.
// Returns OK if all data was sent or successfully queued.
// Returns SOCKET_WRITE_FAILED on hard error (sets state to FAILED).
@@ -114,11 +123,9 @@ APIError APIFrameHelper::write_raw_(const struct iovec *iov, int iovcnt, uint16_
// Drain any existing backlog first
if (!this->overflow_buf_.empty()) [[unlikely]] {
if (this->overflow_buf_.try_drain(this->socket_.get()) == -1) {
HELPER_LOG("Socket write failed with errno %d", errno);
if (this->check_socket_write_err_(errno) != APIError::WOULD_BLOCK)
return APIError::SOCKET_WRITE_FAILED;
}
APIError err = this->drain_overflow_and_handle_errors_();
if (err != APIError::OK)
return err;
}
// If backlog is clear, try direct send
+5 -9
View File
@@ -190,15 +190,11 @@ class APIFrameHelper {
}
protected:
// Drain any backlogged overflow data to the socket.
// Returns OK even for WOULD_BLOCK to avoid connection termination.
APIError try_drain_overflow_buffer_() {
if (!this->overflow_buf_.empty() && this->overflow_buf_.try_drain(this->socket_.get()) == -1) {
if (this->check_socket_write_err_(errno) != APIError::WOULD_BLOCK)
return APIError::SOCKET_WRITE_FAILED;
}
return APIError::OK;
}
// Drain backlogged overflow data to the socket and handle errors.
// Called when overflow_buf_.empty() is false. Out-of-line to keep the
// fast path (empty check) inline at call sites.
// Returns OK for transient errors (WOULD_BLOCK), SOCKET_WRITE_FAILED for hard errors.
APIError drain_overflow_and_handle_errors_();
// Common implementation for writing raw data to socket
APIError write_raw_(const struct iovec *iov, int iovcnt, uint16_t total_write_len);
@@ -153,11 +153,12 @@ APIError APINoiseFrameHelper::loop() {
}
}
APIError err = this->try_drain_overflow_buffer_();
if (err != APIError::OK) {
HELPER_LOG("Overflow drain failed with errno %d", errno);
if (!this->overflow_buf_.empty()) [[unlikely]] {
APIError err = this->drain_overflow_and_handle_errors_();
if (err != APIError::OK)
return err;
}
return err;
return APIError::OK;
}
/** Read a packet into the rx_buf_.
@@ -64,11 +64,12 @@ APIError APIPlaintextFrameHelper::loop() {
if (state_ != State::DATA) {
return APIError::BAD_STATE;
}
APIError err = this->try_drain_overflow_buffer_();
if (err != APIError::OK) {
HELPER_LOG("Overflow drain failed with errno %d", errno);
if (!this->overflow_buf_.empty()) [[unlikely]] {
APIError err = this->drain_overflow_and_handle_errors_();
if (err != APIError::OK)
return err;
}
return err;
return APIError::OK;
}
/** Read a packet into the rx_buf_.