diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 08f01c9391d..d9f1574ad3e 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -130,9 +130,8 @@ void APIConnection::start() { return; } // Initialize client name with peername (IP address) until Hello message provides actual name - char peername[socket::PEERNAME_MAX_LEN]; - size_t len = this->helper_->getpeername_to(peername); - this->helper_->set_client_name(peername, len); + const char *peername = this->helper_->get_client_peername(); + this->helper_->set_client_name(peername, strlen(peername)); } APIConnection::~APIConnection() { @@ -1505,10 +1504,8 @@ void APIConnection::complete_authentication_() { this->flags_.connection_state = static_cast(ConnectionState::AUTHENTICATED); this->log_client_(ESPHOME_LOG_LEVEL_DEBUG, LOG_STR("connected")); #ifdef USE_API_CLIENT_CONNECTED_TRIGGER - char peername_buf[socket::PEERNAME_MAX_LEN]; - this->helper_->getpeername_to(peername_buf); this->parent_->get_client_connected_trigger()->trigger(std::string(this->helper_->get_client_name()), - std::string(peername_buf)); + std::string(this->helper_->get_client_peername())); #endif #ifdef USE_HOMEASSISTANT_TIME if (homeassistant::global_homeassistant_time != nullptr) { @@ -1527,10 +1524,8 @@ bool APIConnection::send_hello_response(const HelloRequest &msg) { this->helper_->set_client_name(msg.client_info.c_str(), msg.client_info.size()); this->client_api_version_major_ = msg.api_version_major; this->client_api_version_minor_ = msg.api_version_minor; - char peername[socket::PEERNAME_MAX_LEN]; - this->helper_->getpeername_to(peername); ESP_LOGV(TAG, "Hello from client: '%s' | %s | API Version %" PRIu32 ".%" PRIu32, this->helper_->get_client_name(), - peername, this->client_api_version_major_, this->client_api_version_minor_); + this->helper_->get_client_peername(), this->client_api_version_major_, this->client_api_version_minor_); HelloResponse resp; resp.api_version_major = 1; @@ -2081,17 +2076,13 @@ void APIConnection::process_state_subscriptions_() { #endif // USE_API_HOMEASSISTANT_STATES void APIConnection::log_client_(int level, const LogString *message) { - char peername[socket::PEERNAME_MAX_LEN]; - this->helper_->getpeername_to(peername); - esp_log_printf_(level, TAG, __LINE__, ESPHOME_LOG_FORMAT("%s (%s): %s"), this->helper_->get_client_name(), peername, - LOG_STR_ARG(message)); + esp_log_printf_(level, TAG, __LINE__, ESPHOME_LOG_FORMAT("%s (%s): %s"), this->helper_->get_client_name(), + this->helper_->get_client_peername(), LOG_STR_ARG(message)); } void APIConnection::log_warning_(const LogString *message, APIError err) { - char peername[socket::PEERNAME_MAX_LEN]; - this->helper_->getpeername_to(peername); - ESP_LOGW(TAG, "%s (%s): %s %s errno=%d", this->helper_->get_client_name(), peername, LOG_STR_ARG(message), - LOG_STR_ARG(api_error_to_logstr(err)), errno); + ESP_LOGW(TAG, "%s (%s): %s %s errno=%d", this->helper_->get_client_name(), this->helper_->get_client_peername(), + LOG_STR_ARG(message), LOG_STR_ARG(api_error_to_logstr(err)), errno); } } // namespace esphome::api diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 2d137404f57..95a3eed2029 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -280,10 +280,8 @@ class APIConnection final : public APIServerConnection { bool send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) override; const char *get_name() const { return this->helper_->get_client_name(); } - /// Get peer name (IP address) into a stack buffer - avoids heap allocation - size_t get_peername_to(std::span buf) const { - return this->helper_->getpeername_to(buf); - } + /// Get peer name (IP address) - cached at connection init time + const char *get_peername() const { return this->helper_->get_client_peername(); } protected: // Helper function to handle authentication completion diff --git a/esphome/components/api/api_frame_helper.cpp b/esphome/components/api/api_frame_helper.cpp index 373d27260a2..dd44fe9e175 100644 --- a/esphome/components/api/api_frame_helper.cpp +++ b/esphome/components/api/api_frame_helper.cpp @@ -16,12 +16,7 @@ static const char *const TAG = "api.frame_helper"; static constexpr size_t API_MAX_LOG_BYTES = 168; #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE -#define HELPER_LOG(msg, ...) \ - do { \ - char peername__[socket::PEERNAME_MAX_LEN]; \ - this->socket_->getpeername_to(peername__); \ - ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, peername__, ##__VA_ARGS__); \ - } while (0) +#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, this->client_peername_, ##__VA_ARGS__) #else #define HELPER_LOG(msg, ...) ((void) 0) #endif @@ -250,6 +245,8 @@ APIError APIFrameHelper::init_common_() { HELPER_LOG("Bad state for init %d", (int) state_); return APIError::BAD_STATE; } + // Cache peername now while socket is valid - needed for error logging after socket failure + this->socket_->getpeername_to(this->client_peername_); int err = this->socket_->setblocking(false); if (err != 0) { state_ = State::FAILED; diff --git a/esphome/components/api/api_frame_helper.h b/esphome/components/api/api_frame_helper.h index 37e972e205e..2364aca4eda 100644 --- a/esphome/components/api/api_frame_helper.h +++ b/esphome/components/api/api_frame_helper.h @@ -86,6 +86,8 @@ class APIFrameHelper { // Get client name (null-terminated) const char *get_client_name() const { return this->client_name_; } + // Get client peername/IP (null-terminated, cached at init time for availability after socket failure) + const char *get_client_peername() const { return this->client_peername_; } // Set client name from buffer with length (truncates if needed) void set_client_name(const char *name, size_t len) { size_t copy_len = std::min(len, sizeof(this->client_name_) - 1); @@ -98,7 +100,6 @@ class APIFrameHelper { virtual APIError read_packet(ReadPacketBuffer *buffer) = 0; bool can_write_without_blocking() { return this->state_ == State::DATA && this->tx_buf_count_ == 0; } int getpeername(struct sockaddr *addr, socklen_t *addrlen) { return socket_->getpeername(addr, addrlen); } - size_t getpeername_to(std::span buf) { return socket_->getpeername_to(buf); } APIError close() { state_ = State::CLOSED; int err = this->socket_->close(); @@ -199,6 +200,8 @@ class APIFrameHelper { // Client name buffer - stores name from Hello message or initial peername char client_name_[CLIENT_INFO_NAME_MAX_LEN]{}; + // Cached peername/IP address - captured at init time for availability after socket failure + char client_peername_[socket::PEERNAME_MAX_LEN]{}; // Group smaller types together uint16_t rx_buf_len_ = 0; diff --git a/esphome/components/api/api_frame_helper_noise.cpp b/esphome/components/api/api_frame_helper_noise.cpp index 11a399feab7..186f0428c74 100644 --- a/esphome/components/api/api_frame_helper_noise.cpp +++ b/esphome/components/api/api_frame_helper_noise.cpp @@ -28,12 +28,7 @@ static constexpr size_t PROLOGUE_INIT_LEN = 12; // strlen("NoiseAPIInit") static constexpr size_t API_MAX_LOG_BYTES = 168; #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE -#define HELPER_LOG(msg, ...) \ - do { \ - char peername__[socket::PEERNAME_MAX_LEN]; \ - this->socket_->getpeername_to(peername__); \ - ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, peername__, ##__VA_ARGS__); \ - } while (0) +#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, this->client_peername_, ##__VA_ARGS__) #else #define HELPER_LOG(msg, ...) ((void) 0) #endif diff --git a/esphome/components/api/api_frame_helper_plaintext.cpp b/esphome/components/api/api_frame_helper_plaintext.cpp index 8629ca71e4c..5d1fac54c81 100644 --- a/esphome/components/api/api_frame_helper_plaintext.cpp +++ b/esphome/components/api/api_frame_helper_plaintext.cpp @@ -21,12 +21,7 @@ static const char *const TAG = "api.plaintext"; static constexpr size_t API_MAX_LOG_BYTES = 168; #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE -#define HELPER_LOG(msg, ...) \ - do { \ - char peername__[socket::PEERNAME_MAX_LEN]; \ - this->socket_->getpeername_to(peername__); \ - ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, peername__, ##__VA_ARGS__); \ - } while (0) +#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, this->client_peername_, ##__VA_ARGS__) #else #define HELPER_LOG(msg, ...) ((void) 0) #endif diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index ade9bcae238..71bccc13371 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -187,9 +187,7 @@ void APIServer::loop() { // Rare case: handle disconnection #ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER - char peername_buf[socket::PEERNAME_MAX_LEN]; - client->get_peername_to(peername_buf); - this->client_disconnected_trigger_->trigger(std::string(client->get_name()), std::string(peername_buf)); + this->client_disconnected_trigger_->trigger(std::string(client->get_name()), std::string(client->get_peername())); #endif #ifdef USE_API_USER_DEFINED_ACTION_RESPONSES this->unregister_active_action_calls_for_connection(client.get()); diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index e91e1b11cbd..6063647accf 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -431,11 +431,8 @@ void VoiceAssistant::client_subscription(api::APIConnection *client, bool subscr if (this->api_client_ != nullptr) { ESP_LOGE(TAG, "Multiple API Clients attempting to connect to Voice Assistant"); - char peername[socket::PEERNAME_MAX_LEN]; - this->api_client_->get_peername_to(peername); - ESP_LOGE(TAG, "Current client: %s (%s)", this->api_client_->get_name(), peername); - client->get_peername_to(peername); - ESP_LOGE(TAG, "New client: %s (%s)", client->get_name(), peername); + ESP_LOGE(TAG, "Current client: %s (%s)", this->api_client_->get_name(), this->api_client_->get_peername()); + ESP_LOGE(TAG, "New client: %s (%s)", client->get_name(), client->get_peername()); return; }