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
11using std::string;
12
13namespace net {
14
15QuicNegotiableValue::QuicNegotiableValue(QuicTag tag, Presence presence)
16    : tag_(tag),
17      presence_(presence),
18      negotiated_(false) {
19}
20
21QuicNegotiableUint32::QuicNegotiableUint32(QuicTag tag, Presence presence)
22    : QuicNegotiableValue(tag, presence) {
23}
24
25void QuicNegotiableUint32::set(uint32 max, uint32 default_value) {
26  DCHECK_LE(default_value, max);
27  max_value_ = max;
28  default_value_ = default_value;
29}
30
31uint32 QuicNegotiableUint32::GetUint32() const {
32  if (negotiated_) {
33    return negotiated_value_;
34  }
35  return default_value_;
36}
37
38void QuicNegotiableUint32::ToHandshakeMessage(
39    CryptoHandshakeMessage* out) const {
40  if (negotiated_) {
41    out->SetValue(tag_, negotiated_value_);
42  } else {
43    out->SetValue(tag_, max_value_);
44  }
45}
46
47QuicErrorCode QuicNegotiableUint32::ReadUint32(
48    const CryptoHandshakeMessage& msg,
49    uint32* out,
50    string* error_details) const {
51  DCHECK(error_details != NULL);
52  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_;
61
62    case QUIC_NO_ERROR:
63      break;
64    default:
65      *error_details = "Bad " + QuicUtils::TagToString(tag_);
66      break;
67  }
68  return error;
69}
70
71QuicErrorCode 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);
78  if (error != QUIC_NO_ERROR) {
79    return error;
80  }
81
82  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_);
188    return QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP;
189  }
190
191  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);
205  if (error != QUIC_NO_ERROR) {
206    return error;
207  }
208
209  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;
214  }
215
216  negotiated_ = true;
217  negotiated_tag_ = *received_tags;
218  return QUIC_NO_ERROR;
219}
220
221QuicConfig::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    max_time_before_crypto_handshake_(QuicTime::Delta::Zero()) {
228  idle_connection_state_lifetime_seconds_.set(0, 0);
229  keepalive_timeout_seconds_.set(0, 0);
230}
231
232QuicConfig::~QuicConfig() {}
233
234void QuicConfig::set_congestion_control(
235    const QuicTagVector& congestion_control,
236    QuicTag default_congestion_control) {
237  congestion_control_.set(congestion_control, default_congestion_control);
238}
239
240QuicTag QuicConfig::congestion_control() const {
241  return congestion_control_.GetTag();
242}
243
244void QuicConfig::set_idle_connection_state_lifetime(
245    QuicTime::Delta max_idle_connection_state_lifetime,
246    QuicTime::Delta default_idle_conection_state_lifetime) {
247  idle_connection_state_lifetime_seconds_.set(
248      max_idle_connection_state_lifetime.ToSeconds(),
249      default_idle_conection_state_lifetime.ToSeconds());
250}
251
252QuicTime::Delta QuicConfig::idle_connection_state_lifetime() const {
253  return QuicTime::Delta::FromSeconds(
254      idle_connection_state_lifetime_seconds_.GetUint32());
255}
256
257QuicTime::Delta QuicConfig::keepalive_timeout() const {
258  return QuicTime::Delta::FromSeconds(
259      keepalive_timeout_seconds_.GetUint32());
260}
261
262void QuicConfig::set_max_streams_per_connection(size_t max_streams,
263                                                size_t default_streams) {
264  max_streams_per_connection_.set(max_streams, default_streams);
265}
266
267uint32 QuicConfig::max_streams_per_connection() const {
268  return max_streams_per_connection_.GetUint32();
269}
270
271void QuicConfig::set_max_time_before_crypto_handshake(
272    QuicTime::Delta max_time_before_crypto_handshake) {
273  max_time_before_crypto_handshake_ = max_time_before_crypto_handshake;
274}
275
276QuicTime::Delta QuicConfig::max_time_before_crypto_handshake() const {
277  return max_time_before_crypto_handshake_;
278}
279
280bool QuicConfig::negotiated() {
281  return congestion_control_.negotiated() &&
282      idle_connection_state_lifetime_seconds_.negotiated() &&
283      keepalive_timeout_seconds_.negotiated() &&
284      max_streams_per_connection_.negotiated();
285}
286
287void QuicConfig::SetDefaults() {
288  congestion_control_.set(QuicTagVector(1, kQBIC), kQBIC);
289  idle_connection_state_lifetime_seconds_.set(kDefaultTimeoutSecs,
290                                              kDefaultInitialTimeoutSecs);
291  // kKATO is optional. Return 0 if not negotiated.
292  keepalive_timeout_seconds_.set(0, 0);
293  max_streams_per_connection_.set(kDefaultMaxStreamsPerConnection,
294                                  kDefaultMaxStreamsPerConnection);
295  max_time_before_crypto_handshake_ = QuicTime::Delta::FromSeconds(
296      kDefaultMaxTimeForCryptoHandshakeSecs);
297}
298
299void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
300  congestion_control_.ToHandshakeMessage(out);
301  idle_connection_state_lifetime_seconds_.ToHandshakeMessage(out);
302  keepalive_timeout_seconds_.ToHandshakeMessage(out);
303  max_streams_per_connection_.ToHandshakeMessage(out);
304}
305
306QuicErrorCode QuicConfig::ProcessClientHello(
307    const CryptoHandshakeMessage& client_hello,
308    string* error_details) {
309  DCHECK(error_details != NULL);
310
311  QuicErrorCode error = QUIC_NO_ERROR;
312  if (error == QUIC_NO_ERROR) {
313    error = congestion_control_.ProcessClientHello(client_hello, error_details);
314  }
315  if (error == QUIC_NO_ERROR) {
316    error = idle_connection_state_lifetime_seconds_.ProcessClientHello(
317        client_hello, error_details);
318  }
319  if (error == QUIC_NO_ERROR) {
320    error = keepalive_timeout_seconds_.ProcessClientHello(
321        client_hello, error_details);
322  }
323  if (error == QUIC_NO_ERROR) {
324    error = max_streams_per_connection_.ProcessClientHello(
325        client_hello, error_details);
326  }
327  return error;
328}
329
330QuicErrorCode QuicConfig::ProcessServerHello(
331    const CryptoHandshakeMessage& server_hello,
332    string* error_details) {
333  DCHECK(error_details != NULL);
334
335  QuicErrorCode error = QUIC_NO_ERROR;
336  if (error == QUIC_NO_ERROR) {
337    error = congestion_control_.ProcessServerHello(server_hello, error_details);
338  }
339  if (error == QUIC_NO_ERROR) {
340    error = idle_connection_state_lifetime_seconds_.ProcessServerHello(
341        server_hello, error_details);
342  }
343  if (error == QUIC_NO_ERROR) {
344    error = keepalive_timeout_seconds_.ProcessServerHello(
345        server_hello, error_details);
346  }
347  if (error == QUIC_NO_ERROR) {
348    error = max_streams_per_connection_.ProcessServerHello(
349        server_hello, error_details);
350  }
351  return error;
352}
353
354}  // namespace net
355
356