| // Copyright 2026 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "quiche/quic/moqt/moqt_control_message_queue.h" |
| |
| #include <array> |
| #include <utility> |
| |
| #include "absl/status/status.h" |
| #include "absl/types/span.h" |
| #include "quiche/common/quiche_buffer_allocator.h" |
| #include "quiche/common/quiche_mem_slice.h" |
| #include "quiche/web_transport/stream_helpers.h" |
| #include "quiche/web_transport/web_transport.h" |
| |
| namespace moqt { |
| |
| absl::Status MoqtControlMessageQueue::OnCanWrite() { |
| if (stream_ == nullptr) { |
| return absl::InternalError("OnCanWrite() called when no stream is bound"); |
| } |
| if (pending_messages_.empty() && fin_queued_) { |
| return webtransport::SendFinOnStream(*stream_); |
| } |
| while (!pending_messages_.empty() && stream_->CanWrite()) { |
| absl::Status status = |
| SendMessage(*stream_, std::move(pending_messages_.front()), |
| fin_queued_ && pending_messages_.size() == 1); |
| pending_messages_.pop_front(); |
| if (!status.ok()) { |
| return status; |
| } |
| } |
| return absl::OkStatus(); |
| } |
| |
| absl::Status MoqtControlMessageQueue::SendOrBufferMessage( |
| quiche::QuicheBuffer message, bool fin) { |
| if (fin_queued_) { |
| return absl::InternalError( |
| "Trying to send data when a FIN has been already queued"); |
| } |
| if (stream_ == nullptr || !stream_->CanWrite()) { |
| fin_queued_ = fin; |
| return AddToQueue(std::move(message)); |
| } |
| return SendMessage(*stream_, std::move(message), fin); |
| } |
| |
| absl::Status MoqtControlMessageQueue::Fin() { |
| fin_queued_ = true; |
| if (stream_ != nullptr) { |
| return OnCanWrite(); |
| } |
| return absl::OkStatus(); |
| } |
| |
| absl::Status MoqtControlMessageQueue::AddToQueue(quiche::QuicheBuffer message) { |
| if (pending_messages_.size() == kMaxPendingMessages) { |
| return absl::ResourceExhaustedError( |
| "Not enough flow credit on the control stream"); |
| } |
| pending_messages_.push_back(std::move(message)); |
| return absl::OkStatus(); |
| } |
| |
| absl::Status MoqtControlMessageQueue::SendMessage(webtransport::Stream& stream, |
| quiche::QuicheBuffer message, |
| bool fin) { |
| webtransport::StreamWriteOptions options; |
| options.set_send_fin(fin); |
| std::array write_vector = {quiche::QuicheMemSlice(std::move(message))}; |
| return stream.Writev(absl::MakeSpan(write_vector), options); |
| } |
| |
| } // namespace moqt |