Add details (where missing) for histograms and remove a few that are not worth provid...
[chromium-blink-merge.git] / net / quic / quic_config.cc
blob9c606714ecefd0225acd658a8387abebc5fa83cc
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"
7 #include <algorithm>
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"
16 using std::min;
17 using std::string;
19 namespace net {
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,
25 QuicTag tag,
26 QuicConfigPresence presence,
27 uint32 default_value,
28 uint32* out,
29 string* error_details) {
30 DCHECK(error_details != NULL);
31 QuicErrorCode error = msg.GetUint32(tag, out);
32 switch (error) {
33 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
34 if (presence == PRESENCE_REQUIRED) {
35 *error_details = "Missing " + QuicUtils::TagToString(tag);
36 break;
38 error = QUIC_NO_ERROR;
39 *out = default_value;
40 break;
41 case QUIC_NO_ERROR:
42 break;
43 default:
44 *error_details = "Bad " + QuicUtils::TagToString(tag);
45 break;
47 return error;
51 QuicConfigValue::QuicConfigValue(QuicTag tag,
52 QuicConfigPresence presence)
53 : tag_(tag),
54 presence_(presence) {
56 QuicConfigValue::~QuicConfigValue() {}
58 QuicNegotiableValue::QuicNegotiableValue(QuicTag tag,
59 QuicConfigPresence presence)
60 : QuicConfigValue(tag, presence),
61 negotiated_(false) {
63 QuicNegotiableValue::~QuicNegotiableValue() {}
65 QuicNegotiableUint32::QuicNegotiableUint32(QuicTag tag,
66 QuicConfigPresence presence)
67 : QuicNegotiableValue(tag, presence),
68 max_value_(0),
69 default_value_(0) {
71 QuicNegotiableUint32::~QuicNegotiableUint32() {}
73 void QuicNegotiableUint32::set(uint32 max, uint32 default_value) {
74 DCHECK_LE(default_value, max);
75 max_value_ = max;
76 default_value_ = default_value;
79 uint32 QuicNegotiableUint32::GetUint32() const {
80 if (negotiated_) {
81 return negotiated_value_;
83 return default_value_;
86 void QuicNegotiableUint32::ToHandshakeMessage(
87 CryptoHandshakeMessage* out) const {
88 if (negotiated_) {
89 out->SetValue(tag_, negotiated_value_);
90 } else {
91 out->SetValue(tag_, max_value_);
95 QuicErrorCode QuicNegotiableUint32::ProcessPeerHello(
96 const CryptoHandshakeMessage& peer_hello,
97 HelloType hello_type,
98 string* error_details) {
99 DCHECK(!negotiated_);
100 DCHECK(error_details != NULL);
101 uint32 value;
102 QuicErrorCode error = ReadUint32(peer_hello,
103 tag_,
104 presence_,
105 default_value_,
106 &value,
107 error_details);
108 if (error != QUIC_NO_ERROR) {
109 return 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;
117 negotiated_ = true;
118 negotiated_value_ = min(value, max_value_);
119 return QUIC_NO_ERROR;
122 QuicNegotiableTag::QuicNegotiableTag(QuicTag tag, QuicConfigPresence presence)
123 : QuicNegotiableValue(tag, presence),
124 negotiated_tag_(0),
125 default_value_(0) {
128 QuicNegotiableTag::~QuicNegotiableTag() {}
130 void QuicNegotiableTag::set(const QuicTagVector& possible,
131 QuicTag default_value) {
132 DCHECK(std::find(possible.begin(), possible.end(), default_value) !=
133 possible.end());
134 possible_values_ = possible;
135 default_value_ = default_value;
138 QuicTag QuicNegotiableTag::GetTag() const {
139 if (negotiated_) {
140 return negotiated_tag_;
142 return default_value_;
145 void QuicNegotiableTag::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
146 if (negotiated_) {
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_);
150 } else {
151 out->SetVector(tag_, possible_values_);
155 QuicErrorCode QuicNegotiableTag::ReadVector(
156 const CryptoHandshakeMessage& msg,
157 const QuicTag** out,
158 size_t* out_length,
159 string* error_details) const {
160 DCHECK(error_details != NULL);
161 QuicErrorCode error = msg.GetTaglist(tag_, out, out_length);
162 switch (error) {
163 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
164 if (presence_ == PRESENCE_REQUIRED) {
165 *error_details = "Missing " + QuicUtils::TagToString(tag_);
166 break;
168 error = QUIC_NO_ERROR;
169 *out_length = 1;
170 *out = &default_value_;
172 case QUIC_NO_ERROR:
173 break;
174 default:
175 *error_details = "Bad " + QuicUtils::TagToString(tag_);
176 break;
178 return error;
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) {
192 return 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;
203 } else {
204 QuicTag negotiated_tag;
205 if (!QuicUtils::FindMutualTag(possible_values_,
206 received_tags,
207 received_tags_length,
208 QuicUtils::LOCAL_PRIORITY,
209 &negotiated_tag,
210 NULL)) {
211 *error_details = "Unsupported " + QuicUtils::TagToString(tag_);
212 return QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP;
214 negotiated_tag_ = negotiated_tag;
217 negotiated_ = true;
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_;
234 return send_value_;
237 void QuicFixedUint32::SetSendValue(uint32 value) {
238 has_send_value_ = true;
239 send_value_ = value;
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_);
269 switch (error) {
270 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
271 if (presence_ == PRESENCE_REQUIRED) {
272 *error_details = "Missing " + QuicUtils::TagToString(tag_);
273 break;
275 error = QUIC_NO_ERROR;
276 break;
277 case QUIC_NO_ERROR:
278 has_receive_value_ = true;
279 break;
280 default:
281 *error_details = "Bad " + QuicUtils::TagToString(tag_);
282 break;
284 return error;
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_;
302 return send_value_;
305 void QuicFixedTag::SetSendValue(uint32 value) {
306 has_send_value_ = true;
307 send_value_ = value;
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_);
337 switch (error) {
338 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
339 if (presence_ == PRESENCE_REQUIRED) {
340 *error_details = "Missing " + QuicUtils::TagToString(tag_);
341 break;
343 error = QUIC_NO_ERROR;
344 break;
345 case QUIC_NO_ERROR:
346 has_receive_value_ = true;
347 break;
348 default:
349 *error_details = "Bad " + QuicUtils::TagToString(tag_);
350 break;
352 return error;
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
365 // QUIC_VERSION_17.
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;
494 if (enable_pacing) {
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);
551 return error;
554 } // namespace net