3#ifdef USE_API_PLAINTEXT
19static const char *
const TAG =
"api.plaintext";
22static constexpr size_t API_MAX_LOG_BYTES = 168;
24#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
25#define HELPER_LOG(msg, ...) \
27 char peername_buf[socket::SOCKADDR_STR_LEN]; \
28 this->get_peername_to(peername_buf); \
29 ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, peername_buf, ##__VA_ARGS__); \
32#define HELPER_LOG(msg, ...) ((void) 0)
35#ifdef HELPER_LOG_PACKETS
36#define LOG_PACKET_RECEIVED(buffer) \
38 char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
39 ESP_LOGVV(TAG, "Received frame: %s", \
40 format_hex_pretty_to(hex_buf_, (buffer).data(), \
41 (buffer).size() < API_MAX_LOG_BYTES ? (buffer).size() : API_MAX_LOG_BYTES)); \
44#define LOG_PACKET_RECEIVED(buffer) ((void) 0)
115 HELPER_LOG(
"Header buffer overflow");
137 uint8_t varint_pos = 1;
141 if (!msg_size_varint.has_value()) {
146 if (msg_size_varint.value > MAX_MESSAGE_SIZE) {
148 HELPER_LOG(
"Bad packet: message size %" PRIu32
" exceeds maximum %u",
149 static_cast<uint32_t>(msg_size_varint.value), MAX_MESSAGE_SIZE);
155 varint_pos += msg_size_varint.consumed;
158 if (!msg_type_varint.has_value()) {
162 if (msg_type_varint.value > std::numeric_limits<uint16_t>::max()) {
164 HELPER_LOG(
"Bad packet: message type %" PRIu32
" exceeds maximum %u",
165 static_cast<uint32_t>(msg_type_varint.value), std::numeric_limits<uint16_t>::max());
175 if (!this->
rx_buf_.
resize(this->rx_header_parsed_len_ + RX_BUF_NULL_TERMINATOR)) [[unlikely]] {
189 if (
static_cast<uint16_t
>(received) != to_read) {
195 LOG_PACKET_RECEIVED(this->
rx_buf_);
224 static constexpr uint8_t INDICATOR_MSG_SIZE = 19;
226 static const char MSG_PROGMEM[] PROGMEM =
"\x00"
227 "Bad indicator byte";
228 char msg[INDICATOR_MSG_SIZE];
229 memcpy_P(msg, MSG_PROGMEM, INDICATOR_MSG_SIZE);
232 static const char MSG[] =
"\x00"
233 "Bad indicator byte";
247ESPHOME_ALWAYS_INLINE
static inline void encode_varint_16(uint16_t value, uint8_t varint_len, uint8_t *p) {
248 if (varint_len >= 2) {
249 *p++ =
static_cast<uint8_t
>(value | 0x80);
251 if (varint_len == 3) {
252 *p++ =
static_cast<uint8_t
>(value | 0x80);
256 *p =
static_cast<uint8_t
>(value);
264 "HEADER_PADDING cannot fit the type varint of the largest message ID");
270ESPHOME_ALWAYS_INLINE
static inline uint8_t write_plaintext_header(uint8_t *buf_start, uint16_t
payload_size,
271 uint16_t message_type, uint8_t padding_size) {
274 uint8_t total_header_len = 1 + size_varint_len + type_varint_len;
286#ifdef ESPHOME_DEBUG_API
287 assert(padding_size >= total_header_len);
289 uint32_t header_offset = padding_size - total_header_len;
292 buf_start[header_offset] = 0x00;
295 encode_varint_16(
payload_size, size_varint_len, buf_start + header_offset + 1);
296 encode_varint_16(message_type, type_varint_len, buf_start + header_offset + 1 + size_varint_len);
298 return total_header_len;
302#ifdef ESPHOME_DEBUG_API
314 std::span<const MessageInfo> messages) {
315#ifdef ESPHOME_DEBUG_API
317 assert(!messages.empty());
324 const auto &first = messages[0];
325 uint8_t *first_start = buffer_data + first.offset;
326 uint8_t header_len = write_plaintext_header(first_start, first.payload_size, first.message_type,
HEADER_PADDING);
328 uint16_t total_len = header_len + first.payload_size;
330 for (
size_t i = 1; i < messages.size(); i++) {
331 const auto &msg = messages[i];
332 header_len = write_plaintext_header(buffer_data + msg.offset, msg.payload_size, msg.message_type, msg.header_size);
333 total_len += header_len + msg.payload_size;
bool resize(size_t n) ESPHOME_ALWAYS_INLINE
Returns false if allocation fails; the buffer is left unchanged. No zero-fill.
APIError handle_socket_read_result_(ssize_t received)
APIError ESPHOME_ALWAYS_INLINE write_raw_fast_buf_(const void *data, uint16_t len)
APIError write_raw_buf_(const void *data, uint16_t len, ssize_t sent=WRITE_NOT_ATTEMPTED)
APIOverflowBuffer overflow_buf_
std::unique_ptr< socket::Socket > socket_
APIError ESPHOME_ALWAYS_INLINE check_data_state_() const
APIError drain_overflow_and_handle_errors_()
bool empty() const
True when no backlogged data is waiting.
uint8_t rx_header_buf_[6]
uint16_t rx_header_parsed_type_
APIError try_read_frame_()
Read a packet into the rx_buf_.
APIError init() override
Initialize the frame helper, returns OK if successful.
uint16_t rx_header_parsed_len_
APIError read_packet(ReadPacketBuffer *buffer) override
APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) override
uint8_t rx_header_buf_pos_
static constexpr uint8_t HEADER_PADDING
APIError write_protobuf_messages(ProtoWriteBuffer buffer, std::span< const MessageInfo > messages) override
static constexpr uint8_t ESPHOME_ALWAYS_INLINE varint16(uint16_t value)
static ProtoVarIntResult ESPHOME_ALWAYS_INLINE parse_non_empty(const uint8_t *buffer, uint32_t len)
Parse a varint from buffer.
static ProtoVarIntResult ESPHOME_ALWAYS_INLINE parse(const uint8_t *buffer, uint32_t len)
Parse a varint from buffer (safe for empty buffers).
APIBuffer * get_buffer() const
@ PROTOCOL_SWITCH_TO_NOISE