// Copyright 2018 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 "osp/impl/quic/quic_service_common.h" #include #include #include "util/osp_logging.h" namespace openscreen { namespace osp { // static std::unique_ptr QuicProtocolConnection::FromExisting( Owner* owner, QuicConnection* connection, ServiceConnectionDelegate* delegate, uint64_t endpoint_id) { OSP_VLOG << "QUIC stream created for endpoint " << endpoint_id; std::unique_ptr stream = connection->MakeOutgoingStream(delegate); auto pc = std::make_unique(owner, endpoint_id, stream->id()); pc->set_stream(stream.get()); delegate->AddStreamPair(ServiceStreamPair(std::move(stream), pc.get())); return pc; } QuicProtocolConnection::QuicProtocolConnection(Owner* owner, uint64_t endpoint_id, uint64_t connection_id) : ProtocolConnection(endpoint_id, connection_id), owner_(owner) {} QuicProtocolConnection::~QuicProtocolConnection() { if (stream_) { stream_->CloseWriteEnd(); owner_->OnConnectionDestroyed(this); stream_ = nullptr; } } void QuicProtocolConnection::Write(const uint8_t* data, size_t data_size) { if (stream_) stream_->Write(data, data_size); } void QuicProtocolConnection::CloseWriteEnd() { if (stream_) stream_->CloseWriteEnd(); } void QuicProtocolConnection::OnClose() { if (observer_) observer_->OnConnectionClosed(*this); } ServiceStreamPair::ServiceStreamPair( std::unique_ptr stream, QuicProtocolConnection* protocol_connection) : stream(std::move(stream)), connection_id(protocol_connection->id()), protocol_connection(std::move(protocol_connection)) {} ServiceStreamPair::~ServiceStreamPair() = default; ServiceStreamPair::ServiceStreamPair(ServiceStreamPair&& other) noexcept = default; ServiceStreamPair& ServiceStreamPair::operator=( ServiceStreamPair&& other) noexcept = default; ServiceConnectionDelegate::ServiceConnectionDelegate(ServiceDelegate* parent, const IPEndpoint& endpoint) : parent_(parent), endpoint_(endpoint) {} ServiceConnectionDelegate::~ServiceConnectionDelegate() { void DestroyClosedStreams(); OSP_DCHECK(streams_.empty()); } void ServiceConnectionDelegate::AddStreamPair(ServiceStreamPair&& stream_pair) { uint64_t stream_id = stream_pair.stream->id(); streams_.emplace(stream_id, std::move(stream_pair)); } void ServiceConnectionDelegate::DropProtocolConnection( QuicProtocolConnection* connection) { auto stream_entry = streams_.find(connection->stream()->id()); if (stream_entry == streams_.end()) return; stream_entry->second.protocol_connection = nullptr; } void ServiceConnectionDelegate::DestroyClosedStreams() { closed_streams_.clear(); } void ServiceConnectionDelegate::OnCryptoHandshakeComplete( uint64_t connection_id) { endpoint_id_ = parent_->OnCryptoHandshakeComplete(this, connection_id); OSP_VLOG << "QUIC connection handshake complete for endpoint " << endpoint_id_; } void ServiceConnectionDelegate::OnIncomingStream( uint64_t connection_id, std::unique_ptr stream) { OSP_VLOG << "Incoming QUIC stream from endpoint " << endpoint_id_; pending_connection_->set_stream(stream.get()); AddStreamPair( ServiceStreamPair(std::move(stream), pending_connection_.get())); parent_->OnIncomingStream(std::move(pending_connection_)); } void ServiceConnectionDelegate::OnConnectionClosed(uint64_t connection_id) { OSP_VLOG << "QUIC connection closed for endpoint " << endpoint_id_; parent_->OnConnectionClosed(endpoint_id_, connection_id); } QuicStream::Delegate* ServiceConnectionDelegate::NextStreamDelegate( uint64_t connection_id, uint64_t stream_id) { OSP_DCHECK(!pending_connection_); pending_connection_ = std::make_unique( parent_, endpoint_id_, stream_id); return this; } void ServiceConnectionDelegate::OnReceived(QuicStream* stream, const char* data, size_t data_size) { auto stream_entry = streams_.find(stream->id()); if (stream_entry == streams_.end()) return; ServiceStreamPair& stream_pair = stream_entry->second; parent_->OnDataReceived(endpoint_id_, stream_pair.connection_id, reinterpret_cast(data), data_size); } void ServiceConnectionDelegate::OnClose(uint64_t stream_id) { OSP_VLOG << "QUIC stream closed for endpoint " << endpoint_id_; auto stream_entry = streams_.find(stream_id); if (stream_entry == streams_.end()) return; ServiceStreamPair& stream_pair = stream_entry->second; parent_->OnDataReceived(endpoint_id_, stream_pair.connection_id, nullptr, 0); if (stream_pair.protocol_connection) { stream_pair.protocol_connection->set_stream(nullptr); 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); } ServiceConnectionData::ServiceConnectionData( std::unique_ptr connection, std::unique_ptr delegate) : connection(std::move(connection)), delegate(std::move(delegate)) {} ServiceConnectionData::ServiceConnectionData(ServiceConnectionData&&) noexcept = default; ServiceConnectionData::~ServiceConnectionData() = default; ServiceConnectionData& ServiceConnectionData::operator=( ServiceConnectionData&&) noexcept = default; } // namespace osp } // namespace openscreen