1 // Copyright 2018 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef OSP_IMPL_QUIC_QUIC_CLIENT_H_ 6 #define OSP_IMPL_QUIC_QUIC_CLIENT_H_ 7 8 #include <cstdint> 9 #include <map> 10 #include <memory> 11 #include <vector> 12 13 #include "osp/impl/quic/quic_connection_factory.h" 14 #include "osp/impl/quic/quic_service_common.h" 15 #include "osp/public/protocol_connection_client.h" 16 #include "platform/api/task_runner.h" 17 #include "platform/api/time.h" 18 #include "platform/base/ip_address.h" 19 #include "util/alarm.h" 20 21 namespace openscreen { 22 namespace osp { 23 24 // This class is the default implementation of ProtocolConnectionClient for the 25 // library. It manages connections to other endpoints as well as the lifetime 26 // of each incoming and outgoing stream. It works in conjunction with a 27 // QuicConnectionFactory implementation and MessageDemuxer. 28 // QuicConnectionFactory provides the actual ability to make a new QUIC 29 // connection with another endpoint. Incoming data is given to the QuicClient 30 // by the underlying QUIC implementation (through QuicConnectionFactory) and 31 // this is in turn handed to MessageDemuxer for routing CBOR messages. 32 // 33 // The two most significant methods of this class are Connect and 34 // CreateProtocolConnection. Both will return a new QUIC stream to a given 35 // endpoint to which the caller can write but the former is allowed to be 36 // asynchronous. If there isn't currently a connection to the specified 37 // endpoint, Connect will start a connection attempt and store the callback for 38 // when the connection completes. CreateProtocolConnection simply returns 39 // nullptr if there's no existing connection. 40 class QuicClient final : public ProtocolConnectionClient, 41 public ServiceConnectionDelegate::ServiceDelegate { 42 public: 43 QuicClient(MessageDemuxer* demuxer, 44 std::unique_ptr<QuicConnectionFactory> connection_factory, 45 ProtocolConnectionServiceObserver* observer, 46 ClockNowFunctionPtr now_function, 47 TaskRunner* task_runner); 48 ~QuicClient() override; 49 50 // ProtocolConnectionClient overrides. 51 bool Start() override; 52 bool Stop() override; 53 ConnectRequest Connect(const IPEndpoint& endpoint, 54 ConnectionRequestCallback* request) override; 55 std::unique_ptr<ProtocolConnection> CreateProtocolConnection( 56 uint64_t endpoint_id) override; 57 58 // QuicProtocolConnection::Owner overrides. 59 void OnConnectionDestroyed(QuicProtocolConnection* connection) override; 60 61 // ServiceConnectionDelegate::ServiceDelegate overrides. 62 uint64_t OnCryptoHandshakeComplete(ServiceConnectionDelegate* delegate, 63 uint64_t connection_id) override; 64 void OnIncomingStream( 65 std::unique_ptr<QuicProtocolConnection> connection) override; 66 void OnConnectionClosed(uint64_t endpoint_id, 67 uint64_t connection_id) override; 68 void OnDataReceived(uint64_t endpoint_id, 69 uint64_t connection_id, 70 const uint8_t* data, 71 size_t data_size) override; 72 73 private: 74 struct PendingConnectionData { 75 explicit PendingConnectionData(ServiceConnectionData&& data); 76 PendingConnectionData(PendingConnectionData&&) noexcept; 77 ~PendingConnectionData(); 78 PendingConnectionData& operator=(PendingConnectionData&&) noexcept; 79 80 ServiceConnectionData data; 81 82 // Pairs of request IDs and the associated connection callback. 83 std::vector<std::pair<uint64_t, ConnectionRequestCallback*>> callbacks; 84 }; 85 86 ConnectRequest CreatePendingConnection(const IPEndpoint& endpoint, 87 ConnectionRequestCallback* request); 88 uint64_t StartConnectionRequest(const IPEndpoint& endpoint, 89 ConnectionRequestCallback* request); 90 void CloseAllConnections(); 91 std::unique_ptr<QuicProtocolConnection> MakeProtocolConnection( 92 QuicConnection* connection, 93 ServiceConnectionDelegate* delegate, 94 uint64_t endpoint_id); 95 96 void CancelConnectRequest(uint64_t request_id) override; 97 98 // Deletes dead QUIC connections then returns the time interval before this 99 // method should be run again. 100 void Cleanup(); 101 102 std::unique_ptr<QuicConnectionFactory> connection_factory_; 103 104 // Maps an IPEndpoint to a generated endpoint ID. This is used to insulate 105 // callers from post-handshake changes to a connections actual peer endpoint. 106 std::map<IPEndpoint, uint64_t> endpoint_map_; 107 108 // Value that will be used for the next new endpoint in a Connect call. 109 uint64_t next_endpoint_id_ = 0; 110 111 // Maps request IDs to their callbacks. The callback is paired with the 112 // IPEndpoint it originally requested to connect to so cancelling the request 113 // can also remove a pending connection. 114 std::map<uint64_t, std::pair<IPEndpoint, ConnectionRequestCallback*>> 115 request_map_; 116 117 // Value that will be used for the next new connection request. 118 uint64_t next_request_id_ = 1; 119 120 // Maps endpoint addresses to data about connections that haven't successfully 121 // completed the QUIC handshake. 122 std::map<IPEndpoint, PendingConnectionData> pending_connections_; 123 124 // Maps endpoint IDs to data about connections that have successfully 125 // completed the QUIC handshake. 126 std::map<uint64_t, ServiceConnectionData> connections_; 127 128 // Connections (endpoint IDs) that need to be destroyed, but have to wait for 129 // the next event loop due to the underlying QUIC implementation's way of 130 // referencing them. 131 std::vector<uint64_t> delete_connections_; 132 133 Alarm cleanup_alarm_; 134 }; 135 136 } // namespace osp 137 } // namespace openscreen 138 139 #endif // OSP_IMPL_QUIC_QUIC_CLIENT_H_ 140