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_flags.h"
13 #include "net/quic/quic_sent_packet_manager.h"
14 #include "net/quic/quic_utils.h"
21 // Reads the value corresponding to |name_| from |msg| into |out|. If the
22 // |name_| is absent in |msg| and |presence| is set to OPTIONAL |out| is set
23 // to |default_value|.
24 QuicErrorCode
ReadUint32(const CryptoHandshakeMessage
& msg
,
26 QuicConfigPresence presence
,
29 string
* error_details
) {
30 DCHECK(error_details
!= NULL
);
31 QuicErrorCode error
= msg
.GetUint32(tag
, out
);
33 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
:
34 if (presence
== PRESENCE_REQUIRED
) {
35 *error_details
= "Missing " + QuicUtils::TagToString(tag
);
38 error
= QUIC_NO_ERROR
;
44 *error_details
= "Bad " + QuicUtils::TagToString(tag
);
51 QuicConfigValue::QuicConfigValue(QuicTag tag
,
52 QuicConfigPresence presence
)
56 QuicConfigValue::~QuicConfigValue() {}
58 QuicNegotiableValue::QuicNegotiableValue(QuicTag tag
,
59 QuicConfigPresence presence
)
60 : QuicConfigValue(tag
, presence
),
63 QuicNegotiableValue::~QuicNegotiableValue() {}
65 QuicNegotiableUint32::QuicNegotiableUint32(QuicTag tag
,
66 QuicConfigPresence presence
)
67 : QuicNegotiableValue(tag
, presence
),
71 QuicNegotiableUint32::~QuicNegotiableUint32() {}
73 void QuicNegotiableUint32::set(uint32 max
, uint32 default_value
) {
74 DCHECK_LE(default_value
, max
);
76 default_value_
= default_value
;
79 uint32
QuicNegotiableUint32::GetUint32() const {
81 return negotiated_value_
;
83 return default_value_
;
86 void QuicNegotiableUint32::ToHandshakeMessage(
87 CryptoHandshakeMessage
* out
) const {
89 out
->SetValue(tag_
, negotiated_value_
);
91 out
->SetValue(tag_
, max_value_
);
95 QuicErrorCode
QuicNegotiableUint32::ProcessPeerHello(
96 const CryptoHandshakeMessage
& peer_hello
,
98 string
* error_details
) {
100 DCHECK(error_details
!= NULL
);
102 QuicErrorCode error
= ReadUint32(peer_hello
,
108 if (error
!= QUIC_NO_ERROR
) {
111 if (hello_type
== SERVER
&& value
> max_value_
) {
112 *error_details
= "Invalid value received for " +
113 QuicUtils::TagToString(tag_
);
114 return QUIC_INVALID_NEGOTIATED_VALUE
;
118 negotiated_value_
= min(value
, max_value_
);
119 return QUIC_NO_ERROR
;
122 QuicNegotiableTag::QuicNegotiableTag(QuicTag tag
, QuicConfigPresence presence
)
123 : QuicNegotiableValue(tag
, presence
),
128 QuicNegotiableTag::~QuicNegotiableTag() {}
130 void QuicNegotiableTag::set(const QuicTagVector
& possible
,
131 QuicTag default_value
) {
132 DCHECK(std::find(possible
.begin(), possible
.end(), default_value
) !=
134 possible_values_
= possible
;
135 default_value_
= default_value
;
138 QuicTag
QuicNegotiableTag::GetTag() const {
140 return negotiated_tag_
;
142 return default_value_
;
145 void QuicNegotiableTag::ToHandshakeMessage(CryptoHandshakeMessage
* out
) const {
147 // Because of the way we serialize and parse handshake messages we can
148 // serialize this as value and still parse it as a vector.
149 out
->SetValue(tag_
, negotiated_tag_
);
151 out
->SetVector(tag_
, possible_values_
);
155 QuicErrorCode
QuicNegotiableTag::ReadVector(
156 const CryptoHandshakeMessage
& msg
,
159 string
* error_details
) const {
160 DCHECK(error_details
!= NULL
);
161 QuicErrorCode error
= msg
.GetTaglist(tag_
, out
, out_length
);
163 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
:
164 if (presence_
== PRESENCE_REQUIRED
) {
165 *error_details
= "Missing " + QuicUtils::TagToString(tag_
);
168 error
= QUIC_NO_ERROR
;
170 *out
= &default_value_
;
175 *error_details
= "Bad " + QuicUtils::TagToString(tag_
);
181 QuicErrorCode
QuicNegotiableTag::ProcessPeerHello(
182 const CryptoHandshakeMessage
& peer_hello
,
183 HelloType hello_type
,
184 string
* error_details
) {
185 DCHECK(!negotiated_
);
186 DCHECK(error_details
!= NULL
);
187 const QuicTag
* received_tags
;
188 size_t received_tags_length
;
189 QuicErrorCode error
= ReadVector(peer_hello
, &received_tags
,
190 &received_tags_length
, error_details
);
191 if (error
!= QUIC_NO_ERROR
) {
195 if (hello_type
== SERVER
) {
196 if (received_tags_length
!= 1 ||
197 std::find(possible_values_
.begin(), possible_values_
.end(),
198 *received_tags
) == possible_values_
.end()) {
199 *error_details
= "Invalid " + QuicUtils::TagToString(tag_
);
200 return QUIC_INVALID_NEGOTIATED_VALUE
;
202 negotiated_tag_
= *received_tags
;
204 QuicTag negotiated_tag
;
205 if (!QuicUtils::FindMutualTag(possible_values_
,
207 received_tags_length
,
208 QuicUtils::LOCAL_PRIORITY
,
211 *error_details
= "Unsupported " + QuicUtils::TagToString(tag_
);
212 return QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP
;
214 negotiated_tag_
= negotiated_tag
;
218 return QUIC_NO_ERROR
;
221 QuicFixedUint32::QuicFixedUint32(QuicTag tag
, QuicConfigPresence presence
)
222 : QuicConfigValue(tag
, presence
),
223 has_send_value_(false),
224 has_receive_value_(false) {
226 QuicFixedUint32::~QuicFixedUint32() {}
228 bool QuicFixedUint32::HasSendValue() const {
229 return has_send_value_
;
232 uint32
QuicFixedUint32::GetSendValue() const {
233 LOG_IF(DFATAL
, !has_send_value_
) << "No send value to get for tag:" << tag_
;
237 void QuicFixedUint32::SetSendValue(uint32 value
) {
238 has_send_value_
= true;
242 bool QuicFixedUint32::HasReceivedValue() const {
243 return has_receive_value_
;
246 uint32
QuicFixedUint32::GetReceivedValue() const {
247 LOG_IF(DFATAL
, !has_receive_value_
)
248 << "No receive value to get for tag:" << tag_
;
249 return receive_value_
;
252 void QuicFixedUint32::SetReceivedValue(uint32 value
) {
253 has_receive_value_
= true;
254 receive_value_
= value
;
257 void QuicFixedUint32::ToHandshakeMessage(CryptoHandshakeMessage
* out
) const {
258 if (has_send_value_
) {
259 out
->SetValue(tag_
, send_value_
);
263 QuicErrorCode
QuicFixedUint32::ProcessPeerHello(
264 const CryptoHandshakeMessage
& peer_hello
,
265 HelloType hello_type
,
266 string
* error_details
) {
267 DCHECK(error_details
!= NULL
);
268 QuicErrorCode error
= peer_hello
.GetUint32(tag_
, &receive_value_
);
270 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
:
271 if (presence_
== PRESENCE_REQUIRED
) {
272 *error_details
= "Missing " + QuicUtils::TagToString(tag_
);
275 error
= QUIC_NO_ERROR
;
278 has_receive_value_
= true;
281 *error_details
= "Bad " + QuicUtils::TagToString(tag_
);
287 QuicFixedTag::QuicFixedTag(QuicTag name
,
288 QuicConfigPresence presence
)
289 : QuicConfigValue(name
, presence
),
290 has_send_value_(false),
291 has_receive_value_(false) {
294 QuicFixedTag::~QuicFixedTag() {}
296 bool QuicFixedTag::HasSendValue() const {
297 return has_send_value_
;
300 uint32
QuicFixedTag::GetSendValue() const {
301 LOG_IF(DFATAL
, !has_send_value_
) << "No send value to get for tag:" << tag_
;
305 void QuicFixedTag::SetSendValue(uint32 value
) {
306 has_send_value_
= true;
310 bool QuicFixedTag::HasReceivedValue() const {
311 return has_receive_value_
;
314 uint32
QuicFixedTag::GetReceivedValue() const {
315 LOG_IF(DFATAL
, !has_receive_value_
)
316 << "No receive value to get for tag:" << tag_
;
317 return receive_value_
;
320 void QuicFixedTag::SetReceivedValue(uint32 value
) {
321 has_receive_value_
= true;
322 receive_value_
= value
;
325 void QuicFixedTag::ToHandshakeMessage(CryptoHandshakeMessage
* out
) const {
326 if (has_send_value_
) {
327 out
->SetValue(tag_
, send_value_
);
331 QuicErrorCode
QuicFixedTag::ProcessPeerHello(
332 const CryptoHandshakeMessage
& client_hello
,
333 HelloType hello_type
,
334 string
* error_details
) {
335 DCHECK(error_details
!= NULL
);
336 QuicErrorCode error
= client_hello
.GetUint32(tag_
, &receive_value_
);
338 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
:
339 if (presence_
== PRESENCE_REQUIRED
) {
340 *error_details
= "Missing " + QuicUtils::TagToString(tag_
);
343 error
= QUIC_NO_ERROR
;
346 has_receive_value_
= true;
349 *error_details
= "Bad " + QuicUtils::TagToString(tag_
);
355 QuicConfig::QuicConfig()
356 : congestion_control_(kCGST
, PRESENCE_REQUIRED
),
357 loss_detection_(kLOSS
, PRESENCE_OPTIONAL
),
358 idle_connection_state_lifetime_seconds_(kICSL
, PRESENCE_REQUIRED
),
359 keepalive_timeout_seconds_(kKATO
, PRESENCE_OPTIONAL
),
360 max_streams_per_connection_(kMSPC
, PRESENCE_REQUIRED
),
361 max_time_before_crypto_handshake_(QuicTime::Delta::Zero()),
362 initial_congestion_window_(kSWND
, PRESENCE_OPTIONAL
),
363 initial_round_trip_time_us_(kIRTT
, PRESENCE_OPTIONAL
),
364 // TODO(rjshade): Make this PRESENCE_REQUIRED when retiring
366 initial_flow_control_window_bytes_(kIFCW
, PRESENCE_OPTIONAL
) {
369 QuicConfig::~QuicConfig() {}
371 void QuicConfig::set_congestion_control(
372 const QuicTagVector
& congestion_control
,
373 QuicTag default_congestion_control
) {
374 congestion_control_
.set(congestion_control
, default_congestion_control
);
377 QuicTag
QuicConfig::congestion_control() const {
378 return congestion_control_
.GetTag();
381 void QuicConfig::SetLossDetectionToSend(QuicTag loss_detection
) {
382 loss_detection_
.SetSendValue(loss_detection
);
385 bool QuicConfig::HasReceivedLossDetection() const {
386 return loss_detection_
.HasReceivedValue();
389 QuicTag
QuicConfig::ReceivedLossDetection() const {
390 return loss_detection_
.GetReceivedValue();
393 void QuicConfig::set_idle_connection_state_lifetime(
394 QuicTime::Delta max_idle_connection_state_lifetime
,
395 QuicTime::Delta default_idle_conection_state_lifetime
) {
396 idle_connection_state_lifetime_seconds_
.set(
397 max_idle_connection_state_lifetime
.ToSeconds(),
398 default_idle_conection_state_lifetime
.ToSeconds());
401 QuicTime::Delta
QuicConfig::idle_connection_state_lifetime() const {
402 return QuicTime::Delta::FromSeconds(
403 idle_connection_state_lifetime_seconds_
.GetUint32());
406 QuicTime::Delta
QuicConfig::keepalive_timeout() const {
407 return QuicTime::Delta::FromSeconds(
408 keepalive_timeout_seconds_
.GetUint32());
411 void QuicConfig::set_max_streams_per_connection(size_t max_streams
,
412 size_t default_streams
) {
413 max_streams_per_connection_
.set(max_streams
, default_streams
);
416 uint32
QuicConfig::max_streams_per_connection() const {
417 return max_streams_per_connection_
.GetUint32();
420 void QuicConfig::set_max_time_before_crypto_handshake(
421 QuicTime::Delta max_time_before_crypto_handshake
) {
422 max_time_before_crypto_handshake_
= max_time_before_crypto_handshake
;
425 QuicTime::Delta
QuicConfig::max_time_before_crypto_handshake() const {
426 return max_time_before_crypto_handshake_
;
429 void QuicConfig::SetInitialCongestionWindowToSend(size_t initial_window
) {
430 initial_congestion_window_
.SetSendValue(initial_window
);
433 bool QuicConfig::HasReceivedInitialCongestionWindow() const {
434 return initial_congestion_window_
.HasReceivedValue();
437 uint32
QuicConfig::ReceivedInitialCongestionWindow() const {
438 return initial_congestion_window_
.GetReceivedValue();
441 void QuicConfig::SetInitialRoundTripTimeUsToSend(size_t rtt
) {
442 initial_round_trip_time_us_
.SetSendValue(rtt
);
445 bool QuicConfig::HasReceivedInitialRoundTripTimeUs() const {
446 return initial_round_trip_time_us_
.HasReceivedValue();
449 uint32
QuicConfig::ReceivedInitialRoundTripTimeUs() const {
450 return initial_round_trip_time_us_
.GetReceivedValue();
453 void QuicConfig::SetInitialFlowControlWindowToSend(uint32 window_bytes
) {
454 initial_flow_control_window_bytes_
.SetSendValue(window_bytes
);
457 bool QuicConfig::HasReceivedInitialFlowControlWindowBytes() const {
458 return initial_flow_control_window_bytes_
.HasReceivedValue();;
461 uint32
QuicConfig::ReceivedInitialFlowControlWindowBytes() const {
462 return initial_flow_control_window_bytes_
.GetReceivedValue();
465 bool QuicConfig::negotiated() {
466 // TODO(ianswett): Add the negotiated parameters once and iterate over all
467 // of them in negotiated, ToHandshakeMessage, ProcessClientHello, and
468 // ProcessServerHello.
469 return congestion_control_
.negotiated() &&
470 idle_connection_state_lifetime_seconds_
.negotiated() &&
471 keepalive_timeout_seconds_
.negotiated() &&
472 max_streams_per_connection_
.negotiated();
475 void QuicConfig::SetDefaults() {
476 QuicTagVector congestion_control
;
477 if (FLAGS_enable_quic_pacing
) {
478 congestion_control
.push_back(kPACE
);
480 congestion_control
.push_back(kQBIC
);
481 congestion_control_
.set(congestion_control
, kQBIC
);
482 idle_connection_state_lifetime_seconds_
.set(kDefaultTimeoutSecs
,
483 kDefaultInitialTimeoutSecs
);
484 // kKATO is optional. Return 0 if not negotiated.
485 keepalive_timeout_seconds_
.set(0, 0);
486 max_streams_per_connection_
.set(kDefaultMaxStreamsPerConnection
,
487 kDefaultMaxStreamsPerConnection
);
488 max_time_before_crypto_handshake_
= QuicTime::Delta::FromSeconds(
489 kDefaultMaxTimeForCryptoHandshakeSecs
);
492 void QuicConfig::EnablePacing(bool enable_pacing
) {
493 QuicTagVector congestion_control
;
495 congestion_control
.push_back(kPACE
);
497 congestion_control
.push_back(kQBIC
);
498 congestion_control_
.set(congestion_control
, kQBIC
);
501 void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage
* out
) const {
502 congestion_control_
.ToHandshakeMessage(out
);
503 idle_connection_state_lifetime_seconds_
.ToHandshakeMessage(out
);
504 keepalive_timeout_seconds_
.ToHandshakeMessage(out
);
505 max_streams_per_connection_
.ToHandshakeMessage(out
);
506 initial_congestion_window_
.ToHandshakeMessage(out
);
507 initial_round_trip_time_us_
.ToHandshakeMessage(out
);
508 loss_detection_
.ToHandshakeMessage(out
);
509 initial_flow_control_window_bytes_
.ToHandshakeMessage(out
);
512 QuicErrorCode
QuicConfig::ProcessPeerHello(
513 const CryptoHandshakeMessage
& peer_hello
,
514 HelloType hello_type
,
515 string
* error_details
) {
516 DCHECK(error_details
!= NULL
);
518 QuicErrorCode error
= QUIC_NO_ERROR
;
519 if (error
== QUIC_NO_ERROR
) {
520 error
= congestion_control_
.ProcessPeerHello(
521 peer_hello
, hello_type
, error_details
);
523 if (error
== QUIC_NO_ERROR
) {
524 error
= idle_connection_state_lifetime_seconds_
.ProcessPeerHello(
525 peer_hello
, hello_type
, error_details
);
527 if (error
== QUIC_NO_ERROR
) {
528 error
= keepalive_timeout_seconds_
.ProcessPeerHello(
529 peer_hello
, hello_type
, error_details
);
531 if (error
== QUIC_NO_ERROR
) {
532 error
= max_streams_per_connection_
.ProcessPeerHello(
533 peer_hello
, hello_type
, error_details
);
535 if (error
== QUIC_NO_ERROR
) {
536 error
= initial_congestion_window_
.ProcessPeerHello(
537 peer_hello
, hello_type
, error_details
);
539 if (error
== QUIC_NO_ERROR
) {
540 error
= initial_round_trip_time_us_
.ProcessPeerHello(
541 peer_hello
, hello_type
, error_details
);
543 if (error
== QUIC_NO_ERROR
) {
544 error
= initial_flow_control_window_bytes_
.ProcessPeerHello(
545 peer_hello
, hello_type
, error_details
);
547 if (error
== QUIC_NO_ERROR
) {
548 error
= loss_detection_
.ProcessPeerHello(
549 peer_hello
, hello_type
, error_details
);