| // 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 <memory> |
| #include <utility> |
| |
| #include "util/osp_logging.h" |
| |
| namespace openscreen { |
| namespace osp { |
| |
| // static |
| std::unique_ptr<QuicProtocolConnection> QuicProtocolConnection::FromExisting( |
| Owner* owner, |
| QuicConnection* connection, |
| ServiceConnectionDelegate* delegate, |
| uint64_t endpoint_id) { |
| OSP_VLOG << "QUIC stream created for endpoint " << endpoint_id; |
| std::unique_ptr<QuicStream> stream = connection->MakeOutgoingStream(delegate); |
| auto pc = std::make_unique<QuicProtocolConnection>(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<QuicStream> 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<QuicStream> 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<QuicProtocolConnection>( |
| 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<const uint8_t*>(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<QuicConnection> connection, |
| std::unique_ptr<ServiceConnectionDelegate> 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 |