diff --git a/esphome/components/api/api_frame_helper.cpp b/esphome/components/api/api_frame_helper.cpp index fe499c38259..de9d0e703d8 100644 --- a/esphome/components/api/api_frame_helper.cpp +++ b/esphome/components/api/api_frame_helper.cpp @@ -100,17 +100,6 @@ const LogString *api_error_to_logstr(APIError err) { return LOG_STR("UNKNOWN"); } -// Default implementation for loop - handles draining overflow buffer -APIError APIFrameHelper::loop() { - if (!this->overflow_buf_.empty() && 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; - } - // Convert WOULD_BLOCK to OK to avoid connection termination - return APIError::OK; -} - // This method writes data to socket or buffers it APIError APIFrameHelper::write_raw_(const struct iovec *iov, int iovcnt, uint16_t total_write_len) { // Returns APIError::OK if all data was sent or successfully queued. diff --git a/esphome/components/api/api_frame_helper.h b/esphome/components/api/api_frame_helper.h index 133f18c1043..5709a77854c 100644 --- a/esphome/components/api/api_frame_helper.h +++ b/esphome/components/api/api_frame_helper.h @@ -105,7 +105,7 @@ class APIFrameHelper { } virtual ~APIFrameHelper() = default; virtual APIError init() = 0; - virtual APIError loop(); + 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(); } int getpeername(struct sockaddr *addr, socklen_t *addrlen) { return socket_->getpeername(addr, addrlen); } @@ -190,6 +190,16 @@ 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; + } + // Common implementation for writing raw data to socket APIError write_raw_(const struct iovec *iov, int iovcnt, uint16_t total_write_len); diff --git a/esphome/components/api/api_frame_helper_noise.cpp b/esphome/components/api/api_frame_helper_noise.cpp index b635d84f168..8e5300abd7e 100644 --- a/esphome/components/api/api_frame_helper_noise.cpp +++ b/esphome/components/api/api_frame_helper_noise.cpp @@ -153,8 +153,7 @@ APIError APINoiseFrameHelper::loop() { } } - // Use base class implementation for buffer sending - return APIFrameHelper::loop(); + return this->try_drain_overflow_buffer_(); } /** Read a packet into the rx_buf_. diff --git a/esphome/components/api/api_frame_helper_plaintext.cpp b/esphome/components/api/api_frame_helper_plaintext.cpp index e97b558fa39..99b880c88c6 100644 --- a/esphome/components/api/api_frame_helper_plaintext.cpp +++ b/esphome/components/api/api_frame_helper_plaintext.cpp @@ -64,8 +64,7 @@ APIError APIPlaintextFrameHelper::loop() { if (state_ != State::DATA) { return APIError::BAD_STATE; } - // Use base class implementation for buffer sending - return APIFrameHelper::loop(); + return this->try_drain_overflow_buffer_(); } /** Read a packet into the rx_buf_.