ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
api_frame_helper_noise.cpp
Go to the documentation of this file.
2#ifdef USE_API
3#ifdef USE_API_NOISE
4#include "api_connection.h" // For ClientInfo struct
8#include "esphome/core/hal.h"
10#include "esphome/core/log.h"
11#include "proto.h"
12#include <cstring>
13#include <cinttypes>
14
15namespace esphome::api {
16
18
19// api_frame_helper.h keeps its own MAX_HANDSHAKE_SIZE because that header is
20// also compiled in plaintext-only builds without the noise component; keep
21// the two definitions from drifting apart.
22static_assert(MAX_HANDSHAKE_SIZE == noise::MAX_HANDSHAKE_SIZE,
23 "api and noise component handshake size limits must match");
24
25ESPHOME_LOG_TAG(TAG, "api.noise");
26static constexpr char PROLOGUE_INIT[] PROGMEM = "NoiseAPIInit";
27static constexpr size_t PROLOGUE_INIT_LEN = 12; // strlen("NoiseAPIInit")
28
29// Maximum bytes to log in hex format (168 * 3 = 504, under TX buffer size of 512)
30static constexpr size_t API_MAX_LOG_BYTES = 168;
31
32#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
33#define HELPER_LOG(msg, ...) \
34 do { \
35 char peername_buf[socket::SOCKADDR_STR_LEN]; \
36 this->get_peername_to(peername_buf); \
37 ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, peername_buf, ##__VA_ARGS__); \
38 } while (0)
39#else
40#define HELPER_LOG(msg, ...) ((void) 0)
41#endif
42
43#ifdef HELPER_LOG_PACKETS
44#define LOG_PACKET_RECEIVED(buffer) \
45 do { \
46 char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
47 ESP_LOGVV(TAG, "Received frame: %s", \
48 format_hex_pretty_to(hex_buf_, (buffer).data(), \
49 (buffer).size() < API_MAX_LOG_BYTES ? (buffer).size() : API_MAX_LOG_BYTES)); \
50 } while (0)
51#else
52#define LOG_PACKET_RECEIVED(buffer) ((void) 0)
53#endif
54
57 APIError err = init_common_();
58 if (err != APIError::OK) {
59 return err;
60 }
61
62 // init prologue
63 uint8_t *dst = prologue_.append(PROLOGUE_INIT_LEN);
64 if (dst == nullptr) [[unlikely]] {
67 }
68 progmem_memcpy(dst, PROLOGUE_INIT, PROLOGUE_INIT_LEN);
69
71 return APIError::OK;
72}
73#ifdef USE_API_OUTGOING_CONNECTION
75 // The peer needs our name and MAC to pick the key before its first message
77 return this->send_server_hello_frame_();
78}
79#endif
80#ifdef USE_API_PLAINTEXT
81APIError APINoiseFrameHelper::init_from_handoff(const uint8_t *header, uint8_t header_len) {
82 APIError err = this->init();
83 if (err != APIError::OK) {
84 return err;
85 }
86 // Seed the header bytes the plaintext helper consumed before detecting the
87 // Noise indicator; try_read_frame_ resumes from rx_header_buf_len_.
88 std::memcpy(this->rx_header_buf_, header, header_len);
89 this->rx_header_buf_len_ = header_len;
90 // Pump the handshake without gating on socket_->ready(): on LWIP the
91 // plaintext helper's partial read can drain rcvevent while the rest of the
92 // client hello sits in the lastdata cache, so ready() may report false even
93 // though data is available.
94 return this->pump_handshake_();
95}
96#endif // USE_API_PLAINTEXT
97
102 while (this->state_ != State::DATA) {
103 APIError err = this->state_action_();
104 if (err == APIError::WOULD_BLOCK) {
105 break;
106 }
107 if (err != APIError::OK) {
108 return err;
109 }
110 }
111 return APIError::OK;
112}
113
114// Helper for handling handshake frame errors
116 if (aerr == APIError::BAD_INDICATOR) {
117 send_explicit_handshake_reject_(LOG_STR("Bad indicator byte"));
118 } else if (aerr == APIError::BAD_HANDSHAKE_PACKET_LEN) {
119 send_explicit_handshake_reject_(LOG_STR("Bad handshake packet len"));
120 }
121 return aerr;
122}
123
124// Helper for handling noise library errors
125APIError APINoiseFrameHelper::handle_noise_error_(int err, const LogString *func_name, APIError api_err) {
126 if (err != 0) {
128 HELPER_LOG("%s failed: %s", LOG_STR_ARG(func_name), LOG_STR_ARG(noise_err_to_logstr(err)));
129 return api_err;
130 }
131 return APIError::OK;
132}
133
136 // Check ready() once, not per state transition. On ESP8266 LWIP raw TCP,
137 // ready() returns false once the rx buffer is consumed. Re-checking each
138 // iteration would block handshake writes that must follow reads,
139 // deadlocking the handshake. pump_handshake_() stops on WOULD_BLOCK when
140 // no more data is available to read.
141 if (state_ != State::DATA && this->socket_->ready()) {
142 APIError err = this->pump_handshake_();
143 if (err != APIError::OK) {
144 return err;
145 }
146 }
147
148 if (!this->overflow_buf_.empty()) [[unlikely]] {
150 }
151 return APIError::OK;
152}
153
164 // read header
165 if (rx_header_buf_len_ < noise::FRAME_HEADER_SIZE) {
166 // no header information yet
167 uint8_t to_read = static_cast<uint8_t>(noise::FRAME_HEADER_SIZE) - rx_header_buf_len_;
168 ssize_t received = this->socket_->read(&rx_header_buf_[rx_header_buf_len_], to_read);
169 APIError err = handle_socket_read_result_(received);
170 if (err != APIError::OK) {
171 return err;
172 }
173 rx_header_buf_len_ += static_cast<uint8_t>(received);
174 if (static_cast<uint8_t>(received) != to_read) {
175 // not a full read
177 }
178
179 if (rx_header_buf_[0] != noise::FRAME_INDICATOR) {
181 HELPER_LOG("Bad indicator byte %u", rx_header_buf_[0]);
183 }
184 // header reading done
185 }
186
187 // read body
188 uint16_t msg_size = (((uint16_t) rx_header_buf_[1]) << 8) | rx_header_buf_[2];
189
190 // Check against size limits to prevent OOM: MAX_HANDSHAKE_SIZE for handshake, MAX_MESSAGE_SIZE for data
191 bool is_data = (state_ == State::DATA);
192 uint16_t limit = is_data ? MAX_MESSAGE_SIZE : MAX_HANDSHAKE_SIZE;
193 if (msg_size > limit) {
195 HELPER_LOG("Bad packet: message size %u exceeds maximum %u", msg_size, limit);
197 }
198
199 // Reserve space for body (+ null terminator in DATA state so protobuf
200 // StringRef fields can be safely null-terminated in-place after decode.
201 // During handshake, rx_buf_.size() is used in prologue construction, so
202 // the buffer must be exactly msg_size to avoid prologue mismatch.)
203 uint16_t alloc_size = msg_size + (is_data ? RX_BUF_NULL_TERMINATOR : 0);
204 if (!this->rx_buf_.resize(alloc_size)) [[unlikely]] {
207 }
208
209 if (rx_buf_len_ < msg_size) {
210 // more data to read
211 uint16_t to_read = msg_size - rx_buf_len_;
212 ssize_t received = this->socket_->read(&rx_buf_[rx_buf_len_], to_read);
213 APIError err = handle_socket_read_result_(received);
214 if (err != APIError::OK) {
215 return err;
216 }
217 rx_buf_len_ += static_cast<uint16_t>(received);
218 if (static_cast<uint16_t>(received) != to_read) {
219 // not all read
221 }
222 }
223
224 LOG_PACKET_RECEIVED(this->rx_buf_);
225
226 // Clear state for next frame (rx_buf_ still contains data for caller)
227 this->rx_buf_len_ = 0;
228 this->rx_header_buf_len_ = 0;
229
230 return APIError::OK;
231}
232
242// Split into per-state methods so the compiler doesn't allocate stack space
243// for all branches simultaneously. On RP2040 the core0 stack lives in a 4KB
244// scratch RAM bank; the Noise crypto path (curve25519) needs ~2KB+ of stack,
245// so every byte saved in the caller matters.
247 switch (this->state_) {
249 HELPER_LOG("Bad state for method: %d", (int) this->state_);
250 return APIError::BAD_STATE;
252#ifdef USE_API_OUTGOING_CONNECTION
254#endif
255 return this->state_action_client_hello_();
257 return this->state_action_server_hello_();
258 case State::HANDSHAKE:
259 return this->state_action_handshake_();
260 case State::CLOSED:
261 case State::FAILED:
262 return APIError::BAD_STATE;
263 default:
264 return APIError::OK;
265 }
266}
268 // waiting for client hello
269 APIError aerr = this->try_read_frame_();
270 if (aerr != APIError::OK) {
272 }
273 // ignore contents, may be used in future for flags
274 // Append 2 size bytes + frame data to the prologue
275 size_t rx_size = this->rx_buf_.size();
276 uint8_t *dst = this->prologue_.append(2 + rx_size);
277 if (dst == nullptr) [[unlikely]] {
280 }
281 dst[0] = (uint8_t) (rx_size >> 8);
282 dst[1] = (uint8_t) rx_size;
283 if (rx_size > 0) {
284 std::memcpy(dst + 2, this->rx_buf_.data(), rx_size);
285 }
286
287#ifdef USE_API_OUTGOING_CONNECTION
289 // Server hello already went out at handoff
290 return this->start_handshake_();
291 }
292#endif
294 return APIError::OK;
295}
297 const auto &name = App.get_name();
298 char mac[MAC_ADDRESS_BUFFER_SIZE];
300
301 // Calculate positions and sizes
302 size_t name_len = name.size() + 1; // including null terminator
303 size_t name_offset = 1;
304 size_t mac_offset = name_offset + name_len;
305 size_t total_size = 1 + name_len + MAC_ADDRESS_BUFFER_SIZE;
306
307 // 1 (proto) + name (max ESPHOME_DEVICE_NAME_MAX_LEN) + 1 (name null)
308 // + mac (MAC_ADDRESS_BUFFER_SIZE - 1) + 1 (mac null)
309 constexpr size_t max_msg_size = 1 + ESPHOME_DEVICE_NAME_MAX_LEN + 1 + MAC_ADDRESS_BUFFER_SIZE;
310 uint8_t msg[max_msg_size];
311
312 // chosen proto
313 msg[0] = 0x01;
314
315 // node name, terminated by null byte
316 std::memcpy(msg + name_offset, name.c_str(), name_len);
317 // node mac, terminated by null byte
318 std::memcpy(msg + mac_offset, mac, MAC_ADDRESS_BUFFER_SIZE);
319
320 return write_frame_(msg, total_size);
321}
323 APIError aerr = this->send_server_hello_frame_();
324 if (aerr != APIError::OK)
325 return aerr;
326 return this->start_handshake_();
327}
329 APIError aerr = init_handshake_();
330 if (aerr != APIError::OK)
331 return aerr;
333 return APIError::OK;
334}
338 return this->state_action_handshake_read_();
340 return this->state_action_handshake_write_();
341 }
342 // bad state for action
343 this->state_ = State::FAILED;
344 HELPER_LOG("Bad action for handshake: %d", (int) action);
346}
348 APIError aerr = this->try_read_frame_();
349 if (aerr != APIError::OK) {
350 return this->handle_handshake_frame_error_(aerr);
351 }
352
353 if (this->rx_buf_.empty()) {
354 this->send_explicit_handshake_reject_(LOG_STR("Empty handshake message"));
356 } else if (this->rx_buf_[0] != noise::HANDSHAKE_STATUS_OK) {
357 HELPER_LOG("Bad handshake error byte: %u", this->rx_buf_[0]);
358 this->send_explicit_handshake_reject_(LOG_STR("Bad handshake error byte"));
360 }
361
362 int err = this->handshake_.read_message(this->rx_buf_.data() + 1, this->rx_buf_.size() - 1);
363 if (err != 0) {
364 // Special handling for MAC failure
366 return this->handle_noise_error_(err, LOG_STR("noise_handshakestate_read_message"),
368 }
369
370 return this->check_handshake_finished_();
371}
373 uint8_t buffer[65];
374 size_t msg_len = 0;
375
376 int err = this->handshake_.write_message(buffer + 1, sizeof(buffer) - 1, msg_len);
377 APIError aerr = this->handle_noise_error_(err, LOG_STR("noise_handshakestate_write_message"),
379 if (aerr != APIError::OK)
380 return aerr;
381 buffer[0] = noise::HANDSHAKE_STATUS_OK;
382
383 aerr = this->write_frame_(buffer, msg_len + 1);
384 if (aerr != APIError::OK)
385 return aerr;
386 return this->check_handshake_finished_();
387}
389 // Max reject message: "Bad handshake packet len" (24) + 1 (failure byte) = 25 bytes
390 uint8_t data[32];
391 static_assert(sizeof(data) >= noise::MAC_FAILURE_PAYLOAD_SIZE,
392 "reject buffer must fit the MAC failure wire contract");
393 size_t data_size = noise::format_reject_payload(data, sizeof(data), reason);
394
395 // temporarily remove failed state
396 auto orig_state = state_;
398 APIError aerr = write_frame_(data, data_size);
399 if (aerr != APIError::OK) {
400 // Best effort; the reject reason is a diagnosis aid, not a protocol step
401 ESP_LOGW(TAG, "Sending handshake reject failed: %d", (int) aerr);
402 }
404 // write_frame_ may have moved the state to FAILED; keep that decision
405 state_ = orig_state;
406 }
407}
409 APIError aerr = this->check_data_state_();
410 if (aerr != APIError::OK)
411 return aerr;
412
413 aerr = this->try_read_frame_();
414 if (aerr != APIError::OK)
415 return aerr;
416
417 NoiseBuffer mbuf;
418 noise_buffer_init(mbuf);
419 // read_packet() must only be called in DATA state; the extra
420 // RX_BUF_NULL_TERMINATOR byte is only allocated in DATA state
421 // (see try_read_frame_), so calling this during handshake would
422 // underflow the size calculation below.
423#ifdef ESPHOME_DEBUG_API
424 assert(this->state_ == State::DATA);
425#endif
426 // rx_buf_ has RX_BUF_NULL_TERMINATOR extra byte for null termination
427 // (only added in DATA state — see try_read_frame_), so subtract it
428 // to get the actual encrypted data size for decryption.
429 size_t encrypted_size = this->rx_buf_.size() - RX_BUF_NULL_TERMINATOR;
430 noise_buffer_set_inout(mbuf, this->rx_buf_.data(), encrypted_size, encrypted_size);
431 int err = noise_cipherstate_decrypt(this->recv_cipher_, &mbuf);
432 APIError decrypt_err =
433 handle_noise_error_(err, LOG_STR("noise_cipherstate_decrypt"), APIError::CIPHERSTATE_DECRYPT_FAILED);
434 if (decrypt_err != APIError::OK) {
435 return decrypt_err;
436 }
437
438 uint16_t msg_size = mbuf.size;
439 uint8_t *msg_data = this->rx_buf_.data();
440 if (msg_size < 4) {
441 this->state_ = State::FAILED;
442 HELPER_LOG("Bad data packet: size %d too short", msg_size);
444 }
445
446 uint16_t type = (((uint16_t) msg_data[0]) << 8) | msg_data[1];
447 uint16_t data_len = (((uint16_t) msg_data[2]) << 8) | msg_data[3];
448 if (data_len > msg_size - 4) {
449 this->state_ = State::FAILED;
450 HELPER_LOG("Bad data packet: data_len %u greater than msg_size %u", data_len, msg_size);
452 }
453
454 buffer->data = msg_data + 4; // Skip 4-byte header (type + length)
455 buffer->data_len = data_len;
456 buffer->type = type;
457 return APIError::OK;
458}
459// Encrypt a single noise message in place and return the encrypted frame length.
460// Returns APIError::OK on success.
461APIError APINoiseFrameHelper::encrypt_noise_message_(uint8_t *buf_start, uint16_t payload_size, uint16_t message_type,
462 uint16_t &encrypted_len_out) {
463 // The noise frame header is written after encryption, when the size is known
464
465 // Write message header (to be encrypted)
466 constexpr uint8_t msg_offset = noise::FRAME_HEADER_SIZE;
467 buf_start[msg_offset] = static_cast<uint8_t>(message_type >> 8); // type high byte
468 buf_start[msg_offset + 1] = static_cast<uint8_t>(message_type); // type low byte
469 buf_start[msg_offset + 2] = static_cast<uint8_t>(payload_size >> 8); // data_len high byte
470 buf_start[msg_offset + 3] = static_cast<uint8_t>(payload_size); // data_len low byte
471 // payload data is already in the buffer starting at offset + 7
472
473 // Encrypt the message in place
474 NoiseBuffer mbuf;
475 noise_buffer_init(mbuf);
476 noise_buffer_set_inout(mbuf, buf_start + msg_offset, 4 + payload_size, 4 + payload_size + this->frame_footer_size_);
477
478 int err = noise_cipherstate_encrypt(this->send_cipher_, &mbuf);
479 APIError aerr =
480 this->handle_noise_error_(err, LOG_STR("noise_cipherstate_encrypt"), APIError::CIPHERSTATE_ENCRYPT_FAILED);
481 if (aerr != APIError::OK)
482 return aerr;
483
484 // Fill in the frame header now that the encrypted size is known
485 noise::write_frame_header(buf_start, static_cast<uint16_t>(mbuf.size));
486
487 encrypted_len_out = static_cast<uint16_t>(noise::FRAME_HEADER_SIZE + mbuf.size);
488 return APIError::OK;
489}
490
492#ifdef ESPHOME_DEBUG_API
493 assert(this->state_ == State::DATA);
494#endif
495
496 APIBuffer *buf = buffer.get_buffer();
497 // Resize buffer to include footer space for Noise MAC
498 if (this->frame_footer_size_ && !buf->resize(buf->size() + this->frame_footer_size_)) [[unlikely]] {
501 }
502
503 uint16_t payload_size = static_cast<uint16_t>(buf->size() - HEADER_PADDING - this->frame_footer_size_);
504 uint8_t *buf_start = buf->data();
505 uint16_t encrypted_len;
506 APIError aerr = this->encrypt_noise_message_(buf_start, payload_size, type, encrypted_len);
507 if (aerr != APIError::OK)
508 return aerr;
509 return this->write_raw_fast_buf_(buf_start, encrypted_len);
510}
511
513#ifdef ESPHOME_DEBUG_API
514 assert(this->state_ == State::DATA);
515 assert(!messages.empty());
516#endif
517
518 // Noise messages are already contiguous in the buffer:
519 // HEADER_PADDING (7) exactly matches the fixed header size, and
520 // footer space (16) is consumed by the encryption MAC.
521 uint8_t *buffer_data = buffer.get_buffer()->data();
522 uint8_t *write_start = buffer_data + messages[0].offset;
523 uint16_t total_write_len = 0;
524
525 for (const auto &msg : messages) {
526 uint8_t *buf_start = buffer_data + msg.offset;
527 uint16_t encrypted_len;
528 APIError aerr = this->encrypt_noise_message_(buf_start, msg.payload_size, msg.message_type, encrypted_len);
529 if (aerr != APIError::OK)
530 return aerr;
531 total_write_len += encrypted_len;
532 }
533
534 return this->write_raw_fast_buf_(write_start, total_write_len);
535}
536
537APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, uint16_t len) {
538 uint8_t header[noise::FRAME_HEADER_SIZE];
540
541 if (len == 0) {
542 return this->write_raw_buf_(header, noise::FRAME_HEADER_SIZE);
543 }
544 struct iovec iov[2];
545 iov[0].iov_base = header;
546 iov[0].iov_len = noise::FRAME_HEADER_SIZE;
547 iov[1].iov_base = const_cast<uint8_t *>(data);
548 iov[1].iov_len = len;
549
550 return this->write_raw_iov_(iov, 2, noise::FRAME_HEADER_SIZE + len);
551}
552
558 int err = this->handshake_.init(this->ctx_, prologue_.data(), prologue_.size());
559 APIError aerr = handle_noise_error_(err, LOG_STR("noise_handshake_init"), APIError::HANDSHAKESTATE_SETUP_FAILED);
560 if (aerr != APIError::OK)
561 return aerr;
562 // init copies the prologue into the handshakestate, so we can get rid of it now
564 return APIError::OK;
565}
566
568#ifdef ESPHOME_DEBUG_API
569 assert(state_ == State::HANDSHAKE);
570#endif
571
575 return APIError::OK;
578 HELPER_LOG("Bad action for handshake: %d", (int) action);
580 }
581 // split() also frees the handshake state
582 int err = this->handshake_.split(send_cipher_, recv_cipher_);
583 APIError aerr =
584 handle_noise_error_(err, LOG_STR("noise_handshakestate_split"), APIError::HANDSHAKESTATE_SPLIT_FAILED);
585 if (aerr != APIError::OK)
586 return aerr;
587
588 this->frame_footer_size_ = noise_cipherstate_get_mac_length(send_cipher_);
589
590 HELPER_LOG("Handshake complete!");
592 return APIError::OK;
593}
594
596 if (send_cipher_ != nullptr) {
597 noise_cipherstate_free(send_cipher_);
598 send_cipher_ = nullptr;
599 }
600 if (recv_cipher_ != nullptr) {
601 noise_cipherstate_free(recv_cipher_);
602 recv_cipher_ = nullptr;
603 }
604}
605
606} // namespace esphome::api
607#endif // USE_API_NOISE
608#endif // USE_API
const StringRef & get_name() const
Get the name of this Application set by pre_setup().
Byte buffer that skips zero-initialization on resize().
Definition api_buffer.h:26
void release()
Release all memory (equivalent to std::vector swap trick).
Definition api_buffer.h:61
uint8_t * append(size_t n)
Grow by n bytes; returns the new bytes, or nullptr on allocation failure.
size_t size() const
Definition api_buffer.h:55
bool resize(size_t n) ESPHOME_ALWAYS_INLINE
Returns false if allocation fails; the buffer is left unchanged. No zero-fill.
Definition api_buffer.h:33
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)
APIError write_raw_iov_(const struct iovec *iov, int iovcnt, uint16_t total_write_len, ssize_t sent=WRITE_NOT_ATTEMPTED)
std::unique_ptr< socket::Socket > socket_
APIError ESPHOME_ALWAYS_INLINE check_data_state_() const
APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) override
APIError encrypt_noise_message_(uint8_t *buf_start, uint16_t payload_size, uint16_t message_type, uint16_t &encrypted_len_out)
APIError pump_handshake_()
Drive the handshake state machine until DATA, WOULD_BLOCK, or a fatal error.
APIError read_packet(ReadPacketBuffer *buffer) override
uint8_t rx_header_buf_[noise::FRAME_HEADER_SIZE]
APIError handle_noise_error_(int err, const LogString *func_name, APIError api_err)
APIError write_protobuf_messages(ProtoWriteBuffer buffer, std::span< const MessageInfo > messages) override
APIError state_action_()
To be called from read/write methods.
APIError try_read_frame_()
Read a packet into the rx_buf_.
APIError loop() override
Run through handshake messages (if in that phase)
APIError handle_handshake_frame_error_(APIError aerr)
void send_explicit_handshake_reject_(const LogString *reason)
APIError write_frame_(const uint8_t *data, uint16_t len)
APIError init() override
Initialize the frame helper, returns OK if successful.
APIError init_handshake_()
Initiate the data structures for the handshake.
APIError init_from_handoff(const uint8_t *header, uint8_t header_len)
noise::NoiseResponderHandshake handshake_
bool empty() const
True when no backlogged data is waiting.
int write_message(uint8_t *out, size_t capacity, size_t &out_len)
Produce the next handshake message into out; out_len receives its size and is zero on error.
Action action() const
ACTION_FAILED is the catch-all: returned before init(), after split() has released the state,...
int init(const NoiseContext &ctx, const uint8_t *prologue, size_t prologue_len)
Create and start the handshake with the context's PSK and the prologue.
int read_message(uint8_t *data, size_t len)
Process one received handshake message.
int split(NoiseCipherState *&send_cipher, NoiseCipherState *&recv_cipher)
Hand out the transport ciphers and free the handshake state.
uint8_t type
uint32_t buffer
Definition gif.cpp:50
__int64 ssize_t
Definition httplib.h:178
ESPHOME_LOG_TAG(TAG, "api.connection")
void write_frame_header(uint8_t *buf, uint16_t payload_len)
Definition noise.h:70
const LogString * noise_err_to_logstr(int err)
Convert a noise error code to a readable error.
Definition noise.cpp:58
size_t format_reject_payload(uint8_t *buf, size_t capacity, const LogString *reason)
Fill buf with a handshake reject payload (status byte plus the reason text, PROGMEM aware); returns t...
Definition noise.cpp:100
const LogString * reject_reason_for(int err)
Reject reason for a failed handshake read.
Definition noise.cpp:96
void progmem_memcpy(void *dst, const void *src, size_t len)
Definition hal.h:56
const void size_t len
Definition hal.h:68
void get_mac_address_into_buffer(std::span< char, MAC_ADDRESS_BUFFER_SIZE > buf)
Get the device MAC address into the given buffer, in lowercase hex notation.
Definition helpers.cpp:848
Application App
Global storage of Application pointer - only one Application can exist.
void * iov_base
Definition headers.h:113
size_t iov_len
Definition headers.h:114
uint32_t payload_size()