ESPHome  2022.9.1
api_frame_helper.cpp
Go to the documentation of this file.
1 #include "api_frame_helper.h"
2 
3 #include "esphome/core/log.h"
4 #include "esphome/core/hal.h"
5 #include "esphome/core/helpers.h"
7 #include "proto.h"
8 #include <cstring>
9 
10 namespace esphome {
11 namespace api {
12 
13 static const char *const TAG = "api.socket";
14 
16 bool is_would_block(ssize_t ret) {
17  if (ret == -1) {
18  return errno == EWOULDBLOCK || errno == EAGAIN;
19  }
20  return ret == 0;
21 }
22 
23 const char *api_error_to_str(APIError err) {
24  // not using switch to ensure compiler doesn't try to build a big table out of it
25  if (err == APIError::OK) {
26  return "OK";
27  } else if (err == APIError::WOULD_BLOCK) {
28  return "WOULD_BLOCK";
29  } else if (err == APIError::BAD_HANDSHAKE_PACKET_LEN) {
30  return "BAD_HANDSHAKE_PACKET_LEN";
31  } else if (err == APIError::BAD_INDICATOR) {
32  return "BAD_INDICATOR";
33  } else if (err == APIError::BAD_DATA_PACKET) {
34  return "BAD_DATA_PACKET";
35  } else if (err == APIError::TCP_NODELAY_FAILED) {
36  return "TCP_NODELAY_FAILED";
37  } else if (err == APIError::TCP_NONBLOCKING_FAILED) {
38  return "TCP_NONBLOCKING_FAILED";
39  } else if (err == APIError::CLOSE_FAILED) {
40  return "CLOSE_FAILED";
41  } else if (err == APIError::SHUTDOWN_FAILED) {
42  return "SHUTDOWN_FAILED";
43  } else if (err == APIError::BAD_STATE) {
44  return "BAD_STATE";
45  } else if (err == APIError::BAD_ARG) {
46  return "BAD_ARG";
47  } else if (err == APIError::SOCKET_READ_FAILED) {
48  return "SOCKET_READ_FAILED";
49  } else if (err == APIError::SOCKET_WRITE_FAILED) {
50  return "SOCKET_WRITE_FAILED";
51  } else if (err == APIError::HANDSHAKESTATE_READ_FAILED) {
52  return "HANDSHAKESTATE_READ_FAILED";
53  } else if (err == APIError::HANDSHAKESTATE_WRITE_FAILED) {
54  return "HANDSHAKESTATE_WRITE_FAILED";
55  } else if (err == APIError::HANDSHAKESTATE_BAD_STATE) {
56  return "HANDSHAKESTATE_BAD_STATE";
57  } else if (err == APIError::CIPHERSTATE_DECRYPT_FAILED) {
58  return "CIPHERSTATE_DECRYPT_FAILED";
59  } else if (err == APIError::CIPHERSTATE_ENCRYPT_FAILED) {
60  return "CIPHERSTATE_ENCRYPT_FAILED";
61  } else if (err == APIError::OUT_OF_MEMORY) {
62  return "OUT_OF_MEMORY";
63  } else if (err == APIError::HANDSHAKESTATE_SETUP_FAILED) {
64  return "HANDSHAKESTATE_SETUP_FAILED";
65  } else if (err == APIError::HANDSHAKESTATE_SPLIT_FAILED) {
66  return "HANDSHAKESTATE_SPLIT_FAILED";
67  } else if (err == APIError::BAD_HANDSHAKE_ERROR_BYTE) {
68  return "BAD_HANDSHAKE_ERROR_BYTE";
69  } else if (err == APIError::CONNECTION_CLOSED) {
70  return "CONNECTION_CLOSED";
71  }
72  return "UNKNOWN";
73 }
74 
75 #define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s: " msg, info_.c_str(), ##__VA_ARGS__)
76 // uncomment to log raw packets
77 //#define HELPER_LOG_PACKETS
78 
79 #ifdef USE_API_NOISE
80 static const char *const PROLOGUE_INIT = "NoiseAPIInit";
81 
83 std::string noise_err_to_str(int err) {
84  if (err == NOISE_ERROR_NO_MEMORY)
85  return "NO_MEMORY";
86  if (err == NOISE_ERROR_UNKNOWN_ID)
87  return "UNKNOWN_ID";
88  if (err == NOISE_ERROR_UNKNOWN_NAME)
89  return "UNKNOWN_NAME";
90  if (err == NOISE_ERROR_MAC_FAILURE)
91  return "MAC_FAILURE";
92  if (err == NOISE_ERROR_NOT_APPLICABLE)
93  return "NOT_APPLICABLE";
94  if (err == NOISE_ERROR_SYSTEM)
95  return "SYSTEM";
96  if (err == NOISE_ERROR_REMOTE_KEY_REQUIRED)
97  return "REMOTE_KEY_REQUIRED";
98  if (err == NOISE_ERROR_LOCAL_KEY_REQUIRED)
99  return "LOCAL_KEY_REQUIRED";
100  if (err == NOISE_ERROR_PSK_REQUIRED)
101  return "PSK_REQUIRED";
102  if (err == NOISE_ERROR_INVALID_LENGTH)
103  return "INVALID_LENGTH";
104  if (err == NOISE_ERROR_INVALID_PARAM)
105  return "INVALID_PARAM";
106  if (err == NOISE_ERROR_INVALID_STATE)
107  return "INVALID_STATE";
108  if (err == NOISE_ERROR_INVALID_NONCE)
109  return "INVALID_NONCE";
110  if (err == NOISE_ERROR_INVALID_PRIVATE_KEY)
111  return "INVALID_PRIVATE_KEY";
112  if (err == NOISE_ERROR_INVALID_PUBLIC_KEY)
113  return "INVALID_PUBLIC_KEY";
114  if (err == NOISE_ERROR_INVALID_FORMAT)
115  return "INVALID_FORMAT";
116  if (err == NOISE_ERROR_INVALID_SIGNATURE)
117  return "INVALID_SIGNATURE";
118  return to_string(err);
119 }
120 
123  if (state_ != State::INITIALIZE || socket_ == nullptr) {
124  HELPER_LOG("Bad state for init %d", (int) state_);
125  return APIError::BAD_STATE;
126  }
127  int err = socket_->setblocking(false);
128  if (err != 0) {
130  HELPER_LOG("Setting nonblocking failed with errno %d", errno);
132  }
133 
134  int enable = 1;
135  err = socket_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(int));
136  if (err != 0) {
138  HELPER_LOG("Setting nodelay failed with errno %d", errno);
140  }
141 
142  // init prologue
143  prologue_.insert(prologue_.end(), PROLOGUE_INIT, PROLOGUE_INIT + strlen(PROLOGUE_INIT));
144 
146  return APIError::OK;
147 }
150  APIError err = state_action_();
151  if (err == APIError::WOULD_BLOCK)
152  return APIError::OK;
153  if (err != APIError::OK)
154  return err;
155  if (!tx_buf_.empty()) {
156  err = try_send_tx_buf_();
157  if (err != APIError::OK) {
158  return err;
159  }
160  }
161  return APIError::OK;
162 }
163 
179  if (frame == nullptr) {
180  HELPER_LOG("Bad argument for try_read_frame_");
181  return APIError::BAD_ARG;
182  }
183 
184  // read header
185  if (rx_header_buf_len_ < 3) {
186  // no header information yet
187  size_t to_read = 3 - rx_header_buf_len_;
188  ssize_t received = socket_->read(&rx_header_buf_[rx_header_buf_len_], to_read);
189  if (received == -1) {
190  if (errno == EWOULDBLOCK || errno == EAGAIN) {
191  return APIError::WOULD_BLOCK;
192  }
194  HELPER_LOG("Socket read failed with errno %d", errno);
196  } else if (received == 0) {
198  HELPER_LOG("Connection closed");
200  }
201  rx_header_buf_len_ += received;
202  if ((size_t) received != to_read) {
203  // not a full read
204  return APIError::WOULD_BLOCK;
205  }
206 
207  // header reading done
208  }
209 
210  // read body
211  uint8_t indicator = rx_header_buf_[0];
212  if (indicator != 0x01) {
214  HELPER_LOG("Bad indicator byte %u", indicator);
216  }
217 
218  uint16_t msg_size = (((uint16_t) rx_header_buf_[1]) << 8) | rx_header_buf_[2];
219 
220  if (state_ != State::DATA && msg_size > 128) {
221  // for handshake message only permit up to 128 bytes
223  HELPER_LOG("Bad packet len for handshake: %d", msg_size);
225  }
226 
227  // reserve space for body
228  if (rx_buf_.size() != msg_size) {
229  rx_buf_.resize(msg_size);
230  }
231 
232  if (rx_buf_len_ < msg_size) {
233  // more data to read
234  size_t to_read = msg_size - rx_buf_len_;
235  ssize_t received = socket_->read(&rx_buf_[rx_buf_len_], to_read);
236  if (received == -1) {
237  if (errno == EWOULDBLOCK || errno == EAGAIN) {
238  return APIError::WOULD_BLOCK;
239  }
241  HELPER_LOG("Socket read failed with errno %d", errno);
243  } else if (received == 0) {
245  HELPER_LOG("Connection closed");
247  }
248  rx_buf_len_ += received;
249  if ((size_t) received != to_read) {
250  // not all read
251  return APIError::WOULD_BLOCK;
252  }
253  }
254 
255  // uncomment for even more debugging
256 #ifdef HELPER_LOG_PACKETS
257  ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(rx_buf_).c_str());
258 #endif
259  frame->msg = std::move(rx_buf_);
260  // consume msg
261  rx_buf_ = {};
262  rx_buf_len_ = 0;
263  rx_header_buf_len_ = 0;
264  return APIError::OK;
265 }
266 
277  int err;
278  APIError aerr;
279  if (state_ == State::INITIALIZE) {
280  HELPER_LOG("Bad state for method: %d", (int) state_);
281  return APIError::BAD_STATE;
282  }
283  if (state_ == State::CLIENT_HELLO) {
284  // waiting for client hello
285  ParsedFrame frame;
286  aerr = try_read_frame_(&frame);
287  if (aerr == APIError::BAD_INDICATOR) {
288  send_explicit_handshake_reject_("Bad indicator byte");
289  return aerr;
290  }
292  send_explicit_handshake_reject_("Bad handshake packet len");
293  return aerr;
294  }
295  if (aerr != APIError::OK)
296  return aerr;
297  // ignore contents, may be used in future for flags
298  prologue_.push_back((uint8_t)(frame.msg.size() >> 8));
299  prologue_.push_back((uint8_t) frame.msg.size());
300  prologue_.insert(prologue_.end(), frame.msg.begin(), frame.msg.end());
301 
303  }
304  if (state_ == State::SERVER_HELLO) {
305  // send server hello
306  std::vector<uint8_t> msg;
307  // chosen proto
308  msg.push_back(0x01);
309 
310  // node name, terminated by null byte
311  const std::string &name = App.get_name();
312  const uint8_t *name_ptr = reinterpret_cast<const uint8_t *>(name.c_str());
313  msg.insert(msg.end(), name_ptr, name_ptr + name.size() + 1);
314 
315  aerr = write_frame_(msg.data(), msg.size());
316  if (aerr != APIError::OK)
317  return aerr;
318 
319  // start handshake
320  aerr = init_handshake_();
321  if (aerr != APIError::OK)
322  return aerr;
323 
325  }
326  if (state_ == State::HANDSHAKE) {
327  int action = noise_handshakestate_get_action(handshake_);
328  if (action == NOISE_ACTION_READ_MESSAGE) {
329  // waiting for handshake msg
330  ParsedFrame frame;
331  aerr = try_read_frame_(&frame);
332  if (aerr == APIError::BAD_INDICATOR) {
333  send_explicit_handshake_reject_("Bad indicator byte");
334  return aerr;
335  }
337  send_explicit_handshake_reject_("Bad handshake packet len");
338  return aerr;
339  }
340  if (aerr != APIError::OK)
341  return aerr;
342 
343  if (frame.msg.empty()) {
344  send_explicit_handshake_reject_("Empty handshake message");
346  } else if (frame.msg[0] != 0x00) {
347  HELPER_LOG("Bad handshake error byte: %u", frame.msg[0]);
348  send_explicit_handshake_reject_("Bad handshake error byte");
350  }
351 
352  NoiseBuffer mbuf;
353  noise_buffer_init(mbuf);
354  noise_buffer_set_input(mbuf, frame.msg.data() + 1, frame.msg.size() - 1);
355  err = noise_handshakestate_read_message(handshake_, &mbuf, nullptr);
356  if (err != 0) {
358  HELPER_LOG("noise_handshakestate_read_message failed: %s", noise_err_to_str(err).c_str());
359  if (err == NOISE_ERROR_MAC_FAILURE) {
360  send_explicit_handshake_reject_("Handshake MAC failure");
361  } else {
362  send_explicit_handshake_reject_("Handshake error");
363  }
365  }
366 
367  aerr = check_handshake_finished_();
368  if (aerr != APIError::OK)
369  return aerr;
370  } else if (action == NOISE_ACTION_WRITE_MESSAGE) {
371  uint8_t buffer[65];
372  NoiseBuffer mbuf;
373  noise_buffer_init(mbuf);
374  noise_buffer_set_output(mbuf, buffer + 1, sizeof(buffer) - 1);
375 
376  err = noise_handshakestate_write_message(handshake_, &mbuf, nullptr);
377  if (err != 0) {
379  HELPER_LOG("noise_handshakestate_write_message failed: %s", noise_err_to_str(err).c_str());
381  }
382  buffer[0] = 0x00; // success
383 
384  aerr = write_frame_(buffer, mbuf.size + 1);
385  if (aerr != APIError::OK)
386  return aerr;
387  aerr = check_handshake_finished_();
388  if (aerr != APIError::OK)
389  return aerr;
390  } else {
391  // bad state for action
393  HELPER_LOG("Bad action for handshake: %d", action);
395  }
396  }
397  if (state_ == State::CLOSED || state_ == State::FAILED) {
398  return APIError::BAD_STATE;
399  }
400  return APIError::OK;
401 }
403  std::vector<uint8_t> data;
404  data.resize(reason.length() + 1);
405  data[0] = 0x01; // failure
406  for (size_t i = 0; i < reason.length(); i++) {
407  data[i + 1] = (uint8_t) reason[i];
408  }
409  // temporarily remove failed state
410  auto orig_state = state_;
412  write_frame_(data.data(), data.size());
413  state_ = orig_state;
414 }
415 
417  int err;
418  APIError aerr;
419  aerr = state_action_();
420  if (aerr != APIError::OK) {
421  return aerr;
422  }
423 
424  if (state_ != State::DATA) {
425  return APIError::WOULD_BLOCK;
426  }
427 
428  ParsedFrame frame;
429  aerr = try_read_frame_(&frame);
430  if (aerr != APIError::OK)
431  return aerr;
432 
433  NoiseBuffer mbuf;
434  noise_buffer_init(mbuf);
435  noise_buffer_set_inout(mbuf, frame.msg.data(), frame.msg.size(), frame.msg.size());
436  err = noise_cipherstate_decrypt(recv_cipher_, &mbuf);
437  if (err != 0) {
439  HELPER_LOG("noise_cipherstate_decrypt failed: %s", noise_err_to_str(err).c_str());
441  }
442 
443  size_t msg_size = mbuf.size;
444  uint8_t *msg_data = frame.msg.data();
445  if (msg_size < 4) {
447  HELPER_LOG("Bad data packet: size %d too short", msg_size);
449  }
450 
451  // uint16_t type;
452  // uint16_t data_len;
453  // uint8_t *data;
454  // uint8_t *padding; zero or more bytes to fill up the rest of the packet
455  uint16_t type = (((uint16_t) msg_data[0]) << 8) | msg_data[1];
456  uint16_t data_len = (((uint16_t) msg_data[2]) << 8) | msg_data[3];
457  if (data_len > msg_size - 4) {
459  HELPER_LOG("Bad data packet: data_len %u greater than msg_size %u", data_len, msg_size);
461  }
462 
463  buffer->container = std::move(frame.msg);
464  buffer->data_offset = 4;
465  buffer->data_len = data_len;
466  buffer->type = type;
467  return APIError::OK;
468 }
470 APIError APINoiseFrameHelper::write_packet(uint16_t type, const uint8_t *payload, size_t payload_len) {
471  int err;
472  APIError aerr;
473  aerr = state_action_();
474  if (aerr != APIError::OK) {
475  return aerr;
476  }
477 
478  if (state_ != State::DATA) {
479  return APIError::WOULD_BLOCK;
480  }
481 
482  size_t padding = 0;
483  size_t msg_len = 4 + payload_len + padding;
484  size_t frame_len = 3 + msg_len + noise_cipherstate_get_mac_length(send_cipher_);
485  auto tmpbuf = std::unique_ptr<uint8_t[]>{new (std::nothrow) uint8_t[frame_len]};
486  if (tmpbuf == nullptr) {
487  HELPER_LOG("Could not allocate for writing packet");
489  }
490 
491  tmpbuf[0] = 0x01; // indicator
492  // tmpbuf[1], tmpbuf[2] to be set later
493  const uint8_t msg_offset = 3;
494  const uint8_t payload_offset = msg_offset + 4;
495  tmpbuf[msg_offset + 0] = (uint8_t)(type >> 8); // type
496  tmpbuf[msg_offset + 1] = (uint8_t) type;
497  tmpbuf[msg_offset + 2] = (uint8_t)(payload_len >> 8); // data_len
498  tmpbuf[msg_offset + 3] = (uint8_t) payload_len;
499  // copy data
500  std::copy(payload, payload + payload_len, &tmpbuf[payload_offset]);
501  // fill padding with zeros
502  std::fill(&tmpbuf[payload_offset + payload_len], &tmpbuf[frame_len], 0);
503 
504  NoiseBuffer mbuf;
505  noise_buffer_init(mbuf);
506  noise_buffer_set_inout(mbuf, &tmpbuf[msg_offset], msg_len, frame_len - msg_offset);
507  err = noise_cipherstate_encrypt(send_cipher_, &mbuf);
508  if (err != 0) {
510  HELPER_LOG("noise_cipherstate_encrypt failed: %s", noise_err_to_str(err).c_str());
512  }
513 
514  size_t total_len = 3 + mbuf.size;
515  tmpbuf[1] = (uint8_t)(mbuf.size >> 8);
516  tmpbuf[2] = (uint8_t) mbuf.size;
517 
518  struct iovec iov;
519  iov.iov_base = &tmpbuf[0];
520  iov.iov_len = total_len;
521 
522  // write raw to not have two packets sent if NAGLE disabled
523  return write_raw_(&iov, 1);
524 }
526  // try send from tx_buf
527  while (state_ != State::CLOSED && !tx_buf_.empty()) {
528  ssize_t sent = socket_->write(tx_buf_.data(), tx_buf_.size());
529  if (sent == -1) {
530  if (errno == EWOULDBLOCK || errno == EAGAIN)
531  break;
533  HELPER_LOG("Socket write failed with errno %d", errno);
535  } else if (sent == 0) {
536  break;
537  }
538  // TODO: inefficient if multiple packets in txbuf
539  // replace with deque of buffers
540  tx_buf_.erase(tx_buf_.begin(), tx_buf_.begin() + sent);
541  }
542 
543  return APIError::OK;
544 }
550 APIError APINoiseFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) {
551  if (iovcnt == 0)
552  return APIError::OK;
553  APIError aerr;
554 
555  size_t total_write_len = 0;
556  for (int i = 0; i < iovcnt; i++) {
557 #ifdef HELPER_LOG_PACKETS
558  ESP_LOGVV(TAG, "Sending raw: %s",
559  format_hex_pretty(reinterpret_cast<uint8_t *>(iov[i].iov_base), iov[i].iov_len).c_str());
560 #endif
561  total_write_len += iov[i].iov_len;
562  }
563 
564  if (!tx_buf_.empty()) {
565  // try to empty tx_buf_ first
566  aerr = try_send_tx_buf_();
567  if (aerr != APIError::OK && aerr != APIError::WOULD_BLOCK)
568  return aerr;
569  }
570 
571  if (!tx_buf_.empty()) {
572  // tx buf not empty, can't write now because then stream would be inconsistent
573  for (int i = 0; i < iovcnt; i++) {
574  tx_buf_.insert(tx_buf_.end(), reinterpret_cast<uint8_t *>(iov[i].iov_base),
575  reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].iov_len);
576  }
577  return APIError::OK;
578  }
579 
580  ssize_t sent = socket_->writev(iov, iovcnt);
581  if (is_would_block(sent)) {
582  // operation would block, add buffer to tx_buf
583  for (int i = 0; i < iovcnt; i++) {
584  tx_buf_.insert(tx_buf_.end(), reinterpret_cast<uint8_t *>(iov[i].iov_base),
585  reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].iov_len);
586  }
587  return APIError::OK;
588  } else if (sent == -1) {
589  // an error occurred
591  HELPER_LOG("Socket write failed with errno %d", errno);
593  } else if ((size_t) sent != total_write_len) {
594  // partially sent, add end to tx_buf
595  size_t to_consume = sent;
596  for (int i = 0; i < iovcnt; i++) {
597  if (to_consume >= iov[i].iov_len) {
598  to_consume -= iov[i].iov_len;
599  } else {
600  tx_buf_.insert(tx_buf_.end(), reinterpret_cast<uint8_t *>(iov[i].iov_base) + to_consume,
601  reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].iov_len);
602  to_consume = 0;
603  }
604  }
605  return APIError::OK;
606  }
607  // fully sent
608  return APIError::OK;
609 }
610 APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, size_t len) {
611  uint8_t header[3];
612  header[0] = 0x01; // indicator
613  header[1] = (uint8_t)(len >> 8);
614  header[2] = (uint8_t) len;
615 
616  struct iovec iov[2];
617  iov[0].iov_base = header;
618  iov[0].iov_len = 3;
619  iov[1].iov_base = const_cast<uint8_t *>(data);
620  iov[1].iov_len = len;
621 
622  return write_raw_(iov, 2);
623 }
624 
630  int err;
631  memset(&nid_, 0, sizeof(nid_));
632  // const char *proto = "Noise_NNpsk0_25519_ChaChaPoly_SHA256";
633  // err = noise_protocol_name_to_id(&nid_, proto, strlen(proto));
634  nid_.pattern_id = NOISE_PATTERN_NN;
635  nid_.cipher_id = NOISE_CIPHER_CHACHAPOLY;
636  nid_.dh_id = NOISE_DH_CURVE25519;
637  nid_.prefix_id = NOISE_PREFIX_STANDARD;
638  nid_.hybrid_id = NOISE_DH_NONE;
639  nid_.hash_id = NOISE_HASH_SHA256;
640  nid_.modifier_ids[0] = NOISE_MODIFIER_PSK0;
641 
642  err = noise_handshakestate_new_by_id(&handshake_, &nid_, NOISE_ROLE_RESPONDER);
643  if (err != 0) {
645  HELPER_LOG("noise_handshakestate_new_by_id failed: %s", noise_err_to_str(err).c_str());
647  }
648 
649  const auto &psk = ctx_->get_psk();
650  err = noise_handshakestate_set_pre_shared_key(handshake_, psk.data(), psk.size());
651  if (err != 0) {
653  HELPER_LOG("noise_handshakestate_set_pre_shared_key failed: %s", noise_err_to_str(err).c_str());
655  }
656 
657  err = noise_handshakestate_set_prologue(handshake_, prologue_.data(), prologue_.size());
658  if (err != 0) {
660  HELPER_LOG("noise_handshakestate_set_prologue failed: %s", noise_err_to_str(err).c_str());
662  }
663  // set_prologue copies it into handshakestate, so we can get rid of it now
664  prologue_ = {};
665 
666  err = noise_handshakestate_start(handshake_);
667  if (err != 0) {
669  HELPER_LOG("noise_handshakestate_start failed: %s", noise_err_to_str(err).c_str());
671  }
672  return APIError::OK;
673 }
674 
676  assert(state_ == State::HANDSHAKE);
677 
678  int action = noise_handshakestate_get_action(handshake_);
679  if (action == NOISE_ACTION_READ_MESSAGE || action == NOISE_ACTION_WRITE_MESSAGE)
680  return APIError::OK;
681  if (action != NOISE_ACTION_SPLIT) {
683  HELPER_LOG("Bad action for handshake: %d", action);
685  }
686  int err = noise_handshakestate_split(handshake_, &send_cipher_, &recv_cipher_);
687  if (err != 0) {
689  HELPER_LOG("noise_handshakestate_split failed: %s", noise_err_to_str(err).c_str());
691  }
692 
693  HELPER_LOG("Handshake complete!");
694  noise_handshakestate_free(handshake_);
695  handshake_ = nullptr;
697  return APIError::OK;
698 }
699 
701  if (handshake_ != nullptr) {
702  noise_handshakestate_free(handshake_);
703  handshake_ = nullptr;
704  }
705  if (send_cipher_ != nullptr) {
706  noise_cipherstate_free(send_cipher_);
707  send_cipher_ = nullptr;
708  }
709  if (recv_cipher_ != nullptr) {
710  noise_cipherstate_free(recv_cipher_);
711  recv_cipher_ = nullptr;
712  }
713 }
714 
717  int err = socket_->close();
718  if (err == -1)
719  return APIError::CLOSE_FAILED;
720  return APIError::OK;
721 }
723  int err = socket_->shutdown(how);
724  if (err == -1)
726  if (how == SHUT_RDWR) {
728  }
729  return APIError::OK;
730 }
731 extern "C" {
732 // declare how noise generates random bytes (here with a good HWRNG based on the RF system)
733 void noise_rand_bytes(void *output, size_t len) {
734  if (!esphome::random_bytes(reinterpret_cast<uint8_t *>(output), len)) {
735  ESP_LOGE(TAG, "Failed to acquire random bytes, rebooting!");
736  arch_restart();
737  }
738 }
739 }
740 #endif // USE_API_NOISE
741 
742 #ifdef USE_API_PLAINTEXT
743 
746  if (state_ != State::INITIALIZE || socket_ == nullptr) {
747  HELPER_LOG("Bad state for init %d", (int) state_);
748  return APIError::BAD_STATE;
749  }
750  int err = socket_->setblocking(false);
751  if (err != 0) {
753  HELPER_LOG("Setting nonblocking failed with errno %d", errno);
755  }
756  int enable = 1;
757  err = socket_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(int));
758  if (err != 0) {
760  HELPER_LOG("Setting nodelay failed with errno %d", errno);
762  }
763 
765  return APIError::OK;
766 }
769  if (state_ != State::DATA) {
770  return APIError::BAD_STATE;
771  }
772  // try send pending TX data
773  if (!tx_buf_.empty()) {
774  APIError err = try_send_tx_buf_();
775  if (err != APIError::OK) {
776  return err;
777  }
778  }
779  return APIError::OK;
780 }
781 
792  if (frame == nullptr) {
793  HELPER_LOG("Bad argument for try_read_frame_");
794  return APIError::BAD_ARG;
795  }
796 
797  // read header
798  while (!rx_header_parsed_) {
799  uint8_t data;
800  ssize_t received = socket_->read(&data, 1);
801  if (received == -1) {
802  if (errno == EWOULDBLOCK || errno == EAGAIN) {
803  return APIError::WOULD_BLOCK;
804  }
806  HELPER_LOG("Socket read failed with errno %d", errno);
808  } else if (received == 0) {
810  HELPER_LOG("Connection closed");
812  }
813  rx_header_buf_.push_back(data);
814 
815  // try parse header
816  if (rx_header_buf_[0] != 0x00) {
818  HELPER_LOG("Bad indicator byte %u", rx_header_buf_[0]);
820  }
821 
822  size_t i = 1;
823  uint32_t consumed = 0;
824  auto msg_size_varint = ProtoVarInt::parse(&rx_header_buf_[i], rx_header_buf_.size() - i, &consumed);
825  if (!msg_size_varint.has_value()) {
826  // not enough data there yet
827  continue;
828  }
829 
830  i += consumed;
831  rx_header_parsed_len_ = msg_size_varint->as_uint32();
832 
833  auto msg_type_varint = ProtoVarInt::parse(&rx_header_buf_[i], rx_header_buf_.size() - i, &consumed);
834  if (!msg_type_varint.has_value()) {
835  // not enough data there yet
836  continue;
837  }
838  rx_header_parsed_type_ = msg_type_varint->as_uint32();
839  rx_header_parsed_ = true;
840  }
841  // header reading done
842 
843  // reserve space for body
844  if (rx_buf_.size() != rx_header_parsed_len_) {
845  rx_buf_.resize(rx_header_parsed_len_);
846  }
847 
848  if (rx_buf_len_ < rx_header_parsed_len_) {
849  // more data to read
850  size_t to_read = rx_header_parsed_len_ - rx_buf_len_;
851  ssize_t received = socket_->read(&rx_buf_[rx_buf_len_], to_read);
852  if (received == -1) {
853  if (errno == EWOULDBLOCK || errno == EAGAIN) {
854  return APIError::WOULD_BLOCK;
855  }
857  HELPER_LOG("Socket read failed with errno %d", errno);
859  } else if (received == 0) {
861  HELPER_LOG("Connection closed");
863  }
864  rx_buf_len_ += received;
865  if ((size_t) received != to_read) {
866  // not all read
867  return APIError::WOULD_BLOCK;
868  }
869  }
870 
871  // uncomment for even more debugging
872 #ifdef HELPER_LOG_PACKETS
873  ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(rx_buf_).c_str());
874 #endif
875  frame->msg = std::move(rx_buf_);
876  // consume msg
877  rx_buf_ = {};
878  rx_buf_len_ = 0;
879  rx_header_buf_.clear();
880  rx_header_parsed_ = false;
881  return APIError::OK;
882 }
883 
885  APIError aerr;
886 
887  if (state_ != State::DATA) {
888  return APIError::WOULD_BLOCK;
889  }
890 
891  ParsedFrame frame;
892  aerr = try_read_frame_(&frame);
893  if (aerr != APIError::OK)
894  return aerr;
895 
896  buffer->container = std::move(frame.msg);
897  buffer->data_offset = 0;
898  buffer->data_len = rx_header_parsed_len_;
899  buffer->type = rx_header_parsed_type_;
900  return APIError::OK;
901 }
903 APIError APIPlaintextFrameHelper::write_packet(uint16_t type, const uint8_t *payload, size_t payload_len) {
904  if (state_ != State::DATA) {
905  return APIError::BAD_STATE;
906  }
907 
908  std::vector<uint8_t> header;
909  header.push_back(0x00);
910  ProtoVarInt(payload_len).encode(header);
911  ProtoVarInt(type).encode(header);
912 
913  struct iovec iov[2];
914  iov[0].iov_base = &header[0];
915  iov[0].iov_len = header.size();
916  iov[1].iov_base = const_cast<uint8_t *>(payload);
917  iov[1].iov_len = payload_len;
918 
919  return write_raw_(iov, 2);
920 }
922  // try send from tx_buf
923  while (state_ != State::CLOSED && !tx_buf_.empty()) {
924  ssize_t sent = socket_->write(tx_buf_.data(), tx_buf_.size());
925  if (is_would_block(sent)) {
926  break;
927  } else if (sent == -1) {
929  HELPER_LOG("Socket write failed with errno %d", errno);
931  }
932  // TODO: inefficient if multiple packets in txbuf
933  // replace with deque of buffers
934  tx_buf_.erase(tx_buf_.begin(), tx_buf_.begin() + sent);
935  }
936 
937  return APIError::OK;
938 }
944 APIError APIPlaintextFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) {
945  if (iovcnt == 0)
946  return APIError::OK;
947  APIError aerr;
948 
949  size_t total_write_len = 0;
950  for (int i = 0; i < iovcnt; i++) {
951 #ifdef HELPER_LOG_PACKETS
952  ESP_LOGVV(TAG, "Sending raw: %s",
953  format_hex_pretty(reinterpret_cast<uint8_t *>(iov[i].iov_base), iov[i].iov_len).c_str());
954 #endif
955  total_write_len += iov[i].iov_len;
956  }
957 
958  if (!tx_buf_.empty()) {
959  // try to empty tx_buf_ first
960  aerr = try_send_tx_buf_();
961  if (aerr != APIError::OK && aerr != APIError::WOULD_BLOCK)
962  return aerr;
963  }
964 
965  if (!tx_buf_.empty()) {
966  // tx buf not empty, can't write now because then stream would be inconsistent
967  for (int i = 0; i < iovcnt; i++) {
968  tx_buf_.insert(tx_buf_.end(), reinterpret_cast<uint8_t *>(iov[i].iov_base),
969  reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].iov_len);
970  }
971  return APIError::OK;
972  }
973 
974  ssize_t sent = socket_->writev(iov, iovcnt);
975  if (is_would_block(sent)) {
976  // operation would block, add buffer to tx_buf
977  for (int i = 0; i < iovcnt; i++) {
978  tx_buf_.insert(tx_buf_.end(), reinterpret_cast<uint8_t *>(iov[i].iov_base),
979  reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].iov_len);
980  }
981  return APIError::OK;
982  } else if (sent == -1) {
983  // an error occurred
985  HELPER_LOG("Socket write failed with errno %d", errno);
987  } else if ((size_t) sent != total_write_len) {
988  // partially sent, add end to tx_buf
989  size_t to_consume = sent;
990  for (int i = 0; i < iovcnt; i++) {
991  if (to_consume >= iov[i].iov_len) {
992  to_consume -= iov[i].iov_len;
993  } else {
994  tx_buf_.insert(tx_buf_.end(), reinterpret_cast<uint8_t *>(iov[i].iov_base) + to_consume,
995  reinterpret_cast<uint8_t *>(iov[i].iov_base) + iov[i].iov_len);
996  to_consume = 0;
997  }
998  }
999  return APIError::OK;
1000  }
1001  // fully sent
1002  return APIError::OK;
1003 }
1004 
1007  int err = socket_->close();
1008  if (err == -1)
1009  return APIError::CLOSE_FAILED;
1010  return APIError::OK;
1011 }
1013  int err = socket_->shutdown(how);
1014  if (err == -1)
1016  if (how == SHUT_RDWR) {
1018  }
1019  return APIError::OK;
1020 }
1021 #endif // USE_API_PLAINTEXT
1022 
1023 } // namespace api
1024 } // namespace esphome
size_t iov_len
Definition: headers.h:91
const char * name
Definition: stm32flash.h:78
APIError write_frame_(const uint8_t *data, size_t len)
void * iov_base
Definition: headers.h:90
std::shared_ptr< APINoiseContext > ctx_
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.
Definition: helpers.cpp:214
Representation of a VarInt - in ProtoBuf should be 64bit but we only use 32bit.
Definition: proto.h:15
const char * api_error_to_str(APIError err)
APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override
static optional< ProtoVarInt > parse(const uint8_t *buffer, uint32_t len, uint32_t *consumed)
Definition: proto.h:20
APIError init() override
Initialize the frame helper, returns OK if successful.
APIError write_raw_(const struct iovec *iov, int iovcnt)
Write the data to the socket, or buffer it a write would block.
bool random_bytes(uint8_t *data, size_t len)
Generate len number of random bytes.
Definition: helpers.cpp:99
std::unique_ptr< socket::Socket > socket_
APIError loop() override
Run through handshake messages (if in that phase)
APIError try_read_frame_(ParsedFrame *frame)
Read a packet into the rx_buf_.
bool is_would_block(ssize_t ret)
Is the given return value (from write syscalls) a wouldblock error?
std::vector< uint8_t > prologue_
void encode(std::vector< uint8_t > &out)
Definition: proto.h:72
APIError loop() override
Not used for plaintext.
APIError try_read_frame_(ParsedFrame *frame)
Read a packet into the rx_buf_.
uint8_t type
APIError shutdown(int how) override
std::string noise_err_to_str(int err)
Convert a noise error code to a readable error.
Application App
Global storage of Application pointer - only one Application can exist.
APIError read_packet(ReadPacketBuffer *buffer) override
const std::string & get_name() const
Get the name of this Application set by set_name().
Definition: application.h:135
void send_explicit_handshake_reject_(const std::string &reason)
void arch_restart()
Definition: core.cpp:30
Definition: headers.h:89
APIError read_packet(ReadPacketBuffer *buffer) override
enum esphome::api::APINoiseFrameHelper::State state_
APIError init() override
Initialize the frame helper, returns OK if successful.
std::string to_string(int value)
Definition: helpers.cpp:36
APIError state_action_()
To be called from read/write methods.
std::string size_t len
Definition: helpers.h:281
APIError write_raw_(const struct iovec *iov, int iovcnt)
Write the data to the socket, or buffer it a write would block.
APIError init_handshake_()
Initiate the data structures for the handshake.
APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override
Definition: a4988.cpp:4
void noise_rand_bytes(void *output, size_t len)
std::vector< uint8_t > container