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 <memory> 12 #include <string> 13 14 #include "absl/base/attributes.h" 15 #include "absl/strings/string_view.h" 16 #include "quiche/quic/core/crypto/crypto_handshake.h" 17 #include "quiche/quic/core/deterministic_connection_id_generator.h" 18 #include "quiche/quic/core/http/quic_spdy_client_session.h" 19 #include "quiche/quic/core/http/quic_spdy_client_stream.h" 20 #include "quiche/quic/core/quic_config.h" 21 #include "quiche/quic/core/quic_connection_id.h" 22 #include "quiche/quic/platform/api/quic_socket_address.h" 23 24 namespace quic { 25 26 class ProofVerifier; 27 class QuicServerId; 28 class SessionCache; 29 30 // A path context which owns the writer. 31 class QUIC_EXPORT_PRIVATE PathMigrationContext 32 : public QuicPathValidationContext { 33 public: PathMigrationContext(std::unique_ptr<QuicPacketWriter> writer,const QuicSocketAddress & self_address,const QuicSocketAddress & peer_address)34 PathMigrationContext(std::unique_ptr<QuicPacketWriter> writer, 35 const QuicSocketAddress& self_address, 36 const QuicSocketAddress& peer_address) 37 : QuicPathValidationContext(self_address, peer_address), 38 alternative_writer_(std::move(writer)) {} 39 WriterToUse()40 QuicPacketWriter* WriterToUse() override { return alternative_writer_.get(); } 41 ReleaseWriter()42 QuicPacketWriter* ReleaseWriter() { return alternative_writer_.release(); } 43 44 private: 45 std::unique_ptr<QuicPacketWriter> alternative_writer_; 46 }; 47 48 // QuicClientBase handles establishing a connection to the passed in 49 // server id, including ensuring that it supports the passed in versions 50 // and config. 51 // Subclasses derived from this class are responsible for creating the 52 // actual QuicSession instance, as well as defining functions that 53 // create and run the underlying network transport. 54 class QuicClientBase : public QuicSession::Visitor { 55 public: 56 // An interface to various network events that the QuicClient will need to 57 // interact with. 58 class NetworkHelper { 59 public: 60 virtual ~NetworkHelper(); 61 62 // Runs one iteration of the event loop. 63 virtual void RunEventLoop() = 0; 64 65 // Used during initialization: creates the UDP socket FD, sets socket 66 // options, and binds the socket to our address. 67 virtual bool CreateUDPSocketAndBind(QuicSocketAddress server_address, 68 QuicIpAddress bind_to_address, 69 int bind_to_port) = 0; 70 71 // Unregister and close all open UDP sockets. 72 virtual void CleanUpAllUDPSockets() = 0; 73 74 // If the client has at least one UDP socket, return address of the latest 75 // created one. Otherwise, return an empty socket address. 76 virtual QuicSocketAddress GetLatestClientAddress() const = 0; 77 78 // Creates a packet writer to be used for the next connection. 79 virtual QuicPacketWriter* CreateQuicPacketWriter() = 0; 80 }; 81 82 QuicClientBase(const QuicServerId& server_id, 83 const ParsedQuicVersionVector& supported_versions, 84 const QuicConfig& config, 85 QuicConnectionHelperInterface* helper, 86 QuicAlarmFactory* alarm_factory, 87 std::unique_ptr<NetworkHelper> network_helper, 88 std::unique_ptr<ProofVerifier> proof_verifier, 89 std::unique_ptr<SessionCache> session_cache); 90 QuicClientBase(const QuicClientBase&) = delete; 91 QuicClientBase& operator=(const QuicClientBase&) = delete; 92 93 virtual ~QuicClientBase(); 94 95 // Implmenets QuicSession::Visitor OnConnectionClosed(QuicConnectionId,QuicErrorCode,const std::string &,ConnectionCloseSource)96 void OnConnectionClosed(QuicConnectionId /*server_connection_id*/, 97 QuicErrorCode /*error*/, 98 const std::string& /*error_details*/, 99 ConnectionCloseSource /*source*/) override {} 100 OnWriteBlocked(QuicBlockedWriterInterface *)101 void OnWriteBlocked(QuicBlockedWriterInterface* /*blocked_writer*/) override { 102 } OnRstStreamReceived(const QuicRstStreamFrame &)103 void OnRstStreamReceived(const QuicRstStreamFrame& /*frame*/) override {} OnStopSendingReceived(const QuicStopSendingFrame &)104 void OnStopSendingReceived(const QuicStopSendingFrame& /*frame*/) override {} TryAddNewConnectionId(const QuicConnectionId &,const QuicConnectionId &)105 bool TryAddNewConnectionId( 106 const QuicConnectionId& /*server_connection_id*/, 107 const QuicConnectionId& /*new_connection_id*/) override { 108 return false; 109 } OnConnectionIdRetired(const QuicConnectionId &)110 void OnConnectionIdRetired( 111 const QuicConnectionId& /*server_connection_id*/) override {} 112 void OnServerPreferredAddressAvailable( 113 const QuicSocketAddress& server_preferred_address) override; 114 115 // Initializes the client to create a connection. Should be called exactly 116 // once before calling StartConnect or Connect. Returns true if the 117 // initialization succeeds, false otherwise. 118 virtual bool Initialize(); 119 120 // "Connect" to the QUIC server, including performing synchronous crypto 121 // handshake. 122 bool Connect(); 123 124 // Start the crypto handshake. This can be done in place of the synchronous 125 // Connect(), but callers are responsible for making sure the crypto handshake 126 // completes. 127 void StartConnect(); 128 129 // Calls session()->Initialize(). Subclasses may override this if any extra 130 // initialization needs to be done. Subclasses should expect that session() 131 // is non-null and valid. 132 virtual void InitializeSession(); 133 134 // Disconnects from the QUIC server. 135 void Disconnect(); 136 137 // Returns true if the crypto handshake has yet to establish encryption. 138 // Returns false if encryption is active (even if the server hasn't confirmed 139 // the handshake) or if the connection has been closed. 140 bool EncryptionBeingEstablished(); 141 142 // Wait for events until the stream with the given ID is closed. 143 void WaitForStreamToClose(QuicStreamId id); 144 145 // Wait for 1-RTT keys become available. 146 // Returns true once 1-RTT keys are available, false otherwise. 147 ABSL_MUST_USE_RESULT bool WaitForOneRttKeysAvailable(); 148 149 // Wait for handshake state proceeds to HANDSHAKE_CONFIRMED. 150 // In QUIC crypto, this does the same as WaitForOneRttKeysAvailable, while in 151 // TLS, this waits for HANDSHAKE_DONE frame is received. 152 ABSL_MUST_USE_RESULT bool WaitForHandshakeConfirmed(); 153 154 // Wait up to 50ms, and handle any events which occur. 155 // Returns true if there are any outstanding requests. 156 bool WaitForEvents(); 157 158 // Performs the part of WaitForEvents() that is done after the actual event 159 // loop call. 160 bool WaitForEventsPostprocessing(); 161 162 // Migrate to a new socket (new_host) during an active connection. 163 bool MigrateSocket(const QuicIpAddress& new_host); 164 165 // Migrate to a new socket (new_host, port) during an active connection. 166 bool MigrateSocketWithSpecifiedPort(const QuicIpAddress& new_host, int port); 167 168 // Validate the new socket and migrate to it if the validation succeeds. 169 // Otherwise stay on the current socket. Return true if the validation has 170 // started. 171 bool ValidateAndMigrateSocket(const QuicIpAddress& new_host); 172 173 // Open a new socket to change to a new ephemeral port. 174 bool ChangeEphemeralPort(); 175 176 QuicSession* session(); 177 const QuicSession* session() const; 178 179 bool connected() const; 180 virtual bool goaway_received() const; 181 server_id()182 const QuicServerId& server_id() const { return server_id_; } 183 184 // This should only be set before the initial Connect() set_server_id(const QuicServerId & server_id)185 void set_server_id(const QuicServerId& server_id) { server_id_ = server_id; } 186 SetUserAgentID(const std::string & user_agent_id)187 void SetUserAgentID(const std::string& user_agent_id) { 188 crypto_config_.set_user_agent_id(user_agent_id); 189 } 190 SetTlsSignatureAlgorithms(std::string signature_algorithms)191 void SetTlsSignatureAlgorithms(std::string signature_algorithms) { 192 crypto_config_.set_tls_signature_algorithms( 193 std::move(signature_algorithms)); 194 } 195 supported_versions()196 const ParsedQuicVersionVector& supported_versions() const { 197 return supported_versions_; 198 } 199 SetSupportedVersions(const ParsedQuicVersionVector & versions)200 void SetSupportedVersions(const ParsedQuicVersionVector& versions) { 201 supported_versions_ = versions; 202 } 203 config()204 QuicConfig* config() { return &config_; } 205 crypto_config()206 QuicCryptoClientConfig* crypto_config() { return &crypto_config_; } 207 208 // Change the initial maximum packet size of the connection. Has to be called 209 // before Connect()/StartConnect() in order to have any effect. set_initial_max_packet_length(QuicByteCount initial_max_packet_length)210 void set_initial_max_packet_length(QuicByteCount initial_max_packet_length) { 211 initial_max_packet_length_ = initial_max_packet_length; 212 } 213 214 // The number of client hellos sent. 215 int GetNumSentClientHellos(); 216 217 // Returns true if early data (0-RTT data) was sent and the server accepted 218 // it. 219 virtual bool EarlyDataAccepted() = 0; 220 221 // Returns true if the handshake was delayed one round trip by the server 222 // because the server wanted proof the client controls its source address 223 // before progressing further. In Google QUIC, this would be due to an 224 // inchoate REJ in the QUIC Crypto handshake; in IETF QUIC this would be due 225 // to a Retry packet. 226 // TODO(nharper): Consider a better name for this method. 227 virtual bool ReceivedInchoateReject() = 0; 228 229 // Gather the stats for the last session and update the stats for the overall 230 // connection. 231 void UpdateStats(); 232 233 // The number of server config updates received. 234 int GetNumReceivedServerConfigUpdates(); 235 236 // Returns any errors that occurred at the connection-level. 237 QuicErrorCode connection_error() const; set_connection_error(QuicErrorCode connection_error)238 void set_connection_error(QuicErrorCode connection_error) { 239 connection_error_ = connection_error; 240 } 241 connected_or_attempting_connect()242 bool connected_or_attempting_connect() const { 243 return connected_or_attempting_connect_; 244 } set_connected_or_attempting_connect(bool connected_or_attempting_connect)245 void set_connected_or_attempting_connect( 246 bool connected_or_attempting_connect) { 247 connected_or_attempting_connect_ = connected_or_attempting_connect; 248 } 249 writer()250 QuicPacketWriter* writer() { return writer_.get(); } set_writer(QuicPacketWriter * writer)251 void set_writer(QuicPacketWriter* writer) { 252 if (writer_.get() != writer) { 253 writer_.reset(writer); 254 } 255 } 256 reset_writer()257 void reset_writer() { writer_.reset(); } 258 259 ProofVerifier* proof_verifier() const; 260 set_bind_to_address(QuicIpAddress address)261 void set_bind_to_address(QuicIpAddress address) { 262 bind_to_address_ = address; 263 } 264 bind_to_address()265 QuicIpAddress bind_to_address() const { return bind_to_address_; } 266 set_local_port(int local_port)267 void set_local_port(int local_port) { local_port_ = local_port; } 268 local_port()269 int local_port() const { return local_port_; } 270 server_address()271 const QuicSocketAddress& server_address() const { return server_address_; } 272 set_server_address(const QuicSocketAddress & server_address)273 void set_server_address(const QuicSocketAddress& server_address) { 274 server_address_ = server_address; 275 } 276 helper()277 QuicConnectionHelperInterface* helper() { return helper_.get(); } 278 alarm_factory()279 QuicAlarmFactory* alarm_factory() { return alarm_factory_.get(); } 280 281 NetworkHelper* network_helper(); 282 const NetworkHelper* network_helper() const; 283 initialized()284 bool initialized() const { return initialized_; } 285 SetPreSharedKey(absl::string_view key)286 void SetPreSharedKey(absl::string_view key) { 287 crypto_config_.set_pre_shared_key(key); 288 } 289 set_connection_debug_visitor(QuicConnectionDebugVisitor * connection_debug_visitor)290 void set_connection_debug_visitor( 291 QuicConnectionDebugVisitor* connection_debug_visitor) { 292 connection_debug_visitor_ = connection_debug_visitor; 293 } 294 295 // Sets the interface name to bind. If empty, will not attempt to bind the 296 // socket to that interface. Defaults to empty string. set_interface_name(std::string interface_name)297 void set_interface_name(std::string interface_name) { 298 interface_name_ = interface_name; 299 } 300 interface_name()301 std::string interface_name() const { return interface_name_; } 302 set_server_connection_id_override(const QuicConnectionId & connection_id)303 void set_server_connection_id_override( 304 const QuicConnectionId& connection_id) { 305 server_connection_id_override_ = connection_id; 306 } 307 set_server_connection_id_length(uint8_t server_connection_id_length)308 void set_server_connection_id_length(uint8_t server_connection_id_length) { 309 server_connection_id_length_ = server_connection_id_length; 310 } 311 set_client_connection_id_length(uint8_t client_connection_id_length)312 void set_client_connection_id_length(uint8_t client_connection_id_length) { 313 client_connection_id_length_ = client_connection_id_length; 314 } 315 316 bool HasPendingPathValidation(); 317 318 void ValidateNewNetwork(const QuicIpAddress& host); 319 AddValidatedPath(std::unique_ptr<QuicPathValidationContext> context)320 void AddValidatedPath(std::unique_ptr<QuicPathValidationContext> context) { 321 validated_paths_.push_back(std::move(context)); 322 } 323 324 const std::vector<std::unique_ptr<QuicPathValidationContext>>& validated_paths()325 validated_paths() const { 326 return validated_paths_; 327 } 328 329 protected: 330 // TODO(rch): Move GetNumSentClientHellosFromSession and 331 // GetNumReceivedServerConfigUpdatesFromSession into a new/better 332 // QuicSpdyClientSession class. The current inherits dependencies from 333 // Spdy. When that happens this class and all its subclasses should 334 // work with QuicSpdyClientSession instead of QuicSession. 335 // That will obviate the need for the pure virtual functions below. 336 337 // Extract the number of sent client hellos from the session. 338 virtual int GetNumSentClientHellosFromSession() = 0; 339 340 // The number of server config updates received. 341 virtual int GetNumReceivedServerConfigUpdatesFromSession() = 0; 342 343 // If this client supports buffering data, resend it. 344 virtual void ResendSavedData() = 0; 345 346 // If this client supports buffering data, clear it. 347 virtual void ClearDataToResend() = 0; 348 349 // Takes ownership of |connection|. If you override this function, 350 // you probably want to call ResetSession() in your destructor. 351 // TODO(rch): Change the connection parameter to take in a 352 // std::unique_ptr<QuicConnection> instead. 353 virtual std::unique_ptr<QuicSession> CreateQuicClientSession( 354 const ParsedQuicVersionVector& supported_versions, 355 QuicConnection* connection) = 0; 356 357 // Generates the next ConnectionId for |server_id_|. By default, if the 358 // cached server config contains a server-designated ID, that ID will be 359 // returned. Otherwise, the next random ID will be returned. 360 QuicConnectionId GetNextConnectionId(); 361 362 // Generates a new, random connection ID (as opposed to a server-designated 363 // connection ID). 364 virtual QuicConnectionId GenerateNewConnectionId(); 365 366 // Returns the client connection ID to use. 367 virtual QuicConnectionId GetClientConnectionId(); 368 369 // Subclasses may need to explicitly clear the session on destruction 370 // if they create it with objects that will be destroyed before this is. 371 // You probably want to call this if you override CreateQuicSpdyClientSession. ResetSession()372 void ResetSession() { session_.reset(); } 373 374 // Returns true if the corresponding of this client has active requests. 375 virtual bool HasActiveRequests() = 0; 376 377 // Allows derived classes to access this when creating connections. 378 ConnectionIdGeneratorInterface& connection_id_generator(); 379 380 private: 381 // Returns true and set |version| if client can reconnect with a different 382 // version. 383 bool CanReconnectWithDifferentVersion(ParsedQuicVersion* version) const; 384 385 std::unique_ptr<QuicPacketWriter> CreateWriterForNewNetwork( 386 const QuicIpAddress& new_host, int port); 387 388 // |server_id_| is a tuple (hostname, port, is_https) of the server. 389 QuicServerId server_id_; 390 391 // Tracks if the client is initialized to connect. 392 bool initialized_; 393 394 // Address of the server. 395 QuicSocketAddress server_address_; 396 397 // If initialized, the address to bind to. 398 QuicIpAddress bind_to_address_; 399 400 // Local port to bind to. Initialize to 0. 401 int local_port_; 402 403 // config_ and crypto_config_ contain configuration and cached state about 404 // servers. 405 QuicConfig config_; 406 QuicCryptoClientConfig crypto_config_; 407 408 // Helper to be used by created connections. Must outlive |session_|. 409 std::unique_ptr<QuicConnectionHelperInterface> helper_; 410 411 // Alarm factory to be used by created connections. Must outlive |session_|. 412 std::unique_ptr<QuicAlarmFactory> alarm_factory_; 413 414 // Writer used to actually send packets to the wire. Must outlive |session_|. 415 std::unique_ptr<QuicPacketWriter> writer_; 416 417 // Session which manages streams. 418 std::unique_ptr<QuicSession> session_; 419 420 // This vector contains QUIC versions which we currently support. 421 // This should be ordered such that the highest supported version is the first 422 // element, with subsequent elements in descending order (versions can be 423 // skipped as necessary). We will always pick supported_versions_[0] as the 424 // initial version to use. 425 ParsedQuicVersionVector supported_versions_; 426 427 // The initial value of maximum packet size of the connection. If set to 428 // zero, the default is used. 429 QuicByteCount initial_max_packet_length_; 430 431 // The number of hellos sent during the current/latest connection. 432 int num_sent_client_hellos_; 433 434 // Used to store any errors that occurred with the overall connection (as 435 // opposed to that associated with the last session object). 436 QuicErrorCode connection_error_; 437 438 // True when the client is attempting to connect. Set to false between a call 439 // to Disconnect() and the subsequent call to StartConnect(). When 440 // connected_or_attempting_connect_ is false, the session object corresponds 441 // to the previous client-level connection. 442 bool connected_or_attempting_connect_; 443 444 // The network helper used to create sockets and manage the event loop. 445 // Not owned by this class. 446 std::unique_ptr<NetworkHelper> network_helper_; 447 448 // The debug visitor set on the connection right after it is constructed. 449 // Not owned, must be valid for the lifetime of the QuicClientBase instance. 450 QuicConnectionDebugVisitor* connection_debug_visitor_; 451 452 // If set, 453 // - GetNextConnectionId will use this as the next server connection id. 454 // - GenerateNewConnectionId will not be called. 455 std::optional<QuicConnectionId> server_connection_id_override_; 456 457 // GenerateNewConnectionId creates a random connection ID of this length. 458 // Defaults to 8. 459 uint8_t server_connection_id_length_; 460 461 // GetClientConnectionId creates a random connection ID of this length. 462 // Defaults to 0. 463 uint8_t client_connection_id_length_; 464 465 // Stores validated paths. 466 std::vector<std::unique_ptr<QuicPathValidationContext>> validated_paths_; 467 468 // Stores the interface name to bind. If empty, will not attempt to bind the 469 // socket to that interface. Defaults to empty string. 470 std::string interface_name_; 471 472 DeterministicConnectionIdGenerator connection_id_generator_{ 473 kQuicDefaultConnectionIdLength}; 474 }; 475 476 } // namespace quic 477 478 #endif // QUICHE_QUIC_TOOLS_QUIC_CLIENT_BASE_H_ 479