mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Fix API socket issues (#2288)
* Fix API socket issues * Fix compile error against beta * Format
This commit is contained in:
		| @@ -36,19 +36,14 @@ void APIConnection::start() { | |||||||
|  |  | ||||||
|   APIError err = helper_->init(); |   APIError err = helper_->init(); | ||||||
|   if (err != APIError::OK) { |   if (err != APIError::OK) { | ||||||
|     ESP_LOGW(TAG, "Helper init failed: %d errno=%d", (int) err, errno); |     on_fatal_error(); | ||||||
|     remove_ = true; |     ESP_LOGW(TAG, "%s: Helper init failed: %s errno=%d", client_info_.c_str(), api_error_to_str(err), errno); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   client_info_ = helper_->getpeername(); |   client_info_ = helper_->getpeername(); | ||||||
|   helper_->set_log_info(client_info_); |   helper_->set_log_info(client_info_); | ||||||
| } | } | ||||||
|  |  | ||||||
| void APIConnection::force_disconnect_client() { |  | ||||||
|   this->helper_->close(); |  | ||||||
|   this->remove_ = true; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void APIConnection::loop() { | void APIConnection::loop() { | ||||||
|   if (this->remove_) |   if (this->remove_) | ||||||
|     return; |     return; | ||||||
| @@ -57,9 +52,11 @@ void APIConnection::loop() { | |||||||
|     // when network is disconnected force disconnect immediately |     // when network is disconnected force disconnect immediately | ||||||
|     // don't wait for timeout |     // don't wait for timeout | ||||||
|     this->on_fatal_error(); |     this->on_fatal_error(); | ||||||
|  |     ESP_LOGW(TAG, "%s: Network unavailable, disconnecting", client_info_.c_str()); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   if (this->next_close_) { |   if (this->next_close_) { | ||||||
|  |     // requested a disconnect | ||||||
|     this->helper_->close(); |     this->helper_->close(); | ||||||
|     this->remove_ = true; |     this->remove_ = true; | ||||||
|     return; |     return; | ||||||
| @@ -68,7 +65,7 @@ void APIConnection::loop() { | |||||||
|   APIError err = helper_->loop(); |   APIError err = helper_->loop(); | ||||||
|   if (err != APIError::OK) { |   if (err != APIError::OK) { | ||||||
|     on_fatal_error(); |     on_fatal_error(); | ||||||
|     ESP_LOGW(TAG, "%s: Socket operation failed: %d", client_info_.c_str(), (int) err); |     ESP_LOGW(TAG, "%s: Socket operation failed: %s errno=%d", client_info_.c_str(), api_error_to_str(err), errno); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   ReadPacketBuffer buffer; |   ReadPacketBuffer buffer; | ||||||
| @@ -77,7 +74,11 @@ void APIConnection::loop() { | |||||||
|     // pass |     // pass | ||||||
|   } else if (err != APIError::OK) { |   } else if (err != APIError::OK) { | ||||||
|     on_fatal_error(); |     on_fatal_error(); | ||||||
|     ESP_LOGW(TAG, "%s: Reading failed: %d", client_info_.c_str(), (int) err); |     if (err == APIError::SOCKET_READ_FAILED && errno == ECONNRESET) { | ||||||
|  |       ESP_LOGW(TAG, "%s: Connection reset", client_info_.c_str()); | ||||||
|  |     } else { | ||||||
|  |       ESP_LOGW(TAG, "%s: Reading failed: %s errno=%d", client_info_.c_str(), api_error_to_str(err), errno); | ||||||
|  |     } | ||||||
|     return; |     return; | ||||||
|   } else { |   } else { | ||||||
|     this->last_traffic_ = millis(); |     this->last_traffic_ = millis(); | ||||||
| @@ -95,8 +96,8 @@ void APIConnection::loop() { | |||||||
|   if (this->sent_ping_) { |   if (this->sent_ping_) { | ||||||
|     // Disconnect if not responded within 2.5*keepalive |     // Disconnect if not responded within 2.5*keepalive | ||||||
|     if (now - this->last_traffic_ > (keepalive * 5) / 2) { |     if (now - this->last_traffic_ > (keepalive * 5) / 2) { | ||||||
|       this->force_disconnect_client(); |       on_fatal_error(); | ||||||
|       ESP_LOGW(TAG, "'%s' didn't respond to ping request in time. Disconnecting...", this->client_info_.c_str()); |       ESP_LOGW(TAG, "%s didn't respond to ping request in time. Disconnecting...", this->client_info_.c_str()); | ||||||
|     } |     } | ||||||
|   } else if (now - this->last_traffic_ > keepalive) { |   } else if (now - this->last_traffic_ > keepalive) { | ||||||
|     this->sent_ping_ = true; |     this->sent_ping_ = true; | ||||||
| @@ -124,12 +125,40 @@ void APIConnection::loop() { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |   if (state_subs_at_ != -1) { | ||||||
|  |     const auto &subs = this->parent_->get_state_subs(); | ||||||
|  |     if (state_subs_at_ >= subs.size()) { | ||||||
|  |       state_subs_at_ = -1; | ||||||
|  |     } else { | ||||||
|  |       auto &it = subs[state_subs_at_]; | ||||||
|  |       SubscribeHomeAssistantStateResponse resp; | ||||||
|  |       resp.entity_id = it.entity_id; | ||||||
|  |       resp.attribute = it.attribute.value(); | ||||||
|  |       if (this->send_subscribe_home_assistant_state_response(resp)) { | ||||||
|  |         state_subs_at_++; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| std::string get_default_unique_id(const std::string &component_type, Nameable *nameable) { | std::string get_default_unique_id(const std::string &component_type, Nameable *nameable) { | ||||||
|   return App.get_name() + component_type + nameable->get_object_id(); |   return App.get_name() + component_type + nameable->get_object_id(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | DisconnectResponse APIConnection::disconnect(const DisconnectRequest &msg) { | ||||||
|  |   // remote initiated disconnect_client | ||||||
|  |   // don't close yet, we still need to send the disconnect response | ||||||
|  |   // close will happen on next loop | ||||||
|  |   ESP_LOGD(TAG, "%s requested disconnected", client_info_.c_str()); | ||||||
|  |   this->next_close_ = true; | ||||||
|  |   DisconnectResponse resp; | ||||||
|  |   return resp; | ||||||
|  | } | ||||||
|  | void APIConnection::on_disconnect_response(const DisconnectResponse &value) { | ||||||
|  |   // pass | ||||||
|  | } | ||||||
|  |  | ||||||
| #ifdef USE_BINARY_SENSOR | #ifdef USE_BINARY_SENSOR | ||||||
| bool APIConnection::send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor, bool state) { | bool APIConnection::send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor, bool state) { | ||||||
|   if (!this->state_subscription_) |   if (!this->state_subscription_) | ||||||
| @@ -703,7 +732,7 @@ ConnectResponse APIConnection::connect(const ConnectRequest &msg) { | |||||||
|   // bool invalid_password = 1; |   // bool invalid_password = 1; | ||||||
|   resp.invalid_password = !correct; |   resp.invalid_password = !correct; | ||||||
|   if (correct) { |   if (correct) { | ||||||
|     ESP_LOGD(TAG, "Client '%s' connected successfully!", this->client_info_.c_str()); |     ESP_LOGD(TAG, "%s: Connected successfully", this->client_info_.c_str()); | ||||||
|     this->connection_state_ = ConnectionState::AUTHENTICATED; |     this->connection_state_ = ConnectionState::AUTHENTICATED; | ||||||
|  |  | ||||||
| #ifdef USE_HOMEASSISTANT_TIME | #ifdef USE_HOMEASSISTANT_TIME | ||||||
| @@ -749,15 +778,7 @@ void APIConnection::execute_service(const ExecuteServiceRequest &msg) { | |||||||
|   } |   } | ||||||
| } | } | ||||||
| void APIConnection::subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) { | void APIConnection::subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) { | ||||||
|   for (auto &it : this->parent_->get_state_subs()) { |   state_subs_at_ = 0; | ||||||
|     SubscribeHomeAssistantStateResponse resp; |  | ||||||
|     resp.entity_id = it.entity_id; |  | ||||||
|     resp.attribute = it.attribute.value(); |  | ||||||
|     if (!this->send_subscribe_home_assistant_state_response(resp)) { |  | ||||||
|       this->on_fatal_error(); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } | } | ||||||
| bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) { | bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) { | ||||||
|   if (this->remove_) |   if (this->remove_) | ||||||
| @@ -770,7 +791,11 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) | |||||||
|     return false; |     return false; | ||||||
|   if (err != APIError::OK) { |   if (err != APIError::OK) { | ||||||
|     on_fatal_error(); |     on_fatal_error(); | ||||||
|     ESP_LOGW(TAG, "%s: Packet write failed %d errno=%d", client_info_.c_str(), (int) err, errno); |     if (err == APIError::SOCKET_WRITE_FAILED && errno == ECONNRESET) { | ||||||
|  |       ESP_LOGW(TAG, "%s: Connection reset", client_info_.c_str()); | ||||||
|  |     } else { | ||||||
|  |       ESP_LOGW(TAG, "%s: Packet write failed %s errno=%d", client_info_.c_str(), api_error_to_str(err), errno); | ||||||
|  |     } | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
|   this->last_traffic_ = millis(); |   this->last_traffic_ = millis(); | ||||||
| @@ -778,14 +803,13 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) | |||||||
| } | } | ||||||
| void APIConnection::on_unauthenticated_access() { | void APIConnection::on_unauthenticated_access() { | ||||||
|   this->on_fatal_error(); |   this->on_fatal_error(); | ||||||
|   ESP_LOGD(TAG, "'%s' tried to access without authentication.", this->client_info_.c_str()); |   ESP_LOGD(TAG, "%s: tried to access without authentication.", this->client_info_.c_str()); | ||||||
| } | } | ||||||
| void APIConnection::on_no_setup_connection() { | void APIConnection::on_no_setup_connection() { | ||||||
|   this->on_fatal_error(); |   this->on_fatal_error(); | ||||||
|   ESP_LOGD(TAG, "'%s' tried to access without full connection.", this->client_info_.c_str()); |   ESP_LOGD(TAG, "%s: tried to access without full connection.", this->client_info_.c_str()); | ||||||
| } | } | ||||||
| void APIConnection::on_fatal_error() { | void APIConnection::on_fatal_error() { | ||||||
|   ESP_LOGV(TAG, "Error: Disconnecting %s", this->client_info_.c_str()); |  | ||||||
|   this->helper_->close(); |   this->helper_->close(); | ||||||
|   this->remove_ = true; |   this->remove_ = true; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -16,7 +16,6 @@ class APIConnection : public APIServerConnection { | |||||||
|   virtual ~APIConnection() = default; |   virtual ~APIConnection() = default; | ||||||
|  |  | ||||||
|   void start(); |   void start(); | ||||||
|   void force_disconnect_client(); |  | ||||||
|   void loop(); |   void loop(); | ||||||
|  |  | ||||||
|   bool send_list_info_done() { |   bool send_list_info_done() { | ||||||
| @@ -88,10 +87,7 @@ class APIConnection : public APIServerConnection { | |||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   void on_disconnect_response(const DisconnectResponse &value) override { |   void on_disconnect_response(const DisconnectResponse &value) override; | ||||||
|     this->helper_->close(); |  | ||||||
|     this->remove_ = true; |  | ||||||
|   } |  | ||||||
|   void on_ping_response(const PingResponse &value) override { |   void on_ping_response(const PingResponse &value) override { | ||||||
|     // we initiated ping |     // we initiated ping | ||||||
|     this->sent_ping_ = false; |     this->sent_ping_ = false; | ||||||
| @@ -102,14 +98,7 @@ class APIConnection : public APIServerConnection { | |||||||
| #endif | #endif | ||||||
|   HelloResponse hello(const HelloRequest &msg) override; |   HelloResponse hello(const HelloRequest &msg) override; | ||||||
|   ConnectResponse connect(const ConnectRequest &msg) override; |   ConnectResponse connect(const ConnectRequest &msg) override; | ||||||
|   DisconnectResponse disconnect(const DisconnectRequest &msg) override { |   DisconnectResponse disconnect(const DisconnectRequest &msg) override; | ||||||
|     // remote initiated disconnect_client |  | ||||||
|     // don't close yet, we still need to send the disconnect response |  | ||||||
|     // close will happen on next loop |  | ||||||
|     this->next_close_ = true; |  | ||||||
|     DisconnectResponse resp; |  | ||||||
|     return resp; |  | ||||||
|   } |  | ||||||
|   PingResponse ping(const PingRequest &msg) override { return {}; } |   PingResponse ping(const PingRequest &msg) override { return {}; } | ||||||
|   DeviceInfoResponse device_info(const DeviceInfoRequest &msg) override; |   DeviceInfoResponse device_info(const DeviceInfoRequest &msg) override; | ||||||
|   void list_entities(const ListEntitiesRequest &msg) override { this->list_entities_iterator_.begin(); } |   void list_entities(const ListEntitiesRequest &msg) override { this->list_entities_iterator_.begin(); } | ||||||
| @@ -177,6 +166,7 @@ class APIConnection : public APIServerConnection { | |||||||
|   APIServer *parent_; |   APIServer *parent_; | ||||||
|   InitialStateIterator initial_state_iterator_; |   InitialStateIterator initial_state_iterator_; | ||||||
|   ListEntitiesIterator list_entities_iterator_; |   ListEntitiesIterator list_entities_iterator_; | ||||||
|  |   int state_subs_at_ = -1; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace api | }  // namespace api | ||||||
|   | |||||||
| @@ -17,6 +17,54 @@ bool is_would_block(ssize_t ret) { | |||||||
|   return ret == 0; |   return ret == 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | const char *api_error_to_str(APIError err) { | ||||||
|  |   // not using switch to ensure compiler doesn't try to build a big table out of it | ||||||
|  |   if (err == APIError::OK) { | ||||||
|  |     return "OK"; | ||||||
|  |   } else if (err == APIError::WOULD_BLOCK) { | ||||||
|  |     return "WOULD_BLOCK"; | ||||||
|  |   } else if (err == APIError::BAD_HANDSHAKE_PACKET_LEN) { | ||||||
|  |     return "BAD_HANDSHAKE_PACKET_LEN"; | ||||||
|  |   } else if (err == APIError::BAD_INDICATOR) { | ||||||
|  |     return "BAD_INDICATOR"; | ||||||
|  |   } else if (err == APIError::BAD_DATA_PACKET) { | ||||||
|  |     return "BAD_DATA_PACKET"; | ||||||
|  |   } else if (err == APIError::TCP_NODELAY_FAILED) { | ||||||
|  |     return "TCP_NODELAY_FAILED"; | ||||||
|  |   } else if (err == APIError::TCP_NONBLOCKING_FAILED) { | ||||||
|  |     return "TCP_NONBLOCKING_FAILED"; | ||||||
|  |   } else if (err == APIError::CLOSE_FAILED) { | ||||||
|  |     return "CLOSE_FAILED"; | ||||||
|  |   } else if (err == APIError::SHUTDOWN_FAILED) { | ||||||
|  |     return "SHUTDOWN_FAILED"; | ||||||
|  |   } else if (err == APIError::BAD_STATE) { | ||||||
|  |     return "BAD_STATE"; | ||||||
|  |   } else if (err == APIError::BAD_ARG) { | ||||||
|  |     return "BAD_ARG"; | ||||||
|  |   } else if (err == APIError::SOCKET_READ_FAILED) { | ||||||
|  |     return "SOCKET_READ_FAILED"; | ||||||
|  |   } else if (err == APIError::SOCKET_WRITE_FAILED) { | ||||||
|  |     return "SOCKET_WRITE_FAILED"; | ||||||
|  |   } else if (err == APIError::HANDSHAKESTATE_READ_FAILED) { | ||||||
|  |     return "HANDSHAKESTATE_READ_FAILED"; | ||||||
|  |   } else if (err == APIError::HANDSHAKESTATE_WRITE_FAILED) { | ||||||
|  |     return "HANDSHAKESTATE_WRITE_FAILED"; | ||||||
|  |   } else if (err == APIError::HANDSHAKESTATE_BAD_STATE) { | ||||||
|  |     return "HANDSHAKESTATE_BAD_STATE"; | ||||||
|  |   } else if (err == APIError::CIPHERSTATE_DECRYPT_FAILED) { | ||||||
|  |     return "CIPHERSTATE_DECRYPT_FAILED"; | ||||||
|  |   } else if (err == APIError::CIPHERSTATE_ENCRYPT_FAILED) { | ||||||
|  |     return "CIPHERSTATE_ENCRYPT_FAILED"; | ||||||
|  |   } else if (err == APIError::OUT_OF_MEMORY) { | ||||||
|  |     return "OUT_OF_MEMORY"; | ||||||
|  |   } else if (err == APIError::HANDSHAKESTATE_SETUP_FAILED) { | ||||||
|  |     return "HANDSHAKESTATE_SETUP_FAILED"; | ||||||
|  |   } else if (err == APIError::HANDSHAKESTATE_SPLIT_FAILED) { | ||||||
|  |     return "HANDSHAKESTATE_SPLIT_FAILED"; | ||||||
|  |   } | ||||||
|  |   return "UNKNOWN"; | ||||||
|  | } | ||||||
|  |  | ||||||
| #define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s: " msg, info_.c_str(), ##__VA_ARGS__) | #define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s: " msg, info_.c_str(), ##__VA_ARGS__) | ||||||
|  |  | ||||||
| #ifdef USE_API_NOISE | #ifdef USE_API_NOISE | ||||||
| @@ -808,14 +856,12 @@ APIError APIPlaintextFrameHelper::try_send_tx_buf_() { | |||||||
|   // try send from tx_buf |   // try send from tx_buf | ||||||
|   while (state_ != State::CLOSED && !tx_buf_.empty()) { |   while (state_ != State::CLOSED && !tx_buf_.empty()) { | ||||||
|     ssize_t sent = socket_->write(tx_buf_.data(), tx_buf_.size()); |     ssize_t sent = socket_->write(tx_buf_.data(), tx_buf_.size()); | ||||||
|     if (sent == -1) { |     if (is_would_block(sent)) { | ||||||
|       if (errno == EWOULDBLOCK || errno == EAGAIN) |  | ||||||
|       break; |       break; | ||||||
|  |     } else if (sent == -1) { | ||||||
|       state_ = State::FAILED; |       state_ = State::FAILED; | ||||||
|       HELPER_LOG("Socket write failed with errno %d", errno); |       HELPER_LOG("Socket write failed with errno %d", errno); | ||||||
|       return APIError::SOCKET_WRITE_FAILED; |       return APIError::SOCKET_WRITE_FAILED; | ||||||
|     } else if (sent == 0) { |  | ||||||
|       break; |  | ||||||
|     } |     } | ||||||
|     // TODO: inefficient if multiple packets in txbuf |     // TODO: inefficient if multiple packets in txbuf | ||||||
|     // replace with deque of buffers |     // replace with deque of buffers | ||||||
| @@ -869,20 +915,6 @@ APIError APIPlaintextFrameHelper::write_raw_(const uint8_t *data, size_t len) { | |||||||
|   // fully sent |   // fully sent | ||||||
|   return APIError::OK; |   return APIError::OK; | ||||||
| } | } | ||||||
| APIError APIPlaintextFrameHelper::write_frame_(const uint8_t *data, size_t len) { |  | ||||||
|   APIError aerr; |  | ||||||
|  |  | ||||||
|   uint8_t header[3]; |  | ||||||
|   header[0] = 0x01;  // indicator |  | ||||||
|   header[1] = (uint8_t)(len >> 8); |  | ||||||
|   header[2] = (uint8_t) len; |  | ||||||
|  |  | ||||||
|   aerr = write_raw_(header, 3); |  | ||||||
|   if (aerr != APIError::OK) |  | ||||||
|     return aerr; |  | ||||||
|   aerr = write_raw_(data, len); |  | ||||||
|   return aerr; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| APIError APIPlaintextFrameHelper::close() { | APIError APIPlaintextFrameHelper::close() { | ||||||
|   state_ = State::CLOSED; |   state_ = State::CLOSED; | ||||||
|   | |||||||
| @@ -53,6 +53,8 @@ enum class APIError : int { | |||||||
|   HANDSHAKESTATE_SPLIT_FAILED = 1020, |   HANDSHAKESTATE_SPLIT_FAILED = 1020, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | const char *api_error_to_str(APIError err); | ||||||
|  |  | ||||||
| class APIFrameHelper { | class APIFrameHelper { | ||||||
|  public: |  public: | ||||||
|   virtual APIError init() = 0; |   virtual APIError init() = 0; | ||||||
| @@ -150,7 +152,6 @@ class APIPlaintextFrameHelper : public APIFrameHelper { | |||||||
|  |  | ||||||
|   APIError try_read_frame_(ParsedFrame *frame); |   APIError try_read_frame_(ParsedFrame *frame); | ||||||
|   APIError try_send_tx_buf_(); |   APIError try_send_tx_buf_(); | ||||||
|   APIError write_frame_(const uint8_t *data, size_t len); |  | ||||||
|   APIError write_raw_(const uint8_t *data, size_t len); |   APIError write_raw_(const uint8_t *data, size_t len); | ||||||
|  |  | ||||||
|   std::unique_ptr<socket::Socket> socket_; |   std::unique_ptr<socket::Socket> socket_; | ||||||
|   | |||||||
| @@ -105,7 +105,7 @@ void APIServer::loop() { | |||||||
|                                 [](const std::unique_ptr<APIConnection> &conn) { return !conn->remove_; }); |                                 [](const std::unique_ptr<APIConnection> &conn) { return !conn->remove_; }); | ||||||
|   // print disconnection messages |   // print disconnection messages | ||||||
|   for (auto it = new_end; it != this->clients_.end(); ++it) { |   for (auto it = new_end; it != this->clients_.end(); ++it) { | ||||||
|     ESP_LOGD(TAG, "Disconnecting %s", (*it)->client_info_.c_str()); |     ESP_LOGV(TAG, "Removing connection to %s", (*it)->client_info_.c_str()); | ||||||
|   } |   } | ||||||
|   // resize vector |   // resize vector | ||||||
|   this->clients_.erase(new_end, this->clients_.end()); |   this->clients_.erase(new_end, this->clients_.end()); | ||||||
|   | |||||||
| @@ -109,14 +109,17 @@ class LWIPRawImpl : public Socket { | |||||||
|     LWIP_LOG("tcp_bind(%p ip=%u port=%u)", pcb_, ip.addr, port); |     LWIP_LOG("tcp_bind(%p ip=%u port=%u)", pcb_, ip.addr, port); | ||||||
|     err_t err = tcp_bind(pcb_, &ip, port); |     err_t err = tcp_bind(pcb_, &ip, port); | ||||||
|     if (err == ERR_USE) { |     if (err == ERR_USE) { | ||||||
|  |       LWIP_LOG("  -> err ERR_USE"); | ||||||
|       errno = EADDRINUSE; |       errno = EADDRINUSE; | ||||||
|       return -1; |       return -1; | ||||||
|     } |     } | ||||||
|     if (err == ERR_VAL) { |     if (err == ERR_VAL) { | ||||||
|  |       LWIP_LOG("  -> err ERR_VAL"); | ||||||
|       errno = EINVAL; |       errno = EINVAL; | ||||||
|       return -1; |       return -1; | ||||||
|     } |     } | ||||||
|     if (err != ERR_OK) { |     if (err != ERR_OK) { | ||||||
|  |       LWIP_LOG("  -> err %d", err); | ||||||
|       errno = EIO; |       errno = EIO; | ||||||
|       return -1; |       return -1; | ||||||
|     } |     } | ||||||
| @@ -124,12 +127,13 @@ class LWIPRawImpl : public Socket { | |||||||
|   } |   } | ||||||
|   int close() override { |   int close() override { | ||||||
|     if (pcb_ == nullptr) { |     if (pcb_ == nullptr) { | ||||||
|       errno = EBADF; |       errno = ECONNRESET; | ||||||
|       return -1; |       return -1; | ||||||
|     } |     } | ||||||
|     LWIP_LOG("tcp_close(%p)", pcb_); |     LWIP_LOG("tcp_close(%p)", pcb_); | ||||||
|     err_t err = tcp_close(pcb_); |     err_t err = tcp_close(pcb_); | ||||||
|     if (err != ERR_OK) { |     if (err != ERR_OK) { | ||||||
|  |       LWIP_LOG("  -> err %d", err); | ||||||
|       tcp_abort(pcb_); |       tcp_abort(pcb_); | ||||||
|       pcb_ = nullptr; |       pcb_ = nullptr; | ||||||
|       errno = err == ERR_MEM ? ENOMEM : EIO; |       errno = err == ERR_MEM ? ENOMEM : EIO; | ||||||
| @@ -140,7 +144,7 @@ class LWIPRawImpl : public Socket { | |||||||
|   } |   } | ||||||
|   int shutdown(int how) override { |   int shutdown(int how) override { | ||||||
|     if (pcb_ == nullptr) { |     if (pcb_ == nullptr) { | ||||||
|       errno = EBADF; |       errno = ECONNRESET; | ||||||
|       return -1; |       return -1; | ||||||
|     } |     } | ||||||
|     bool shut_rx = false, shut_tx = false; |     bool shut_rx = false, shut_tx = false; | ||||||
| @@ -157,6 +161,7 @@ class LWIPRawImpl : public Socket { | |||||||
|     LWIP_LOG("tcp_shutdown(%p shut_rx=%d shut_tx=%d)", pcb_, shut_rx ? 1 : 0, shut_tx ? 1 : 0); |     LWIP_LOG("tcp_shutdown(%p shut_rx=%d shut_tx=%d)", pcb_, shut_rx ? 1 : 0, shut_tx ? 1 : 0); | ||||||
|     err_t err = tcp_shutdown(pcb_, shut_rx, shut_tx); |     err_t err = tcp_shutdown(pcb_, shut_rx, shut_tx); | ||||||
|     if (err != ERR_OK) { |     if (err != ERR_OK) { | ||||||
|  |       LWIP_LOG("  -> err %d", err); | ||||||
|       errno = err == ERR_MEM ? ENOMEM : EIO; |       errno = err == ERR_MEM ? ENOMEM : EIO; | ||||||
|       return -1; |       return -1; | ||||||
|     } |     } | ||||||
| @@ -165,7 +170,7 @@ class LWIPRawImpl : public Socket { | |||||||
|  |  | ||||||
|   int getpeername(struct sockaddr *name, socklen_t *addrlen) override { |   int getpeername(struct sockaddr *name, socklen_t *addrlen) override { | ||||||
|     if (pcb_ == nullptr) { |     if (pcb_ == nullptr) { | ||||||
|       errno = EBADF; |       errno = ECONNRESET; | ||||||
|       return -1; |       return -1; | ||||||
|     } |     } | ||||||
|     if (name == nullptr || addrlen == nullptr) { |     if (name == nullptr || addrlen == nullptr) { | ||||||
| @@ -185,7 +190,7 @@ class LWIPRawImpl : public Socket { | |||||||
|   } |   } | ||||||
|   std::string getpeername() override { |   std::string getpeername() override { | ||||||
|     if (pcb_ == nullptr) { |     if (pcb_ == nullptr) { | ||||||
|       errno = EBADF; |       errno = ECONNRESET; | ||||||
|       return ""; |       return ""; | ||||||
|     } |     } | ||||||
|     char buffer[24]; |     char buffer[24]; | ||||||
| @@ -196,7 +201,7 @@ class LWIPRawImpl : public Socket { | |||||||
|   } |   } | ||||||
|   int getsockname(struct sockaddr *name, socklen_t *addrlen) override { |   int getsockname(struct sockaddr *name, socklen_t *addrlen) override { | ||||||
|     if (pcb_ == nullptr) { |     if (pcb_ == nullptr) { | ||||||
|       errno = EBADF; |       errno = ECONNRESET; | ||||||
|       return -1; |       return -1; | ||||||
|     } |     } | ||||||
|     if (name == nullptr || addrlen == nullptr) { |     if (name == nullptr || addrlen == nullptr) { | ||||||
| @@ -216,7 +221,7 @@ class LWIPRawImpl : public Socket { | |||||||
|   } |   } | ||||||
|   std::string getsockname() override { |   std::string getsockname() override { | ||||||
|     if (pcb_ == nullptr) { |     if (pcb_ == nullptr) { | ||||||
|       errno = EBADF; |       errno = ECONNRESET; | ||||||
|       return ""; |       return ""; | ||||||
|     } |     } | ||||||
|     char buffer[24]; |     char buffer[24]; | ||||||
| @@ -227,7 +232,7 @@ class LWIPRawImpl : public Socket { | |||||||
|   } |   } | ||||||
|   int getsockopt(int level, int optname, void *optval, socklen_t *optlen) override { |   int getsockopt(int level, int optname, void *optval, socklen_t *optlen) override { | ||||||
|     if (pcb_ == nullptr) { |     if (pcb_ == nullptr) { | ||||||
|       errno = EBADF; |       errno = ECONNRESET; | ||||||
|       return -1; |       return -1; | ||||||
|     } |     } | ||||||
|     if (optlen == nullptr || optval == nullptr) { |     if (optlen == nullptr || optval == nullptr) { | ||||||
| @@ -261,7 +266,7 @@ class LWIPRawImpl : public Socket { | |||||||
|   } |   } | ||||||
|   int setsockopt(int level, int optname, const void *optval, socklen_t optlen) override { |   int setsockopt(int level, int optname, const void *optval, socklen_t optlen) override { | ||||||
|     if (pcb_ == nullptr) { |     if (pcb_ == nullptr) { | ||||||
|       errno = EBADF; |       errno = ECONNRESET; | ||||||
|       return -1; |       return -1; | ||||||
|     } |     } | ||||||
|     if (level == SOL_SOCKET && optname == SO_REUSEADDR) { |     if (level == SOL_SOCKET && optname == SO_REUSEADDR) { | ||||||
| @@ -314,7 +319,7 @@ class LWIPRawImpl : public Socket { | |||||||
|   } |   } | ||||||
|   ssize_t read(void *buf, size_t len) override { |   ssize_t read(void *buf, size_t len) override { | ||||||
|     if (pcb_ == nullptr) { |     if (pcb_ == nullptr) { | ||||||
|       errno = EBADF; |       errno = ECONNRESET; | ||||||
|       return -1; |       return -1; | ||||||
|     } |     } | ||||||
|     if (rx_closed_ && rx_buf_ == nullptr) { |     if (rx_closed_ && rx_buf_ == nullptr) { | ||||||
| @@ -368,7 +373,7 @@ class LWIPRawImpl : public Socket { | |||||||
|   } |   } | ||||||
|   ssize_t write(const void *buf, size_t len) override { |   ssize_t write(const void *buf, size_t len) override { | ||||||
|     if (pcb_ == nullptr) { |     if (pcb_ == nullptr) { | ||||||
|       errno = EBADF; |       errno = ECONNRESET; | ||||||
|       return -1; |       return -1; | ||||||
|     } |     } | ||||||
|     if (len == 0) |     if (len == 0) | ||||||
| @@ -386,24 +391,37 @@ class LWIPRawImpl : public Socket { | |||||||
|     LWIP_LOG("tcp_write(%p buf=%p %u)", pcb_, buf, to_send); |     LWIP_LOG("tcp_write(%p buf=%p %u)", pcb_, buf, to_send); | ||||||
|     err_t err = tcp_write(pcb_, buf, to_send, TCP_WRITE_FLAG_COPY); |     err_t err = tcp_write(pcb_, buf, to_send, TCP_WRITE_FLAG_COPY); | ||||||
|     if (err == ERR_MEM) { |     if (err == ERR_MEM) { | ||||||
|  |       LWIP_LOG("  -> err ERR_MEM"); | ||||||
|       errno = EWOULDBLOCK; |       errno = EWOULDBLOCK; | ||||||
|       return -1; |       return -1; | ||||||
|     } |     } | ||||||
|     if (err != ERR_OK) { |     if (err != ERR_OK) { | ||||||
|       errno = EIO; |       LWIP_LOG("  -> err %d", err); | ||||||
|  |       errno = ECONNRESET; | ||||||
|       return -1; |       return -1; | ||||||
|     } |     } | ||||||
|  |     if (tcp_nagle_disabled(pcb_)) { | ||||||
|       LWIP_LOG("tcp_output(%p)", pcb_); |       LWIP_LOG("tcp_output(%p)", pcb_); | ||||||
|       err = tcp_output(pcb_); |       err = tcp_output(pcb_); | ||||||
|  |       if (err == ERR_ABRT) { | ||||||
|  |         LWIP_LOG("  -> err ERR_ABRT"); | ||||||
|  |         // sometimes lwip returns ERR_ABRT for no apparent reason | ||||||
|  |         // the connection works fine afterwards, and back with ESPAsyncTCP we | ||||||
|  |         // indirectly also ignored this error | ||||||
|  |         // FIXME: figure out where this is returned and what it means in this context | ||||||
|  |         return to_send; | ||||||
|  |       } | ||||||
|       if (err != ERR_OK) { |       if (err != ERR_OK) { | ||||||
|       errno = EIO; |         LWIP_LOG("  -> err %d", err); | ||||||
|  |         errno = ECONNRESET; | ||||||
|         return -1; |         return -1; | ||||||
|       } |       } | ||||||
|  |     } | ||||||
|     return to_send; |     return to_send; | ||||||
|   } |   } | ||||||
|   int setblocking(bool blocking) override { |   int setblocking(bool blocking) override { | ||||||
|     if (pcb_ == nullptr) { |     if (pcb_ == nullptr) { | ||||||
|       errno = EBADF; |       errno = ECONNRESET; | ||||||
|       return -1; |       return -1; | ||||||
|     } |     } | ||||||
|     if (blocking) { |     if (blocking) { | ||||||
| @@ -466,7 +484,7 @@ class LWIPRawImpl : public Socket { | |||||||
|  |  | ||||||
|   static void s_err_fn(void *arg, err_t err) { |   static void s_err_fn(void *arg, err_t err) { | ||||||
|     LWIPRawImpl *arg_this = reinterpret_cast<LWIPRawImpl *>(arg); |     LWIPRawImpl *arg_this = reinterpret_cast<LWIPRawImpl *>(arg); | ||||||
|     return arg_this->err_fn(err); |     arg_this->err_fn(err); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   static err_t s_recv_fn(void *arg, struct tcp_pcb *pcb, struct pbuf *pb, err_t err) { |   static err_t s_recv_fn(void *arg, struct tcp_pcb *pcb, struct pbuf *pb, err_t err) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user