ESPHome  2024.11.0
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 #ifdef USE_API
9 #ifdef USE_API_NOISE
10 #include "noise/protocol.h"
11 #endif
12 
13 #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 int getpeername(struct sockaddr *addr, socklen_t *addrlen) = 0;
71  virtual APIError close() = 0;
72  virtual APIError shutdown(int how) = 0;
73  // Give this helper a name for logging
74  virtual void set_log_info(std::string info) = 0;
75 };
76 
77 #ifdef USE_API_NOISE
79  public:
80  APINoiseFrameHelper(std::unique_ptr<socket::Socket> socket, std::shared_ptr<APINoiseContext> ctx)
81  : socket_(std::move(socket)), ctx_(std::move(std::move(ctx))) {}
82  ~APINoiseFrameHelper() override;
83  APIError init() override;
84  APIError loop() override;
85  APIError read_packet(ReadPacketBuffer *buffer) override;
86  bool can_write_without_blocking() override;
87  APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override;
88  std::string getpeername() override { return this->socket_->getpeername(); }
89  int getpeername(struct sockaddr *addr, socklen_t *addrlen) override {
90  return this->socket_->getpeername(addr, addrlen);
91  }
92  APIError close() override;
93  APIError shutdown(int how) override;
94  // Give this helper a name for logging
95  void set_log_info(std::string info) override { info_ = std::move(info); }
96 
97  protected:
98  struct ParsedFrame {
99  std::vector<uint8_t> msg;
100  };
101 
102  APIError state_action_();
103  APIError try_read_frame_(ParsedFrame *frame);
104  APIError try_send_tx_buf_();
105  APIError write_frame_(const uint8_t *data, size_t len);
106  APIError write_raw_(const struct iovec *iov, int iovcnt);
107  APIError init_handshake_();
108  APIError check_handshake_finished_();
109  void send_explicit_handshake_reject_(const std::string &reason);
110 
111  std::unique_ptr<socket::Socket> socket_;
112 
113  std::string info_;
114  uint8_t rx_header_buf_[3];
115  size_t rx_header_buf_len_ = 0;
116  std::vector<uint8_t> rx_buf_;
117  size_t rx_buf_len_ = 0;
118 
119  std::vector<uint8_t> tx_buf_;
120  std::vector<uint8_t> prologue_;
121 
122  std::shared_ptr<APINoiseContext> ctx_;
123  NoiseHandshakeState *handshake_{nullptr};
124  NoiseCipherState *send_cipher_{nullptr};
125  NoiseCipherState *recv_cipher_{nullptr};
126  NoiseProtocolId nid_;
127 
128  enum class State {
129  INITIALIZE = 1,
130  CLIENT_HELLO = 2,
131  SERVER_HELLO = 3,
132  HANDSHAKE = 4,
133  DATA = 5,
134  CLOSED = 6,
135  FAILED = 7,
136  EXPLICIT_REJECT = 8,
137  } state_ = State::INITIALIZE;
138 };
139 #endif // USE_API_NOISE
140 
141 #ifdef USE_API_PLAINTEXT
143  public:
144  APIPlaintextFrameHelper(std::unique_ptr<socket::Socket> socket) : socket_(std::move(socket)) {}
145  ~APIPlaintextFrameHelper() override = default;
146  APIError init() override;
147  APIError loop() override;
148  APIError read_packet(ReadPacketBuffer *buffer) override;
149  bool can_write_without_blocking() override;
150  APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override;
151  std::string getpeername() override { return this->socket_->getpeername(); }
152  int getpeername(struct sockaddr *addr, socklen_t *addrlen) override {
153  return this->socket_->getpeername(addr, addrlen);
154  }
155  APIError close() override;
156  APIError shutdown(int how) override;
157  // Give this helper a name for logging
158  void set_log_info(std::string info) override { info_ = std::move(info); }
159 
160  protected:
161  struct ParsedFrame {
162  std::vector<uint8_t> msg;
163  };
164 
165  APIError try_read_frame_(ParsedFrame *frame);
166  APIError try_send_tx_buf_();
167  APIError write_raw_(const struct iovec *iov, int iovcnt);
168 
169  std::unique_ptr<socket::Socket> socket_;
170 
171  std::string info_;
172  std::vector<uint8_t> rx_header_buf_;
173  bool rx_header_parsed_ = false;
174  uint32_t rx_header_parsed_type_ = 0;
175  uint32_t rx_header_parsed_len_ = 0;
176 
177  std::vector<uint8_t> rx_buf_;
178  size_t rx_buf_len_ = 0;
179 
180  std::vector<uint8_t> tx_buf_;
181 
182  enum class State {
183  INITIALIZE = 1,
184  DATA = 2,
185  CLOSED = 3,
186  FAILED = 4,
187  } state_ = State::INITIALIZE;
188 };
189 #endif
190 
191 } // namespace api
192 } // namespace esphome
193 #endif
void loop()
std::shared_ptr< APINoiseContext > ctx_
std::string getpeername() override
const char * api_error_to_str(APIError err)
STL namespace.
uint32_t socklen_t
Definition: headers.h:97
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:100
int getpeername(struct sockaddr *addr, socklen_t *addrlen) override
std::string size_t len
Definition: helpers.h:293
std::unique_ptr< socket::Socket > socket_
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
void init()
Definition: core.cpp:80
std::vector< uint8_t > container
int getpeername(struct sockaddr *addr, socklen_t *addrlen) override
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.