blob: 5e66616da9c4641277d26bf2b7cf4591a23a91f9 [file] [log] [blame]
// Copyright (c) 2019 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/quic_transport/quic_transport_stream.h"
#include <sys/types.h>
#include "absl/strings/string_view.h"
#include "quic/core/quic_buffer_allocator.h"
#include "quic/core/quic_error_codes.h"
#include "quic/core/quic_types.h"
#include "quic/core/quic_utils.h"
namespace quic {
QuicTransportStream::QuicTransportStream(
QuicStreamId id,
QuicSession* session,
QuicTransportSessionInterface* session_interface)
: QuicStream(id,
session,
/*is_static=*/false,
QuicUtils::GetStreamType(id,
session->connection()->perspective(),
session->IsIncomingStream(id),
session->version())),
session_interface_(session_interface) {}
size_t QuicTransportStream::Read(char* buffer, size_t buffer_size) {
if (!session_interface_->IsSessionReady()) {
return 0;
}
iovec iov;
iov.iov_base = buffer;
iov.iov_len = buffer_size;
const size_t result = sequencer()->Readv(&iov, 1);
if (sequencer()->IsClosed()) {
MaybeNotifyFinRead();
}
return result;
}
size_t QuicTransportStream::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);
size_t bytes_read = Read(&(*output)[old_size], bytes_to_read);
QUICHE_DCHECK_EQ(bytes_to_read, bytes_read);
output->resize(old_size + bytes_read);
return bytes_read;
}
bool QuicTransportStream::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 =
WriteMemSlices(QuicMemSliceSpan(&memslice), /*fin=*/false);
if (consumed.bytes_consumed == data.size()) {
return true;
}
if (consumed.bytes_consumed == 0) {
return false;
}
// QuicTransportStream::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(quic_bug_10893_1)
<< "WriteMemSlices() unexpectedly partially consumed the input "
"data, provided: "
<< data.size() << ", written: " << consumed.bytes_consumed;
OnUnrecoverableError(
QUIC_INTERNAL_ERROR,
"WriteMemSlices() unexpectedly partially consumed the input data");
return false;
}
bool QuicTransportStream::SendFin() {
if (!CanWrite()) {
return false;
}
QuicMemSlice empty;
QuicConsumedData consumed =
WriteMemSlices(QuicMemSliceSpan(&empty), /*fin=*/true);
QUICHE_DCHECK_EQ(consumed.bytes_consumed, 0u);
return consumed.fin_consumed;
}
bool QuicTransportStream::CanWrite() const {
return session_interface_->IsSessionReady() && CanWriteNewData() &&
!write_side_closed();
}
size_t QuicTransportStream::ReadableBytes() const {
if (!session_interface_->IsSessionReady()) {
return 0;
}
return sequencer()->ReadableBytes();
}
void QuicTransportStream::OnDataAvailable() {
if (sequencer()->IsClosed()) {
MaybeNotifyFinRead();
return;
}
if (visitor_ == nullptr) {
return;
}
if (ReadableBytes() == 0) {
return;
}
visitor_->OnCanRead();
}
void QuicTransportStream::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();
}
}
void QuicTransportStream::MaybeNotifyFinRead() {
if (visitor_ == nullptr || fin_read_notified_) {
return;
}
fin_read_notified_ = true;
visitor_->OnFinRead();
OnFinRead();
}
} // namespace quic