| // Copyright (c) 2015 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. | 
 |  | 
 | // A base class for the toy client, which connects to a specified port and sends | 
 | // QUIC request to that endpoint. | 
 |  | 
 | #ifndef QUICHE_QUIC_TOOLS_QUIC_CLIENT_BASE_H_ | 
 | #define QUICHE_QUIC_TOOLS_QUIC_CLIENT_BASE_H_ | 
 |  | 
 | #include <string> | 
 |  | 
 | #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" | 
 | #include "net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index.h" | 
 | #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h" | 
 | #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h" | 
 | #include "net/third_party/quiche/src/quic/core/quic_config.h" | 
 | #include "net/third_party/quiche/src/quic/platform/api/quic_macros.h" | 
 | #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" | 
 | #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" | 
 |  | 
 | namespace quic { | 
 |  | 
 | class ProofVerifier; | 
 | class QuicServerId; | 
 |  | 
 | // QuicClientBase handles establishing a connection to the passed in | 
 | // server id, including ensuring that it supports the passed in versions | 
 | // and config. | 
 | // Subclasses derived from this class are responsible for creating the | 
 | // actual QuicSession instance, as well as defining functions that | 
 | // create and run the underlying network transport. | 
 | class QuicClientBase { | 
 |  public: | 
 |   // An interface to various network events that the QuicClient will need to | 
 |   // interact with. | 
 |   class NetworkHelper { | 
 |    public: | 
 |     virtual ~NetworkHelper(); | 
 |  | 
 |     // Runs one iteration of the event loop. | 
 |     virtual void RunEventLoop() = 0; | 
 |  | 
 |     // Used during initialization: creates the UDP socket FD, sets socket | 
 |     // options, and binds the socket to our address. | 
 |     virtual bool CreateUDPSocketAndBind(QuicSocketAddress server_address, | 
 |                                         QuicIpAddress bind_to_address, | 
 |                                         int bind_to_port) = 0; | 
 |  | 
 |     // Unregister and close all open UDP sockets. | 
 |     virtual void CleanUpAllUDPSockets() = 0; | 
 |  | 
 |     // If the client has at least one UDP socket, return address of the latest | 
 |     // created one. Otherwise, return an empty socket address. | 
 |     virtual QuicSocketAddress GetLatestClientAddress() const = 0; | 
 |  | 
 |     // Creates a packet writer to be used for the next connection. | 
 |     virtual QuicPacketWriter* CreateQuicPacketWriter() = 0; | 
 |   }; | 
 |  | 
 |   QuicClientBase(const QuicServerId& server_id, | 
 |                  const ParsedQuicVersionVector& supported_versions, | 
 |                  const QuicConfig& config, | 
 |                  QuicConnectionHelperInterface* helper, | 
 |                  QuicAlarmFactory* alarm_factory, | 
 |                  std::unique_ptr<NetworkHelper> network_helper, | 
 |                  std::unique_ptr<ProofVerifier> proof_verifier); | 
 |   QuicClientBase(const QuicClientBase&) = delete; | 
 |   QuicClientBase& operator=(const QuicClientBase&) = delete; | 
 |  | 
 |   virtual ~QuicClientBase(); | 
 |  | 
 |   // Initializes the client to create a connection. Should be called exactly | 
 |   // once before calling StartConnect or Connect. Returns true if the | 
 |   // initialization succeeds, false otherwise. | 
 |   virtual bool Initialize(); | 
 |  | 
 |   // "Connect" to the QUIC server, including performing synchronous crypto | 
 |   // handshake. | 
 |   bool Connect(); | 
 |  | 
 |   // Start the crypto handshake.  This can be done in place of the synchronous | 
 |   // Connect(), but callers are responsible for making sure the crypto handshake | 
 |   // completes. | 
 |   void StartConnect(); | 
 |  | 
 |   // Calls session()->Initialize(). Subclasses may override this if any extra | 
 |   // initialization needs to be done. Subclasses should expect that session() | 
 |   // is non-null and valid. | 
 |   virtual void InitializeSession(); | 
 |  | 
 |   // Disconnects from the QUIC server. | 
 |   void Disconnect(); | 
 |  | 
 |   // Returns true if the crypto handshake has yet to establish encryption. | 
 |   // Returns false if encryption is active (even if the server hasn't confirmed | 
 |   // the handshake) or if the connection has been closed. | 
 |   bool EncryptionBeingEstablished(); | 
 |  | 
 |   // Wait for events until the stream with the given ID is closed. | 
 |   void WaitForStreamToClose(QuicStreamId id); | 
 |  | 
 |   // Wait for events until the handshake is confirmed. | 
 |   // Returns true if the crypto handshake succeeds, false otherwise. | 
 |   bool WaitForCryptoHandshakeConfirmed() QUIC_MUST_USE_RESULT; | 
 |  | 
 |   // Wait up to 50ms, and handle any events which occur. | 
 |   // Returns true if there are any outstanding requests. | 
 |   bool WaitForEvents(); | 
 |  | 
 |   // Migrate to a new socket (new_host) during an active connection. | 
 |   bool MigrateSocket(const QuicIpAddress& new_host); | 
 |  | 
 |   // Migrate to a new socket (new_host, port) during an active connection. | 
 |   bool MigrateSocketWithSpecifiedPort(const QuicIpAddress& new_host, int port); | 
 |  | 
 |   // Open a new socket to change to a new ephemeral port. | 
 |   bool ChangeEphemeralPort(); | 
 |  | 
 |   QuicSession* session(); | 
 |  | 
 |   bool connected() const; | 
 |   bool goaway_received() const; | 
 |  | 
 |   const QuicServerId& server_id() const { return server_id_; } | 
 |  | 
 |   // This should only be set before the initial Connect() | 
 |   void set_server_id(const QuicServerId& server_id) { server_id_ = server_id; } | 
 |  | 
 |   void SetUserAgentID(const std::string& user_agent_id) { | 
 |     crypto_config_.set_user_agent_id(user_agent_id); | 
 |   } | 
 |  | 
 |   // SetChannelIDSource sets a ChannelIDSource that will be called, when the | 
 |   // server supports channel IDs, to obtain a channel ID for signing a message | 
 |   // proving possession of the channel ID. | 
 |   void SetChannelIDSource(std::unique_ptr<ChannelIDSource> source) { | 
 |     crypto_config_.SetChannelIDSource(std::move(source)); | 
 |   } | 
 |  | 
 |   const ParsedQuicVersionVector& supported_versions() const { | 
 |     return supported_versions_; | 
 |   } | 
 |  | 
 |   void SetSupportedVersions(const ParsedQuicVersionVector& versions) { | 
 |     supported_versions_ = versions; | 
 |   } | 
 |  | 
 |   QuicConfig* config() { return &config_; } | 
 |  | 
 |   QuicCryptoClientConfig* crypto_config() { return &crypto_config_; } | 
 |  | 
 |   // Change the initial maximum packet size of the connection.  Has to be called | 
 |   // before Connect()/StartConnect() in order to have any effect. | 
 |   void set_initial_max_packet_length(QuicByteCount initial_max_packet_length) { | 
 |     initial_max_packet_length_ = initial_max_packet_length; | 
 |   } | 
 |  | 
 |   int num_stateless_rejects_received() const { | 
 |     return num_stateless_rejects_received_; | 
 |   } | 
 |  | 
 |   // The number of client hellos sent, taking stateless rejects into | 
 |   // account.  In the case of a stateless reject, the initial | 
 |   // connection object may be torn down and a new one created.  The | 
 |   // user cannot rely upon the latest connection object to get the | 
 |   // total number of client hellos sent, and should use this function | 
 |   // instead. | 
 |   int GetNumSentClientHellos(); | 
 |  | 
 |   // Gather the stats for the last session and update the stats for the overall | 
 |   // connection. | 
 |   void UpdateStats(); | 
 |  | 
 |   // The number of server config updates received.  We assume no | 
 |   // updates can be sent during a previously, statelessly rejected | 
 |   // connection, so only the latest session is taken into account. | 
 |   int GetNumReceivedServerConfigUpdates(); | 
 |  | 
 |   // Returns any errors that occurred at the connection-level (as | 
 |   // opposed to the session-level).  When a stateless reject occurs, | 
 |   // the error of the last session may not reflect the overall state | 
 |   // of the connection. | 
 |   QuicErrorCode connection_error() const; | 
 |   void set_connection_error(QuicErrorCode connection_error) { | 
 |     connection_error_ = connection_error; | 
 |   } | 
 |  | 
 |   bool connected_or_attempting_connect() const { | 
 |     return connected_or_attempting_connect_; | 
 |   } | 
 |   void set_connected_or_attempting_connect( | 
 |       bool connected_or_attempting_connect) { | 
 |     connected_or_attempting_connect_ = connected_or_attempting_connect; | 
 |   } | 
 |  | 
 |   QuicPacketWriter* writer() { return writer_.get(); } | 
 |   void set_writer(QuicPacketWriter* writer) { | 
 |     if (writer_.get() != writer) { | 
 |       writer_.reset(writer); | 
 |     } | 
 |   } | 
 |  | 
 |   void reset_writer() { writer_.reset(); } | 
 |  | 
 |   ProofVerifier* proof_verifier() const; | 
 |  | 
 |   void set_bind_to_address(QuicIpAddress address) { | 
 |     bind_to_address_ = address; | 
 |   } | 
 |  | 
 |   QuicIpAddress bind_to_address() const { return bind_to_address_; } | 
 |  | 
 |   void set_local_port(int local_port) { local_port_ = local_port; } | 
 |  | 
 |   int local_port() const { return local_port_; } | 
 |  | 
 |   const QuicSocketAddress& server_address() const { return server_address_; } | 
 |  | 
 |   void set_server_address(const QuicSocketAddress& server_address) { | 
 |     server_address_ = server_address; | 
 |   } | 
 |  | 
 |   QuicConnectionHelperInterface* helper() { return helper_.get(); } | 
 |  | 
 |   NetworkHelper* network_helper(); | 
 |   const NetworkHelper* network_helper() const; | 
 |  | 
 |   bool initialized() const { return initialized_; } | 
 |  | 
 |   void SetPreSharedKey(QuicStringPiece key) { | 
 |     crypto_config_.set_pre_shared_key(key); | 
 |   } | 
 |  | 
 |  protected: | 
 |   // TODO(rch): Move GetNumSentClientHellosFromSession and | 
 |   // GetNumReceivedServerConfigUpdatesFromSession into a new/better | 
 |   // QuicSpdyClientSession class. The current inherits dependencies from | 
 |   // Spdy. When that happens this class and all its subclasses should | 
 |   // work with QuicSpdyClientSession instead of QuicSession. | 
 |   // That will obviate the need for the pure virtual functions below. | 
 |  | 
 |   // Extract the number of sent client hellos from the session. | 
 |   virtual int GetNumSentClientHellosFromSession() = 0; | 
 |  | 
 |   // The number of server config updates received.  We assume no | 
 |   // updates can be sent during a previously, statelessly rejected | 
 |   // connection, so only the latest session is taken into account. | 
 |   virtual int GetNumReceivedServerConfigUpdatesFromSession() = 0; | 
 |  | 
 |   // If this client supports buffering data, resend it. | 
 |   virtual void ResendSavedData() = 0; | 
 |  | 
 |   // If this client supports buffering data, clear it. | 
 |   virtual void ClearDataToResend() = 0; | 
 |  | 
 |   // Takes ownership of |connection|. If you override this function, | 
 |   // you probably want to call ResetSession() in your destructor. | 
 |   // TODO(rch): Change the connection parameter to take in a | 
 |   // std::unique_ptr<QuicConnection> instead. | 
 |   virtual std::unique_ptr<QuicSession> CreateQuicClientSession( | 
 |       const ParsedQuicVersionVector& supported_versions, | 
 |       QuicConnection* connection) = 0; | 
 |  | 
 |   // Generates the next ConnectionId for |server_id_|.  By default, if the | 
 |   // cached server config contains a server-designated ID, that ID will be | 
 |   // returned.  Otherwise, the next random ID will be returned. | 
 |   QuicConnectionId GetNextConnectionId(); | 
 |  | 
 |   // Returns the next server-designated ConnectionId from the cached config for | 
 |   // |server_id_|, if it exists.  Otherwise, returns 0. | 
 |   QuicConnectionId GetNextServerDesignatedConnectionId(); | 
 |  | 
 |   // Generates a new, random connection ID (as opposed to a server-designated | 
 |   // connection ID). | 
 |   virtual QuicConnectionId GenerateNewConnectionId(); | 
 |  | 
 |   QuicAlarmFactory* alarm_factory() { return alarm_factory_.get(); } | 
 |  | 
 |   // Subclasses may need to explicitly clear the session on destruction | 
 |   // if they create it with objects that will be destroyed before this is. | 
 |   // You probably want to call this if you override CreateQuicSpdyClientSession. | 
 |   void ResetSession() { session_.reset(); } | 
 |  | 
 |   // Returns true if the corresponding of this client has active requests. | 
 |   virtual bool HasActiveRequests() = 0; | 
 |  | 
 |  private: | 
 |   // Returns true and set |version| if client can reconnect with a different | 
 |   // version. | 
 |   bool CanReconnectWithDifferentVersion(ParsedQuicVersion* version) const; | 
 |  | 
 |   // |server_id_| is a tuple (hostname, port, is_https) of the server. | 
 |   QuicServerId server_id_; | 
 |  | 
 |   // Tracks if the client is initialized to connect. | 
 |   bool initialized_; | 
 |  | 
 |   // Address of the server. | 
 |   QuicSocketAddress server_address_; | 
 |  | 
 |   // If initialized, the address to bind to. | 
 |   QuicIpAddress bind_to_address_; | 
 |  | 
 |   // Local port to bind to. Initialize to 0. | 
 |   int local_port_; | 
 |  | 
 |   // config_ and crypto_config_ contain configuration and cached state about | 
 |   // servers. | 
 |   QuicConfig config_; | 
 |   QuicCryptoClientConfig crypto_config_; | 
 |  | 
 |   // Helper to be used by created connections. Must outlive |session_|. | 
 |   std::unique_ptr<QuicConnectionHelperInterface> helper_; | 
 |  | 
 |   // Alarm factory to be used by created connections. Must outlive |session_|. | 
 |   std::unique_ptr<QuicAlarmFactory> alarm_factory_; | 
 |  | 
 |   // Writer used to actually send packets to the wire. Must outlive |session_|. | 
 |   std::unique_ptr<QuicPacketWriter> writer_; | 
 |  | 
 |   // Session which manages streams. | 
 |   std::unique_ptr<QuicSession> session_; | 
 |  | 
 |   // This vector contains QUIC versions which we currently support. | 
 |   // This should be ordered such that the highest supported version is the first | 
 |   // element, with subsequent elements in descending order (versions can be | 
 |   // skipped as necessary). We will always pick supported_versions_[0] as the | 
 |   // initial version to use. | 
 |   ParsedQuicVersionVector supported_versions_; | 
 |  | 
 |   // The initial value of maximum packet size of the connection.  If set to | 
 |   // zero, the default is used. | 
 |   QuicByteCount initial_max_packet_length_; | 
 |  | 
 |   // The number of stateless rejects received during the current/latest | 
 |   // connection. | 
 |   // TODO(jokulik): Consider some consistent naming scheme (or other) for member | 
 |   // variables that are kept per-request, per-connection, and over the client's | 
 |   // lifetime. | 
 |   int num_stateless_rejects_received_; | 
 |  | 
 |   // The number of hellos sent during the current/latest connection. | 
 |   int num_sent_client_hellos_; | 
 |  | 
 |   // Used to store any errors that occurred with the overall connection (as | 
 |   // opposed to that associated with the last session object). | 
 |   QuicErrorCode connection_error_; | 
 |  | 
 |   // True when the client is attempting to connect or re-connect the session (in | 
 |   // the case of a stateless reject).  Set to false  between a call to | 
 |   // Disconnect() and the subsequent call to StartConnect().  When | 
 |   // connected_or_attempting_connect_ is false, the session object corresponds | 
 |   // to the previous client-level connection. | 
 |   bool connected_or_attempting_connect_; | 
 |  | 
 |   // The network helper used to create sockets and manage the event loop. | 
 |   // Not owned by this class. | 
 |   std::unique_ptr<NetworkHelper> network_helper_; | 
 | }; | 
 |  | 
 | }  // namespace quic | 
 |  | 
 | #endif  // QUICHE_QUIC_TOOLS_QUIC_CLIENT_BASE_H_ |