blob: 6c1e09a78d0ad9e8b8e3fd9b5d355c56e41ee668 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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"
QUICHE team5015e2e2019-12-11 09:38:06 -080020#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050021
22namespace quic {
23
24class ProofVerifier;
25class QuicServerId;
nharper41ac9df2019-11-11 15:09:23 -080026class SessionCache;
QUICHE teama6ef0a62019-03-07 20:34:33 -050027
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.
34class 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,
nharper41ac9df2019-11-11 15:09:23 -080068 std::unique_ptr<ProofVerifier> proof_verifier,
69 std::unique_ptr<SessionCache> session_cache);
QUICHE teama6ef0a62019-03-07 20:34:33 -050070 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.
danzh711bd182019-05-01 13:44:19 -0700107 QUIC_MUST_USE_RESULT bool WaitForCryptoHandshakeConfirmed();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500108
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
127 const QuicServerId& server_id() const { return server_id_; }
128
129 // This should only be set before the initial Connect()
130 void set_server_id(const QuicServerId& server_id) { server_id_ = server_id; }
131
vasilvvc48c8712019-03-11 13:38:16 -0700132 void SetUserAgentID(const std::string& user_agent_id) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500133 crypto_config_.set_user_agent_id(user_agent_id);
134 }
135
QUICHE teama6ef0a62019-03-07 20:34:33 -0500136 const ParsedQuicVersionVector& supported_versions() const {
137 return supported_versions_;
138 }
139
140 void SetSupportedVersions(const ParsedQuicVersionVector& versions) {
141 supported_versions_ = versions;
142 }
143
144 QuicConfig* config() { return &config_; }
145
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.
150 void set_initial_max_packet_length(QuicByteCount initial_max_packet_length) {
151 initial_max_packet_length_ = initial_max_packet_length;
152 }
153
wub4b1a5e62019-06-06 12:20:05 -0700154 // The number of client hellos sent.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500155 int GetNumSentClientHellos();
156
nharper4084fc92020-02-10 14:43:35 -0800157 // 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
QUICHE teama6ef0a62019-03-07 20:34:33 -0500169 // Gather the stats for the last session and update the stats for the overall
170 // connection.
171 void UpdateStats();
172
wub4b1a5e62019-06-06 12:20:05 -0700173 // The number of server config updates received.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500174 int GetNumReceivedServerConfigUpdates();
175
wub4b1a5e62019-06-06 12:20:05 -0700176 // Returns any errors that occurred at the connection-level.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500177 QuicErrorCode connection_error() const;
178 void set_connection_error(QuicErrorCode connection_error) {
179 connection_error_ = connection_error;
180 }
181
182 bool connected_or_attempting_connect() const {
183 return connected_or_attempting_connect_;
184 }
185 void set_connected_or_attempting_connect(
186 bool connected_or_attempting_connect) {
187 connected_or_attempting_connect_ = connected_or_attempting_connect;
188 }
189
190 QuicPacketWriter* writer() { return writer_.get(); }
191 void set_writer(QuicPacketWriter* writer) {
192 if (writer_.get() != writer) {
193 writer_.reset(writer);
194 }
195 }
196
197 void reset_writer() { writer_.reset(); }
198
199 ProofVerifier* proof_verifier() const;
200
201 void set_bind_to_address(QuicIpAddress address) {
202 bind_to_address_ = address;
203 }
204
205 QuicIpAddress bind_to_address() const { return bind_to_address_; }
206
207 void set_local_port(int local_port) { local_port_ = local_port; }
208
209 int local_port() const { return local_port_; }
210
211 const QuicSocketAddress& server_address() const { return server_address_; }
212
213 void set_server_address(const QuicSocketAddress& server_address) {
214 server_address_ = server_address;
215 }
216
217 QuicConnectionHelperInterface* helper() { return helper_.get(); }
218
219 NetworkHelper* network_helper();
220 const NetworkHelper* network_helper() const;
221
222 bool initialized() const { return initialized_; }
223
QUICHE team5015e2e2019-12-11 09:38:06 -0800224 void SetPreSharedKey(quiche::QuicheStringPiece key) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500225 crypto_config_.set_pre_shared_key(key);
226 }
227
dschinazi2ee30ae2020-02-04 02:17:21 -0800228 void set_connection_debug_visitor(
229 QuicConnectionDebugVisitor* connection_debug_visitor) {
230 connection_debug_visitor_ = connection_debug_visitor;
231 }
232
QUICHE teama6ef0a62019-03-07 20:34:33 -0500233 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
wub4b1a5e62019-06-06 12:20:05 -0700244 // The number of server config updates received.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500245 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
dschinazi346b7ce2019-06-05 01:38:18 -0700274 // Returns the client connection ID to use.
275 virtual QuicConnectionId GetClientConnectionId();
276
QUICHE teama6ef0a62019-03-07 20:34:33 -0500277 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.
282 void ResetSession() { session_.reset(); }
283
QUICHE teamc2653c42019-03-08 13:30:06 -0800284 // Returns true if the corresponding of this client has active requests.
285 virtual bool HasActiveRequests() = 0;
286
QUICHE teama6ef0a62019-03-07 20:34:33 -0500287 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
QUICHE teama6ef0a62019-03-07 20:34:33 -0500335 // 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
wub4b1a5e62019-06-06 12:20:05 -0700342 // True when the client is attempting to connect. Set to false between a call
343 // to Disconnect() and the subsequent call to StartConnect(). When
QUICHE teama6ef0a62019-03-07 20:34:33 -0500344 // 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_;
dschinazi2ee30ae2020-02-04 02:17:21 -0800351
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_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500355};
356
357} // namespace quic
358
359#endif // QUICHE_QUIC_TOOLS_QUIC_CLIENT_BASE_H_