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.
4
5 #include "net/quic/quic_config.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10 #include "net/quic/quic_sent_packet_manager.h"
11
12 using std::string;
13
14 namespace net {
15
QuicNegotiableValue(QuicTag tag,Presence presence)16 QuicNegotiableValue::QuicNegotiableValue(QuicTag tag, Presence presence)
17 : tag_(tag),
18 presence_(presence),
19 negotiated_(false) {
20 }
21
QuicNegotiableUint32(QuicTag tag,Presence presence)22 QuicNegotiableUint32::QuicNegotiableUint32(QuicTag tag, Presence presence)
23 : QuicNegotiableValue(tag, presence),
24 max_value_(0),
25 default_value_(0) {
26 }
27
set(uint32 max,uint32 default_value)28 void QuicNegotiableUint32::set(uint32 max, uint32 default_value) {
29 DCHECK_LE(default_value, max);
30 max_value_ = max;
31 default_value_ = default_value;
32 }
33
GetUint32() const34 uint32 QuicNegotiableUint32::GetUint32() const {
35 if (negotiated_) {
36 return negotiated_value_;
37 }
38 return default_value_;
39 }
40
ToHandshakeMessage(CryptoHandshakeMessage * out) const41 void QuicNegotiableUint32::ToHandshakeMessage(
42 CryptoHandshakeMessage* out) const {
43 if (negotiated_) {
44 out->SetValue(tag_, negotiated_value_);
45 } else {
46 out->SetValue(tag_, max_value_);
47 }
48 }
49
ReadUint32(const CryptoHandshakeMessage & msg,uint32 * out,string * error_details) const50 QuicErrorCode QuicNegotiableUint32::ReadUint32(
51 const CryptoHandshakeMessage& msg,
52 uint32* out,
53 string* error_details) const {
54 DCHECK(error_details != NULL);
55 QuicErrorCode error = msg.GetUint32(tag_, out);
56 switch (error) {
57 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
58 if (presence_ == QuicNegotiableValue::PRESENCE_REQUIRED) {
59 *error_details = "Missing " + QuicUtils::TagToString(tag_);
60 break;
61 }
62 error = QUIC_NO_ERROR;
63 *out = default_value_;
64
65 case QUIC_NO_ERROR:
66 break;
67 default:
68 *error_details = "Bad " + QuicUtils::TagToString(tag_);
69 break;
70 }
71 return error;
72 }
73
ProcessClientHello(const CryptoHandshakeMessage & client_hello,string * error_details)74 QuicErrorCode QuicNegotiableUint32::ProcessClientHello(
75 const CryptoHandshakeMessage& client_hello,
76 string* error_details) {
77 DCHECK(!negotiated_);
78 DCHECK(error_details != NULL);
79 uint32 value;
80 QuicErrorCode error = ReadUint32(client_hello, &value, error_details);
81 if (error != QUIC_NO_ERROR) {
82 return error;
83 }
84
85 negotiated_ = true;
86 negotiated_value_ = std::min(value, max_value_);
87
88 return QUIC_NO_ERROR;
89 }
90
ProcessServerHello(const CryptoHandshakeMessage & server_hello,string * error_details)91 QuicErrorCode QuicNegotiableUint32::ProcessServerHello(
92 const CryptoHandshakeMessage& server_hello,
93 string* error_details) {
94 DCHECK(!negotiated_);
95 DCHECK(error_details != NULL);
96 uint32 value;
97 QuicErrorCode error = ReadUint32(server_hello, &value, error_details);
98 if (error != QUIC_NO_ERROR) {
99 return error;
100 }
101
102 if (value > max_value_) {
103 *error_details = "Invalid value received for " +
104 QuicUtils::TagToString(tag_);
105 return QUIC_INVALID_NEGOTIATED_VALUE;
106 }
107
108 negotiated_ = true;
109 negotiated_value_ = value;
110 return QUIC_NO_ERROR;
111 }
112
QuicNegotiableTag(QuicTag tag,Presence presence)113 QuicNegotiableTag::QuicNegotiableTag(QuicTag tag, Presence presence)
114 : QuicNegotiableValue(tag, presence),
115 negotiated_tag_(0),
116 default_value_(0) {
117 }
118
~QuicNegotiableTag()119 QuicNegotiableTag::~QuicNegotiableTag() {}
120
set(const QuicTagVector & possible,QuicTag default_value)121 void QuicNegotiableTag::set(const QuicTagVector& possible,
122 QuicTag default_value) {
123 DCHECK(std::find(possible.begin(), possible.end(), default_value) !=
124 possible.end());
125 possible_values_ = possible;
126 default_value_ = default_value;
127 }
128
GetTag() const129 QuicTag QuicNegotiableTag::GetTag() const {
130 if (negotiated_) {
131 return negotiated_tag_;
132 }
133 return default_value_;
134 }
135
ToHandshakeMessage(CryptoHandshakeMessage * out) const136 void QuicNegotiableTag::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
137 if (negotiated_) {
138 // Because of the way we serialize and parse handshake messages we can
139 // serialize this as value and still parse it as a vector.
140 out->SetValue(tag_, negotiated_tag_);
141 } else {
142 out->SetVector(tag_, possible_values_);
143 }
144 }
145
ReadVector(const CryptoHandshakeMessage & msg,const QuicTag ** out,size_t * out_length,string * error_details) const146 QuicErrorCode QuicNegotiableTag::ReadVector(
147 const CryptoHandshakeMessage& msg,
148 const QuicTag** out,
149 size_t* out_length,
150 string* error_details) const {
151 DCHECK(error_details != NULL);
152 QuicErrorCode error = msg.GetTaglist(tag_, out, out_length);
153 switch (error) {
154 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
155 if (presence_ == PRESENCE_REQUIRED) {
156 *error_details = "Missing " + QuicUtils::TagToString(tag_);
157 break;
158 }
159 error = QUIC_NO_ERROR;
160 *out_length = 1;
161 *out = &default_value_;
162
163 case QUIC_NO_ERROR:
164 break;
165 default:
166 *error_details = "Bad " + QuicUtils::TagToString(tag_);
167 break;
168 }
169 return error;
170 }
171
ProcessClientHello(const CryptoHandshakeMessage & client_hello,string * error_details)172 QuicErrorCode QuicNegotiableTag::ProcessClientHello(
173 const CryptoHandshakeMessage& client_hello,
174 string* error_details) {
175 DCHECK(!negotiated_);
176 DCHECK(error_details != NULL);
177 const QuicTag* received_tags;
178 size_t received_tags_length;
179 QuicErrorCode error = ReadVector(client_hello, &received_tags,
180 &received_tags_length, error_details);
181 if (error != QUIC_NO_ERROR) {
182 return error;
183 }
184
185 QuicTag negotiated_tag;
186 if (!QuicUtils::FindMutualTag(possible_values_,
187 received_tags,
188 received_tags_length,
189 QuicUtils::LOCAL_PRIORITY,
190 &negotiated_tag,
191 NULL)) {
192 *error_details = "Unsuported " + QuicUtils::TagToString(tag_);
193 return QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP;
194 }
195
196 negotiated_ = true;
197 negotiated_tag_ = negotiated_tag;
198 return QUIC_NO_ERROR;
199 }
200
ProcessServerHello(const CryptoHandshakeMessage & server_hello,string * error_details)201 QuicErrorCode QuicNegotiableTag::ProcessServerHello(
202 const CryptoHandshakeMessage& server_hello,
203 string* error_details) {
204 DCHECK(!negotiated_);
205 DCHECK(error_details != NULL);
206 const QuicTag* received_tags;
207 size_t received_tags_length;
208 QuicErrorCode error = ReadVector(server_hello, &received_tags,
209 &received_tags_length, error_details);
210 if (error != QUIC_NO_ERROR) {
211 return error;
212 }
213
214 if (received_tags_length != 1 ||
215 std::find(possible_values_.begin(), possible_values_.end(),
216 *received_tags) == possible_values_.end()) {
217 *error_details = "Invalid " + QuicUtils::TagToString(tag_);
218 return QUIC_INVALID_NEGOTIATED_VALUE;
219 }
220
221 negotiated_ = true;
222 negotiated_tag_ = *received_tags;
223 return QUIC_NO_ERROR;
224 }
225
QuicConfig()226 QuicConfig::QuicConfig() :
227 congestion_control_(kCGST, QuicNegotiableValue::PRESENCE_REQUIRED),
228 idle_connection_state_lifetime_seconds_(
229 kICSL, QuicNegotiableValue::PRESENCE_REQUIRED),
230 keepalive_timeout_seconds_(kKATO, QuicNegotiableValue::PRESENCE_OPTIONAL),
231 max_streams_per_connection_(kMSPC, QuicNegotiableValue::PRESENCE_REQUIRED),
232 max_time_before_crypto_handshake_(QuicTime::Delta::Zero()),
233 server_initial_congestion_window_(
234 kSWND, QuicNegotiableValue::PRESENCE_OPTIONAL),
235 initial_round_trip_time_us_(kIRTT, QuicNegotiableValue::PRESENCE_OPTIONAL) {
236 // All optional non-zero parameters should be initialized here.
237 server_initial_congestion_window_.set(kMaxInitialWindow,
238 kDefaultInitialWindow);
239 }
240
~QuicConfig()241 QuicConfig::~QuicConfig() {}
242
set_congestion_control(const QuicTagVector & congestion_control,QuicTag default_congestion_control)243 void QuicConfig::set_congestion_control(
244 const QuicTagVector& congestion_control,
245 QuicTag default_congestion_control) {
246 congestion_control_.set(congestion_control, default_congestion_control);
247 }
248
congestion_control() const249 QuicTag QuicConfig::congestion_control() const {
250 return congestion_control_.GetTag();
251 }
252
set_idle_connection_state_lifetime(QuicTime::Delta max_idle_connection_state_lifetime,QuicTime::Delta default_idle_conection_state_lifetime)253 void QuicConfig::set_idle_connection_state_lifetime(
254 QuicTime::Delta max_idle_connection_state_lifetime,
255 QuicTime::Delta default_idle_conection_state_lifetime) {
256 idle_connection_state_lifetime_seconds_.set(
257 max_idle_connection_state_lifetime.ToSeconds(),
258 default_idle_conection_state_lifetime.ToSeconds());
259 }
260
idle_connection_state_lifetime() const261 QuicTime::Delta QuicConfig::idle_connection_state_lifetime() const {
262 return QuicTime::Delta::FromSeconds(
263 idle_connection_state_lifetime_seconds_.GetUint32());
264 }
265
keepalive_timeout() const266 QuicTime::Delta QuicConfig::keepalive_timeout() const {
267 return QuicTime::Delta::FromSeconds(
268 keepalive_timeout_seconds_.GetUint32());
269 }
270
set_max_streams_per_connection(size_t max_streams,size_t default_streams)271 void QuicConfig::set_max_streams_per_connection(size_t max_streams,
272 size_t default_streams) {
273 max_streams_per_connection_.set(max_streams, default_streams);
274 }
275
max_streams_per_connection() const276 uint32 QuicConfig::max_streams_per_connection() const {
277 return max_streams_per_connection_.GetUint32();
278 }
279
set_max_time_before_crypto_handshake(QuicTime::Delta max_time_before_crypto_handshake)280 void QuicConfig::set_max_time_before_crypto_handshake(
281 QuicTime::Delta max_time_before_crypto_handshake) {
282 max_time_before_crypto_handshake_ = max_time_before_crypto_handshake;
283 }
284
max_time_before_crypto_handshake() const285 QuicTime::Delta QuicConfig::max_time_before_crypto_handshake() const {
286 return max_time_before_crypto_handshake_;
287 }
288
set_server_initial_congestion_window(size_t max_initial_window,size_t default_initial_window)289 void QuicConfig::set_server_initial_congestion_window(size_t max_initial_window,
290 size_t default_initial_window) {
291 server_initial_congestion_window_.set(max_initial_window,
292 default_initial_window);
293 }
294
server_initial_congestion_window() const295 uint32 QuicConfig::server_initial_congestion_window() const {
296 return server_initial_congestion_window_.GetUint32();
297 }
298
set_initial_round_trip_time_us(size_t max_rtt,size_t default_rtt)299 void QuicConfig::set_initial_round_trip_time_us(size_t max_rtt,
300 size_t default_rtt) {
301 initial_round_trip_time_us_.set(max_rtt, default_rtt);
302 }
303
initial_round_trip_time_us() const304 uint32 QuicConfig::initial_round_trip_time_us() const {
305 return initial_round_trip_time_us_.GetUint32();
306 }
307
negotiated()308 bool QuicConfig::negotiated() {
309 // TODO(ianswett): Add the negotiated parameters once and iterate over all
310 // of them in negotiated, ToHandshakeMessage, ProcessClientHello, and
311 // ProcessServerHello.
312 return congestion_control_.negotiated() &&
313 idle_connection_state_lifetime_seconds_.negotiated() &&
314 keepalive_timeout_seconds_.negotiated() &&
315 max_streams_per_connection_.negotiated() &&
316 server_initial_congestion_window_.negotiated() &&
317 initial_round_trip_time_us_.negotiated();
318 }
319
SetDefaults()320 void QuicConfig::SetDefaults() {
321 QuicTagVector congestion_control;
322 if (FLAGS_enable_quic_pacing) {
323 congestion_control.push_back(kPACE);
324 }
325 congestion_control.push_back(kQBIC);
326 congestion_control_.set(congestion_control, kQBIC);
327 idle_connection_state_lifetime_seconds_.set(kDefaultTimeoutSecs,
328 kDefaultInitialTimeoutSecs);
329 // kKATO is optional. Return 0 if not negotiated.
330 keepalive_timeout_seconds_.set(0, 0);
331 max_streams_per_connection_.set(kDefaultMaxStreamsPerConnection,
332 kDefaultMaxStreamsPerConnection);
333 max_time_before_crypto_handshake_ = QuicTime::Delta::FromSeconds(
334 kDefaultMaxTimeForCryptoHandshakeSecs);
335 server_initial_congestion_window_.set(kDefaultInitialWindow,
336 kDefaultInitialWindow);
337 }
338
ToHandshakeMessage(CryptoHandshakeMessage * out) const339 void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
340 congestion_control_.ToHandshakeMessage(out);
341 idle_connection_state_lifetime_seconds_.ToHandshakeMessage(out);
342 keepalive_timeout_seconds_.ToHandshakeMessage(out);
343 max_streams_per_connection_.ToHandshakeMessage(out);
344 server_initial_congestion_window_.ToHandshakeMessage(out);
345 // TODO(ianswett): Don't transmit parameters which are optional and not set.
346 initial_round_trip_time_us_.ToHandshakeMessage(out);
347 }
348
ProcessClientHello(const CryptoHandshakeMessage & client_hello,string * error_details)349 QuicErrorCode QuicConfig::ProcessClientHello(
350 const CryptoHandshakeMessage& client_hello,
351 string* error_details) {
352 DCHECK(error_details != NULL);
353
354 QuicErrorCode error = QUIC_NO_ERROR;
355 if (error == QUIC_NO_ERROR) {
356 error = congestion_control_.ProcessClientHello(client_hello, error_details);
357 }
358 if (error == QUIC_NO_ERROR) {
359 error = idle_connection_state_lifetime_seconds_.ProcessClientHello(
360 client_hello, error_details);
361 }
362 if (error == QUIC_NO_ERROR) {
363 error = keepalive_timeout_seconds_.ProcessClientHello(
364 client_hello, error_details);
365 }
366 if (error == QUIC_NO_ERROR) {
367 error = max_streams_per_connection_.ProcessClientHello(
368 client_hello, error_details);
369 }
370 if (error == QUIC_NO_ERROR) {
371 error = server_initial_congestion_window_.ProcessClientHello(
372 client_hello, error_details);
373 }
374 if (error == QUIC_NO_ERROR) {
375 error = initial_round_trip_time_us_.ProcessClientHello(
376 client_hello, error_details);
377 }
378 return error;
379 }
380
ProcessServerHello(const CryptoHandshakeMessage & server_hello,string * error_details)381 QuicErrorCode QuicConfig::ProcessServerHello(
382 const CryptoHandshakeMessage& server_hello,
383 string* error_details) {
384 DCHECK(error_details != NULL);
385
386 QuicErrorCode error = QUIC_NO_ERROR;
387 if (error == QUIC_NO_ERROR) {
388 error = congestion_control_.ProcessServerHello(server_hello, error_details);
389 }
390 if (error == QUIC_NO_ERROR) {
391 error = idle_connection_state_lifetime_seconds_.ProcessServerHello(
392 server_hello, error_details);
393 }
394 if (error == QUIC_NO_ERROR) {
395 error = keepalive_timeout_seconds_.ProcessServerHello(
396 server_hello, error_details);
397 }
398 if (error == QUIC_NO_ERROR) {
399 error = max_streams_per_connection_.ProcessServerHello(
400 server_hello, error_details);
401 }
402 if (error == QUIC_NO_ERROR) {
403 error = server_initial_congestion_window_.ProcessServerHello(
404 server_hello, error_details);
405 }
406 if (error == QUIC_NO_ERROR) {
407 error = initial_round_trip_time_us_.ProcessServerHello(
408 server_hello, error_details);
409 }
410 return error;
411 }
412
413 } // namespace net
414