ESPHome  2022.9.1
api_frame_helper.h
Go to the documentation of this file.
1 #pragma once
2 #include <cstdint>
3 #include <deque>
4 #include <utility>
5 #include <vector>
6 
7 #include "esphome/core/defines.h"
8 
9 #ifdef USE_API_NOISE
10 #include "noise/protocol.h"
11 #endif
12 
14 #include "api_noise_context.h"
15 
16 namespace esphome {
17 namespace api {
18 
20  std::vector<uint8_t> container;
21  uint16_t type;
22  size_t data_offset;
23  size_t data_len;
24 };
25 
26 struct PacketBuffer {
27  const std::vector<uint8_t> container;
28  uint16_t type;
29  uint8_t data_offset;
30  uint8_t data_len;
31 };
32 
33 enum class APIError : int {
34  OK = 0,
35  WOULD_BLOCK = 1001,
37  BAD_INDICATOR = 1003,
38  BAD_DATA_PACKET = 1004,
39  TCP_NODELAY_FAILED = 1005,
41  CLOSE_FAILED = 1007,
42  SHUTDOWN_FAILED = 1008,
43  BAD_STATE = 1009,
44  BAD_ARG = 1010,
45  SOCKET_READ_FAILED = 1011,
46  SOCKET_WRITE_FAILED = 1012,
52  OUT_OF_MEMORY = 1018,
56  CONNECTION_CLOSED = 1022,
57 };
58 
59 const char *api_error_to_str(APIError err);
60 
62  public:
63  virtual ~APIFrameHelper() = default;
64  virtual APIError init() = 0;
65  virtual APIError loop() = 0;
66  virtual APIError read_packet(ReadPacketBuffer *buffer) = 0;
67  virtual bool can_write_without_blocking() = 0;
68  virtual APIError write_packet(uint16_t type, const uint8_t *data, size_t len) = 0;
69  virtual std::string getpeername() = 0;
70  virtual APIError close() = 0;
71  virtual APIError shutdown(int how) = 0;
72  // Give this helper a name for logging
73  virtual void set_log_info(std::string info) = 0;
74 };
75 
76 #ifdef USE_API_NOISE
78  public:
79  APINoiseFrameHelper(std::unique_ptr<socket::Socket> socket, std::shared_ptr<APINoiseContext> ctx)
80  : socket_(std::move(socket)), ctx_(std::move(std::move(ctx))) {}
81  ~APINoiseFrameHelper() override;
82  APIError init() override;
83  APIError loop() override;
84  APIError read_packet(ReadPacketBuffer *buffer) override;
85  bool can_write_without_blocking() override;
86  APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override;
87  std::string getpeername() override { return socket_->getpeername(); }
88  APIError close() override;
89  APIError shutdown(int how) override;
90  // Give this helper a name for logging
91  void set_log_info(std::string info) override { info_ = std::move(info); }
92 
93  protected:
94  struct ParsedFrame {
95  std::vector<uint8_t> msg;
96  };
97 
98  APIError state_action_();
99  APIError try_read_frame_(ParsedFrame *frame);
100  APIError try_send_tx_buf_();
101  APIError write_frame_(const uint8_t *data, size_t len);
102  APIError write_raw_(const struct iovec *iov, int iovcnt);
103  APIError init_handshake_();
104  APIError check_handshake_finished_();
105  void send_explicit_handshake_reject_(const std::string &reason);
106 
107  std::unique_ptr<socket::Socket> socket_;
108 
109  std::string info_;
110  uint8_t rx_header_buf_[3];
111  size_t rx_header_buf_len_ = 0;
112  std::vector<uint8_t> rx_buf_;
113  size_t rx_buf_len_ = 0;
114 
115  std::vector<uint8_t> tx_buf_;
116  std::vector<uint8_t> prologue_;
117 
118  std::shared_ptr<APINoiseContext> ctx_;
119  NoiseHandshakeState *handshake_{nullptr};
120  NoiseCipherState *send_cipher_{nullptr};
121  NoiseCipherState *recv_cipher_{nullptr};
122  NoiseProtocolId nid_;
123 
124  enum class State {
125  INITIALIZE = 1,
126  CLIENT_HELLO = 2,
127  SERVER_HELLO = 3,
128  HANDSHAKE = 4,
129  DATA = 5,
130  CLOSED = 6,
131  FAILED = 7,
132  EXPLICIT_REJECT = 8,
133  } state_ = State::INITIALIZE;
134 };
135 #endif // USE_API_NOISE
136 
137 #ifdef USE_API_PLAINTEXT
139  public:
140  APIPlaintextFrameHelper(std::unique_ptr<socket::Socket> socket) : socket_(std::move(socket)) {}
141  ~APIPlaintextFrameHelper() override = default;
142  APIError init() override;
143  APIError loop() override;
144  APIError read_packet(ReadPacketBuffer *buffer) override;
145  bool can_write_without_blocking() override;
146  APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override;
147  std::string getpeername() override { return socket_->getpeername(); }
148  APIError close() override;
149  APIError shutdown(int how) override;
150  // Give this helper a name for logging
151  void set_log_info(std::string info) override { info_ = std::move(info); }
152 
153  protected:
154  struct ParsedFrame {
155  std::vector<uint8_t> msg;
156  };
157 
158  APIError try_read_frame_(ParsedFrame *frame);
159  APIError try_send_tx_buf_();
160  APIError write_raw_(const struct iovec *iov, int iovcnt);
161 
162  std::unique_ptr<socket::Socket> socket_;
163 
164  std::string info_;
165  std::vector<uint8_t> rx_header_buf_;
166  bool rx_header_parsed_ = false;
167  uint32_t rx_header_parsed_type_ = 0;
168  uint32_t rx_header_parsed_len_ = 0;
169 
170  std::vector<uint8_t> rx_buf_;
171  size_t rx_buf_len_ = 0;
172 
173  std::vector<uint8_t> tx_buf_;
174 
175  enum class State {
176  INITIALIZE = 1,
177  DATA = 2,
178  CLOSED = 3,
179  FAILED = 4,
180  } state_ = State::INITIALIZE;
181 };
182 #endif
183 
184 } // namespace api
185 } // namespace esphome
void loop()
std::shared_ptr< APINoiseContext > ctx_
std::string getpeername() override
const char * api_error_to_str(APIError err)
STL namespace.
std::unique_ptr< socket::Socket > socket_
std::vector< uint8_t > prologue_
void set_log_info(std::string info) override
void set_log_info(std::string info) override
Definition: headers.h:89
std::string size_t len
Definition: helpers.h:281
std::unique_ptr< socket::Socket > socket_
Definition: a4988.cpp:4
void init()
Definition: core.cpp:85
std::vector< uint8_t > container
APIPlaintextFrameHelper(std::unique_ptr< socket::Socket > socket)
APINoiseFrameHelper(std::unique_ptr< socket::Socket > socket, std::shared_ptr< APINoiseContext > ctx)
const std::vector< uint8_t > container
std::unique_ptr< Socket > socket(int domain, int type, int protocol)
Create a socket of the given domain, type and protocol.