• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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