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 void OnPathDegrading() override; 115 116 // Initializes the client to create a connection. Should be called exactly 117 // once before calling StartConnect or Connect. Returns true if the 118 // initialization succeeds, false otherwise. 119 virtual bool Initialize(); 120 121 // "Connect" to the QUIC server, including performing synchronous crypto 122 // handshake. 123 bool Connect(); 124 125 // Start the crypto handshake. This can be done in place of the synchronous 126 // Connect(), but callers are responsible for making sure the crypto handshake 127 // completes. 128 void StartConnect(); 129 130 // Calls session()->Initialize(). Subclasses may override this if any extra 131 // initialization needs to be done. Subclasses should expect that session() 132 // is non-null and valid. 133 virtual void InitializeSession(); 134 135 // Disconnects from the QUIC server. 136 void Disconnect(); 137 138 // Returns true if the crypto handshake has yet to establish encryption. 139 // Returns false if encryption is active (even if the server hasn't confirmed 140 // the handshake) or if the connection has been closed. 141 bool EncryptionBeingEstablished(); 142 143 // Wait for events until the stream with the given ID is closed. 144 void WaitForStreamToClose(QuicStreamId id); 145 146 // Wait for 1-RTT keys become available. 147 // Returns true once 1-RTT keys are available, false otherwise. 148 ABSL_MUST_USE_RESULT bool WaitForOneRttKeysAvailable(); 149 150 // Wait for handshake state proceeds to HANDSHAKE_CONFIRMED. 151 // In QUIC crypto, this does the same as WaitForOneRttKeysAvailable, while in 152 // TLS, this waits for HANDSHAKE_DONE frame is received. 153 ABSL_MUST_USE_RESULT bool WaitForHandshakeConfirmed(); 154 155 // Wait up to 50ms, and handle any events which occur. 156 // Returns true if there are any outstanding requests. 157 bool WaitForEvents(); 158 159 // Performs the part of WaitForEvents() that is done after the actual event 160 // loop call. 161 bool WaitForEventsPostprocessing(); 162 163 // Migrate to a new socket (new_host) during an active connection. 164 bool MigrateSocket(const QuicIpAddress& new_host); 165 166 // Migrate to a new socket (new_host, port) during an active connection. 167 bool MigrateSocketWithSpecifiedPort(const QuicIpAddress& new_host, int port); 168 169 // Validate the new socket and migrate to it if the validation succeeds. 170 // Otherwise stay on the current socket. Return true if the validation has 171 // started. 172 bool ValidateAndMigrateSocket(const QuicIpAddress& new_host); 173 174 // Open a new socket to change to a new ephemeral port. 175 bool ChangeEphemeralPort(); 176 177 QuicSession* session(); 178 const QuicSession* session() const; 179 180 bool connected() const; 181 virtual bool goaway_received() const; 182 server_id()183 const QuicServerId& server_id() const { return server_id_; } 184 185 // This should only be set before the initial Connect() set_server_id(const QuicServerId & server_id)186 void set_server_id(const QuicServerId& server_id) { server_id_ = server_id; } 187 SetUserAgentID(const std::string & user_agent_id)188 void SetUserAgentID(const std::string& user_agent_id) { 189 crypto_config_.set_user_agent_id(user_agent_id); 190 } 191 SetTlsSignatureAlgorithms(std::string signature_algorithms)192 void SetTlsSignatureAlgorithms(std::string signature_algorithms) { 193 crypto_config_.set_tls_signature_algorithms( 194 std::move(signature_algorithms)); 195 } 196 supported_versions()197 const ParsedQuicVersionVector& supported_versions() const { 198 return supported_versions_; 199 } 200 SetSupportedVersions(const ParsedQuicVersionVector & versions)201 void SetSupportedVersions(const ParsedQuicVersionVector& versions) { 202 supported_versions_ = versions; 203 } 204 config()205 QuicConfig* config() { return &config_; } 206 crypto_config()207 QuicCryptoClientConfig* crypto_config() { return &crypto_config_; } 208 209 // Change the initial maximum packet size of the connection. Has to be called 210 // before Connect()/StartConnect() in order to have any effect. set_initial_max_packet_length(QuicByteCount initial_max_packet_length)211 void set_initial_max_packet_length(QuicByteCount initial_max_packet_length) { 212 initial_max_packet_length_ = initial_max_packet_length; 213 } 214 215 // The number of client hellos sent. 216 int GetNumSentClientHellos(); 217 218 // Returns true if early data (0-RTT data) was sent and the server accepted 219 // it. 220 virtual bool EarlyDataAccepted() = 0; 221 222 // Returns true if the handshake was delayed one round trip by the server 223 // because the server wanted proof the client controls its source address 224 // before progressing further. In Google QUIC, this would be due to an 225 // inchoate REJ in the QUIC Crypto handshake; in IETF QUIC this would be due 226 // to a Retry packet. 227 // TODO(nharper): Consider a better name for this method. 228 virtual bool ReceivedInchoateReject() = 0; 229 230 // Gather the stats for the last session and update the stats for the overall 231 // connection. 232 void UpdateStats(); 233 234 // The number of server config updates received. 235 int GetNumReceivedServerConfigUpdates(); 236 237 // Returns any errors that occurred at the connection-level. 238 QuicErrorCode connection_error() const; set_connection_error(QuicErrorCode connection_error)239 void set_connection_error(QuicErrorCode connection_error) { 240 connection_error_ = connection_error; 241 } 242 connected_or_attempting_connect()243 bool connected_or_attempting_connect() const { 244 return connected_or_attempting_connect_; 245 } set_connected_or_attempting_connect(bool connected_or_attempting_connect)246 void set_connected_or_attempting_connect( 247 bool connected_or_attempting_connect) { 248 connected_or_attempting_connect_ = connected_or_attempting_connect; 249 } 250 writer()251 QuicPacketWriter* writer() { return writer_.get(); } set_writer(QuicPacketWriter * writer)252 void set_writer(QuicPacketWriter* writer) { 253 if (writer_.get() != writer) { 254 writer_.reset(writer); 255 } 256 } 257 reset_writer()258 void reset_writer() { writer_.reset(); } 259 260 ProofVerifier* proof_verifier() const; 261 set_bind_to_address(QuicIpAddress address)262 void set_bind_to_address(QuicIpAddress address) { 263 bind_to_address_ = address; 264 } 265 bind_to_address()266 QuicIpAddress bind_to_address() const { return bind_to_address_; } 267 set_local_port(int local_port)268 void set_local_port(int local_port) { local_port_ = local_port; } 269 local_port()270 int local_port() const { return local_port_; } 271 server_address()272 const QuicSocketAddress& server_address() const { return server_address_; } 273 set_server_address(const QuicSocketAddress & server_address)274 void set_server_address(const QuicSocketAddress& server_address) { 275 server_address_ = server_address; 276 } 277 helper()278 QuicConnectionHelperInterface* helper() { return helper_.get(); } 279 alarm_factory()280 QuicAlarmFactory* alarm_factory() { return alarm_factory_.get(); } 281 282 NetworkHelper* network_helper(); 283 const NetworkHelper* network_helper() const; 284 initialized()285 bool initialized() const { return initialized_; } 286 SetPreSharedKey(absl::string_view key)287 void SetPreSharedKey(absl::string_view key) { 288 crypto_config_.set_pre_shared_key(key); 289 } 290 set_connection_debug_visitor(QuicConnectionDebugVisitor * connection_debug_visitor)291 void set_connection_debug_visitor( 292 QuicConnectionDebugVisitor* connection_debug_visitor) { 293 connection_debug_visitor_ = connection_debug_visitor; 294 } 295 296 // Sets the interface name to bind. If empty, will not attempt to bind the 297 // socket to that interface. Defaults to empty string. set_interface_name(std::string interface_name)298 void set_interface_name(std::string interface_name) { 299 interface_name_ = interface_name; 300 } 301 interface_name()302 std::string interface_name() const { return interface_name_; } 303 set_server_connection_id_override(const QuicConnectionId & connection_id)304 void set_server_connection_id_override( 305 const QuicConnectionId& connection_id) { 306 server_connection_id_override_ = connection_id; 307 } 308 set_server_connection_id_length(uint8_t server_connection_id_length)309 void set_server_connection_id_length(uint8_t server_connection_id_length) { 310 server_connection_id_length_ = server_connection_id_length; 311 } 312 set_client_connection_id_length(uint8_t client_connection_id_length)313 void set_client_connection_id_length(uint8_t client_connection_id_length) { 314 client_connection_id_length_ = client_connection_id_length; 315 } 316 317 bool HasPendingPathValidation(); 318 319 void ValidateNewNetwork(const QuicIpAddress& host); 320 AddValidatedPath(std::unique_ptr<QuicPathValidationContext> context)321 void AddValidatedPath(std::unique_ptr<QuicPathValidationContext> context) { 322 validated_paths_.push_back(std::move(context)); 323 } 324 325 const std::vector<std::unique_ptr<QuicPathValidationContext>>& validated_paths()326 validated_paths() const { 327 return validated_paths_; 328 } 329 330 // Enable port migration upon path degrading after given number of PTOs. 331 // If no value is provided, path degrading will be detected after 4 PTOs by 332 // default. EnablePortMigrationUponPathDegrading(std::optional<int> num_ptos_for_path_degrading)333 void EnablePortMigrationUponPathDegrading( 334 std::optional<int> num_ptos_for_path_degrading) { 335 allow_port_migration_ = true; 336 if (num_ptos_for_path_degrading.has_value()) { 337 session_->connection() 338 ->sent_packet_manager() 339 .set_num_ptos_for_path_degrading(num_ptos_for_path_degrading.value()); 340 } 341 } 342 343 virtual void OnSocketMigrationProbingSuccess( 344 std::unique_ptr<QuicPathValidationContext> context); 345 OnSocketMigrationProbingFailure()346 virtual void OnSocketMigrationProbingFailure() {} 347 348 protected: 349 // TODO(rch): Move GetNumSentClientHellosFromSession and 350 // GetNumReceivedServerConfigUpdatesFromSession into a new/better 351 // QuicSpdyClientSession class. The current inherits dependencies from 352 // Spdy. When that happens this class and all its subclasses should 353 // work with QuicSpdyClientSession instead of QuicSession. 354 // That will obviate the need for the pure virtual functions below. 355 356 // Extract the number of sent client hellos from the session. 357 virtual int GetNumSentClientHellosFromSession() = 0; 358 359 // The number of server config updates received. 360 virtual int GetNumReceivedServerConfigUpdatesFromSession() = 0; 361 362 // If this client supports buffering data, resend it. 363 virtual void ResendSavedData() = 0; 364 365 // If this client supports buffering data, clear it. 366 virtual void ClearDataToResend() = 0; 367 368 // Takes ownership of |connection|. If you override this function, 369 // you probably want to call ResetSession() in your destructor. 370 // TODO(rch): Change the connection parameter to take in a 371 // std::unique_ptr<QuicConnection> instead. 372 virtual std::unique_ptr<QuicSession> CreateQuicClientSession( 373 const ParsedQuicVersionVector& supported_versions, 374 QuicConnection* connection) = 0; 375 376 // Generates the next ConnectionId for |server_id_|. By default, if the 377 // cached server config contains a server-designated ID, that ID will be 378 // returned. Otherwise, the next random ID will be returned. 379 QuicConnectionId GetNextConnectionId(); 380 381 // Generates a new, random connection ID (as opposed to a server-designated 382 // connection ID). 383 virtual QuicConnectionId GenerateNewConnectionId(); 384 385 // Returns the client connection ID to use. 386 virtual QuicConnectionId GetClientConnectionId(); 387 388 // Subclasses may need to explicitly clear the session on destruction 389 // if they create it with objects that will be destroyed before this is. 390 // You probably want to call this if you override CreateQuicSpdyClientSession. ResetSession()391 void ResetSession() { session_.reset(); } 392 393 // Returns true if the corresponding of this client has active requests. 394 virtual bool HasActiveRequests() = 0; 395 396 // Allows derived classes to access this when creating connections. 397 ConnectionIdGeneratorInterface& connection_id_generator(); 398 399 private: 400 // Returns true and set |version| if client can reconnect with a different 401 // version. 402 bool CanReconnectWithDifferentVersion(ParsedQuicVersion* version) const; 403 404 std::unique_ptr<QuicPacketWriter> CreateWriterForNewNetwork( 405 const QuicIpAddress& new_host, int port); 406 407 // |server_id_| is a tuple (hostname, port, is_https) of the server. 408 QuicServerId server_id_; 409 410 // Tracks if the client is initialized to connect. 411 bool initialized_; 412 413 // Address of the server. 414 QuicSocketAddress server_address_; 415 416 // If initialized, the address to bind to. 417 QuicIpAddress bind_to_address_; 418 419 // Local port to bind to. Initialize to 0. 420 int local_port_; 421 422 // config_ and crypto_config_ contain configuration and cached state about 423 // servers. 424 QuicConfig config_; 425 QuicCryptoClientConfig crypto_config_; 426 427 // Helper to be used by created connections. Must outlive |session_|. 428 std::unique_ptr<QuicConnectionHelperInterface> helper_; 429 430 // Alarm factory to be used by created connections. Must outlive |session_|. 431 std::unique_ptr<QuicAlarmFactory> alarm_factory_; 432 433 // Writer used to actually send packets to the wire. Must outlive |session_|. 434 std::unique_ptr<QuicPacketWriter> writer_; 435 436 // Session which manages streams. 437 std::unique_ptr<QuicSession> session_; 438 439 // This vector contains QUIC versions which we currently support. 440 // This should be ordered such that the highest supported version is the first 441 // element, with subsequent elements in descending order (versions can be 442 // skipped as necessary). We will always pick supported_versions_[0] as the 443 // initial version to use. 444 ParsedQuicVersionVector supported_versions_; 445 446 // The initial value of maximum packet size of the connection. If set to 447 // zero, the default is used. 448 QuicByteCount initial_max_packet_length_; 449 450 // The number of hellos sent during the current/latest connection. 451 int num_sent_client_hellos_; 452 453 // Used to store any errors that occurred with the overall connection (as 454 // opposed to that associated with the last session object). 455 QuicErrorCode connection_error_; 456 457 // True when the client is attempting to connect. Set to false between a call 458 // to Disconnect() and the subsequent call to StartConnect(). When 459 // connected_or_attempting_connect_ is false, the session object corresponds 460 // to the previous client-level connection. 461 bool connected_or_attempting_connect_; 462 463 // The network helper used to create sockets and manage the event loop. 464 // Not owned by this class. 465 std::unique_ptr<NetworkHelper> network_helper_; 466 467 // The debug visitor set on the connection right after it is constructed. 468 // Not owned, must be valid for the lifetime of the QuicClientBase instance. 469 QuicConnectionDebugVisitor* connection_debug_visitor_; 470 471 // If set, 472 // - GetNextConnectionId will use this as the next server connection id. 473 // - GenerateNewConnectionId will not be called. 474 std::optional<QuicConnectionId> server_connection_id_override_; 475 476 // GenerateNewConnectionId creates a random connection ID of this length. 477 // Defaults to 8. 478 uint8_t server_connection_id_length_; 479 480 // GetClientConnectionId creates a random connection ID of this length. 481 // Defaults to 0. 482 uint8_t client_connection_id_length_; 483 484 // Stores validated paths. 485 std::vector<std::unique_ptr<QuicPathValidationContext>> validated_paths_; 486 487 // Stores the interface name to bind. If empty, will not attempt to bind the 488 // socket to that interface. Defaults to empty string. 489 std::string interface_name_; 490 491 DeterministicConnectionIdGenerator connection_id_generator_{ 492 kQuicDefaultConnectionIdLength}; 493 494 bool allow_port_migration_{false}; 495 }; 496 497 } // namespace quic 498 499 #endif // QUICHE_QUIC_TOOLS_QUIC_CLIENT_BASE_H_ 500