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_utils.h"
19 // Reads the value corresponding to |name_| from |msg| into |out|. If the
20 // |name_| is absent in |msg| and |presence| is set to OPTIONAL |out| is set
21 // to |default_value|.
22 QuicErrorCode
ReadUint32(const CryptoHandshakeMessage
& msg
,
24 QuicConfigPresence presence
,
27 string
* error_details
) {
28 DCHECK(error_details
!= nullptr);
29 QuicErrorCode error
= msg
.GetUint32(tag
, out
);
31 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
:
32 if (presence
== PRESENCE_REQUIRED
) {
33 *error_details
= "Missing " + QuicUtils::TagToString(tag
);
36 error
= QUIC_NO_ERROR
;
42 *error_details
= "Bad " + QuicUtils::TagToString(tag
);
48 QuicConfigValue::QuicConfigValue(QuicTag tag
,
49 QuicConfigPresence presence
)
53 QuicConfigValue::~QuicConfigValue() {}
55 QuicNegotiableValue::QuicNegotiableValue(QuicTag tag
,
56 QuicConfigPresence presence
)
57 : QuicConfigValue(tag
, presence
),
60 QuicNegotiableValue::~QuicNegotiableValue() {}
62 QuicNegotiableUint32::QuicNegotiableUint32(QuicTag tag
,
63 QuicConfigPresence presence
)
64 : QuicNegotiableValue(tag
, presence
),
67 negotiated_value_(0) {
69 QuicNegotiableUint32::~QuicNegotiableUint32() {}
71 void QuicNegotiableUint32::set(uint32 max
, uint32 default_value
) {
72 DCHECK_LE(default_value
, max
);
74 default_value_
= default_value
;
77 uint32
QuicNegotiableUint32::GetUint32() const {
79 return negotiated_value_
;
81 return default_value_
;
84 void QuicNegotiableUint32::ToHandshakeMessage(
85 CryptoHandshakeMessage
* out
) const {
87 out
->SetValue(tag_
, negotiated_value_
);
89 out
->SetValue(tag_
, max_value_
);
93 QuicErrorCode
QuicNegotiableUint32::ProcessPeerHello(
94 const CryptoHandshakeMessage
& peer_hello
,
96 string
* error_details
) {
97 DCHECK(!negotiated());
98 DCHECK(error_details
!= nullptr);
100 QuicErrorCode error
= ReadUint32(peer_hello
,
106 if (error
!= QUIC_NO_ERROR
) {
109 if (hello_type
== SERVER
&& value
> max_value_
) {
111 "Invalid value received for " + QuicUtils::TagToString(tag_
);
112 return QUIC_INVALID_NEGOTIATED_VALUE
;
115 set_negotiated(true);
116 negotiated_value_
= min(value
, max_value_
);
117 return QUIC_NO_ERROR
;
120 QuicNegotiableTag::QuicNegotiableTag(QuicTag tag
, QuicConfigPresence presence
)
121 : QuicNegotiableValue(tag
, presence
),
126 QuicNegotiableTag::~QuicNegotiableTag() {}
128 void QuicNegotiableTag::set(const QuicTagVector
& possible
,
129 QuicTag default_value
) {
130 DCHECK(ContainsQuicTag(possible
, default_value
));
131 possible_values_
= possible
;
132 default_value_
= default_value
;
135 void QuicNegotiableTag::ToHandshakeMessage(CryptoHandshakeMessage
* out
) const {
137 // Because of the way we serialize and parse handshake messages we can
138 // serialize this as value and still parse it as a vector.
139 out
->SetValue(tag_
, negotiated_tag_
);
141 out
->SetVector(tag_
, possible_values_
);
145 QuicErrorCode
QuicNegotiableTag::ReadVector(
146 const CryptoHandshakeMessage
& msg
,
149 string
* error_details
) const {
150 DCHECK(error_details
!= nullptr);
151 QuicErrorCode error
= msg
.GetTaglist(tag_
, out
, out_length
);
153 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
:
154 if (presence_
== PRESENCE_REQUIRED
) {
155 *error_details
= "Missing " + QuicUtils::TagToString(tag_
);
158 error
= QUIC_NO_ERROR
;
160 *out
= &default_value_
;
165 *error_details
= "Bad " + QuicUtils::TagToString(tag_
);
171 QuicErrorCode
QuicNegotiableTag::ProcessPeerHello(
172 const CryptoHandshakeMessage
& peer_hello
,
173 HelloType hello_type
,
174 string
* error_details
) {
175 DCHECK(!negotiated());
176 DCHECK(error_details
!= nullptr);
177 const QuicTag
* received_tags
;
178 size_t received_tags_length
;
179 QuicErrorCode error
= ReadVector(peer_hello
, &received_tags
,
180 &received_tags_length
, error_details
);
181 if (error
!= QUIC_NO_ERROR
) {
185 if (hello_type
== SERVER
) {
186 if (received_tags_length
!= 1 ||
187 !ContainsQuicTag(possible_values_
, *received_tags
)) {
188 *error_details
= "Invalid " + QuicUtils::TagToString(tag_
);
189 return QUIC_INVALID_NEGOTIATED_VALUE
;
191 negotiated_tag_
= *received_tags
;
193 QuicTag negotiated_tag
;
194 if (!QuicUtils::FindMutualTag(possible_values_
,
196 received_tags_length
,
197 QuicUtils::LOCAL_PRIORITY
,
200 *error_details
= "Unsupported " + QuicUtils::TagToString(tag_
);
201 return QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP
;
203 negotiated_tag_
= negotiated_tag
;
206 set_negotiated(true);
207 return QUIC_NO_ERROR
;
210 QuicFixedUint32::QuicFixedUint32(QuicTag tag
, QuicConfigPresence presence
)
211 : QuicConfigValue(tag
, presence
),
212 has_send_value_(false),
213 has_receive_value_(false) {
215 QuicFixedUint32::~QuicFixedUint32() {}
217 bool QuicFixedUint32::HasSendValue() const {
218 return has_send_value_
;
221 uint32
QuicFixedUint32::GetSendValue() const {
222 LOG_IF(DFATAL
, !has_send_value_
)
223 << "No send value to get for tag:" << QuicUtils::TagToString(tag_
);
227 void QuicFixedUint32::SetSendValue(uint32 value
) {
228 has_send_value_
= true;
232 bool QuicFixedUint32::HasReceivedValue() const {
233 return has_receive_value_
;
236 uint32
QuicFixedUint32::GetReceivedValue() const {
237 LOG_IF(DFATAL
, !has_receive_value_
)
238 << "No receive value to get for tag:" << QuicUtils::TagToString(tag_
);
239 return receive_value_
;
242 void QuicFixedUint32::SetReceivedValue(uint32 value
) {
243 has_receive_value_
= true;
244 receive_value_
= value
;
247 void QuicFixedUint32::ToHandshakeMessage(CryptoHandshakeMessage
* out
) const {
248 if (has_send_value_
) {
249 out
->SetValue(tag_
, send_value_
);
253 QuicErrorCode
QuicFixedUint32::ProcessPeerHello(
254 const CryptoHandshakeMessage
& peer_hello
,
255 HelloType hello_type
,
256 string
* error_details
) {
257 DCHECK(error_details
!= nullptr);
258 QuicErrorCode error
= peer_hello
.GetUint32(tag_
, &receive_value_
);
260 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
:
261 if (presence_
== PRESENCE_OPTIONAL
) {
262 return QUIC_NO_ERROR
;
264 *error_details
= "Missing " + QuicUtils::TagToString(tag_
);
267 has_receive_value_
= true;
270 *error_details
= "Bad " + QuicUtils::TagToString(tag_
);
276 QuicFixedTagVector::QuicFixedTagVector(QuicTag name
,
277 QuicConfigPresence presence
)
278 : QuicConfigValue(name
, presence
),
279 has_send_values_(false),
280 has_receive_values_(false) {
283 QuicFixedTagVector::~QuicFixedTagVector() {}
285 bool QuicFixedTagVector::HasSendValues() const {
286 return has_send_values_
;
289 QuicTagVector
QuicFixedTagVector::GetSendValues() const {
290 LOG_IF(DFATAL
, !has_send_values_
)
291 << "No send values to get for tag:" << QuicUtils::TagToString(tag_
);
295 void QuicFixedTagVector::SetSendValues(const QuicTagVector
& values
) {
296 has_send_values_
= true;
297 send_values_
= values
;
300 bool QuicFixedTagVector::HasReceivedValues() const {
301 return has_receive_values_
;
304 QuicTagVector
QuicFixedTagVector::GetReceivedValues() const {
305 LOG_IF(DFATAL
, !has_receive_values_
)
306 << "No receive value to get for tag:" << QuicUtils::TagToString(tag_
);
307 return receive_values_
;
310 void QuicFixedTagVector::SetReceivedValues(const QuicTagVector
& values
) {
311 has_receive_values_
= true;
312 receive_values_
= values
;
315 void QuicFixedTagVector::ToHandshakeMessage(CryptoHandshakeMessage
* out
) const {
316 if (has_send_values_
) {
317 out
->SetVector(tag_
, send_values_
);
321 QuicErrorCode
QuicFixedTagVector::ProcessPeerHello(
322 const CryptoHandshakeMessage
& peer_hello
,
323 HelloType hello_type
,
324 string
* error_details
) {
325 DCHECK(error_details
!= nullptr);
326 const QuicTag
* received_tags
;
327 size_t received_tags_length
;
328 QuicErrorCode error
=
329 peer_hello
.GetTaglist(tag_
, &received_tags
, &received_tags_length
);
331 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND
:
332 if (presence_
== PRESENCE_OPTIONAL
) {
333 return QUIC_NO_ERROR
;
335 *error_details
= "Missing " + QuicUtils::TagToString(tag_
);
338 DVLOG(1) << "Received Connection Option tags from receiver.";
339 has_receive_values_
= true;
340 for (size_t i
= 0; i
< received_tags_length
; ++i
) {
341 receive_values_
.push_back(received_tags
[i
]);
345 *error_details
= "Bad " + QuicUtils::TagToString(tag_
);
351 QuicConfig::QuicConfig()
352 : max_time_before_crypto_handshake_(QuicTime::Delta::Zero()),
353 max_idle_time_before_crypto_handshake_(QuicTime::Delta::Zero()),
354 max_undecryptable_packets_(0),
355 connection_options_(kCOPT
, PRESENCE_OPTIONAL
),
356 idle_connection_state_lifetime_seconds_(kICSL
, PRESENCE_REQUIRED
),
357 silent_close_(kSCLS
, PRESENCE_OPTIONAL
),
358 max_streams_per_connection_(kMSPC
, PRESENCE_REQUIRED
),
359 bytes_for_connection_id_(kTCID
, PRESENCE_OPTIONAL
),
360 initial_round_trip_time_us_(kIRTT
, PRESENCE_OPTIONAL
),
361 initial_stream_flow_control_window_bytes_(kSFCW
, PRESENCE_OPTIONAL
),
362 initial_session_flow_control_window_bytes_(kCFCW
, PRESENCE_OPTIONAL
),
363 socket_receive_buffer_(kSRBF
, PRESENCE_OPTIONAL
) {
367 QuicConfig::~QuicConfig() {}
369 bool QuicConfig::SetInitialReceivedConnectionOptions(
370 const QuicTagVector
& tags
) {
371 if (HasReceivedConnectionOptions()) {
372 // If we have already received connection options (via handshake or due to a
373 // previous call), don't re-initialize.
376 connection_options_
.SetReceivedValues(tags
);
380 void QuicConfig::SetConnectionOptionsToSend(
381 const QuicTagVector
& connection_options
) {
382 connection_options_
.SetSendValues(connection_options
);
385 bool QuicConfig::HasReceivedConnectionOptions() const {
386 return connection_options_
.HasReceivedValues();
389 QuicTagVector
QuicConfig::ReceivedConnectionOptions() const {
390 return connection_options_
.GetReceivedValues();
393 bool QuicConfig::HasSendConnectionOptions() const {
394 return connection_options_
.HasSendValues();
397 QuicTagVector
QuicConfig::SendConnectionOptions() const {
398 return connection_options_
.GetSendValues();
401 bool QuicConfig::HasClientSentConnectionOption(QuicTag tag
,
402 Perspective perspective
) const {
403 if (perspective
== Perspective::IS_SERVER
) {
404 if (HasReceivedConnectionOptions() &&
405 ContainsQuicTag(ReceivedConnectionOptions(), tag
)) {
408 } else if (HasSendConnectionOptions() &&
409 ContainsQuicTag(SendConnectionOptions(), tag
)) {
415 void QuicConfig::SetIdleConnectionStateLifetime(
416 QuicTime::Delta max_idle_connection_state_lifetime
,
417 QuicTime::Delta default_idle_conection_state_lifetime
) {
418 idle_connection_state_lifetime_seconds_
.set(
419 static_cast<uint32
>(max_idle_connection_state_lifetime
.ToSeconds()),
420 static_cast<uint32
>(default_idle_conection_state_lifetime
.ToSeconds()));
423 QuicTime::Delta
QuicConfig::IdleConnectionStateLifetime() const {
424 return QuicTime::Delta::FromSeconds(
425 idle_connection_state_lifetime_seconds_
.GetUint32());
428 // TODO(ianswett) Use this for silent close on mobile, or delete.
429 void QuicConfig::SetSilentClose(bool silent_close
) {
430 silent_close_
.set(silent_close
? 1 : 0, silent_close
? 1 : 0);
433 bool QuicConfig::SilentClose() const {
434 return silent_close_
.GetUint32() > 0;
437 void QuicConfig::SetMaxStreamsPerConnection(size_t max_streams
,
438 size_t default_streams
) {
439 max_streams_per_connection_
.set(max_streams
, default_streams
);
442 uint32
QuicConfig::MaxStreamsPerConnection() const {
443 return max_streams_per_connection_
.GetUint32();
446 bool QuicConfig::HasSetBytesForConnectionIdToSend() const {
447 return bytes_for_connection_id_
.HasSendValue();
450 void QuicConfig::SetBytesForConnectionIdToSend(uint32 bytes
) {
451 bytes_for_connection_id_
.SetSendValue(bytes
);
454 bool QuicConfig::HasReceivedBytesForConnectionId() const {
455 return bytes_for_connection_id_
.HasReceivedValue();
458 uint32
QuicConfig::ReceivedBytesForConnectionId() const {
459 return bytes_for_connection_id_
.GetReceivedValue();
462 void QuicConfig::SetInitialRoundTripTimeUsToSend(uint32 rtt
) {
463 initial_round_trip_time_us_
.SetSendValue(rtt
);
466 bool QuicConfig::HasReceivedInitialRoundTripTimeUs() const {
467 return initial_round_trip_time_us_
.HasReceivedValue();
470 uint32
QuicConfig::ReceivedInitialRoundTripTimeUs() const {
471 return initial_round_trip_time_us_
.GetReceivedValue();
474 bool QuicConfig::HasInitialRoundTripTimeUsToSend() const {
475 return initial_round_trip_time_us_
.HasSendValue();
478 uint32
QuicConfig::GetInitialRoundTripTimeUsToSend() const {
479 return initial_round_trip_time_us_
.GetSendValue();
482 void QuicConfig::SetInitialStreamFlowControlWindowToSend(uint32 window_bytes
) {
483 if (window_bytes
< kMinimumFlowControlSendWindow
) {
484 LOG(DFATAL
) << "Initial stream flow control receive window ("
485 << window_bytes
<< ") cannot be set lower than default ("
486 << kMinimumFlowControlSendWindow
<< ").";
487 window_bytes
= kMinimumFlowControlSendWindow
;
489 initial_stream_flow_control_window_bytes_
.SetSendValue(window_bytes
);
492 uint32
QuicConfig::GetInitialStreamFlowControlWindowToSend() const {
493 return initial_stream_flow_control_window_bytes_
.GetSendValue();
496 bool QuicConfig::HasReceivedInitialStreamFlowControlWindowBytes() const {
497 return initial_stream_flow_control_window_bytes_
.HasReceivedValue();
500 uint32
QuicConfig::ReceivedInitialStreamFlowControlWindowBytes() const {
501 return initial_stream_flow_control_window_bytes_
.GetReceivedValue();
504 void QuicConfig::SetInitialSessionFlowControlWindowToSend(uint32 window_bytes
) {
505 if (window_bytes
< kMinimumFlowControlSendWindow
) {
506 LOG(DFATAL
) << "Initial session flow control receive window ("
507 << window_bytes
<< ") cannot be set lower than default ("
508 << kMinimumFlowControlSendWindow
<< ").";
509 window_bytes
= kMinimumFlowControlSendWindow
;
511 initial_session_flow_control_window_bytes_
.SetSendValue(window_bytes
);
514 uint32
QuicConfig::GetInitialSessionFlowControlWindowToSend() const {
515 return initial_session_flow_control_window_bytes_
.GetSendValue();
518 bool QuicConfig::HasReceivedInitialSessionFlowControlWindowBytes() const {
519 return initial_session_flow_control_window_bytes_
.HasReceivedValue();
522 uint32
QuicConfig::ReceivedInitialSessionFlowControlWindowBytes() const {
523 return initial_session_flow_control_window_bytes_
.GetReceivedValue();
526 void QuicConfig::SetSocketReceiveBufferToSend(uint32 tcp_receive_window
) {
527 socket_receive_buffer_
.SetSendValue(tcp_receive_window
);
530 bool QuicConfig::HasReceivedSocketReceiveBuffer() const {
531 return socket_receive_buffer_
.HasReceivedValue();
534 uint32
QuicConfig::ReceivedSocketReceiveBuffer() const {
535 return socket_receive_buffer_
.GetReceivedValue();
538 bool QuicConfig::negotiated() const {
539 // TODO(ianswett): Add the negotiated parameters once and iterate over all
540 // of them in negotiated, ToHandshakeMessage, ProcessClientHello, and
541 // ProcessServerHello.
542 return idle_connection_state_lifetime_seconds_
.negotiated() &&
543 max_streams_per_connection_
.negotiated();
546 void QuicConfig::SetDefaults() {
547 idle_connection_state_lifetime_seconds_
.set(kMaximumIdleTimeoutSecs
,
548 kDefaultIdleTimeoutSecs
);
549 silent_close_
.set(1, 0);
550 SetMaxStreamsPerConnection(kDefaultMaxStreamsPerConnection
,
551 kDefaultMaxStreamsPerConnection
);
552 max_time_before_crypto_handshake_
=
553 QuicTime::Delta::FromSeconds(kMaxTimeForCryptoHandshakeSecs
);
554 max_idle_time_before_crypto_handshake_
=
555 QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs
);
556 max_undecryptable_packets_
= kDefaultMaxUndecryptablePackets
;
558 SetInitialStreamFlowControlWindowToSend(kMinimumFlowControlSendWindow
);
559 SetInitialSessionFlowControlWindowToSend(kMinimumFlowControlSendWindow
);
562 void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage
* out
) const {
563 idle_connection_state_lifetime_seconds_
.ToHandshakeMessage(out
);
564 silent_close_
.ToHandshakeMessage(out
);
565 max_streams_per_connection_
.ToHandshakeMessage(out
);
566 bytes_for_connection_id_
.ToHandshakeMessage(out
);
567 initial_round_trip_time_us_
.ToHandshakeMessage(out
);
568 initial_stream_flow_control_window_bytes_
.ToHandshakeMessage(out
);
569 initial_session_flow_control_window_bytes_
.ToHandshakeMessage(out
);
570 socket_receive_buffer_
.ToHandshakeMessage(out
);
571 connection_options_
.ToHandshakeMessage(out
);
574 QuicErrorCode
QuicConfig::ProcessPeerHello(
575 const CryptoHandshakeMessage
& peer_hello
,
576 HelloType hello_type
,
577 string
* error_details
) {
578 DCHECK(error_details
!= nullptr);
580 QuicErrorCode error
= QUIC_NO_ERROR
;
581 if (error
== QUIC_NO_ERROR
) {
582 error
= idle_connection_state_lifetime_seconds_
.ProcessPeerHello(
583 peer_hello
, hello_type
, error_details
);
585 if (error
== QUIC_NO_ERROR
) {
587 silent_close_
.ProcessPeerHello(peer_hello
, hello_type
, error_details
);
589 if (error
== QUIC_NO_ERROR
) {
590 error
= max_streams_per_connection_
.ProcessPeerHello(
591 peer_hello
, hello_type
, error_details
);
593 if (error
== QUIC_NO_ERROR
) {
594 error
= bytes_for_connection_id_
.ProcessPeerHello(
595 peer_hello
, hello_type
, error_details
);
597 if (error
== QUIC_NO_ERROR
) {
598 error
= initial_round_trip_time_us_
.ProcessPeerHello(
599 peer_hello
, hello_type
, error_details
);
601 if (error
== QUIC_NO_ERROR
) {
602 error
= initial_stream_flow_control_window_bytes_
.ProcessPeerHello(
603 peer_hello
, hello_type
, error_details
);
605 if (error
== QUIC_NO_ERROR
) {
606 error
= initial_session_flow_control_window_bytes_
.ProcessPeerHello(
607 peer_hello
, hello_type
, error_details
);
609 if (error
== QUIC_NO_ERROR
) {
610 error
= socket_receive_buffer_
.ProcessPeerHello(
611 peer_hello
, hello_type
, error_details
);
613 if (error
== QUIC_NO_ERROR
) {
614 error
= connection_options_
.ProcessPeerHello(
615 peer_hello
, hello_type
, error_details
);