diff --git a/esphome/components/api/api_frame_helper.cpp b/esphome/components/api/api_frame_helper.cpp index 0f2bc89e73..c18bba0bee 100644 --- a/esphome/components/api/api_frame_helper.cpp +++ b/esphome/components/api/api_frame_helper.cpp @@ -112,8 +112,13 @@ APIError APIFrameHelper::drain_overflow_and_handle_errors_() { return APIError::OK; } -// Write data to socket, overflow to backlog buffer if LWIP TCP send buffer is full. -// Slow path: handles partial writes, errors, and overflow buffering. +// Single-buffer slow path: wraps data in iovec and delegates to the iovec slow path. +APIError APIFrameHelper::write_raw_slow_(const void *data, uint16_t len, ssize_t sent) { + struct iovec iov = {const_cast(data), len}; + return this->write_raw_slow_(&iov, 1, len, sent); +} + +// Multi-buffer slow path: handles partial writes, errors, and overflow buffering. // Called when the inline fast path in the header couldn't complete the write. // sent == -1 means either the fast path write returned -1, or there was overflow backlog. APIError APIFrameHelper::write_raw_slow_(const struct iovec *iov, int iovcnt, uint16_t total_write_len, ssize_t sent) { diff --git a/esphome/components/api/api_frame_helper.h b/esphome/components/api/api_frame_helper.h index 0bf04735a2..172cb3e5fd 100644 --- a/esphome/components/api/api_frame_helper.h +++ b/esphome/components/api/api_frame_helper.h @@ -199,8 +199,7 @@ class APIFrameHelper { if (sent == static_cast(len)) [[likely]] return APIError::OK; } - struct iovec iov = {const_cast(data), len}; - return this->write_raw_slow_(&iov, 1, len, sent); + return this->write_raw_slow_(data, len, sent); } // Write multiple iovec buffers to the socket (inlined fast path) inline APIError ESPHOME_ALWAYS_INLINE write_raw_(const struct iovec *iov, int iovcnt, uint16_t total_write_len) { @@ -213,7 +212,8 @@ class APIFrameHelper { } return this->write_raw_slow_(iov, iovcnt, total_write_len, sent); } - // Slow path (out-of-line): handle partial writes, errors, overflow buffering + // Slow paths (out-of-line): handle partial writes, errors, overflow buffering + APIError write_raw_slow_(const void *data, uint16_t len, ssize_t sent); APIError write_raw_slow_(const struct iovec *iov, int iovcnt, uint16_t total_write_len, ssize_t sent); // Socket ownership (4 bytes on 32-bit, 8 bytes on 64-bit) diff --git a/esphome/components/api/api_frame_helper_noise.cpp b/esphome/components/api/api_frame_helper_noise.cpp index d13a3472c4..d7348ae669 100644 --- a/esphome/components/api/api_frame_helper_noise.cpp +++ b/esphome/components/api/api_frame_helper_noise.cpp @@ -539,13 +539,13 @@ APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, uint16_t len) { header[1] = (uint8_t) (len >> 8); header[2] = (uint8_t) len; - // Handshake-only path — use slow path directly to avoid inlining write_raw_ fast path + if (len == 0) { + return this->write_raw_slow_(header, 3, -1); + } + // Handshake path — use iovec slow path directly to avoid inlining write_raw_ fast path struct iovec iov[2]; iov[0].iov_base = header; iov[0].iov_len = 3; - if (len == 0) { - return this->write_raw_slow_(iov, 1, 3, -1); - } iov[1].iov_base = const_cast(data); iov[1].iov_len = len; diff --git a/esphome/components/api/api_frame_helper_plaintext.cpp b/esphome/components/api/api_frame_helper_plaintext.cpp index c9e178a900..9a134039e7 100644 --- a/esphome/components/api/api_frame_helper_plaintext.cpp +++ b/esphome/components/api/api_frame_helper_plaintext.cpp @@ -219,15 +219,11 @@ APIError APIPlaintextFrameHelper::read_packet(ReadPacketBuffer *buffer) { "Bad indicator byte"; char msg[INDICATOR_MSG_SIZE]; memcpy_P(msg, MSG_PROGMEM, INDICATOR_MSG_SIZE); - // Error path — use slow path directly to avoid inlining write_raw_ fast path - struct iovec iov = {msg, INDICATOR_MSG_SIZE}; - this->write_raw_slow_(&iov, 1, INDICATOR_MSG_SIZE, -1); + this->write_raw_slow_(msg, INDICATOR_MSG_SIZE, -1); #else static const char MSG[] = "\x00" "Bad indicator byte"; - // Error path — use slow path directly to avoid inlining write_raw_ fast path - struct iovec iov = {const_cast(MSG), INDICATOR_MSG_SIZE}; - this->write_raw_slow_(&iov, 1, INDICATOR_MSG_SIZE, -1); + this->write_raw_slow_(MSG, INDICATOR_MSG_SIZE, -1); #endif } return aerr;