From 23e0a39a2f8e6077cb481c687dd05d0096416b26 Mon Sep 17 00:00:00 2001 From: Oxan van Leeuwen Date: Wed, 22 Mar 2023 22:51:16 +0100 Subject: [PATCH] Fix handling of errors returned by writev() --- components/stream_server/stream_server.cpp | 32 +++++++++++++++++----- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/components/stream_server/stream_server.cpp b/components/stream_server/stream_server.cpp index 27c5451..e996e04 100644 --- a/components/stream_server/stream_server.cpp +++ b/components/stream_server/stream_server.cpp @@ -137,9 +137,10 @@ void StreamServerComponent::read() { } void StreamServerComponent::flush() { + ssize_t written; this->buf_tail_ = this->buf_head_; for (Client &client : this->clients_) { - if (client.position == this->buf_head_) + if (client.disconnected || client.position == this->buf_head_) continue; // Split the write into two parts: from the current position to the end of the ring buffer, and from the start @@ -149,22 +150,39 @@ void StreamServerComponent::flush() { iov[0].iov_len = std::min(this->buf_head_ - client.position, this->buf_ahead(client.position)); iov[1].iov_base = &this->buf_[0]; iov[1].iov_len = this->buf_head_ - (client.position + iov[0].iov_len); - client.position += client.socket->writev(iov, 2); + if ((written = client.socket->writev(iov, 2)) > 0) { + client.position += written; + } else if (written == 0 || errno == ECONNRESET) { + ESP_LOGD(TAG, "Client %s disconnected", client.identifier.c_str()); + client.disconnected = true; + continue; // don't consider this client when calculating the tail position + } else if (errno == EWOULDBLOCK || errno == EAGAIN) { + // Expected if the (TCP) transmit buffer is full, nothing to do. + } else { + ESP_LOGE(TAG, "Failed to write to client %s with error %d!", client.identifier.c_str(), errno); + } + this->buf_tail_ = std::min(this->buf_tail_, client.position); } } void StreamServerComponent::write() { uint8_t buf[128]; - ssize_t len; + ssize_t read; for (Client &client : this->clients_) { - while ((len = client.socket->read(&buf, sizeof(buf))) > 0) - this->stream_->write_array(buf, len); + if (client.disconnected) + continue; + + while ((read = client.socket->read(&buf, sizeof(buf))) > 0) + this->stream_->write_array(buf, read); - if (len == 0) { + if (read == 0 || errno == ECONNRESET) { ESP_LOGD(TAG, "Client %s disconnected", client.identifier.c_str()); client.disconnected = true; - continue; + } else if (errno == EWOULDBLOCK || errno == EAGAIN) { + // Expected if the (TCP) receive buffer is empty, nothing to do. + } else { + ESP_LOGW(TAG, "Failed to read from client %s with error %d!", client.identifier.c_str(), errno); } } }