1 // Copyright (c) 2013 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.
5 #include "net/quic/quic_config.h"
9 #include "base/logging.h"
10 #include "net/quic/crypto/crypto_handshake_message.h"
11 #include "net/quic/crypto/crypto_protocol.h"
12 #include "net/quic/quic_sent_packet_manager.h"
13 #include "net/quic/quic_utils.h"
19 QuicNegotiableValue::QuicNegotiableValue(QuicTag tag
, Presence presence
)
25 QuicNegotiableUint32::QuicNegotiableUint32(QuicTag tag
, Presence presence
)
26 : QuicNegotiableValue(tag
, presence
),
31 void QuicNegotiableUint32::set(uint32 max
, uint32 default_value
) {
32 DCHECK_LE(default_value
, max
);
34 default_value_
= default_value
;
37 uint32
QuicNegotiableUint32::GetUint32() const {
39 return negotiated_value_
;
41 return default_value_
;
44 void QuicNegotiableUint32::ToHandshakeMessage(
45 CryptoHandshakeMessage
* out
) const {
47 out
->SetValue(tag_
, negotiated_value_
);
49 out
->SetValue(tag_
, max_value_
);
53 QuicErrorCode
QuicNegotiableUint32::ReadUint32(
54 const CryptoHandshakeMessage
& msg
,
56 string
* error_details
) const {
57 DCHECK(error_details
!= NULL
);
58 QuicErrorCode error
= msg
.GetUint32(tag_
, out
);
60 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
:
61 if (presence_
== QuicNegotiableValue::PRESENCE_REQUIRED
) {
62 *error_details
= "Missing " + QuicUtils::TagToString(tag_
);
65 error
= QUIC_NO_ERROR
;
66 *out
= default_value_
;
71 *error_details
= "Bad " + QuicUtils::TagToString(tag_
);
77 QuicErrorCode
QuicNegotiableUint32::ProcessClientHello(
78 const CryptoHandshakeMessage
& client_hello
,
79 string
* error_details
) {
81 DCHECK(error_details
!= NULL
);
83 QuicErrorCode error
= ReadUint32(client_hello
, &value
, error_details
);
84 if (error
!= QUIC_NO_ERROR
) {
89 negotiated_value_
= std::min(value
, max_value_
);
94 QuicErrorCode
QuicNegotiableUint32::ProcessServerHello(
95 const CryptoHandshakeMessage
& server_hello
,
96 string
* error_details
) {
98 DCHECK(error_details
!= NULL
);
100 QuicErrorCode error
= ReadUint32(server_hello
, &value
, error_details
);
101 if (error
!= QUIC_NO_ERROR
) {
105 if (value
> max_value_
) {
106 *error_details
= "Invalid value received for " +
107 QuicUtils::TagToString(tag_
);
108 return QUIC_INVALID_NEGOTIATED_VALUE
;
112 negotiated_value_
= value
;
113 return QUIC_NO_ERROR
;
116 QuicNegotiableTag::QuicNegotiableTag(QuicTag tag
, Presence presence
)
117 : QuicNegotiableValue(tag
, presence
),
122 QuicNegotiableTag::~QuicNegotiableTag() {}
124 void QuicNegotiableTag::set(const QuicTagVector
& possible
,
125 QuicTag default_value
) {
126 DCHECK(std::find(possible
.begin(), possible
.end(), default_value
) !=
128 possible_values_
= possible
;
129 default_value_
= default_value
;
132 QuicTag
QuicNegotiableTag::GetTag() const {
134 return negotiated_tag_
;
136 return default_value_
;
139 void QuicNegotiableTag::ToHandshakeMessage(CryptoHandshakeMessage
* out
) const {
141 // Because of the way we serialize and parse handshake messages we can
142 // serialize this as value and still parse it as a vector.
143 out
->SetValue(tag_
, negotiated_tag_
);
145 out
->SetVector(tag_
, possible_values_
);
149 QuicErrorCode
QuicNegotiableTag::ReadVector(
150 const CryptoHandshakeMessage
& msg
,
153 string
* error_details
) const {
154 DCHECK(error_details
!= NULL
);
155 QuicErrorCode error
= msg
.GetTaglist(tag_
, out
, out_length
);
157 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
:
158 if (presence_
== PRESENCE_REQUIRED
) {
159 *error_details
= "Missing " + QuicUtils::TagToString(tag_
);
162 error
= QUIC_NO_ERROR
;
164 *out
= &default_value_
;
169 *error_details
= "Bad " + QuicUtils::TagToString(tag_
);
175 QuicErrorCode
QuicNegotiableTag::ProcessClientHello(
176 const CryptoHandshakeMessage
& client_hello
,
177 string
* error_details
) {
178 DCHECK(!negotiated_
);
179 DCHECK(error_details
!= NULL
);
180 const QuicTag
* received_tags
;
181 size_t received_tags_length
;
182 QuicErrorCode error
= ReadVector(client_hello
, &received_tags
,
183 &received_tags_length
, error_details
);
184 if (error
!= QUIC_NO_ERROR
) {
188 QuicTag negotiated_tag
;
189 if (!QuicUtils::FindMutualTag(possible_values_
,
191 received_tags_length
,
192 QuicUtils::LOCAL_PRIORITY
,
195 *error_details
= "Unsuported " + QuicUtils::TagToString(tag_
);
196 return QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP
;
200 negotiated_tag_
= negotiated_tag
;
201 return QUIC_NO_ERROR
;
204 QuicErrorCode
QuicNegotiableTag::ProcessServerHello(
205 const CryptoHandshakeMessage
& server_hello
,
206 string
* error_details
) {
207 DCHECK(!negotiated_
);
208 DCHECK(error_details
!= NULL
);
209 const QuicTag
* received_tags
;
210 size_t received_tags_length
;
211 QuicErrorCode error
= ReadVector(server_hello
, &received_tags
,
212 &received_tags_length
, error_details
);
213 if (error
!= QUIC_NO_ERROR
) {
217 if (received_tags_length
!= 1 ||
218 std::find(possible_values_
.begin(), possible_values_
.end(),
219 *received_tags
) == possible_values_
.end()) {
220 *error_details
= "Invalid " + QuicUtils::TagToString(tag_
);
221 return QUIC_INVALID_NEGOTIATED_VALUE
;
225 negotiated_tag_
= *received_tags
;
226 return QUIC_NO_ERROR
;
229 QuicConfig::QuicConfig() :
230 congestion_control_(kCGST
, QuicNegotiableValue::PRESENCE_REQUIRED
),
231 idle_connection_state_lifetime_seconds_(
232 kICSL
, QuicNegotiableValue::PRESENCE_REQUIRED
),
233 keepalive_timeout_seconds_(kKATO
, QuicNegotiableValue::PRESENCE_OPTIONAL
),
234 max_streams_per_connection_(kMSPC
, QuicNegotiableValue::PRESENCE_REQUIRED
),
235 max_time_before_crypto_handshake_(QuicTime::Delta::Zero()),
236 server_initial_congestion_window_(
237 kSWND
, QuicNegotiableValue::PRESENCE_OPTIONAL
),
238 initial_round_trip_time_us_(kIRTT
, QuicNegotiableValue::PRESENCE_OPTIONAL
) {
239 // All optional non-zero parameters should be initialized here.
240 server_initial_congestion_window_
.set(kMaxInitialWindow
,
241 kDefaultInitialWindow
);
244 QuicConfig::~QuicConfig() {}
246 void QuicConfig::set_congestion_control(
247 const QuicTagVector
& congestion_control
,
248 QuicTag default_congestion_control
) {
249 congestion_control_
.set(congestion_control
, default_congestion_control
);
252 QuicTag
QuicConfig::congestion_control() const {
253 return congestion_control_
.GetTag();
256 void QuicConfig::set_idle_connection_state_lifetime(
257 QuicTime::Delta max_idle_connection_state_lifetime
,
258 QuicTime::Delta default_idle_conection_state_lifetime
) {
259 idle_connection_state_lifetime_seconds_
.set(
260 max_idle_connection_state_lifetime
.ToSeconds(),
261 default_idle_conection_state_lifetime
.ToSeconds());
264 QuicTime::Delta
QuicConfig::idle_connection_state_lifetime() const {
265 return QuicTime::Delta::FromSeconds(
266 idle_connection_state_lifetime_seconds_
.GetUint32());
269 QuicTime::Delta
QuicConfig::keepalive_timeout() const {
270 return QuicTime::Delta::FromSeconds(
271 keepalive_timeout_seconds_
.GetUint32());
274 void QuicConfig::set_max_streams_per_connection(size_t max_streams
,
275 size_t default_streams
) {
276 max_streams_per_connection_
.set(max_streams
, default_streams
);
279 uint32
QuicConfig::max_streams_per_connection() const {
280 return max_streams_per_connection_
.GetUint32();
283 void QuicConfig::set_max_time_before_crypto_handshake(
284 QuicTime::Delta max_time_before_crypto_handshake
) {
285 max_time_before_crypto_handshake_
= max_time_before_crypto_handshake
;
288 QuicTime::Delta
QuicConfig::max_time_before_crypto_handshake() const {
289 return max_time_before_crypto_handshake_
;
292 void QuicConfig::set_server_initial_congestion_window(size_t max_initial_window
,
293 size_t default_initial_window
) {
294 server_initial_congestion_window_
.set(max_initial_window
,
295 default_initial_window
);
298 uint32
QuicConfig::server_initial_congestion_window() const {
299 return server_initial_congestion_window_
.GetUint32();
302 void QuicConfig::set_initial_round_trip_time_us(size_t max_rtt
,
303 size_t default_rtt
) {
304 initial_round_trip_time_us_
.set(max_rtt
, default_rtt
);
307 uint32
QuicConfig::initial_round_trip_time_us() const {
308 return initial_round_trip_time_us_
.GetUint32();
311 bool QuicConfig::negotiated() {
312 // TODO(ianswett): Add the negotiated parameters once and iterate over all
313 // of them in negotiated, ToHandshakeMessage, ProcessClientHello, and
314 // ProcessServerHello.
315 return congestion_control_
.negotiated() &&
316 idle_connection_state_lifetime_seconds_
.negotiated() &&
317 keepalive_timeout_seconds_
.negotiated() &&
318 max_streams_per_connection_
.negotiated() &&
319 server_initial_congestion_window_
.negotiated() &&
320 initial_round_trip_time_us_
.negotiated();
323 void QuicConfig::SetDefaults() {
324 QuicTagVector congestion_control
;
325 if (FLAGS_enable_quic_pacing
) {
326 congestion_control
.push_back(kPACE
);
328 congestion_control
.push_back(kQBIC
);
329 congestion_control_
.set(congestion_control
, kQBIC
);
330 idle_connection_state_lifetime_seconds_
.set(kDefaultTimeoutSecs
,
331 kDefaultInitialTimeoutSecs
);
332 // kKATO is optional. Return 0 if not negotiated.
333 keepalive_timeout_seconds_
.set(0, 0);
334 max_streams_per_connection_
.set(kDefaultMaxStreamsPerConnection
,
335 kDefaultMaxStreamsPerConnection
);
336 max_time_before_crypto_handshake_
= QuicTime::Delta::FromSeconds(
337 kDefaultMaxTimeForCryptoHandshakeSecs
);
338 server_initial_congestion_window_
.set(kDefaultInitialWindow
,
339 kDefaultInitialWindow
);
342 void QuicConfig::EnablePacing(bool enable_pacing
) {
343 QuicTagVector congestion_control
;
345 congestion_control
.push_back(kPACE
);
347 congestion_control
.push_back(kQBIC
);
348 congestion_control_
.set(congestion_control
, kQBIC
);
351 void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage
* out
) const {
352 congestion_control_
.ToHandshakeMessage(out
);
353 idle_connection_state_lifetime_seconds_
.ToHandshakeMessage(out
);
354 keepalive_timeout_seconds_
.ToHandshakeMessage(out
);
355 max_streams_per_connection_
.ToHandshakeMessage(out
);
356 server_initial_congestion_window_
.ToHandshakeMessage(out
);
357 // TODO(ianswett): Don't transmit parameters which are optional and not set.
358 initial_round_trip_time_us_
.ToHandshakeMessage(out
);
361 QuicErrorCode
QuicConfig::ProcessClientHello(
362 const CryptoHandshakeMessage
& client_hello
,
363 string
* error_details
) {
364 DCHECK(error_details
!= NULL
);
366 QuicErrorCode error
= QUIC_NO_ERROR
;
367 if (error
== QUIC_NO_ERROR
) {
368 error
= congestion_control_
.ProcessClientHello(client_hello
, error_details
);
370 if (error
== QUIC_NO_ERROR
) {
371 error
= idle_connection_state_lifetime_seconds_
.ProcessClientHello(
372 client_hello
, error_details
);
374 if (error
== QUIC_NO_ERROR
) {
375 error
= keepalive_timeout_seconds_
.ProcessClientHello(
376 client_hello
, error_details
);
378 if (error
== QUIC_NO_ERROR
) {
379 error
= max_streams_per_connection_
.ProcessClientHello(
380 client_hello
, error_details
);
382 if (error
== QUIC_NO_ERROR
) {
383 error
= server_initial_congestion_window_
.ProcessClientHello(
384 client_hello
, error_details
);
386 if (error
== QUIC_NO_ERROR
) {
387 error
= initial_round_trip_time_us_
.ProcessClientHello(
388 client_hello
, error_details
);
393 QuicErrorCode
QuicConfig::ProcessServerHello(
394 const CryptoHandshakeMessage
& server_hello
,
395 string
* error_details
) {
396 DCHECK(error_details
!= NULL
);
398 QuicErrorCode error
= QUIC_NO_ERROR
;
399 if (error
== QUIC_NO_ERROR
) {
400 error
= congestion_control_
.ProcessServerHello(server_hello
, error_details
);
402 if (error
== QUIC_NO_ERROR
) {
403 error
= idle_connection_state_lifetime_seconds_
.ProcessServerHello(
404 server_hello
, error_details
);
406 if (error
== QUIC_NO_ERROR
) {
407 error
= keepalive_timeout_seconds_
.ProcessServerHello(
408 server_hello
, error_details
);
410 if (error
== QUIC_NO_ERROR
) {
411 error
= max_streams_per_connection_
.ProcessServerHello(
412 server_hello
, error_details
);
414 if (error
== QUIC_NO_ERROR
) {
415 error
= server_initial_congestion_window_
.ProcessServerHello(
416 server_hello
, error_details
);
418 if (error
== QUIC_NO_ERROR
) {
419 error
= initial_round_trip_time_us_
.ProcessServerHello(
420 server_hello
, error_details
);