blob: dff69cc423e4e6bd64ecb268aba9ff6077125505 [file] [edit]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "osp/impl/quic/quic_service_common.h"
#include <memory>
#include <utility>
#include "util/osp_logging.h"
namespace openscreen::osp {
// static
std::unique_ptr<QuicProtocolConnection> QuicProtocolConnection::FromExisting(
Owner& owner,
QuicConnection* connection,
ServiceConnectionDelegate* delegate,
uint64_t instance_id) {
OSP_VLOG << "QUIC stream created for instance " << instance_id;
QuicStream* stream = connection->MakeOutgoingStream(delegate);
auto pc = std::make_unique<QuicProtocolConnection>(
owner, *stream, instance_id, stream->GetStreamId());
delegate->AddStreamPair(ServiceStreamPair{stream, pc->id(), pc.get()});
return pc;
}
QuicProtocolConnection::QuicProtocolConnection(Owner& owner,
QuicStream& stream,
uint64_t instance_id,
uint64_t protocol_connection_id)
: ProtocolConnection(instance_id, protocol_connection_id),
owner_(owner),
stream_(&stream) {}
QuicProtocolConnection::~QuicProtocolConnection() {
if (stream_) {
stream_->CloseWriteEnd();
owner_.OnConnectionDestroyed(this);
stream_ = nullptr;
}
}
void QuicProtocolConnection::Write(const ByteView& bytes) {
if (stream_) {
stream_->Write(bytes);
}
}
void QuicProtocolConnection::CloseWriteEnd() {
if (stream_) {
stream_->CloseWriteEnd();
}
}
void QuicProtocolConnection::OnClose() {
stream_ = nullptr;
if (observer_) {
observer_->OnConnectionClosed(*this);
}
}
ServiceConnectionDelegate::ServiceConnectionDelegate(
ServiceDelegate& parent,
const std::string& instance_name)
: parent_(parent), instance_name_(instance_name) {}
ServiceConnectionDelegate::~ServiceConnectionDelegate() {
void DestroyClosedStreams();
OSP_CHECK(streams_.empty());
}
void ServiceConnectionDelegate::AddStreamPair(
const ServiceStreamPair& stream_pair) {
const uint64_t stream_id = stream_pair.stream->GetStreamId();
streams_.emplace(stream_id, stream_pair);
}
void ServiceConnectionDelegate::DropProtocolConnection(
QuicProtocolConnection* connection) {
auto stream_entry = streams_.find(connection->stream()->GetStreamId());
if (stream_entry == streams_.end()) {
return;
}
stream_entry->second.protocol_connection = nullptr;
}
void ServiceConnectionDelegate::DestroyClosedStreams() {
closed_streams_.clear();
}
void ServiceConnectionDelegate::OnCryptoHandshakeComplete() {
instance_id_ = parent_.OnCryptoHandshakeComplete(this);
OSP_VLOG << "QUIC connection handshake complete for instance "
<< instance_id_;
}
void ServiceConnectionDelegate::OnIncomingStream(QuicStream* stream) {
OSP_VLOG << "Incoming QUIC stream from instance " << instance_id_;
auto protocol_connection = std::make_unique<QuicProtocolConnection>(
parent_, *stream, instance_id_, stream->GetStreamId());
AddStreamPair(ServiceStreamPair{stream, protocol_connection->id(),
protocol_connection.get()});
parent_.OnIncomingStream(std::move(protocol_connection));
}
void ServiceConnectionDelegate::OnConnectionClosed() {
OSP_VLOG << "QUIC connection closed for instance " << instance_id_;
parent_.OnConnectionClosed(instance_id_);
}
QuicStream::Delegate& ServiceConnectionDelegate::NextStreamDelegate() {
return *this;
}
void ServiceConnectionDelegate::OnReceived(QuicStream* stream,
const ByteView& bytes) {
auto stream_entry = streams_.find(stream->GetStreamId());
if (stream_entry == streams_.end()) {
return;
}
ServiceStreamPair& stream_pair = stream_entry->second;
parent_.OnDataReceived(instance_id_, stream_pair.protocol_connection_id,
bytes);
}
void ServiceConnectionDelegate::OnClose(uint64_t stream_id) {
OSP_VLOG << "QUIC stream closed for instance " << instance_id_;
auto stream_entry = streams_.find(stream_id);
if (stream_entry == streams_.end()) {
return;
}
ServiceStreamPair& stream_pair = stream_entry->second;
parent_.OnDataReceived(instance_id_, stream_pair.protocol_connection_id,
ByteView());
if (stream_pair.protocol_connection) {
stream_pair.protocol_connection->OnClose();
}
// NOTE: If this OnClose is the result of the read end closing when the write
// end was already closed, there will likely still be a call to OnReceived.
// We need to delay actually destroying the stream object until the end of the
// event loop.
closed_streams_.push_back(std::move(stream_entry->second));
streams_.erase(stream_entry);
}
} // namespace openscreen::osp