// 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. #ifndef OSP_IMPL_QUIC_QUIC_CLIENT_H_ #define OSP_IMPL_QUIC_QUIC_CLIENT_H_ #include #include #include #include #include "osp/impl/quic/quic_connection_factory.h" #include "osp/impl/quic/quic_service_common.h" #include "osp/public/protocol_connection_client.h" #include "platform/api/task_runner.h" #include "platform/api/time.h" #include "platform/base/ip_address.h" #include "util/alarm.h" namespace openscreen { namespace 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 // QuicConnectionFactory implementation and MessageDemuxer. // QuicConnectionFactory 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 QuicConnectionFactory) 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 ServiceConnectionDelegate::ServiceDelegate { public: QuicClient(MessageDemuxer* demuxer, std::unique_ptr connection_factory, ProtocolConnectionServiceObserver* observer, ClockNowFunctionPtr now_function, TaskRunner* task_runner); ~QuicClient() override; // ProtocolConnectionClient overrides. bool Start() override; bool Stop() override; ConnectRequest Connect(const IPEndpoint& endpoint, ConnectionRequestCallback* request) override; std::unique_ptr CreateProtocolConnection( uint64_t endpoint_id) override; // QuicProtocolConnection::Owner overrides. void OnConnectionDestroyed(QuicProtocolConnection* connection) override; // ServiceConnectionDelegate::ServiceDelegate overrides. uint64_t OnCryptoHandshakeComplete(ServiceConnectionDelegate* delegate, uint64_t connection_id) override; void OnIncomingStream( std::unique_ptr connection) override; void OnConnectionClosed(uint64_t endpoint_id, uint64_t connection_id) override; void OnDataReceived(uint64_t endpoint_id, uint64_t connection_id, const uint8_t* data, size_t data_size) override; private: struct PendingConnectionData { explicit PendingConnectionData(ServiceConnectionData&& data); PendingConnectionData(PendingConnectionData&&) noexcept; ~PendingConnectionData(); PendingConnectionData& operator=(PendingConnectionData&&) noexcept; ServiceConnectionData data; // Pairs of request IDs and the associated connection callback. std::vector> callbacks; }; ConnectRequest CreatePendingConnection(const IPEndpoint& endpoint, ConnectionRequestCallback* request); uint64_t StartConnectionRequest(const IPEndpoint& endpoint, ConnectionRequestCallback* request); void CloseAllConnections(); std::unique_ptr MakeProtocolConnection( QuicConnection* connection, ServiceConnectionDelegate* delegate, uint64_t endpoint_id); void CancelConnectRequest(uint64_t request_id) override; // Deletes dead QUIC connections then returns the time interval before this // method should be run again. void Cleanup(); std::unique_ptr connection_factory_; // Maps an IPEndpoint to a generated endpoint ID. This is used to insulate // callers from post-handshake changes to a connections actual peer endpoint. std::map endpoint_map_; // Value that will be used for the next new endpoint in a Connect call. uint64_t next_endpoint_id_ = 0; // Maps request IDs to their callbacks. The callback is paired with the // IPEndpoint it originally requested to connect to so cancelling the request // can also remove a pending connection. std::map> request_map_; // Value that will be used for the next new connection request. uint64_t next_request_id_ = 1; // Maps endpoint addresses to data about connections that haven't successfully // completed the QUIC handshake. std::map pending_connections_; // Maps endpoint IDs to data about connections that have successfully // completed the QUIC handshake. std::map connections_; // Connections (endpoint IDs) that need to be destroyed, but have to wait for // the next event loop due to the underlying QUIC implementation's way of // referencing them. std::vector delete_connections_; Alarm cleanup_alarm_; }; } // namespace osp } // namespace openscreen #endif // OSP_IMPL_QUIC_QUIC_CLIENT_H_