14static const char *
const TAG =
"api.socket";
19 return errno == EWOULDBLOCK || errno == EAGAIN;
31 return "BAD_HANDSHAKE_PACKET_LEN";
33 return "BAD_INDICATOR";
35 return "BAD_DATA_PACKET";
37 return "TCP_NODELAY_FAILED";
39 return "TCP_NONBLOCKING_FAILED";
41 return "CLOSE_FAILED";
43 return "SHUTDOWN_FAILED";
49 return "SOCKET_READ_FAILED";
51 return "SOCKET_WRITE_FAILED";
53 return "HANDSHAKESTATE_READ_FAILED";
55 return "HANDSHAKESTATE_WRITE_FAILED";
57 return "HANDSHAKESTATE_BAD_STATE";
59 return "CIPHERSTATE_DECRYPT_FAILED";
61 return "CIPHERSTATE_ENCRYPT_FAILED";
63 return "OUT_OF_MEMORY";
65 return "HANDSHAKESTATE_SETUP_FAILED";
67 return "HANDSHAKESTATE_SPLIT_FAILED";
69 return "BAD_HANDSHAKE_ERROR_BYTE";
71 return "CONNECTION_CLOSED";
77template<
typename StateEnum>
79 std::vector<uint8_t> &tx_buf,
const std::string &info, StateEnum &
state,
80 StateEnum failed_state) {
88 size_t total_write_len = 0;
89 for (
int i = 0; i < iovcnt; i++) {
90#ifdef HELPER_LOG_PACKETS
91 ESP_LOGVV(TAG,
"Sending raw: %s",
92 format_hex_pretty(
reinterpret_cast<uint8_t *
>(iov[i].iov_base), iov[i].iov_len).c_str());
94 total_write_len += iov[i].
iov_len;
97 if (!tx_buf.empty()) {
99 while (!tx_buf.empty()) {
100 ssize_t sent = socket->write(tx_buf.data(), tx_buf.size());
103 }
else if (sent == -1) {
104 ESP_LOGVV(TAG,
"%s: Socket write failed with errno %d", info.c_str(), errno);
105 state = failed_state;
110 tx_buf.erase(tx_buf.begin(), tx_buf.begin() + sent);
114 if (!tx_buf.empty()) {
117 tx_buf.reserve(tx_buf.size() + total_write_len);
118 for (
int i = 0; i < iovcnt; i++) {
119 tx_buf.insert(tx_buf.end(),
reinterpret_cast<uint8_t *
>(iov[i].
iov_base),
125 ssize_t sent = socket->writev(iov, iovcnt);
129 tx_buf.reserve(tx_buf.size() + total_write_len);
130 for (
int i = 0; i < iovcnt; i++) {
131 tx_buf.insert(tx_buf.end(),
reinterpret_cast<uint8_t *
>(iov[i].
iov_base),
135 }
else if (sent == -1) {
137 ESP_LOGVV(TAG,
"%s: Socket write failed with errno %d", info.c_str(), errno);
138 state = failed_state;
140 }
else if ((
size_t) sent != total_write_len) {
142 size_t remaining = total_write_len - sent;
144 tx_buf.reserve(tx_buf.size() + remaining);
146 size_t to_consume = sent;
147 for (
int i = 0; i < iovcnt; i++) {
148 if (to_consume >= iov[i].iov_len) {
151 tx_buf.insert(tx_buf.end(),
reinterpret_cast<uint8_t *
>(iov[i].
iov_base) + to_consume,
161#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s: " msg, info_.c_str(), ##__VA_ARGS__)
166static const char *
const PROLOGUE_INIT =
"NoiseAPIInit";
170 if (err == NOISE_ERROR_NO_MEMORY)
172 if (err == NOISE_ERROR_UNKNOWN_ID)
174 if (err == NOISE_ERROR_UNKNOWN_NAME)
175 return "UNKNOWN_NAME";
176 if (err == NOISE_ERROR_MAC_FAILURE)
177 return "MAC_FAILURE";
178 if (err == NOISE_ERROR_NOT_APPLICABLE)
179 return "NOT_APPLICABLE";
180 if (err == NOISE_ERROR_SYSTEM)
182 if (err == NOISE_ERROR_REMOTE_KEY_REQUIRED)
183 return "REMOTE_KEY_REQUIRED";
184 if (err == NOISE_ERROR_LOCAL_KEY_REQUIRED)
185 return "LOCAL_KEY_REQUIRED";
186 if (err == NOISE_ERROR_PSK_REQUIRED)
187 return "PSK_REQUIRED";
188 if (err == NOISE_ERROR_INVALID_LENGTH)
189 return "INVALID_LENGTH";
190 if (err == NOISE_ERROR_INVALID_PARAM)
191 return "INVALID_PARAM";
192 if (err == NOISE_ERROR_INVALID_STATE)
193 return "INVALID_STATE";
194 if (err == NOISE_ERROR_INVALID_NONCE)
195 return "INVALID_NONCE";
196 if (err == NOISE_ERROR_INVALID_PRIVATE_KEY)
197 return "INVALID_PRIVATE_KEY";
198 if (err == NOISE_ERROR_INVALID_PUBLIC_KEY)
199 return "INVALID_PUBLIC_KEY";
200 if (err == NOISE_ERROR_INVALID_FORMAT)
201 return "INVALID_FORMAT";
202 if (err == NOISE_ERROR_INVALID_SIGNATURE)
203 return "INVALID_SIGNATURE";
210 HELPER_LOG(
"Bad state for init %d", (
int)
state_);
213 int err =
socket_->setblocking(
false);
216 HELPER_LOG(
"Setting nonblocking failed with errno %d", errno);
221 err =
socket_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &enable,
sizeof(
int));
224 HELPER_LOG(
"Setting nodelay failed with errno %d", errno);
229 prologue_.insert(
prologue_.end(), PROLOGUE_INIT, PROLOGUE_INIT + strlen(PROLOGUE_INIT));
265 if (frame ==
nullptr) {
266 HELPER_LOG(
"Bad argument for try_read_frame_");
275 if (received == -1) {
276 if (errno == EWOULDBLOCK || errno == EAGAIN) {
280 HELPER_LOG(
"Socket read failed with errno %d", errno);
282 }
else if (received == 0) {
284 HELPER_LOG(
"Connection closed");
288 if ((
size_t) received != to_read) {
298 if (indicator != 0x01) {
300 HELPER_LOG(
"Bad indicator byte %u", indicator);
309 HELPER_LOG(
"Bad packet len for handshake: %d", msg_size);
314 if (
rx_buf_.size() != msg_size) {
322 if (received == -1) {
323 if (errno == EWOULDBLOCK || errno == EAGAIN) {
327 HELPER_LOG(
"Socket read failed with errno %d", errno);
329 }
else if (received == 0) {
331 HELPER_LOG(
"Connection closed");
335 if ((
size_t) received != to_read) {
342#ifdef HELPER_LOG_PACKETS
366 HELPER_LOG(
"Bad state for method: %d", (
int)
state_);
392 std::vector<uint8_t> msg;
398 const uint8_t *name_ptr =
reinterpret_cast<const uint8_t *
>(name.c_str());
399 msg.insert(msg.end(), name_ptr, name_ptr + name.size() + 1);
402 const uint8_t *mac_ptr =
reinterpret_cast<const uint8_t *
>(mac.c_str());
403 msg.insert(msg.end(), mac_ptr, mac_ptr + mac.size() + 1);
417 int action = noise_handshakestate_get_action(
handshake_);
418 if (action == NOISE_ACTION_READ_MESSAGE) {
433 if (frame.
msg.empty()) {
436 }
else if (frame.
msg[0] != 0x00) {
437 HELPER_LOG(
"Bad handshake error byte: %u", frame.
msg[0]);
443 noise_buffer_init(mbuf);
444 noise_buffer_set_input(mbuf, frame.
msg.data() + 1, frame.
msg.size() - 1);
445 err = noise_handshakestate_read_message(
handshake_, &mbuf,
nullptr);
448 HELPER_LOG(
"noise_handshakestate_read_message failed: %s",
noise_err_to_str(err).c_str());
449 if (err == NOISE_ERROR_MAC_FAILURE) {
460 }
else if (action == NOISE_ACTION_WRITE_MESSAGE) {
463 noise_buffer_init(mbuf);
464 noise_buffer_set_output(mbuf, buffer + 1,
sizeof(buffer) - 1);
466 err = noise_handshakestate_write_message(
handshake_, &mbuf,
nullptr);
469 HELPER_LOG(
"noise_handshakestate_write_message failed: %s",
noise_err_to_str(err).c_str());
483 HELPER_LOG(
"Bad action for handshake: %d", action);
493 std::vector<uint8_t> data;
494 data.resize(reason.length() + 1);
498 if (!reason.empty()) {
499 std::memcpy(data.data() + 1, reason.c_str(), reason.length());
527 noise_buffer_init(mbuf);
528 noise_buffer_set_inout(mbuf, frame.
msg.data(), frame.
msg.size(), frame.
msg.size());
532 HELPER_LOG(
"noise_cipherstate_decrypt failed: %s",
noise_err_to_str(err).c_str());
536 size_t msg_size = mbuf.size;
537 uint8_t *msg_data = frame.
msg.data();
540 HELPER_LOG(
"Bad data packet: size %d too short", msg_size);
548 uint16_t
type = (((uint16_t) msg_data[0]) << 8) | msg_data[1];
549 uint16_t data_len = (((uint16_t) msg_data[2]) << 8) | msg_data[3];
550 if (data_len > msg_size - 4) {
552 HELPER_LOG(
"Bad data packet: data_len %u greater than msg_size %u", data_len, msg_size);
575 std::vector<uint8_t> *raw_buffer = buffer.
get_buffer();
579 size_t msg_len = 4 + payload_len + padding;
591 uint8_t *buf_start = raw_buffer->data();
594 const uint8_t msg_offset = 3;
595 buf_start[msg_offset + 0] = (uint8_t) (
type >> 8);
596 buf_start[msg_offset + 1] = (uint8_t)
type;
597 buf_start[msg_offset + 2] = (uint8_t) (payload_len >> 8);
598 buf_start[msg_offset + 3] = (uint8_t) payload_len;
602 noise_buffer_init(mbuf);
604 noise_buffer_set_inout(mbuf, buf_start + msg_offset, msg_len, msg_len +
frame_footer_size_);
608 HELPER_LOG(
"noise_cipherstate_encrypt failed: %s",
noise_err_to_str(err).c_str());
612 size_t total_len = 3 + mbuf.size;
613 buf_start[1] = (uint8_t) (mbuf.size >> 8);
614 buf_start[2] = (uint8_t) mbuf.size;
630 if (errno == EWOULDBLOCK || errno == EAGAIN)
633 HELPER_LOG(
"Socket write failed with errno %d", errno);
635 }
else if (sent == 0) {
648 header[1] = (uint8_t) (
len >> 8);
649 header[2] = (uint8_t)
len;
657 iov[1].
iov_base =
const_cast<uint8_t *
>(data);
672 nid_.pattern_id = NOISE_PATTERN_NN;
673 nid_.cipher_id = NOISE_CIPHER_CHACHAPOLY;
674 nid_.dh_id = NOISE_DH_CURVE25519;
675 nid_.prefix_id = NOISE_PREFIX_STANDARD;
676 nid_.hybrid_id = NOISE_DH_NONE;
677 nid_.hash_id = NOISE_HASH_SHA256;
678 nid_.modifier_ids[0] = NOISE_MODIFIER_PSK0;
680 err = noise_handshakestate_new_by_id(&
handshake_, &
nid_, NOISE_ROLE_RESPONDER);
683 HELPER_LOG(
"noise_handshakestate_new_by_id failed: %s",
noise_err_to_str(err).c_str());
687 const auto &psk =
ctx_->get_psk();
688 err = noise_handshakestate_set_pre_shared_key(
handshake_, psk.data(), psk.size());
691 HELPER_LOG(
"noise_handshakestate_set_pre_shared_key failed: %s",
noise_err_to_str(err).c_str());
698 HELPER_LOG(
"noise_handshakestate_set_prologue failed: %s",
noise_err_to_str(err).c_str());
707 HELPER_LOG(
"noise_handshakestate_start failed: %s",
noise_err_to_str(err).c_str());
716 int action = noise_handshakestate_get_action(
handshake_);
717 if (action == NOISE_ACTION_READ_MESSAGE || action == NOISE_ACTION_WRITE_MESSAGE)
719 if (action != NOISE_ACTION_SPLIT) {
721 HELPER_LOG(
"Bad action for handshake: %d", action);
727 HELPER_LOG(
"noise_handshakestate_split failed: %s",
noise_err_to_str(err).c_str());
733 HELPER_LOG(
"Handshake complete!");
763 int err =
socket_->shutdown(how);
766 if (how == SHUT_RDWR) {
775 ESP_LOGE(TAG,
"Failed to acquire random bytes, rebooting!");
782template APIError APIFrameHelper::write_raw_<APINoiseFrameHelper::State>(
783 const struct iovec *iov,
int iovcnt,
socket::Socket *socket, std::vector<uint8_t> &tx_buf_,
const std::string &info,
787#ifdef USE_API_PLAINTEXT
792 HELPER_LOG(
"Bad state for init %d", (
int)
state_);
795 int err =
socket_->setblocking(
false);
798 HELPER_LOG(
"Setting nonblocking failed with errno %d", errno);
802 err =
socket_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &enable,
sizeof(
int));
805 HELPER_LOG(
"Setting nodelay failed with errno %d", errno);
837 if (frame ==
nullptr) {
838 HELPER_LOG(
"Bad argument for try_read_frame_");
850 if (received == -1) {
851 if (errno == EWOULDBLOCK || errno == EAGAIN) {
855 HELPER_LOG(
"Socket read failed with errno %d", errno);
857 }
else if (received == 0) {
859 HELPER_LOG(
"Connection closed");
869 HELPER_LOG(
"Bad indicator byte %u", data);
880 HELPER_LOG(
"Header buffer overflow");
906 uint32_t consumed = 0;
908 if (!msg_size_varint.has_value()) {
916 if (!msg_type_varint.has_value()) {
934 if (received == -1) {
935 if (errno == EWOULDBLOCK || errno == EAGAIN) {
939 HELPER_LOG(
"Socket read failed with errno %d", errno);
941 }
else if (received == 0) {
943 HELPER_LOG(
"Connection closed");
947 if ((
size_t) received != to_read) {
954#ifdef HELPER_LOG_PACKETS
989 const char msg[] =
"\x00"
990 "Bad indicator byte";
1010 std::vector<uint8_t> *raw_buffer = buffer.
get_buffer();
1017 size_t total_header_len = 1 + size_varint_len + type_varint_len;
1046 uint8_t *buf_start = raw_buffer->data();
1050 buf_start[header_offset] = 0x00;
1061 iov.
iov_base = buf_start + header_offset;
1062 iov.
iov_len = total_header_len + payload_len;
1072 }
else if (sent == -1) {
1074 HELPER_LOG(
"Socket write failed with errno %d", errno);
1093 int err =
socket_->shutdown(how);
1096 if (how == SHUT_RDWR) {
1103template APIError APIFrameHelper::write_raw_<APIPlaintextFrameHelper::State>(
1104 const struct iovec *iov,
int iovcnt,
socket::Socket *socket, std::vector<uint8_t> &tx_buf_,
const std::string &info,
const std::string & get_name() const
Get the name of this Application set by pre_setup().
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)
uint8_t frame_header_padding_
uint8_t frame_footer_size_
APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) override
NoiseCipherState * send_cipher_
APIError read_packet(ReadPacketBuffer *buffer) override
NoiseCipherState * recv_cipher_
APIError try_read_frame_(ParsedFrame *frame)
Read a packet into the rx_buf_.
enum esphome::api::APINoiseFrameHelper::State state_
~APINoiseFrameHelper() override
std::vector< uint8_t > prologue_
APIError state_action_()
To be called from read/write methods.
APIError write_frame_(const uint8_t *data, size_t len)
bool can_write_without_blocking() override
APIError loop() override
Run through handshake messages (if in that phase)
std::vector< uint8_t > tx_buf_
NoiseHandshakeState * handshake_
APIError close() override
uint8_t rx_header_buf_[3]
std::shared_ptr< APINoiseContext > ctx_
APIError write_raw_(const struct iovec *iov, int iovcnt)
APIError try_send_tx_buf_()
APIError init() override
Initialize the frame helper, returns OK if successful.
std::unique_ptr< socket::Socket > socket_
APIError check_handshake_finished_()
void send_explicit_handshake_reject_(const std::string &reason)
size_t rx_header_buf_len_
APIError init_handshake_()
Initiate the data structures for the handshake.
std::vector< uint8_t > rx_buf_
APIError shutdown(int how) override
std::vector< uint8_t > rx_buf_
enum esphome::api::APIPlaintextFrameHelper::State state_
APIError init() override
Initialize the frame helper, returns OK if successful.
bool can_write_without_blocking() override
std::vector< uint8_t > tx_buf_
std::unique_ptr< socket::Socket > socket_
APIError loop() override
Not used for plaintext.
APIError try_send_tx_buf_()
APIError read_packet(ReadPacketBuffer *buffer) override
APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) override
APIError shutdown(int how) override
uint8_t rx_header_buf_pos_
uint8_t rx_header_buf_[5]
uint32_t rx_header_parsed_type_
APIError close() override
APIError try_read_frame_(ParsedFrame *frame)
Read a packet into the rx_buf_.
uint32_t rx_header_parsed_len_
APIError write_raw_(const struct iovec *iov, int iovcnt)
static uint32_t varint(uint32_t value)
ProtoSize class for Protocol Buffer serialization size calculation.
Representation of a VarInt - in ProtoBuf should be 64bit but we only use 32bit.
void encode_to_buffer_unchecked(uint8_t *buffer, size_t len)
Encode the varint value to a pre-allocated buffer without bounds checking.
static optional< ProtoVarInt > parse(const uint8_t *buffer, uint32_t len, uint32_t *consumed)
std::vector< uint8_t > * get_buffer() const
@ HANDSHAKESTATE_READ_FAILED
@ HANDSHAKESTATE_BAD_STATE
@ HANDSHAKESTATE_SPLIT_FAILED
@ BAD_HANDSHAKE_PACKET_LEN
@ BAD_HANDSHAKE_ERROR_BYTE
@ HANDSHAKESTATE_SETUP_FAILED
@ CIPHERSTATE_ENCRYPT_FAILED
@ CIPHERSTATE_DECRYPT_FAILED
@ HANDSHAKESTATE_WRITE_FAILED
void noise_rand_bytes(void *output, size_t len)
std::string noise_err_to_str(int err)
Convert a noise error code to a readable error.
bool is_would_block(ssize_t ret)
Is the given return value (from write syscalls) a wouldblock error?
const char * api_error_to_str(APIError err)
Providing packet encoding functions for exchanging data with a remote host.
bool random_bytes(uint8_t *data, size_t len)
Generate len number of random bytes.
std::string to_string(int value)
std::string get_mac_address()
Get the device MAC address as a string, in lowercase hex notation.
Application App
Global storage of Application pointer - only one Application can exist.
std::string format_hex_pretty(const uint8_t *data, size_t length)
Format the byte array data of length len in pretty-printed, human-readable hex.
std::vector< uint8_t > msg
std::vector< uint8_t > msg
std::vector< uint8_t > container