blob: 07b9ab03cd430c94fdcdd63f0fb0b991272462ba [file] [log] [blame]
// 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.
#ifndef OSP_IMPL_QUIC_QUIC_CLIENT_H_
#define OSP_IMPL_QUIC_QUIC_CLIENT_H_
#include <cstdint>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "osp/impl/quic/certificates/quic_agent_certificate.h"
#include "osp/impl/quic/quic_connection_factory_client.h"
#include "osp/impl/quic/quic_service_base.h"
#include "osp/public/protocol_connection_client.h"
namespace openscreen::osp {
// This class is the default implementation of ProtocolConnectionClient for the
// library. It manages connections to other endpoints as well as the lifetime
// of each incoming and outgoing stream. It works in conjunction with a
// QuicConnectionFactoryClient and MessageDemuxer.
// QuicConnectionFactoryClient provides the actual ability to make a new QUIC
// connection with another endpoint. Incoming data is given to the QuicClient
// by the underlying QUIC implementation (through QuicConnectionFactoryClient)
// and this is in turn handed to MessageDemuxer for routing CBOR messages.
//
// The two most significant methods of this class are Connect and
// CreateProtocolConnection. Both will return a new QUIC stream to a given
// endpoint to which the caller can write but the former is allowed to be
// asynchronous. If there isn't currently a connection to the specified
// endpoint, Connect will start a connection attempt and store the callback for
// when the connection completes. CreateProtocolConnection simply returns
// nullptr if there's no existing connection.
class QuicClient final : public ProtocolConnectionClient,
public QuicServiceBase {
public:
static QuicAgentCertificate& GetAgentCertificate();
QuicClient(const ServiceConfig& config,
MessageDemuxer& demuxer,
std::unique_ptr<QuicConnectionFactoryClient> connection_factory,
ProtocolConnectionServiceObserver& observer,
ClockNowFunctionPtr now_function,
TaskRunner& task_runner);
QuicClient(const QuicClient&) = delete;
QuicClient& operator=(const QuicClient&) = delete;
QuicClient(QuicClient&&) noexcept = delete;
QuicClient& operator=(QuicClient&&) noexcept = delete;
~QuicClient() override;
// ProtocolConnectionClient overrides.
bool Start() override;
bool Stop() override;
bool Suspend() override;
bool Resume() override;
State GetState() override;
MessageDemuxer& GetMessageDemuxer() override;
InstanceRequestIds& GetInstanceRequestIds() override;
std::unique_ptr<ProtocolConnection> CreateProtocolConnection(
uint64_t instance_id) override;
bool Connect(std::string_view instance_name,
ConnectRequest& request,
ConnectionRequestCallback* request_callback) override;
// QuicServiceBase overrides.
uint64_t OnCryptoHandshakeComplete(std::string_view instance_name) override;
void OnConnectionClosed(uint64_t instance_id) override;
void OnClientCertificates(std::string_view instance_name,
const std::vector<std::string>& certs) override;
private:
// FakeQuicBridge needs to access `instance_infos_` and struct InstanceInfo
// for tests.
friend class FakeQuicBridge;
struct PendingConnectionData {
explicit PendingConnectionData(ServiceConnectionData&& data);
PendingConnectionData(const PendingConnectionData&) = delete;
PendingConnectionData& operator=(const PendingConnectionData&) = delete;
PendingConnectionData(PendingConnectionData&&) noexcept;
PendingConnectionData& operator=(PendingConnectionData&&) noexcept;
~PendingConnectionData();
ServiceConnectionData data;
// Pairs of request IDs and the associated connection callback.
std::vector<std::pair<uint64_t, ConnectionRequestCallback*>> callbacks;
};
// This struct holds necessary information of an instance used to build
// connection.
struct InstanceInfo {
// Agent fingerprint.
std::string fingerprint;
// The network endpoints to create a new connection to the Open Screen
// service. At least one of them is valid and use |v4_endpoint| first if it
// is valid.
IPEndpoint v4_endpoint;
IPEndpoint v6_endpoint;
};
// ServiceListener::Observer overrides.
void OnStarted() override;
void OnStopped() override;
void OnSuspended() override;
void OnSearching() override;
void OnReceiverAdded(const ServiceInfo& info) override;
void OnReceiverChanged(const ServiceInfo& info) override;
void OnReceiverRemoved(const ServiceInfo& info) override;
void OnAllReceiversRemoved() override;
void OnError(const Error& error) override;
void OnMetrics(ServiceListener::Metrics) override;
// QuicServiceBase overrides.
void CloseAllConnections() override;
bool CreatePendingConnection(std::string_view instance_name,
ConnectRequest& request,
ConnectionRequestCallback* request_callback);
uint64_t StartConnectionRequest(std::string_view instance_name,
ConnectionRequestCallback* request_callback);
void CancelConnectRequest(uint64_t request_id) override;
std::unique_ptr<QuicConnectionFactoryClient> connection_factory_;
// Value that will be used for the next new connection request.
uint64_t next_request_id_ = 1u;
// Maps an instance name to data about connections that haven't successfully
// completed the QUIC handshake.
std::map<std::string, PendingConnectionData, std::less<>>
pending_connections_;
// Maps an instance name to necessary information of the instance used to
// build connection.
std::map<std::string, InstanceInfo, std::less<>> instance_infos_;
};
} // namespace openscreen::osp
#endif // OSP_IMPL_QUIC_QUIC_CLIENT_H_