1 // Copyright (c) 2015 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 // A base class for the toy client, which connects to a specified port and sends 6 // QUIC request to that endpoint. 7 8 #ifndef QUICHE_QUIC_TOOLS_QUIC_CLIENT_BASE_H_ 9 #define QUICHE_QUIC_TOOLS_QUIC_CLIENT_BASE_H_ 10 11 #include <string> 12 13 #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" 14 #include "net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index.h" 15 #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h" 16 #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h" 17 #include "net/third_party/quiche/src/quic/core/quic_config.h" 18 #include "net/third_party/quiche/src/quic/platform/api/quic_macros.h" 19 #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" 20 #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" 21 22 namespace quic { 23 24 class ProofVerifier; 25 class QuicServerId; 26 class SessionCache; 27 28 // QuicClientBase handles establishing a connection to the passed in 29 // server id, including ensuring that it supports the passed in versions 30 // and config. 31 // Subclasses derived from this class are responsible for creating the 32 // actual QuicSession instance, as well as defining functions that 33 // create and run the underlying network transport. 34 class QuicClientBase { 35 public: 36 // An interface to various network events that the QuicClient will need to 37 // interact with. 38 class NetworkHelper { 39 public: 40 virtual ~NetworkHelper(); 41 42 // Runs one iteration of the event loop. 43 virtual void RunEventLoop() = 0; 44 45 // Used during initialization: creates the UDP socket FD, sets socket 46 // options, and binds the socket to our address. 47 virtual bool CreateUDPSocketAndBind(QuicSocketAddress server_address, 48 QuicIpAddress bind_to_address, 49 int bind_to_port) = 0; 50 51 // Unregister and close all open UDP sockets. 52 virtual void CleanUpAllUDPSockets() = 0; 53 54 // If the client has at least one UDP socket, return address of the latest 55 // created one. Otherwise, return an empty socket address. 56 virtual QuicSocketAddress GetLatestClientAddress() const = 0; 57 58 // Creates a packet writer to be used for the next connection. 59 virtual QuicPacketWriter* CreateQuicPacketWriter() = 0; 60 }; 61 62 QuicClientBase(const QuicServerId& server_id, 63 const ParsedQuicVersionVector& supported_versions, 64 const QuicConfig& config, 65 QuicConnectionHelperInterface* helper, 66 QuicAlarmFactory* alarm_factory, 67 std::unique_ptr<NetworkHelper> network_helper, 68 std::unique_ptr<ProofVerifier> proof_verifier, 69 std::unique_ptr<SessionCache> session_cache); 70 QuicClientBase(const QuicClientBase&) = delete; 71 QuicClientBase& operator=(const QuicClientBase&) = delete; 72 73 virtual ~QuicClientBase(); 74 75 // Initializes the client to create a connection. Should be called exactly 76 // once before calling StartConnect or Connect. Returns true if the 77 // initialization succeeds, false otherwise. 78 virtual bool Initialize(); 79 80 // "Connect" to the QUIC server, including performing synchronous crypto 81 // handshake. 82 bool Connect(); 83 84 // Start the crypto handshake. This can be done in place of the synchronous 85 // Connect(), but callers are responsible for making sure the crypto handshake 86 // completes. 87 void StartConnect(); 88 89 // Calls session()->Initialize(). Subclasses may override this if any extra 90 // initialization needs to be done. Subclasses should expect that session() 91 // is non-null and valid. 92 virtual void InitializeSession(); 93 94 // Disconnects from the QUIC server. 95 void Disconnect(); 96 97 // Returns true if the crypto handshake has yet to establish encryption. 98 // Returns false if encryption is active (even if the server hasn't confirmed 99 // the handshake) or if the connection has been closed. 100 bool EncryptionBeingEstablished(); 101 102 // Wait for events until the stream with the given ID is closed. 103 void WaitForStreamToClose(QuicStreamId id); 104 105 // Wait for events until the handshake is confirmed. 106 // Returns true if the crypto handshake succeeds, false otherwise. 107 QUIC_MUST_USE_RESULT bool WaitForCryptoHandshakeConfirmed(); 108 109 // Wait up to 50ms, and handle any events which occur. 110 // Returns true if there are any outstanding requests. 111 bool WaitForEvents(); 112 113 // Migrate to a new socket (new_host) during an active connection. 114 bool MigrateSocket(const QuicIpAddress& new_host); 115 116 // Migrate to a new socket (new_host, port) during an active connection. 117 bool MigrateSocketWithSpecifiedPort(const QuicIpAddress& new_host, int port); 118 119 // Open a new socket to change to a new ephemeral port. 120 bool ChangeEphemeralPort(); 121 122 QuicSession* session(); 123 124 bool connected() const; 125 bool goaway_received() const; 126 server_id()127 const QuicServerId& server_id() const { return server_id_; } 128 129 // This should only be set before the initial Connect() set_server_id(const QuicServerId & server_id)130 void set_server_id(const QuicServerId& server_id) { server_id_ = server_id; } 131 SetUserAgentID(const std::string & user_agent_id)132 void SetUserAgentID(const std::string& user_agent_id) { 133 crypto_config_.set_user_agent_id(user_agent_id); 134 } 135 supported_versions()136 const ParsedQuicVersionVector& supported_versions() const { 137 return supported_versions_; 138 } 139 SetSupportedVersions(const ParsedQuicVersionVector & versions)140 void SetSupportedVersions(const ParsedQuicVersionVector& versions) { 141 supported_versions_ = versions; 142 } 143 config()144 QuicConfig* config() { return &config_; } 145 crypto_config()146 QuicCryptoClientConfig* crypto_config() { return &crypto_config_; } 147 148 // Change the initial maximum packet size of the connection. Has to be called 149 // before Connect()/StartConnect() in order to have any effect. set_initial_max_packet_length(QuicByteCount initial_max_packet_length)150 void set_initial_max_packet_length(QuicByteCount initial_max_packet_length) { 151 initial_max_packet_length_ = initial_max_packet_length; 152 } 153 154 // The number of client hellos sent. 155 int GetNumSentClientHellos(); 156 157 // Returns true if early data (0-RTT data) was sent and the server accepted 158 // it. 159 virtual bool EarlyDataAccepted() = 0; 160 161 // Returns true if the handshake was delayed one round trip by the server 162 // because the server wanted proof the client controls its source address 163 // before progressing further. In Google QUIC, this would be due to an 164 // inchoate REJ in the QUIC Crypto handshake; in IETF QUIC this would be due 165 // to a Retry packet. 166 // TODO(nharper): Consider a better name for this method. 167 virtual bool ReceivedInchoateReject() = 0; 168 169 // Gather the stats for the last session and update the stats for the overall 170 // connection. 171 void UpdateStats(); 172 173 // The number of server config updates received. 174 int GetNumReceivedServerConfigUpdates(); 175 176 // Returns any errors that occurred at the connection-level. 177 QuicErrorCode connection_error() const; set_connection_error(QuicErrorCode connection_error)178 void set_connection_error(QuicErrorCode connection_error) { 179 connection_error_ = connection_error; 180 } 181 connected_or_attempting_connect()182 bool connected_or_attempting_connect() const { 183 return connected_or_attempting_connect_; 184 } set_connected_or_attempting_connect(bool connected_or_attempting_connect)185 void set_connected_or_attempting_connect( 186 bool connected_or_attempting_connect) { 187 connected_or_attempting_connect_ = connected_or_attempting_connect; 188 } 189 writer()190 QuicPacketWriter* writer() { return writer_.get(); } set_writer(QuicPacketWriter * writer)191 void set_writer(QuicPacketWriter* writer) { 192 if (writer_.get() != writer) { 193 writer_.reset(writer); 194 } 195 } 196 reset_writer()197 void reset_writer() { writer_.reset(); } 198 199 ProofVerifier* proof_verifier() const; 200 set_bind_to_address(QuicIpAddress address)201 void set_bind_to_address(QuicIpAddress address) { 202 bind_to_address_ = address; 203 } 204 bind_to_address()205 QuicIpAddress bind_to_address() const { return bind_to_address_; } 206 set_local_port(int local_port)207 void set_local_port(int local_port) { local_port_ = local_port; } 208 local_port()209 int local_port() const { return local_port_; } 210 server_address()211 const QuicSocketAddress& server_address() const { return server_address_; } 212 set_server_address(const QuicSocketAddress & server_address)213 void set_server_address(const QuicSocketAddress& server_address) { 214 server_address_ = server_address; 215 } 216 helper()217 QuicConnectionHelperInterface* helper() { return helper_.get(); } 218 219 NetworkHelper* network_helper(); 220 const NetworkHelper* network_helper() const; 221 initialized()222 bool initialized() const { return initialized_; } 223 SetPreSharedKey(quiche::QuicheStringPiece key)224 void SetPreSharedKey(quiche::QuicheStringPiece key) { 225 crypto_config_.set_pre_shared_key(key); 226 } 227 set_connection_debug_visitor(QuicConnectionDebugVisitor * connection_debug_visitor)228 void set_connection_debug_visitor( 229 QuicConnectionDebugVisitor* connection_debug_visitor) { 230 connection_debug_visitor_ = connection_debug_visitor; 231 } 232 233 protected: 234 // TODO(rch): Move GetNumSentClientHellosFromSession and 235 // GetNumReceivedServerConfigUpdatesFromSession into a new/better 236 // QuicSpdyClientSession class. The current inherits dependencies from 237 // Spdy. When that happens this class and all its subclasses should 238 // work with QuicSpdyClientSession instead of QuicSession. 239 // That will obviate the need for the pure virtual functions below. 240 241 // Extract the number of sent client hellos from the session. 242 virtual int GetNumSentClientHellosFromSession() = 0; 243 244 // The number of server config updates received. 245 virtual int GetNumReceivedServerConfigUpdatesFromSession() = 0; 246 247 // If this client supports buffering data, resend it. 248 virtual void ResendSavedData() = 0; 249 250 // If this client supports buffering data, clear it. 251 virtual void ClearDataToResend() = 0; 252 253 // Takes ownership of |connection|. If you override this function, 254 // you probably want to call ResetSession() in your destructor. 255 // TODO(rch): Change the connection parameter to take in a 256 // std::unique_ptr<QuicConnection> instead. 257 virtual std::unique_ptr<QuicSession> CreateQuicClientSession( 258 const ParsedQuicVersionVector& supported_versions, 259 QuicConnection* connection) = 0; 260 261 // Generates the next ConnectionId for |server_id_|. By default, if the 262 // cached server config contains a server-designated ID, that ID will be 263 // returned. Otherwise, the next random ID will be returned. 264 QuicConnectionId GetNextConnectionId(); 265 266 // Returns the next server-designated ConnectionId from the cached config for 267 // |server_id_|, if it exists. Otherwise, returns 0. 268 QuicConnectionId GetNextServerDesignatedConnectionId(); 269 270 // Generates a new, random connection ID (as opposed to a server-designated 271 // connection ID). 272 virtual QuicConnectionId GenerateNewConnectionId(); 273 274 // Returns the client connection ID to use. 275 virtual QuicConnectionId GetClientConnectionId(); 276 alarm_factory()277 QuicAlarmFactory* alarm_factory() { return alarm_factory_.get(); } 278 279 // Subclasses may need to explicitly clear the session on destruction 280 // if they create it with objects that will be destroyed before this is. 281 // You probably want to call this if you override CreateQuicSpdyClientSession. ResetSession()282 void ResetSession() { session_.reset(); } 283 284 // Returns true if the corresponding of this client has active requests. 285 virtual bool HasActiveRequests() = 0; 286 287 private: 288 // Returns true and set |version| if client can reconnect with a different 289 // version. 290 bool CanReconnectWithDifferentVersion(ParsedQuicVersion* version) const; 291 292 // |server_id_| is a tuple (hostname, port, is_https) of the server. 293 QuicServerId server_id_; 294 295 // Tracks if the client is initialized to connect. 296 bool initialized_; 297 298 // Address of the server. 299 QuicSocketAddress server_address_; 300 301 // If initialized, the address to bind to. 302 QuicIpAddress bind_to_address_; 303 304 // Local port to bind to. Initialize to 0. 305 int local_port_; 306 307 // config_ and crypto_config_ contain configuration and cached state about 308 // servers. 309 QuicConfig config_; 310 QuicCryptoClientConfig crypto_config_; 311 312 // Helper to be used by created connections. Must outlive |session_|. 313 std::unique_ptr<QuicConnectionHelperInterface> helper_; 314 315 // Alarm factory to be used by created connections. Must outlive |session_|. 316 std::unique_ptr<QuicAlarmFactory> alarm_factory_; 317 318 // Writer used to actually send packets to the wire. Must outlive |session_|. 319 std::unique_ptr<QuicPacketWriter> writer_; 320 321 // Session which manages streams. 322 std::unique_ptr<QuicSession> session_; 323 324 // This vector contains QUIC versions which we currently support. 325 // This should be ordered such that the highest supported version is the first 326 // element, with subsequent elements in descending order (versions can be 327 // skipped as necessary). We will always pick supported_versions_[0] as the 328 // initial version to use. 329 ParsedQuicVersionVector supported_versions_; 330 331 // The initial value of maximum packet size of the connection. If set to 332 // zero, the default is used. 333 QuicByteCount initial_max_packet_length_; 334 335 // The number of hellos sent during the current/latest connection. 336 int num_sent_client_hellos_; 337 338 // Used to store any errors that occurred with the overall connection (as 339 // opposed to that associated with the last session object). 340 QuicErrorCode connection_error_; 341 342 // True when the client is attempting to connect. Set to false between a call 343 // to Disconnect() and the subsequent call to StartConnect(). When 344 // connected_or_attempting_connect_ is false, the session object corresponds 345 // to the previous client-level connection. 346 bool connected_or_attempting_connect_; 347 348 // The network helper used to create sockets and manage the event loop. 349 // Not owned by this class. 350 std::unique_ptr<NetworkHelper> network_helper_; 351 352 // The debug visitor set on the connection right after it is constructed. 353 // Not owned, must be valid for the lifetime of the QuicClientBase instance. 354 QuicConnectionDebugVisitor* connection_debug_visitor_; 355 }; 356 357 } // namespace quic 358 359 #endif // QUICHE_QUIC_TOOLS_QUIC_CLIENT_BASE_H_ 360