This source file includes following definitions.
- ReadUint32
 
- presence_
 
- negotiated_
 
- default_value_
 
- set
 
- GetUint32
 
- ToHandshakeMessage
 
- ProcessClientHello
 
- ProcessServerHello
 
- default_value_
 
- set
 
- GetTag
 
- ToHandshakeMessage
 
- ReadVector
 
- ProcessClientHello
 
- ProcessServerHello
 
- value_
 
- GetUint32
 
- ToHandshakeMessage
 
- ProcessClientHello
 
- ProcessServerHello
 
- peer_initial_flow_control_window_bytes_
 
- set_congestion_control
 
- congestion_control
 
- set_loss_detection
 
- loss_detection
 
- set_idle_connection_state_lifetime
 
- idle_connection_state_lifetime
 
- keepalive_timeout
 
- set_max_streams_per_connection
 
- max_streams_per_connection
 
- set_max_time_before_crypto_handshake
 
- max_time_before_crypto_handshake
 
- set_server_initial_congestion_window
 
- server_initial_congestion_window
 
- set_initial_round_trip_time_us
 
- initial_round_trip_time_us
 
- set_peer_initial_flow_control_window_bytes
 
- peer_initial_flow_control_window_bytes
 
- negotiated
 
- SetDefaults
 
- EnablePacing
 
- ToHandshakeMessage
 
- ProcessClientHello
 
- ProcessServerHello
 
#include "net/quic/quic_config.h"
#include <algorithm>
#include "base/logging.h"
#include "net/quic/crypto/crypto_handshake_message.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/quic_flags.h"
#include "net/quic/quic_sent_packet_manager.h"
#include "net/quic/quic_utils.h"
using std::min;
using std::string;
namespace net {
QuicErrorCode ReadUint32(const CryptoHandshakeMessage& msg,
                         QuicTag tag,
                         QuicConfigPresence presence,
                         uint32 default_value,
                         uint32* out,
                         string* error_details) {
  DCHECK(error_details != NULL);
  QuicErrorCode error = msg.GetUint32(tag, out);
  switch (error) {
    case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
      if (presence == PRESENCE_REQUIRED) {
        *error_details = "Missing " + QuicUtils::TagToString(tag);
        break;
      }
      error = QUIC_NO_ERROR;
      *out = default_value;
      break;
    case QUIC_NO_ERROR:
      break;
    default:
      *error_details = "Bad " + QuicUtils::TagToString(tag);
      break;
  }
  return error;
}
QuicConfigValue::QuicConfigValue(QuicTag tag,
                                 QuicConfigPresence presence)
    : tag_(tag),
      presence_(presence) {
}
QuicConfigValue::~QuicConfigValue() {}
QuicNegotiableValue::QuicNegotiableValue(QuicTag tag,
                                         QuicConfigPresence presence)
    : QuicConfigValue(tag, presence),
      negotiated_(false) {
}
QuicNegotiableValue::~QuicNegotiableValue() {}
QuicNegotiableUint32::QuicNegotiableUint32(QuicTag tag,
                                           QuicConfigPresence presence)
    : QuicNegotiableValue(tag, presence),
      max_value_(0),
      default_value_(0) {
}
QuicNegotiableUint32::~QuicNegotiableUint32() {}
void QuicNegotiableUint32::set(uint32 max, uint32 default_value) {
  DCHECK_LE(default_value, max);
  max_value_ = max;
  default_value_ = default_value;
}
uint32 QuicNegotiableUint32::GetUint32() const {
  if (negotiated_) {
    return negotiated_value_;
  }
  return default_value_;
}
void QuicNegotiableUint32::ToHandshakeMessage(
    CryptoHandshakeMessage* out) const {
  if (negotiated_) {
    out->SetValue(tag_, negotiated_value_);
  } else {
    out->SetValue(tag_, max_value_);
  }
}
QuicErrorCode QuicNegotiableUint32::ProcessClientHello(
    const CryptoHandshakeMessage& client_hello,
    string* error_details) {
  DCHECK(!negotiated_);
  DCHECK(error_details != NULL);
  uint32 value;
  QuicErrorCode error = ReadUint32(client_hello,
                                   tag_,
                                   presence_,
                                   default_value_,
                                   &value,
                                   error_details);
  if (error != QUIC_NO_ERROR) {
    return error;
  }
  negotiated_ = true;
  negotiated_value_ = min(value, max_value_);
  return QUIC_NO_ERROR;
}
QuicErrorCode QuicNegotiableUint32::ProcessServerHello(
    const CryptoHandshakeMessage& server_hello,
    string* error_details) {
  DCHECK(!negotiated_);
  DCHECK(error_details != NULL);
  uint32 value;
  QuicErrorCode error = ReadUint32(server_hello,
                                   tag_,
                                   presence_,
                                   max_value_,
                                   &value,
                                   error_details);
  if (error != QUIC_NO_ERROR) {
    return error;
  }
  if (value > max_value_) {
    *error_details = "Invalid value received for " +
        QuicUtils::TagToString(tag_);
    return QUIC_INVALID_NEGOTIATED_VALUE;
  }
  negotiated_ = true;
  negotiated_value_ = value;
  return QUIC_NO_ERROR;
}
QuicNegotiableTag::QuicNegotiableTag(QuicTag tag, QuicConfigPresence presence)
    : QuicNegotiableValue(tag, presence),
      negotiated_tag_(0),
      default_value_(0) {
}
QuicNegotiableTag::~QuicNegotiableTag() {}
void QuicNegotiableTag::set(const QuicTagVector& possible,
                            QuicTag default_value) {
  DCHECK(std::find(possible.begin(), possible.end(), default_value) !=
            possible.end());
  possible_values_ = possible;
  default_value_ = default_value;
}
QuicTag QuicNegotiableTag::GetTag() const {
  if (negotiated_) {
    return negotiated_tag_;
  }
  return default_value_;
}
void QuicNegotiableTag::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
  if (negotiated_) {
    
    
    out->SetValue(tag_, negotiated_tag_);
  } else {
    out->SetVector(tag_, possible_values_);
  }
}
QuicErrorCode QuicNegotiableTag::ReadVector(
    const CryptoHandshakeMessage& msg,
    const QuicTag** out,
    size_t* out_length,
    string* error_details) const {
  DCHECK(error_details != NULL);
  QuicErrorCode error = msg.GetTaglist(tag_, out, out_length);
  switch (error) {
    case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
      if (presence_ == PRESENCE_REQUIRED) {
        *error_details = "Missing " + QuicUtils::TagToString(tag_);
        break;
      }
      error = QUIC_NO_ERROR;
      *out_length = 1;
      *out = &default_value_;
    case QUIC_NO_ERROR:
      break;
    default:
      *error_details = "Bad " + QuicUtils::TagToString(tag_);
      break;
  }
  return error;
}
QuicErrorCode QuicNegotiableTag::ProcessClientHello(
    const CryptoHandshakeMessage& client_hello,
    string* error_details) {
  DCHECK(!negotiated_);
  DCHECK(error_details != NULL);
  const QuicTag* received_tags;
  size_t received_tags_length;
  QuicErrorCode error = ReadVector(client_hello, &received_tags,
                                   &received_tags_length, error_details);
  if (error != QUIC_NO_ERROR) {
    return error;
  }
  QuicTag negotiated_tag;
  if (!QuicUtils::FindMutualTag(possible_values_,
                                received_tags,
                                received_tags_length,
                                QuicUtils::LOCAL_PRIORITY,
                                &negotiated_tag,
                                NULL)) {
    *error_details = "Unsuported " + QuicUtils::TagToString(tag_);
    return QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP;
  }
  negotiated_ = true;
  negotiated_tag_ = negotiated_tag;
  return QUIC_NO_ERROR;
}
QuicErrorCode QuicNegotiableTag::ProcessServerHello(
    const CryptoHandshakeMessage& server_hello,
    string* error_details) {
  DCHECK(!negotiated_);
  DCHECK(error_details != NULL);
  const QuicTag* received_tags;
  size_t received_tags_length;
  QuicErrorCode error = ReadVector(server_hello, &received_tags,
                                   &received_tags_length, error_details);
  if (error != QUIC_NO_ERROR) {
    return error;
  }
  if (received_tags_length != 1 ||
      std::find(possible_values_.begin(), possible_values_.end(),
                *received_tags) == possible_values_.end()) {
    *error_details = "Invalid " + QuicUtils::TagToString(tag_);
    return QUIC_INVALID_NEGOTIATED_VALUE;
  }
  negotiated_ = true;
  negotiated_tag_ = *received_tags;
  return QUIC_NO_ERROR;
}
QuicFixedUint32::QuicFixedUint32(QuicTag tag,
                                 QuicConfigPresence presence,
                                 uint32 default_value)
    : QuicConfigValue(tag, presence),
      value_(default_value) {
}
QuicFixedUint32::~QuicFixedUint32() {}
uint32 QuicFixedUint32::GetUint32() const {
  return value_;
}
void QuicFixedUint32::ToHandshakeMessage(
    CryptoHandshakeMessage* out) const {
  out->SetValue(tag_, value_);
}
QuicErrorCode QuicFixedUint32::ProcessClientHello(
    const CryptoHandshakeMessage& client_hello,
    string* error_details) {
  DCHECK(error_details != NULL);
  QuicErrorCode error =
      ReadUint32(client_hello, tag_, presence_, value_, &value_, error_details);
  if (error != QUIC_NO_ERROR) {
    return error;
  }
  return QUIC_NO_ERROR;
}
QuicErrorCode QuicFixedUint32::ProcessServerHello(
    const CryptoHandshakeMessage& server_hello,
    string* error_details) {
  DCHECK(error_details != NULL);
  QuicErrorCode error =
      ReadUint32(server_hello, tag_, presence_, value_, &value_, error_details);
  if (error != QUIC_NO_ERROR) {
    return error;
  }
  return QUIC_NO_ERROR;
}
QuicConfig::QuicConfig()
    : congestion_control_(kCGST, PRESENCE_REQUIRED),
      loss_detection_(kLOSS, PRESENCE_OPTIONAL),
      idle_connection_state_lifetime_seconds_(kICSL, PRESENCE_REQUIRED),
      keepalive_timeout_seconds_(kKATO, PRESENCE_OPTIONAL),
      max_streams_per_connection_(kMSPC, PRESENCE_REQUIRED),
      max_time_before_crypto_handshake_(QuicTime::Delta::Zero()),
      server_initial_congestion_window_(kSWND, PRESENCE_OPTIONAL),
      initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL),
      
      
      peer_initial_flow_control_window_bytes_(kIFCW, PRESENCE_OPTIONAL,
                                              kDefaultFlowControlSendWindow) {
  
  server_initial_congestion_window_.set(kMaxInitialWindow,
                                        kDefaultInitialWindow);
  QuicTagVector loss_detection;
  loss_detection.push_back(kNACK);
  loss_detection.push_back(kTIME);
  loss_detection_.set(loss_detection, kNACK);
}
QuicConfig::~QuicConfig() {}
void QuicConfig::set_congestion_control(
    const QuicTagVector& congestion_control,
    QuicTag default_congestion_control) {
  congestion_control_.set(congestion_control, default_congestion_control);
}
QuicTag QuicConfig::congestion_control() const {
  return congestion_control_.GetTag();
}
void QuicConfig::set_loss_detection(
    const QuicTagVector& loss_detection,
    QuicTag default_loss_detection) {
  loss_detection_.set(loss_detection, default_loss_detection);
}
QuicTag QuicConfig::loss_detection() const {
  return loss_detection_.GetTag();
}
void QuicConfig::set_idle_connection_state_lifetime(
    QuicTime::Delta max_idle_connection_state_lifetime,
    QuicTime::Delta default_idle_conection_state_lifetime) {
  idle_connection_state_lifetime_seconds_.set(
      max_idle_connection_state_lifetime.ToSeconds(),
      default_idle_conection_state_lifetime.ToSeconds());
}
QuicTime::Delta QuicConfig::idle_connection_state_lifetime() const {
  return QuicTime::Delta::FromSeconds(
      idle_connection_state_lifetime_seconds_.GetUint32());
}
QuicTime::Delta QuicConfig::keepalive_timeout() const {
  return QuicTime::Delta::FromSeconds(
      keepalive_timeout_seconds_.GetUint32());
}
void QuicConfig::set_max_streams_per_connection(size_t max_streams,
                                                size_t default_streams) {
  max_streams_per_connection_.set(max_streams, default_streams);
}
uint32 QuicConfig::max_streams_per_connection() const {
  return max_streams_per_connection_.GetUint32();
}
void QuicConfig::set_max_time_before_crypto_handshake(
    QuicTime::Delta max_time_before_crypto_handshake) {
  max_time_before_crypto_handshake_ = max_time_before_crypto_handshake;
}
QuicTime::Delta QuicConfig::max_time_before_crypto_handshake() const {
  return max_time_before_crypto_handshake_;
}
void QuicConfig::set_server_initial_congestion_window(size_t max_initial_window,
                                               size_t default_initial_window) {
  server_initial_congestion_window_.set(max_initial_window,
                                        default_initial_window);
}
uint32 QuicConfig::server_initial_congestion_window() const {
  return server_initial_congestion_window_.GetUint32();
}
void QuicConfig::set_initial_round_trip_time_us(size_t max_rtt,
                                                size_t default_rtt) {
  initial_round_trip_time_us_.set(max_rtt, default_rtt);
}
uint32 QuicConfig::initial_round_trip_time_us() const {
  return initial_round_trip_time_us_.GetUint32();
}
void QuicConfig::set_peer_initial_flow_control_window_bytes(uint32 window) {
  peer_initial_flow_control_window_bytes_.set_value(window);
}
uint32 QuicConfig::peer_initial_flow_control_window_bytes() const {
  return peer_initial_flow_control_window_bytes_.GetUint32();
}
bool QuicConfig::negotiated() {
  
  
  
  return congestion_control_.negotiated() &&
      loss_detection_.negotiated() &&
      idle_connection_state_lifetime_seconds_.negotiated() &&
      keepalive_timeout_seconds_.negotiated() &&
      max_streams_per_connection_.negotiated() &&
      server_initial_congestion_window_.negotiated() &&
      initial_round_trip_time_us_.negotiated();
}
void QuicConfig::SetDefaults() {
  QuicTagVector congestion_control;
  if (FLAGS_enable_quic_pacing) {
    congestion_control.push_back(kPACE);
  }
  congestion_control.push_back(kQBIC);
  congestion_control_.set(congestion_control, kQBIC);
  idle_connection_state_lifetime_seconds_.set(kDefaultTimeoutSecs,
                                              kDefaultInitialTimeoutSecs);
  
  keepalive_timeout_seconds_.set(0, 0);
  max_streams_per_connection_.set(kDefaultMaxStreamsPerConnection,
                                  kDefaultMaxStreamsPerConnection);
  max_time_before_crypto_handshake_ = QuicTime::Delta::FromSeconds(
      kDefaultMaxTimeForCryptoHandshakeSecs);
  server_initial_congestion_window_.set(kDefaultInitialWindow,
                                        kDefaultInitialWindow);
  QuicTagVector loss_detection;
  loss_detection.push_back(kNACK);
  loss_detection_.set(loss_detection, kNACK);
}
void QuicConfig::EnablePacing(bool enable_pacing) {
  QuicTagVector congestion_control;
  if (enable_pacing) {
    congestion_control.push_back(kPACE);
  }
  congestion_control.push_back(kQBIC);
  congestion_control_.set(congestion_control, kQBIC);
}
void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
  congestion_control_.ToHandshakeMessage(out);
  idle_connection_state_lifetime_seconds_.ToHandshakeMessage(out);
  keepalive_timeout_seconds_.ToHandshakeMessage(out);
  max_streams_per_connection_.ToHandshakeMessage(out);
  server_initial_congestion_window_.ToHandshakeMessage(out);
  
  initial_round_trip_time_us_.ToHandshakeMessage(out);
  loss_detection_.ToHandshakeMessage(out);
  
  
}
QuicErrorCode QuicConfig::ProcessClientHello(
    const CryptoHandshakeMessage& client_hello,
    string* error_details) {
  DCHECK(error_details != NULL);
  QuicErrorCode error = QUIC_NO_ERROR;
  if (error == QUIC_NO_ERROR) {
    error = congestion_control_.ProcessClientHello(client_hello, error_details);
  }
  if (error == QUIC_NO_ERROR) {
    error = idle_connection_state_lifetime_seconds_.ProcessClientHello(
        client_hello, error_details);
  }
  if (error == QUIC_NO_ERROR) {
    error = keepalive_timeout_seconds_.ProcessClientHello(
        client_hello, error_details);
  }
  if (error == QUIC_NO_ERROR) {
    error = max_streams_per_connection_.ProcessClientHello(
        client_hello, error_details);
  }
  if (error == QUIC_NO_ERROR) {
    error = server_initial_congestion_window_.ProcessClientHello(
        client_hello, error_details);
  }
  if (error == QUIC_NO_ERROR) {
    error = initial_round_trip_time_us_.ProcessClientHello(
        client_hello, error_details);
  }
  if (error == QUIC_NO_ERROR) {
    error = peer_initial_flow_control_window_bytes_.ProcessClientHello(
        client_hello, error_details);
  }
  if (error == QUIC_NO_ERROR) {
    error = loss_detection_.ProcessClientHello(client_hello, error_details);
  }
  return error;
}
QuicErrorCode QuicConfig::ProcessServerHello(
    const CryptoHandshakeMessage& server_hello,
    string* error_details) {
  DCHECK(error_details != NULL);
  QuicErrorCode error = QUIC_NO_ERROR;
  if (error == QUIC_NO_ERROR) {
    error = congestion_control_.ProcessServerHello(server_hello, error_details);
  }
  if (error == QUIC_NO_ERROR) {
    error = idle_connection_state_lifetime_seconds_.ProcessServerHello(
        server_hello, error_details);
  }
  if (error == QUIC_NO_ERROR) {
    error = keepalive_timeout_seconds_.ProcessServerHello(
        server_hello, error_details);
  }
  if (error == QUIC_NO_ERROR) {
    error = max_streams_per_connection_.ProcessServerHello(
        server_hello, error_details);
  }
  if (error == QUIC_NO_ERROR) {
    error = server_initial_congestion_window_.ProcessServerHello(
        server_hello, error_details);
  }
  if (error == QUIC_NO_ERROR) {
    error = initial_round_trip_time_us_.ProcessServerHello(
        server_hello, error_details);
  }
  if (error == QUIC_NO_ERROR) {
    error = peer_initial_flow_control_window_bytes_.ProcessServerHello(
        server_hello, error_details);
  }
  if (error == QUIC_NO_ERROR) {
    error = loss_detection_.ProcessServerHello(server_hello, error_details);
  }
  return error;
}
}