mirror of
https://github.com/esphome/esphome.git
synced 2025-07-27 13:46:48 +00:00
Optimize API component memory usage by reordering class members to reduce padding (#9111)
This commit is contained in:
parent
43c677ef37
commit
eeb0710ad4
@ -61,8 +61,8 @@ void APIConnection::start() {
|
|||||||
APIError err = this->helper_->init();
|
APIError err = this->helper_->init();
|
||||||
if (err != APIError::OK) {
|
if (err != APIError::OK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
ESP_LOGW(TAG, "%s: Helper init failed: %s errno=%d", this->client_combined_info_.c_str(), api_error_to_str(err),
|
ESP_LOGW(TAG, "%s: Helper init failed: %s errno=%d", this->get_client_combined_info().c_str(),
|
||||||
errno);
|
api_error_to_str(err), errno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->client_info_ = helper_->getpeername();
|
this->client_info_ = helper_->getpeername();
|
||||||
@ -91,7 +91,7 @@ void APIConnection::loop() {
|
|||||||
// when network is disconnected force disconnect immediately
|
// when network is disconnected force disconnect immediately
|
||||||
// don't wait for timeout
|
// don't wait for timeout
|
||||||
this->on_fatal_error();
|
this->on_fatal_error();
|
||||||
ESP_LOGW(TAG, "%s: Network unavailable; disconnecting", this->client_combined_info_.c_str());
|
ESP_LOGW(TAG, "%s: Network unavailable; disconnecting", this->get_client_combined_info().c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this->next_close_) {
|
if (this->next_close_) {
|
||||||
@ -104,7 +104,7 @@ void APIConnection::loop() {
|
|||||||
APIError err = this->helper_->loop();
|
APIError err = this->helper_->loop();
|
||||||
if (err != APIError::OK) {
|
if (err != APIError::OK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", this->client_combined_info_.c_str(),
|
ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", this->get_client_combined_info().c_str(),
|
||||||
api_error_to_str(err), errno);
|
api_error_to_str(err), errno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -118,12 +118,12 @@ void APIConnection::loop() {
|
|||||||
} else if (err != APIError::OK) {
|
} else if (err != APIError::OK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
if (err == APIError::SOCKET_READ_FAILED && errno == ECONNRESET) {
|
if (err == APIError::SOCKET_READ_FAILED && errno == ECONNRESET) {
|
||||||
ESP_LOGW(TAG, "%s: Connection reset", this->client_combined_info_.c_str());
|
ESP_LOGW(TAG, "%s: Connection reset", this->get_client_combined_info().c_str());
|
||||||
} else if (err == APIError::CONNECTION_CLOSED) {
|
} else if (err == APIError::CONNECTION_CLOSED) {
|
||||||
ESP_LOGW(TAG, "%s: Connection closed", this->client_combined_info_.c_str());
|
ESP_LOGW(TAG, "%s: Connection closed", this->get_client_combined_info().c_str());
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGW(TAG, "%s: Reading failed: %s errno=%d", this->client_combined_info_.c_str(), api_error_to_str(err),
|
ESP_LOGW(TAG, "%s: Reading failed: %s errno=%d", this->get_client_combined_info().c_str(),
|
||||||
errno);
|
api_error_to_str(err), errno);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -157,7 +157,7 @@ void APIConnection::loop() {
|
|||||||
// Disconnect if not responded within 2.5*keepalive
|
// Disconnect if not responded within 2.5*keepalive
|
||||||
if (now - this->last_traffic_ > (KEEPALIVE_TIMEOUT_MS * 5) / 2) {
|
if (now - this->last_traffic_ > (KEEPALIVE_TIMEOUT_MS * 5) / 2) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
ESP_LOGW(TAG, "%s is unresponsive; disconnecting", this->client_combined_info_.c_str());
|
ESP_LOGW(TAG, "%s is unresponsive; disconnecting", this->get_client_combined_info().c_str());
|
||||||
}
|
}
|
||||||
} else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && now > this->next_ping_retry_) {
|
} else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && now > this->next_ping_retry_) {
|
||||||
ESP_LOGVV(TAG, "Sending keepalive PING");
|
ESP_LOGVV(TAG, "Sending keepalive PING");
|
||||||
@ -166,7 +166,7 @@ void APIConnection::loop() {
|
|||||||
this->next_ping_retry_ = now + ping_retry_interval;
|
this->next_ping_retry_ = now + ping_retry_interval;
|
||||||
this->ping_retries_++;
|
this->ping_retries_++;
|
||||||
std::string warn_str = str_sprintf("%s: Sending keepalive failed %u time(s);",
|
std::string warn_str = str_sprintf("%s: Sending keepalive failed %u time(s);",
|
||||||
this->client_combined_info_.c_str(), this->ping_retries_);
|
this->get_client_combined_info().c_str(), this->ping_retries_);
|
||||||
if (this->ping_retries_ >= max_ping_retries) {
|
if (this->ping_retries_ >= max_ping_retries) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
ESP_LOGE(TAG, "%s disconnecting", warn_str.c_str());
|
ESP_LOGE(TAG, "%s disconnecting", warn_str.c_str());
|
||||||
@ -233,7 +233,7 @@ DisconnectResponse APIConnection::disconnect(const DisconnectRequest &msg) {
|
|||||||
// remote initiated disconnect_client
|
// remote initiated disconnect_client
|
||||||
// don't close yet, we still need to send the disconnect response
|
// don't close yet, we still need to send the disconnect response
|
||||||
// close will happen on next loop
|
// close will happen on next loop
|
||||||
ESP_LOGD(TAG, "%s disconnected", this->client_combined_info_.c_str());
|
ESP_LOGD(TAG, "%s disconnected", this->get_client_combined_info().c_str());
|
||||||
this->next_close_ = true;
|
this->next_close_ = true;
|
||||||
DisconnectResponse resp;
|
DisconnectResponse resp;
|
||||||
return resp;
|
return resp;
|
||||||
@ -1544,8 +1544,7 @@ bool APIConnection::try_send_log_message(int level, const char *tag, const char
|
|||||||
HelloResponse APIConnection::hello(const HelloRequest &msg) {
|
HelloResponse APIConnection::hello(const HelloRequest &msg) {
|
||||||
this->client_info_ = msg.client_info;
|
this->client_info_ = msg.client_info;
|
||||||
this->client_peername_ = this->helper_->getpeername();
|
this->client_peername_ = this->helper_->getpeername();
|
||||||
this->client_combined_info_ = this->client_info_ + " (" + this->client_peername_ + ")";
|
this->helper_->set_log_info(this->get_client_combined_info());
|
||||||
this->helper_->set_log_info(this->client_combined_info_);
|
|
||||||
this->client_api_version_major_ = msg.api_version_major;
|
this->client_api_version_major_ = msg.api_version_major;
|
||||||
this->client_api_version_minor_ = msg.api_version_minor;
|
this->client_api_version_minor_ = msg.api_version_minor;
|
||||||
ESP_LOGV(TAG, "Hello from client: '%s' | %s | API Version %" PRIu32 ".%" PRIu32, this->client_info_.c_str(),
|
ESP_LOGV(TAG, "Hello from client: '%s' | %s | API Version %" PRIu32 ".%" PRIu32, this->client_info_.c_str(),
|
||||||
@ -1567,7 +1566,7 @@ ConnectResponse APIConnection::connect(const ConnectRequest &msg) {
|
|||||||
// bool invalid_password = 1;
|
// bool invalid_password = 1;
|
||||||
resp.invalid_password = !correct;
|
resp.invalid_password = !correct;
|
||||||
if (correct) {
|
if (correct) {
|
||||||
ESP_LOGD(TAG, "%s connected", this->client_combined_info_.c_str());
|
ESP_LOGD(TAG, "%s connected", this->get_client_combined_info().c_str());
|
||||||
this->connection_state_ = ConnectionState::AUTHENTICATED;
|
this->connection_state_ = ConnectionState::AUTHENTICATED;
|
||||||
this->parent_->get_client_connected_trigger()->trigger(this->client_info_, this->client_peername_);
|
this->parent_->get_client_connected_trigger()->trigger(this->client_info_, this->client_peername_);
|
||||||
#ifdef USE_HOMEASSISTANT_TIME
|
#ifdef USE_HOMEASSISTANT_TIME
|
||||||
@ -1673,7 +1672,7 @@ bool APIConnection::try_to_clear_buffer(bool log_out_of_space) {
|
|||||||
APIError err = this->helper_->loop();
|
APIError err = this->helper_->loop();
|
||||||
if (err != APIError::OK) {
|
if (err != APIError::OK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", this->client_combined_info_.c_str(),
|
ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", this->get_client_combined_info().c_str(),
|
||||||
api_error_to_str(err), errno);
|
api_error_to_str(err), errno);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1695,10 +1694,10 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint16_t message_type)
|
|||||||
if (err != APIError::OK) {
|
if (err != APIError::OK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
if (err == APIError::SOCKET_WRITE_FAILED && errno == ECONNRESET) {
|
if (err == APIError::SOCKET_WRITE_FAILED && errno == ECONNRESET) {
|
||||||
ESP_LOGW(TAG, "%s: Connection reset", this->client_combined_info_.c_str());
|
ESP_LOGW(TAG, "%s: Connection reset", this->get_client_combined_info().c_str());
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGW(TAG, "%s: Packet write failed %s errno=%d", this->client_combined_info_.c_str(), api_error_to_str(err),
|
ESP_LOGW(TAG, "%s: Packet write failed %s errno=%d", this->get_client_combined_info().c_str(),
|
||||||
errno);
|
api_error_to_str(err), errno);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1707,11 +1706,11 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint16_t message_type)
|
|||||||
}
|
}
|
||||||
void APIConnection::on_unauthenticated_access() {
|
void APIConnection::on_unauthenticated_access() {
|
||||||
this->on_fatal_error();
|
this->on_fatal_error();
|
||||||
ESP_LOGD(TAG, "%s requested access without authentication", this->client_combined_info_.c_str());
|
ESP_LOGD(TAG, "%s requested access without authentication", this->get_client_combined_info().c_str());
|
||||||
}
|
}
|
||||||
void APIConnection::on_no_setup_connection() {
|
void APIConnection::on_no_setup_connection() {
|
||||||
this->on_fatal_error();
|
this->on_fatal_error();
|
||||||
ESP_LOGD(TAG, "%s requested access without full connection", this->client_combined_info_.c_str());
|
ESP_LOGD(TAG, "%s requested access without full connection", this->get_client_combined_info().c_str());
|
||||||
}
|
}
|
||||||
void APIConnection::on_fatal_error() {
|
void APIConnection::on_fatal_error() {
|
||||||
this->helper_->close();
|
this->helper_->close();
|
||||||
@ -1860,10 +1859,10 @@ void APIConnection::process_batch_() {
|
|||||||
if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
|
if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
|
||||||
on_fatal_error();
|
on_fatal_error();
|
||||||
if (err == APIError::SOCKET_WRITE_FAILED && errno == ECONNRESET) {
|
if (err == APIError::SOCKET_WRITE_FAILED && errno == ECONNRESET) {
|
||||||
ESP_LOGW(TAG, "%s: Connection reset during batch write", this->client_combined_info_.c_str());
|
ESP_LOGW(TAG, "%s: Connection reset during batch write", this->get_client_combined_info().c_str());
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGW(TAG, "%s: Batch write failed %s errno=%d", this->client_combined_info_.c_str(), api_error_to_str(err),
|
ESP_LOGW(TAG, "%s: Batch write failed %s errno=%d", this->get_client_combined_info().c_str(),
|
||||||
errno);
|
api_error_to_str(err), errno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,7 +275,13 @@ class APIConnection : public APIServerConnection {
|
|||||||
bool try_to_clear_buffer(bool log_out_of_space);
|
bool try_to_clear_buffer(bool log_out_of_space);
|
||||||
bool send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) override;
|
bool send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) override;
|
||||||
|
|
||||||
std::string get_client_combined_info() const { return this->client_combined_info_; }
|
std::string get_client_combined_info() const {
|
||||||
|
if (this->client_info_ == this->client_peername_) {
|
||||||
|
// Before Hello message, both are the same (just IP:port)
|
||||||
|
return this->client_info_;
|
||||||
|
}
|
||||||
|
return this->client_info_ + " (" + this->client_peername_ + ")";
|
||||||
|
}
|
||||||
|
|
||||||
// Buffer allocator methods for batch processing
|
// Buffer allocator methods for batch processing
|
||||||
ProtoWriteBuffer allocate_single_message_buffer(uint16_t size);
|
ProtoWriteBuffer allocate_single_message_buffer(uint16_t size);
|
||||||
@ -432,37 +438,44 @@ class APIConnection : public APIServerConnection {
|
|||||||
// Helper function to get estimated message size for buffer pre-allocation
|
// Helper function to get estimated message size for buffer pre-allocation
|
||||||
static uint16_t get_estimated_message_size(uint16_t message_type);
|
static uint16_t get_estimated_message_size(uint16_t message_type);
|
||||||
|
|
||||||
enum class ConnectionState {
|
// Pointers first (4 bytes each, naturally aligned)
|
||||||
|
std::unique_ptr<APIFrameHelper> helper_;
|
||||||
|
APIServer *parent_;
|
||||||
|
|
||||||
|
// 4-byte aligned types
|
||||||
|
uint32_t last_traffic_;
|
||||||
|
uint32_t next_ping_retry_{0};
|
||||||
|
int state_subs_at_ = -1;
|
||||||
|
|
||||||
|
// Strings (12 bytes each on 32-bit)
|
||||||
|
std::string client_info_;
|
||||||
|
std::string client_peername_;
|
||||||
|
|
||||||
|
// 2-byte aligned types
|
||||||
|
uint16_t client_api_version_major_{0};
|
||||||
|
uint16_t client_api_version_minor_{0};
|
||||||
|
|
||||||
|
// Group all 1-byte types together to minimize padding
|
||||||
|
enum class ConnectionState : uint8_t {
|
||||||
WAITING_FOR_HELLO,
|
WAITING_FOR_HELLO,
|
||||||
CONNECTED,
|
CONNECTED,
|
||||||
AUTHENTICATED,
|
AUTHENTICATED,
|
||||||
} connection_state_{ConnectionState::WAITING_FOR_HELLO};
|
} connection_state_{ConnectionState::WAITING_FOR_HELLO};
|
||||||
|
uint8_t log_subscription_{ESPHOME_LOG_LEVEL_NONE};
|
||||||
bool remove_{false};
|
bool remove_{false};
|
||||||
|
|
||||||
std::unique_ptr<APIFrameHelper> helper_;
|
|
||||||
|
|
||||||
std::string client_info_;
|
|
||||||
std::string client_peername_;
|
|
||||||
std::string client_combined_info_;
|
|
||||||
uint32_t client_api_version_major_{0};
|
|
||||||
uint32_t client_api_version_minor_{0};
|
|
||||||
#ifdef USE_ESP32_CAMERA
|
|
||||||
esp32_camera::CameraImageReader image_reader_;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool state_subscription_{false};
|
bool state_subscription_{false};
|
||||||
int log_subscription_{ESPHOME_LOG_LEVEL_NONE};
|
|
||||||
uint32_t last_traffic_;
|
|
||||||
uint32_t next_ping_retry_{0};
|
|
||||||
uint8_t ping_retries_{0};
|
|
||||||
bool sent_ping_{false};
|
bool sent_ping_{false};
|
||||||
bool service_call_subscription_{false};
|
bool service_call_subscription_{false};
|
||||||
bool next_close_ = false;
|
bool next_close_ = false;
|
||||||
APIServer *parent_;
|
uint8_t ping_retries_{0};
|
||||||
|
// 8 bytes used, no padding needed
|
||||||
|
|
||||||
|
// Larger objects at the end
|
||||||
InitialStateIterator initial_state_iterator_;
|
InitialStateIterator initial_state_iterator_;
|
||||||
ListEntitiesIterator list_entities_iterator_;
|
ListEntitiesIterator list_entities_iterator_;
|
||||||
int state_subs_at_ = -1;
|
#ifdef USE_ESP32_CAMERA
|
||||||
|
esp32_camera::CameraImageReader image_reader_;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Function pointer type for message encoding
|
// Function pointer type for message encoding
|
||||||
using MessageCreatorPtr = uint16_t (*)(EntityBase *, APIConnection *, uint32_t remaining_size, bool is_single);
|
using MessageCreatorPtr = uint16_t (*)(EntityBase *, APIConnection *, uint32_t remaining_size, bool is_single);
|
||||||
|
@ -125,38 +125,6 @@ class APIFrameHelper {
|
|||||||
const uint8_t *current_data() const { return data.data() + offset; }
|
const uint8_t *current_data() const { return data.data() + offset; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Queue of data buffers to be sent
|
|
||||||
std::deque<SendBuffer> tx_buf_;
|
|
||||||
|
|
||||||
// Common state enum for all frame helpers
|
|
||||||
// Note: Not all states are used by all implementations
|
|
||||||
// - INITIALIZE: Used by both Noise and Plaintext
|
|
||||||
// - CLIENT_HELLO, SERVER_HELLO, HANDSHAKE: Only used by Noise protocol
|
|
||||||
// - DATA: Used by both Noise and Plaintext
|
|
||||||
// - CLOSED: Used by both Noise and Plaintext
|
|
||||||
// - FAILED: Used by both Noise and Plaintext
|
|
||||||
// - EXPLICIT_REJECT: Only used by Noise protocol
|
|
||||||
enum class State {
|
|
||||||
INITIALIZE = 1,
|
|
||||||
CLIENT_HELLO = 2, // Noise only
|
|
||||||
SERVER_HELLO = 3, // Noise only
|
|
||||||
HANDSHAKE = 4, // Noise only
|
|
||||||
DATA = 5,
|
|
||||||
CLOSED = 6,
|
|
||||||
FAILED = 7,
|
|
||||||
EXPLICIT_REJECT = 8, // Noise only
|
|
||||||
};
|
|
||||||
|
|
||||||
// Current state of the frame helper
|
|
||||||
State state_{State::INITIALIZE};
|
|
||||||
|
|
||||||
// Helper name for logging
|
|
||||||
std::string info_;
|
|
||||||
|
|
||||||
// Socket for communication
|
|
||||||
socket::Socket *socket_{nullptr};
|
|
||||||
std::unique_ptr<socket::Socket> socket_owned_;
|
|
||||||
|
|
||||||
// Common implementation for writing raw data to socket
|
// Common implementation for writing raw data to socket
|
||||||
APIError write_raw_(const struct iovec *iov, int iovcnt);
|
APIError write_raw_(const struct iovec *iov, int iovcnt);
|
||||||
|
|
||||||
@ -169,15 +137,41 @@ class APIFrameHelper {
|
|||||||
APIError write_raw_(const struct iovec *iov, int iovcnt, socket::Socket *socket, std::vector<uint8_t> &tx_buf,
|
APIError write_raw_(const struct iovec *iov, int iovcnt, socket::Socket *socket, std::vector<uint8_t> &tx_buf,
|
||||||
const std::string &info, StateEnum &state, StateEnum failed_state);
|
const std::string &info, StateEnum &state, StateEnum failed_state);
|
||||||
|
|
||||||
|
// Pointers first (4 bytes each)
|
||||||
|
socket::Socket *socket_{nullptr};
|
||||||
|
std::unique_ptr<socket::Socket> socket_owned_;
|
||||||
|
|
||||||
|
// Common state enum for all frame helpers
|
||||||
|
// Note: Not all states are used by all implementations
|
||||||
|
// - INITIALIZE: Used by both Noise and Plaintext
|
||||||
|
// - CLIENT_HELLO, SERVER_HELLO, HANDSHAKE: Only used by Noise protocol
|
||||||
|
// - DATA: Used by both Noise and Plaintext
|
||||||
|
// - CLOSED: Used by both Noise and Plaintext
|
||||||
|
// - FAILED: Used by both Noise and Plaintext
|
||||||
|
// - EXPLICIT_REJECT: Only used by Noise protocol
|
||||||
|
enum class State : uint8_t {
|
||||||
|
INITIALIZE = 1,
|
||||||
|
CLIENT_HELLO = 2, // Noise only
|
||||||
|
SERVER_HELLO = 3, // Noise only
|
||||||
|
HANDSHAKE = 4, // Noise only
|
||||||
|
DATA = 5,
|
||||||
|
CLOSED = 6,
|
||||||
|
FAILED = 7,
|
||||||
|
EXPLICIT_REJECT = 8, // Noise only
|
||||||
|
};
|
||||||
|
|
||||||
|
// Containers (size varies, but typically 12+ bytes on 32-bit)
|
||||||
|
std::deque<SendBuffer> tx_buf_;
|
||||||
|
std::string info_;
|
||||||
|
std::vector<struct iovec> reusable_iovs_;
|
||||||
|
std::vector<uint8_t> rx_buf_;
|
||||||
|
|
||||||
|
// Group smaller types together
|
||||||
|
uint16_t rx_buf_len_ = 0;
|
||||||
|
State state_{State::INITIALIZE};
|
||||||
uint8_t frame_header_padding_{0};
|
uint8_t frame_header_padding_{0};
|
||||||
uint8_t frame_footer_size_{0};
|
uint8_t frame_footer_size_{0};
|
||||||
|
// 5 bytes total, 3 bytes padding
|
||||||
// Reusable IOV array for write_protobuf_packets to avoid repeated allocations
|
|
||||||
std::vector<struct iovec> reusable_iovs_;
|
|
||||||
|
|
||||||
// Receive buffer for reading frame data
|
|
||||||
std::vector<uint8_t> rx_buf_;
|
|
||||||
uint16_t rx_buf_len_ = 0;
|
|
||||||
|
|
||||||
// Common initialization for both plaintext and noise protocols
|
// Common initialization for both plaintext and noise protocols
|
||||||
APIError init_common_();
|
APIError init_common_();
|
||||||
@ -213,19 +207,28 @@ class APINoiseFrameHelper : public APIFrameHelper {
|
|||||||
APIError init_handshake_();
|
APIError init_handshake_();
|
||||||
APIError check_handshake_finished_();
|
APIError check_handshake_finished_();
|
||||||
void send_explicit_handshake_reject_(const std::string &reason);
|
void send_explicit_handshake_reject_(const std::string &reason);
|
||||||
|
|
||||||
|
// Pointers first (4 bytes each)
|
||||||
|
NoiseHandshakeState *handshake_{nullptr};
|
||||||
|
NoiseCipherState *send_cipher_{nullptr};
|
||||||
|
NoiseCipherState *recv_cipher_{nullptr};
|
||||||
|
|
||||||
|
// Shared pointer (8 bytes on 32-bit = 4 bytes control block pointer + 4 bytes object pointer)
|
||||||
|
std::shared_ptr<APINoiseContext> ctx_;
|
||||||
|
|
||||||
|
// Vector (12 bytes on 32-bit)
|
||||||
|
std::vector<uint8_t> prologue_;
|
||||||
|
|
||||||
|
// NoiseProtocolId (size depends on implementation)
|
||||||
|
NoiseProtocolId nid_;
|
||||||
|
|
||||||
|
// Group small types together
|
||||||
// Fixed-size header buffer for noise protocol:
|
// Fixed-size header buffer for noise protocol:
|
||||||
// 1 byte for indicator + 2 bytes for message size (16-bit value, not varint)
|
// 1 byte for indicator + 2 bytes for message size (16-bit value, not varint)
|
||||||
// Note: Maximum message size is UINT16_MAX (65535), with a limit of 128 bytes during handshake phase
|
// Note: Maximum message size is UINT16_MAX (65535), with a limit of 128 bytes during handshake phase
|
||||||
uint8_t rx_header_buf_[3];
|
uint8_t rx_header_buf_[3];
|
||||||
uint8_t rx_header_buf_len_ = 0;
|
uint8_t rx_header_buf_len_ = 0;
|
||||||
|
// 4 bytes total, no padding
|
||||||
std::vector<uint8_t> prologue_;
|
|
||||||
|
|
||||||
std::shared_ptr<APINoiseContext> ctx_;
|
|
||||||
NoiseHandshakeState *handshake_{nullptr};
|
|
||||||
NoiseCipherState *send_cipher_{nullptr};
|
|
||||||
NoiseCipherState *recv_cipher_{nullptr};
|
|
||||||
NoiseProtocolId nid_;
|
|
||||||
};
|
};
|
||||||
#endif // USE_API_NOISE
|
#endif // USE_API_NOISE
|
||||||
|
|
||||||
@ -252,6 +255,12 @@ class APIPlaintextFrameHelper : public APIFrameHelper {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
APIError try_read_frame_(ParsedFrame *frame);
|
APIError try_read_frame_(ParsedFrame *frame);
|
||||||
|
|
||||||
|
// Group 2-byte aligned types
|
||||||
|
uint16_t rx_header_parsed_type_ = 0;
|
||||||
|
uint16_t rx_header_parsed_len_ = 0;
|
||||||
|
|
||||||
|
// Group 1-byte types together
|
||||||
// Fixed-size header buffer for plaintext protocol:
|
// Fixed-size header buffer for plaintext protocol:
|
||||||
// We now store the indicator byte + the two varints.
|
// We now store the indicator byte + the two varints.
|
||||||
// To match noise protocol's maximum message size (UINT16_MAX = 65535), we need:
|
// To match noise protocol's maximum message size (UINT16_MAX = 65535), we need:
|
||||||
@ -263,8 +272,7 @@ class APIPlaintextFrameHelper : public APIFrameHelper {
|
|||||||
uint8_t rx_header_buf_[6]; // 1 byte indicator + 5 bytes for varints (3 for size + 2 for type)
|
uint8_t rx_header_buf_[6]; // 1 byte indicator + 5 bytes for varints (3 for size + 2 for type)
|
||||||
uint8_t rx_header_buf_pos_ = 0;
|
uint8_t rx_header_buf_pos_ = 0;
|
||||||
bool rx_header_parsed_ = false;
|
bool rx_header_parsed_ = false;
|
||||||
uint16_t rx_header_parsed_type_ = 0;
|
// 8 bytes total, no padding needed
|
||||||
uint16_t rx_header_parsed_len_ = 0;
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -142,19 +142,27 @@ class APIServer : public Component, public Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool shutting_down_ = false;
|
// Pointers and pointer-like types first (4 bytes each)
|
||||||
std::unique_ptr<socket::Socket> socket_ = nullptr;
|
std::unique_ptr<socket::Socket> socket_ = nullptr;
|
||||||
uint16_t port_{6053};
|
Trigger<std::string, std::string> *client_connected_trigger_ = new Trigger<std::string, std::string>();
|
||||||
|
Trigger<std::string, std::string> *client_disconnected_trigger_ = new Trigger<std::string, std::string>();
|
||||||
|
|
||||||
|
// 4-byte aligned types
|
||||||
uint32_t reboot_timeout_{300000};
|
uint32_t reboot_timeout_{300000};
|
||||||
uint32_t batch_delay_{100};
|
uint32_t batch_delay_{100};
|
||||||
uint32_t last_connected_{0};
|
uint32_t last_connected_{0};
|
||||||
|
|
||||||
|
// Vectors and strings (12 bytes each on 32-bit)
|
||||||
std::vector<std::unique_ptr<APIConnection>> clients_;
|
std::vector<std::unique_ptr<APIConnection>> clients_;
|
||||||
std::string password_;
|
std::string password_;
|
||||||
std::vector<uint8_t> shared_write_buffer_; // Shared proto write buffer for all connections
|
std::vector<uint8_t> shared_write_buffer_; // Shared proto write buffer for all connections
|
||||||
std::vector<HomeAssistantStateSubscription> state_subs_;
|
std::vector<HomeAssistantStateSubscription> state_subs_;
|
||||||
std::vector<UserServiceDescriptor *> user_services_;
|
std::vector<UserServiceDescriptor *> user_services_;
|
||||||
Trigger<std::string, std::string> *client_connected_trigger_ = new Trigger<std::string, std::string>();
|
|
||||||
Trigger<std::string, std::string> *client_disconnected_trigger_ = new Trigger<std::string, std::string>();
|
// Group smaller types together
|
||||||
|
uint16_t port_{6053};
|
||||||
|
bool shutting_down_ = false;
|
||||||
|
// 3 bytes used, 1 byte padding
|
||||||
|
|
||||||
#ifdef USE_API_NOISE
|
#ifdef USE_API_NOISE
|
||||||
std::shared_ptr<APINoiseContext> noise_ctx_ = std::make_shared<APINoiseContext>();
|
std::shared_ptr<APINoiseContext> noise_ctx_ = std::make_shared<APINoiseContext>();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user