• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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