From 4a39f14037acabc685cd15ca8babf2d72cf06822 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 21 Jul 2025 11:20:49 -1000 Subject: [PATCH] [api] Optimize noise handshake with memcpy for faster connection setup --- .../components/api/api_frame_helper_noise.cpp | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/esphome/components/api/api_frame_helper_noise.cpp b/esphome/components/api/api_frame_helper_noise.cpp index 3c2c9e059e..f2e3cba779 100644 --- a/esphome/components/api/api_frame_helper_noise.cpp +++ b/esphome/components/api/api_frame_helper_noise.cpp @@ -73,7 +73,10 @@ APIError APINoiseFrameHelper::init() { } // init prologue - prologue_.insert(prologue_.end(), PROLOGUE_INIT, PROLOGUE_INIT + strlen(PROLOGUE_INIT)); + size_t old_size = prologue_.size(); + size_t init_len = strlen(PROLOGUE_INIT); + prologue_.resize(old_size + init_len); + std::memcpy(prologue_.data() + old_size, PROLOGUE_INIT, init_len); state_ = State::CLIENT_HELLO; return APIError::OK; @@ -223,11 +226,12 @@ APIError APINoiseFrameHelper::state_action_() { return handle_handshake_frame_error_(aerr); } // ignore contents, may be used in future for flags - // Reserve space for: existing prologue + 2 size bytes + frame data - prologue_.reserve(prologue_.size() + 2 + frame.size()); - prologue_.push_back((uint8_t) (frame.size() >> 8)); - prologue_.push_back((uint8_t) frame.size()); - prologue_.insert(prologue_.end(), frame.begin(), frame.end()); + // Resize for: existing prologue + 2 size bytes + frame data + size_t old_size = prologue_.size(); + prologue_.resize(old_size + 2 + frame.size()); + prologue_[old_size] = (uint8_t) (frame.size() >> 8); + prologue_[old_size + 1] = (uint8_t) frame.size(); + std::memcpy(prologue_.data() + old_size + 2, frame.data(), frame.size()); state_ = State::SERVER_HELLO; } @@ -237,18 +241,22 @@ APIError APINoiseFrameHelper::state_action_() { const std::string &mac = get_mac_address(); std::vector msg; - // Reserve space for: 1 byte proto + name + null + mac + null - msg.reserve(1 + name.size() + 1 + mac.size() + 1); + // Calculate positions and sizes + size_t name_len = name.size() + 1; // including null terminator + size_t mac_len = mac.size() + 1; // including null terminator + size_t name_offset = 1; + size_t mac_offset = name_offset + name_len; + size_t total_size = 1 + name_len + mac_len; + + msg.resize(total_size); // chosen proto - msg.push_back(0x01); + msg[0] = 0x01; // node name, terminated by null byte - const uint8_t *name_ptr = reinterpret_cast(name.c_str()); - msg.insert(msg.end(), name_ptr, name_ptr + name.size() + 1); + std::memcpy(msg.data() + name_offset, name.c_str(), name_len); // node mac, terminated by null byte - const uint8_t *mac_ptr = reinterpret_cast(mac.c_str()); - msg.insert(msg.end(), mac_ptr, mac_ptr + mac.size() + 1); + std::memcpy(msg.data() + mac_offset, mac.c_str(), mac_len); aerr = write_frame_(msg.data(), msg.size()); if (aerr != APIError::OK)