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