// Copyright 2021 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 "quic/core/web_transport_stream_adapter.h" namespace quic { WebTransportStreamAdapter::WebTransportStreamAdapter( QuicSession* session, QuicStream* stream, QuicStreamSequencer* sequencer) : session_(session), stream_(stream), sequencer_(sequencer) {} WebTransportStream::ReadResult WebTransportStreamAdapter::Read( char* buffer, size_t buffer_size) { iovec iov; iov.iov_base = buffer; iov.iov_len = buffer_size; const size_t result = sequencer_->Readv(&iov, 1); if (!fin_read_ && sequencer_->IsClosed()) { fin_read_ = true; stream_->OnFinRead(); } return ReadResult{result, sequencer_->IsClosed()}; } WebTransportStream::ReadResult WebTransportStreamAdapter::Read( std::string* output) { const size_t old_size = output->size(); const size_t bytes_to_read = ReadableBytes(); output->resize(old_size + bytes_to_read); ReadResult result = Read(&(*output)[old_size], bytes_to_read); QUICHE_DCHECK_EQ(bytes_to_read, result.bytes_read); output->resize(old_size + result.bytes_read); return result; } bool WebTransportStreamAdapter::Write(absl::string_view data) { if (!CanWrite()) { return false; } QuicUniqueBufferPtr buffer = MakeUniqueBuffer( session_->connection()->helper()->GetStreamSendBufferAllocator(), data.size()); memcpy(buffer.get(), data.data(), data.size()); QuicMemSlice memslice(std::move(buffer), data.size()); QuicConsumedData consumed = stream_->WriteMemSlices(QuicMemSliceSpan(&memslice), /*fin=*/false); if (consumed.bytes_consumed == data.size()) { return true; } if (consumed.bytes_consumed == 0) { return false; } // WebTransportStream::Write() is an all-or-nothing write API. To achieve // that property, it relies on WriteMemSlices() being an all-or-nothing API. // If WriteMemSlices() fails to provide that guarantee, we have no way to // communicate a partial write to the caller, and thus it's safer to just // close the connection. QUIC_BUG(WebTransportStreamAdapter partial write) << "WriteMemSlices() unexpectedly partially consumed the input " "data, provided: " << data.size() << ", written: " << consumed.bytes_consumed; stream_->OnUnrecoverableError( QUIC_INTERNAL_ERROR, "WriteMemSlices() unexpectedly partially consumed the input data"); return false; } bool WebTransportStreamAdapter::SendFin() { if (!CanWrite()) { return false; } QuicMemSlice empty; QuicConsumedData consumed = stream_->WriteMemSlices(QuicMemSliceSpan(&empty), /*fin=*/true); QUICHE_DCHECK_EQ(consumed.bytes_consumed, 0u); return consumed.fin_consumed; } bool WebTransportStreamAdapter::CanWrite() const { return stream_->CanWriteNewData() && !stream_->write_side_closed(); } size_t WebTransportStreamAdapter::ReadableBytes() const { return sequencer_->ReadableBytes(); } void WebTransportStreamAdapter::OnDataAvailable() { if (visitor_ == nullptr) { return; } const bool fin_readable = sequencer_->IsClosed() && !fin_read_; if (ReadableBytes() == 0 && !fin_readable) { return; } visitor_->OnCanRead(); } void WebTransportStreamAdapter::OnCanWriteNewData() { // Ensure the origin check has been completed, as the stream can be notified // about being writable before that. if (!CanWrite()) { return; } if (visitor_ != nullptr) { visitor_->OnCanWrite(); } } } // namespace quic