blob: eacde842e27e2826d6c4ad89896ce0063674ffd3 [file] [log] [blame]
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001// 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
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +01007#include <algorithm>
8
9#include "base/logging.h"
10
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010011using std::string;
12
13namespace net {
14
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010015QuicNegotiableValue::QuicNegotiableValue(QuicTag tag, Presence presence)
16 : tag_(tag),
17 presence_(presence),
18 negotiated_(false) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010019}
20
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010021QuicNegotiableUint32::QuicNegotiableUint32(QuicTag tag, Presence presence)
22 : QuicNegotiableValue(tag, presence) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010023}
24
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010025void QuicNegotiableUint32::set(uint32 max, uint32 default_value) {
26 DCHECK_LE(default_value, max);
27 max_value_ = max;
28 default_value_ = default_value;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010029}
30
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010031uint32 QuicNegotiableUint32::GetUint32() const {
32 if (negotiated_) {
33 return negotiated_value_;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010034 }
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010035 return default_value_;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010036}
37
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010038void QuicNegotiableUint32::ToHandshakeMessage(
39 CryptoHandshakeMessage* out) const {
40 if (negotiated_) {
41 out->SetValue(tag_, negotiated_value_);
42 } else {
43 out->SetValue(tag_, max_value_);
44 }
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010045}
46
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010047QuicErrorCode QuicNegotiableUint32::ReadUint32(
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010048 const CryptoHandshakeMessage& msg,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010049 uint32* out,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010050 string* error_details) const {
51 DCHECK(error_details != NULL);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010052 QuicErrorCode error = msg.GetUint32(tag_, out);
53 switch (error) {
54 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
55 if (presence_ == QuicNegotiableValue::PRESENCE_REQUIRED) {
56 *error_details = "Missing " + QuicUtils::TagToString(tag_);
57 break;
58 }
59 error = QUIC_NO_ERROR;
60 *out = default_value_;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010061
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010062 case QUIC_NO_ERROR:
63 break;
64 default:
65 *error_details = "Bad " + QuicUtils::TagToString(tag_);
66 break;
67 }
68 return error;
69}
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010070
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010071QuicErrorCode QuicNegotiableUint32::ProcessClientHello(
72 const CryptoHandshakeMessage& client_hello,
73 string* error_details) {
74 DCHECK(!negotiated_);
75 DCHECK(error_details != NULL);
76 uint32 value;
77 QuicErrorCode error = ReadUint32(client_hello, &value, error_details);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010078 if (error != QUIC_NO_ERROR) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010079 return error;
80 }
81
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010082 negotiated_ = true;
83 negotiated_value_ = std::min(value, max_value_);
84
85 return QUIC_NO_ERROR;
86}
87
88QuicErrorCode QuicNegotiableUint32::ProcessServerHello(
89 const CryptoHandshakeMessage& server_hello,
90 string* error_details) {
91 DCHECK(!negotiated_);
92 DCHECK(error_details != NULL);
93 uint32 value;
94 QuicErrorCode error = ReadUint32(server_hello, &value, error_details);
95 if (error != QUIC_NO_ERROR) {
96 return error;
97 }
98
99 if (value > max_value_) {
100 *error_details = "Invalid value received for " +
101 QuicUtils::TagToString(tag_);
102 return QUIC_INVALID_NEGOTIATED_VALUE;
103 }
104
105 negotiated_ = true;
106 negotiated_value_ = value;
107 return QUIC_NO_ERROR;
108}
109
110QuicNegotiableTag::QuicNegotiableTag(QuicTag tag, Presence presence)
111 : QuicNegotiableValue(tag, presence) {
112}
113
114QuicNegotiableTag::~QuicNegotiableTag() {}
115
116void QuicNegotiableTag::set(const QuicTagVector& possible,
117 QuicTag default_value) {
118 DCHECK(std::find(possible.begin(), possible.end(), default_value) !=
119 possible.end());
120 possible_values_ = possible;
121 default_value_ = default_value;
122}
123
124QuicTag QuicNegotiableTag::GetTag() const {
125 if (negotiated_) {
126 return negotiated_tag_;
127 }
128 return default_value_;
129}
130
131void QuicNegotiableTag::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
132 if (negotiated_) {
133 // Because of the way we serialize and parse handshake messages we can
134 // serialize this as value and still parse it as a vector.
135 out->SetValue(tag_, negotiated_tag_);
136 } else {
137 out->SetVector(tag_, possible_values_);
138 }
139}
140
141QuicErrorCode QuicNegotiableTag::ReadVector(
142 const CryptoHandshakeMessage& msg,
143 const QuicTag** out,
144 size_t* out_length,
145 string* error_details) const {
146 DCHECK(error_details != NULL);
147 QuicErrorCode error = msg.GetTaglist(tag_, out, out_length);
148 switch (error) {
149 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
150 if (presence_ == PRESENCE_REQUIRED) {
151 *error_details = "Missing " + QuicUtils::TagToString(tag_);
152 break;
153 }
154 error = QUIC_NO_ERROR;
155 *out_length = 1;
156 *out = &default_value_;
157
158 case QUIC_NO_ERROR:
159 break;
160 default:
161 *error_details = "Bad " + QuicUtils::TagToString(tag_);
162 break;
163 }
164 return error;
165}
166
167QuicErrorCode QuicNegotiableTag::ProcessClientHello(
168 const CryptoHandshakeMessage& client_hello,
169 string* error_details) {
170 DCHECK(!negotiated_);
171 DCHECK(error_details != NULL);
172 const QuicTag* received_tags;
173 size_t received_tags_length;
174 QuicErrorCode error = ReadVector(client_hello, &received_tags,
175 &received_tags_length, error_details);
176 if (error != QUIC_NO_ERROR) {
177 return error;
178 }
179
180 QuicTag negotiated_tag;
181 if (!QuicUtils::FindMutualTag(possible_values_,
182 received_tags,
183 received_tags_length,
184 QuicUtils::LOCAL_PRIORITY,
185 &negotiated_tag,
186 NULL)) {
187 *error_details = "Unsuported " + QuicUtils::TagToString(tag_);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100188 return QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP;
189 }
190
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100191 negotiated_ = true;
192 negotiated_tag_ = negotiated_tag;
193 return QUIC_NO_ERROR;
194}
195
196QuicErrorCode QuicNegotiableTag::ProcessServerHello(
197 const CryptoHandshakeMessage& server_hello,
198 string* error_details) {
199 DCHECK(!negotiated_);
200 DCHECK(error_details != NULL);
201 const QuicTag* received_tags;
202 size_t received_tags_length;
203 QuicErrorCode error = ReadVector(server_hello, &received_tags,
204 &received_tags_length, error_details);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100205 if (error != QUIC_NO_ERROR) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100206 return error;
207 }
208
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100209 if (received_tags_length != 1 ||
210 std::find(possible_values_.begin(), possible_values_.end(),
211 *received_tags) == possible_values_.end()) {
212 *error_details = "Invalid " + QuicUtils::TagToString(tag_);
213 return QUIC_INVALID_NEGOTIATED_VALUE;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100214 }
215
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100216 negotiated_ = true;
217 negotiated_tag_ = *received_tags;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100218 return QUIC_NO_ERROR;
219}
220
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100221QuicConfig::QuicConfig() :
222 congestion_control_(kCGST, QuicNegotiableValue::PRESENCE_REQUIRED),
223 idle_connection_state_lifetime_seconds_(
224 kICSL, QuicNegotiableValue::PRESENCE_REQUIRED),
225 keepalive_timeout_seconds_(kKATO, QuicNegotiableValue::PRESENCE_OPTIONAL),
226 max_streams_per_connection_(kMSPC, QuicNegotiableValue::PRESENCE_REQUIRED) {
227 idle_connection_state_lifetime_seconds_.set(0, 0);
228 keepalive_timeout_seconds_.set(0, 0);
229}
230
231QuicConfig::~QuicConfig() {}
232
233void QuicConfig::set_congestion_control(
234 const QuicTagVector& congestion_control,
235 QuicTag default_congestion_control) {
236 congestion_control_.set(congestion_control, default_congestion_control);
237}
238
239QuicTag QuicConfig::congestion_control() const {
240 return congestion_control_.GetTag();
241}
242
243void QuicConfig::set_idle_connection_state_lifetime(
244 QuicTime::Delta max_idle_connection_state_lifetime,
245 QuicTime::Delta default_idle_conection_state_lifetime) {
246 idle_connection_state_lifetime_seconds_.set(
247 max_idle_connection_state_lifetime.ToSeconds(),
248 default_idle_conection_state_lifetime.ToSeconds());
249}
250
251QuicTime::Delta QuicConfig::idle_connection_state_lifetime() const {
252 return QuicTime::Delta::FromSeconds(
253 idle_connection_state_lifetime_seconds_.GetUint32());
254}
255
256QuicTime::Delta QuicConfig::keepalive_timeout() const {
257 return QuicTime::Delta::FromSeconds(
258 keepalive_timeout_seconds_.GetUint32());
259}
260
261void QuicConfig::set_max_streams_per_connection(size_t max_streams,
262 size_t default_streams) {
263 max_streams_per_connection_.set(max_streams, default_streams);
264}
265
266uint32 QuicConfig::max_streams_per_connection() const {
267 return max_streams_per_connection_.GetUint32();
268}
269
270bool QuicConfig::negotiated() {
271 return congestion_control_.negotiated() &&
272 idle_connection_state_lifetime_seconds_.negotiated() &&
273 keepalive_timeout_seconds_.negotiated() &&
274 max_streams_per_connection_.negotiated();
275}
276
277void QuicConfig::SetDefaults() {
278 congestion_control_.set(QuicTagVector(1, kQBIC), kQBIC);
279 idle_connection_state_lifetime_seconds_.set(kDefaultTimeoutSecs,
280 kDefaultTimeoutSecs);
281 // kKATO is optional. Return 0 if not negotiated.
282 keepalive_timeout_seconds_.set(0, 0);
283 max_streams_per_connection_.set(kDefaultMaxStreamsPerConnection,
284 kDefaultMaxStreamsPerConnection);
285}
286
287void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
288 congestion_control_.ToHandshakeMessage(out);
289 idle_connection_state_lifetime_seconds_.ToHandshakeMessage(out);
290 keepalive_timeout_seconds_.ToHandshakeMessage(out);
291 max_streams_per_connection_.ToHandshakeMessage(out);
292}
293
294QuicErrorCode QuicConfig::ProcessClientHello(
295 const CryptoHandshakeMessage& client_hello,
296 string* error_details) {
297 DCHECK(error_details != NULL);
298
299 QuicErrorCode error = QUIC_NO_ERROR;
300 if (error == QUIC_NO_ERROR) {
301 error = congestion_control_.ProcessClientHello(client_hello, error_details);
302 }
303 if (error == QUIC_NO_ERROR) {
304 error = idle_connection_state_lifetime_seconds_.ProcessClientHello(
305 client_hello, error_details);
306 }
307 if (error == QUIC_NO_ERROR) {
308 error = keepalive_timeout_seconds_.ProcessClientHello(
309 client_hello, error_details);
310 }
311 if (error == QUIC_NO_ERROR) {
312 error = max_streams_per_connection_.ProcessClientHello(
313 client_hello, error_details);
314 }
315 return error;
316}
317
318QuicErrorCode QuicConfig::ProcessServerHello(
319 const CryptoHandshakeMessage& server_hello,
320 string* error_details) {
321 DCHECK(error_details != NULL);
322
323 QuicErrorCode error = QUIC_NO_ERROR;
324 if (error == QUIC_NO_ERROR) {
325 error = congestion_control_.ProcessServerHello(server_hello, error_details);
326 }
327 if (error == QUIC_NO_ERROR) {
328 error = idle_connection_state_lifetime_seconds_.ProcessServerHello(
329 server_hello, error_details);
330 }
331 if (error == QUIC_NO_ERROR) {
332 error = keepalive_timeout_seconds_.ProcessServerHello(
333 server_hello, error_details);
334 }
335 if (error == QUIC_NO_ERROR) {
336 error = max_streams_per_connection_.ProcessServerHello(
337 server_hello, error_details);
338 }
339 return error;
340}
341
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100342} // namespace net
343