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 
     11 using std::string;
     12 
     13 namespace net {
     14 
     15 QuicNegotiableValue::QuicNegotiableValue(QuicTag tag, Presence presence)
     16     : tag_(tag),
     17       presence_(presence),
     18       negotiated_(false) {
     19 }
     20 
     21 QuicNegotiableUint32::QuicNegotiableUint32(QuicTag tag, Presence presence)
     22     : QuicNegotiableValue(tag, presence) {
     23 }
     24 
     25 void QuicNegotiableUint32::set(uint32 max, uint32 default_value) {
     26   DCHECK_LE(default_value, max);
     27   max_value_ = max;
     28   default_value_ = default_value;
     29 }
     30 
     31 uint32 QuicNegotiableUint32::GetUint32() const {
     32   if (negotiated_) {
     33     return negotiated_value_;
     34   }
     35   return default_value_;
     36 }
     37 
     38 void 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 
     47 QuicErrorCode 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 
     71 QuicErrorCode 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 
     88 QuicErrorCode 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 
    110 QuicNegotiableTag::QuicNegotiableTag(QuicTag tag, Presence presence)
    111     : QuicNegotiableValue(tag, presence) {
    112 }
    113 
    114 QuicNegotiableTag::~QuicNegotiableTag() {}
    115 
    116 void 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 
    124 QuicTag QuicNegotiableTag::GetTag() const {
    125   if (negotiated_) {
    126     return negotiated_tag_;
    127   }
    128   return default_value_;
    129 }
    130 
    131 void 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 
    141 QuicErrorCode 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 
    167 QuicErrorCode 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 
    196 QuicErrorCode 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 
    221 QuicConfig::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 
    232 QuicConfig::~QuicConfig() {}
    233 
    234 void 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 
    240 QuicTag QuicConfig::congestion_control() const {
    241   return congestion_control_.GetTag();
    242 }
    243 
    244 void 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 
    252 QuicTime::Delta QuicConfig::idle_connection_state_lifetime() const {
    253   return QuicTime::Delta::FromSeconds(
    254       idle_connection_state_lifetime_seconds_.GetUint32());
    255 }
    256 
    257 QuicTime::Delta QuicConfig::keepalive_timeout() const {
    258   return QuicTime::Delta::FromSeconds(
    259       keepalive_timeout_seconds_.GetUint32());
    260 }
    261 
    262 void 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 
    267 uint32 QuicConfig::max_streams_per_connection() const {
    268   return max_streams_per_connection_.GetUint32();
    269 }
    270 
    271 void 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 
    276 QuicTime::Delta QuicConfig::max_time_before_crypto_handshake() const {
    277   return max_time_before_crypto_handshake_;
    278 }
    279 
    280 bool 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 
    287 void 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 
    299 void 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 
    306 QuicErrorCode 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 
    330 QuicErrorCode 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