Home | History | Annotate | Download | only in quic
      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 
     16 QuicNegotiableValue::QuicNegotiableValue(QuicTag tag, Presence presence)
     17     : tag_(tag),
     18       presence_(presence),
     19       negotiated_(false) {
     20 }
     21 
     22 QuicNegotiableUint32::QuicNegotiableUint32(QuicTag tag, Presence presence)
     23     : QuicNegotiableValue(tag, presence),
     24       max_value_(0),
     25       default_value_(0) {
     26 }
     27 
     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 
     34 uint32 QuicNegotiableUint32::GetUint32() const {
     35   if (negotiated_) {
     36     return negotiated_value_;
     37   }
     38   return default_value_;
     39 }
     40 
     41 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 
     50 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 
     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 
     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 
    113 QuicNegotiableTag::QuicNegotiableTag(QuicTag tag, Presence presence)
    114     : QuicNegotiableValue(tag, presence),
    115       negotiated_tag_(0),
    116       default_value_(0) {
    117 }
    118 
    119 QuicNegotiableTag::~QuicNegotiableTag() {}
    120 
    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 
    129 QuicTag QuicNegotiableTag::GetTag() const {
    130   if (negotiated_) {
    131     return negotiated_tag_;
    132   }
    133   return default_value_;
    134 }
    135 
    136 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 
    146 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 
    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 
    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 
    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 
    241 QuicConfig::~QuicConfig() {}
    242 
    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 
    249 QuicTag QuicConfig::congestion_control() const {
    250   return congestion_control_.GetTag();
    251 }
    252 
    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 
    261 QuicTime::Delta QuicConfig::idle_connection_state_lifetime() const {
    262   return QuicTime::Delta::FromSeconds(
    263       idle_connection_state_lifetime_seconds_.GetUint32());
    264 }
    265 
    266 QuicTime::Delta QuicConfig::keepalive_timeout() const {
    267   return QuicTime::Delta::FromSeconds(
    268       keepalive_timeout_seconds_.GetUint32());
    269 }
    270 
    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 
    276 uint32 QuicConfig::max_streams_per_connection() const {
    277   return max_streams_per_connection_.GetUint32();
    278 }
    279 
    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 
    285 QuicTime::Delta QuicConfig::max_time_before_crypto_handshake() const {
    286   return max_time_before_crypto_handshake_;
    287 }
    288 
    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 
    295 uint32 QuicConfig::server_initial_congestion_window() const {
    296   return server_initial_congestion_window_.GetUint32();
    297 }
    298 
    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 
    304 uint32 QuicConfig::initial_round_trip_time_us() const {
    305   return initial_round_trip_time_us_.GetUint32();
    306 }
    307 
    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 
    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 
    339 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 
    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 
    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