mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Implement zero-copy for strings in base API calls (#10851)
This commit is contained in:
		| @@ -102,7 +102,7 @@ message HelloRequest { | ||||
|   // For example "Home Assistant" | ||||
|   // Not strictly necessary to send but nice for debugging | ||||
|   // purposes. | ||||
|   string client_info = 1; | ||||
|   string client_info = 1 [(pointer_to_buffer) = true]; | ||||
|   uint32 api_version_major = 2; | ||||
|   uint32 api_version_minor = 3; | ||||
| } | ||||
| @@ -139,7 +139,7 @@ message AuthenticationRequest { | ||||
|   option (ifdef) = "USE_API_PASSWORD"; | ||||
|  | ||||
|   // The password to log in with | ||||
|   string password = 1; | ||||
|   string password = 1 [(pointer_to_buffer) = true]; | ||||
| } | ||||
|  | ||||
| // Confirmation of successful connection. After this the connection is available for all traffic. | ||||
| @@ -824,7 +824,7 @@ message GetTimeResponse { | ||||
|   option (no_delay) = true; | ||||
|  | ||||
|   fixed32 epoch_seconds = 1; | ||||
|   string timezone = 2; | ||||
|   string timezone = 2 [(pointer_to_buffer) = true]; | ||||
| } | ||||
|  | ||||
| // ==================== USER-DEFINES SERVICES ==================== | ||||
|   | ||||
| @@ -1078,8 +1078,14 @@ void APIConnection::on_get_time_response(const GetTimeResponse &value) { | ||||
|   if (homeassistant::global_homeassistant_time != nullptr) { | ||||
|     homeassistant::global_homeassistant_time->set_epoch_time(value.epoch_seconds); | ||||
| #ifdef USE_TIME_TIMEZONE | ||||
|     if (!value.timezone.empty() && value.timezone != homeassistant::global_homeassistant_time->get_timezone()) { | ||||
|       homeassistant::global_homeassistant_time->set_timezone(value.timezone); | ||||
|     if (value.timezone_len > 0) { | ||||
|       const std::string ¤t_tz = homeassistant::global_homeassistant_time->get_timezone(); | ||||
|       // Compare without allocating a string | ||||
|       if (current_tz.length() != value.timezone_len || | ||||
|           memcmp(current_tz.c_str(), value.timezone, value.timezone_len) != 0) { | ||||
|         homeassistant::global_homeassistant_time->set_timezone( | ||||
|             std::string(reinterpret_cast<const char *>(value.timezone), value.timezone_len)); | ||||
|       } | ||||
|     } | ||||
| #endif | ||||
|   } | ||||
| @@ -1374,7 +1380,7 @@ void APIConnection::complete_authentication_() { | ||||
| } | ||||
|  | ||||
| bool APIConnection::send_hello_response(const HelloRequest &msg) { | ||||
|   this->client_info_.name = msg.client_info; | ||||
|   this->client_info_.name.assign(reinterpret_cast<const char *>(msg.client_info), msg.client_info_len); | ||||
|   this->client_info_.peername = this->helper_->getpeername(); | ||||
|   this->client_api_version_major_ = msg.api_version_major; | ||||
|   this->client_api_version_minor_ = msg.api_version_minor; | ||||
| @@ -1402,7 +1408,7 @@ bool APIConnection::send_hello_response(const HelloRequest &msg) { | ||||
| bool APIConnection::send_authenticate_response(const AuthenticationRequest &msg) { | ||||
|   AuthenticationResponse resp; | ||||
|   // bool invalid_password = 1; | ||||
|   resp.invalid_password = !this->parent_->check_password(msg.password); | ||||
|   resp.invalid_password = !this->parent_->check_password(msg.password, msg.password_len); | ||||
|   if (!resp.invalid_password) { | ||||
|     this->complete_authentication_(); | ||||
|   } | ||||
|   | ||||
| @@ -22,9 +22,12 @@ bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { | ||||
| } | ||||
| bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { | ||||
|   switch (field_id) { | ||||
|     case 1: | ||||
|       this->client_info = value.as_string(); | ||||
|     case 1: { | ||||
|       // Use raw data directly to avoid allocation | ||||
|       this->client_info = value.data(); | ||||
|       this->client_info_len = value.size(); | ||||
|       break; | ||||
|     } | ||||
|     default: | ||||
|       return false; | ||||
|   } | ||||
| @@ -45,9 +48,12 @@ void HelloResponse::calculate_size(ProtoSize &size) const { | ||||
| #ifdef USE_API_PASSWORD | ||||
| bool AuthenticationRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { | ||||
|   switch (field_id) { | ||||
|     case 1: | ||||
|       this->password = value.as_string(); | ||||
|     case 1: { | ||||
|       // Use raw data directly to avoid allocation | ||||
|       this->password = value.data(); | ||||
|       this->password_len = value.size(); | ||||
|       break; | ||||
|     } | ||||
|     default: | ||||
|       return false; | ||||
|   } | ||||
| @@ -917,9 +923,12 @@ bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDel | ||||
| #endif | ||||
| bool GetTimeResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { | ||||
|   switch (field_id) { | ||||
|     case 2: | ||||
|       this->timezone = value.as_string(); | ||||
|     case 2: { | ||||
|       // Use raw data directly to avoid allocation | ||||
|       this->timezone = value.data(); | ||||
|       this->timezone_len = value.size(); | ||||
|       break; | ||||
|     } | ||||
|     default: | ||||
|       return false; | ||||
|   } | ||||
|   | ||||
| @@ -330,11 +330,12 @@ class CommandProtoMessage : public ProtoDecodableMessage { | ||||
| class HelloRequest final : public ProtoDecodableMessage { | ||||
|  public: | ||||
|   static constexpr uint8_t MESSAGE_TYPE = 1; | ||||
|   static constexpr uint8_t ESTIMATED_SIZE = 17; | ||||
|   static constexpr uint8_t ESTIMATED_SIZE = 27; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   const char *message_name() const override { return "hello_request"; } | ||||
| #endif | ||||
|   std::string client_info{}; | ||||
|   const uint8_t *client_info{nullptr}; | ||||
|   uint16_t client_info_len{0}; | ||||
|   uint32_t api_version_major{0}; | ||||
|   uint32_t api_version_minor{0}; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
| @@ -370,11 +371,12 @@ class HelloResponse final : public ProtoMessage { | ||||
| class AuthenticationRequest final : public ProtoDecodableMessage { | ||||
|  public: | ||||
|   static constexpr uint8_t MESSAGE_TYPE = 3; | ||||
|   static constexpr uint8_t ESTIMATED_SIZE = 9; | ||||
|   static constexpr uint8_t ESTIMATED_SIZE = 19; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   const char *message_name() const override { return "authentication_request"; } | ||||
| #endif | ||||
|   std::string password{}; | ||||
|   const uint8_t *password{nullptr}; | ||||
|   uint16_t password_len{0}; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
| @@ -1188,12 +1190,13 @@ class GetTimeRequest final : public ProtoMessage { | ||||
| class GetTimeResponse final : public ProtoDecodableMessage { | ||||
|  public: | ||||
|   static constexpr uint8_t MESSAGE_TYPE = 37; | ||||
|   static constexpr uint8_t ESTIMATED_SIZE = 14; | ||||
|   static constexpr uint8_t ESTIMATED_SIZE = 24; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   const char *message_name() const override { return "get_time_response"; } | ||||
| #endif | ||||
|   uint32_t epoch_seconds{0}; | ||||
|   std::string timezone{}; | ||||
|   const uint8_t *timezone{nullptr}; | ||||
|   uint16_t timezone_len{0}; | ||||
| #ifdef HAS_PROTO_MESSAGE_DUMP | ||||
|   void dump_to(std::string &out) const override; | ||||
| #endif | ||||
|   | ||||
| @@ -670,7 +670,9 @@ template<> const char *proto_enum_to_string<enums::ZWaveProxyRequestType>(enums: | ||||
|  | ||||
| void HelloRequest::dump_to(std::string &out) const { | ||||
|   MessageDumpHelper helper(out, "HelloRequest"); | ||||
|   dump_field(out, "client_info", this->client_info); | ||||
|   out.append("  client_info: "); | ||||
|   out.append(format_hex_pretty(this->client_info, this->client_info_len)); | ||||
|   out.append("\n"); | ||||
|   dump_field(out, "api_version_major", this->api_version_major); | ||||
|   dump_field(out, "api_version_minor", this->api_version_minor); | ||||
| } | ||||
| @@ -682,7 +684,12 @@ void HelloResponse::dump_to(std::string &out) const { | ||||
|   dump_field(out, "name", this->name_ref_); | ||||
| } | ||||
| #ifdef USE_API_PASSWORD | ||||
| void AuthenticationRequest::dump_to(std::string &out) const { dump_field(out, "password", this->password); } | ||||
| void AuthenticationRequest::dump_to(std::string &out) const { | ||||
|   MessageDumpHelper helper(out, "AuthenticationRequest"); | ||||
|   out.append("  password: "); | ||||
|   out.append(format_hex_pretty(this->password, this->password_len)); | ||||
|   out.append("\n"); | ||||
| } | ||||
| void AuthenticationResponse::dump_to(std::string &out) const { | ||||
|   MessageDumpHelper helper(out, "AuthenticationResponse"); | ||||
|   dump_field(out, "invalid_password", this->invalid_password); | ||||
| @@ -1136,7 +1143,9 @@ void GetTimeRequest::dump_to(std::string &out) const { out.append("GetTimeReques | ||||
| void GetTimeResponse::dump_to(std::string &out) const { | ||||
|   MessageDumpHelper helper(out, "GetTimeResponse"); | ||||
|   dump_field(out, "epoch_seconds", this->epoch_seconds); | ||||
|   dump_field(out, "timezone", this->timezone); | ||||
|   out.append("  timezone: "); | ||||
|   out.append(format_hex_pretty(this->timezone, this->timezone_len)); | ||||
|   out.append("\n"); | ||||
| } | ||||
| #ifdef USE_API_SERVICES | ||||
| void ListEntitiesServicesArgument::dump_to(std::string &out) const { | ||||
|   | ||||
| @@ -217,12 +217,12 @@ void APIServer::dump_config() { | ||||
| } | ||||
|  | ||||
| #ifdef USE_API_PASSWORD | ||||
| bool APIServer::check_password(const std::string &password) const { | ||||
| bool APIServer::check_password(const uint8_t *password_data, size_t password_len) const { | ||||
|   // depend only on input password length | ||||
|   const char *a = this->password_.c_str(); | ||||
|   uint32_t len_a = this->password_.length(); | ||||
|   const char *b = password.c_str(); | ||||
|   uint32_t len_b = password.length(); | ||||
|   const char *b = reinterpret_cast<const char *>(password_data); | ||||
|   uint32_t len_b = password_len; | ||||
|  | ||||
|   // disable optimization with volatile | ||||
|   volatile uint32_t length = len_b; | ||||
| @@ -245,6 +245,7 @@ bool APIServer::check_password(const std::string &password) const { | ||||
|  | ||||
|   return result == 0; | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| void APIServer::handle_disconnect(APIConnection *conn) {} | ||||
|   | ||||
| @@ -37,7 +37,7 @@ class APIServer : public Component, public Controller { | ||||
|   void on_shutdown() override; | ||||
|   bool teardown() override; | ||||
| #ifdef USE_API_PASSWORD | ||||
|   bool check_password(const std::string &password) const; | ||||
|   bool check_password(const uint8_t *password_data, size_t password_len) const; | ||||
|   void set_password(const std::string &password); | ||||
| #endif | ||||
|   void set_port(uint16_t port); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user