summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/base/ip_endpoint.cc10
-rw-r--r--net/base/net_util.cc11
-rw-r--r--net/base/net_util.h5
-rw-r--r--net/base/net_util_unittest.cc8
-rw-r--r--net/net.gyp7
-rw-r--r--net/quic/congestion_control/hybrid_slow_start.cc1
-rw-r--r--net/quic/congestion_control/tcp_cubic_sender.cc1
-rw-r--r--net/quic/crypto/cert_compressor.cc24
-rw-r--r--net/quic/crypto/cert_compressor.h18
-rw-r--r--net/quic/crypto/cert_compressor_test.cc8
-rw-r--r--net/quic/crypto/common_cert_set.cc16
-rw-r--r--net/quic/crypto/common_cert_set.h16
-rw-r--r--net/quic/crypto/common_cert_set_test.cc12
-rw-r--r--net/quic/crypto/crypto_handshake.cc65
-rw-r--r--net/quic/crypto/crypto_handshake.h9
-rw-r--r--net/quic/crypto/crypto_handshake_test.cc3
-rw-r--r--net/quic/crypto/crypto_protocol.h1
-rw-r--r--net/quic/crypto/crypto_server_config.cc64
-rw-r--r--net/quic/crypto/crypto_server_config.h44
-rw-r--r--net/quic/crypto/crypto_utils.cc47
-rw-r--r--net/quic/crypto/crypto_utils.h20
-rw-r--r--net/quic/quic_client_session.cc10
-rw-r--r--net/quic/quic_client_session.h9
-rw-r--r--net/quic/quic_client_session_test.cc5
-rw-r--r--net/quic/quic_config.cc362
-rw-r--r--net/quic/quic_config.h170
-rw-r--r--net/quic/quic_config_test.cc167
-rw-r--r--net/quic/quic_connection.cc144
-rw-r--r--net/quic/quic_connection.h13
-rw-r--r--net/quic/quic_connection_helper_test.cc22
-rw-r--r--net/quic/quic_connection_test.cc109
-rw-r--r--net/quic/quic_crypto_client_stream.cc18
-rw-r--r--net/quic/quic_crypto_client_stream.h3
-rw-r--r--net/quic/quic_crypto_client_stream_factory.h1
-rw-r--r--net/quic/quic_crypto_client_stream_test.cc19
-rw-r--r--net/quic/quic_crypto_server_stream.cc9
-rw-r--r--net/quic/quic_crypto_server_stream.h7
-rw-r--r--net/quic/quic_crypto_server_stream_test.cc57
-rw-r--r--net/quic/quic_crypto_stream.cc5
-rw-r--r--net/quic/quic_crypto_stream.h2
-rw-r--r--net/quic/quic_framer.cc33
-rw-r--r--net/quic/quic_framer.h3
-rw-r--r--net/quic/quic_framer_test.cc79
-rw-r--r--net/quic/quic_http_stream_test.cc5
-rw-r--r--net/quic/quic_protocol.h19
-rw-r--r--net/quic/quic_reliable_client_stream_test.cc1
-rw-r--r--net/quic/quic_session.cc15
-rw-r--r--net/quic/quic_session.h14
-rw-r--r--net/quic/quic_session_test.cc33
-rw-r--r--net/quic/quic_spdy_compressor.cc2
-rw-r--r--net/quic/quic_spdy_decompressor.cc10
-rw-r--r--net/quic/quic_spdy_decompressor.h1
-rw-r--r--net/quic/quic_spdy_decompressor_test.cc16
-rw-r--r--net/quic/quic_stream_factory.cc3
-rw-r--r--net/quic/quic_utils.cc82
-rw-r--r--net/quic/quic_utils.h26
-rw-r--r--net/quic/reliable_quic_stream.cc5
-rw-r--r--net/quic/reliable_quic_stream.h1
-rw-r--r--net/quic/test_tools/crypto_test_utils.cc37
-rw-r--r--net/quic/test_tools/crypto_test_utils.h13
-rw-r--r--net/quic/test_tools/mock_crypto_client_stream.cc3
-rw-r--r--net/quic/test_tools/mock_crypto_client_stream.h1
-rw-r--r--net/quic/test_tools/mock_crypto_client_stream_factory.cc5
-rw-r--r--net/quic/test_tools/mock_crypto_client_stream_factory.h1
-rw-r--r--net/quic/test_tools/quic_client_session_peer.cc21
-rw-r--r--net/quic/test_tools/quic_client_session_peer.h29
-rw-r--r--net/quic/test_tools/quic_connection_peer.cc24
-rw-r--r--net/quic/test_tools/quic_connection_peer.h13
-rw-r--r--net/quic/test_tools/quic_session_peer.cc8
-rw-r--r--net/quic/test_tools/quic_session_peer.h3
-rw-r--r--net/quic/test_tools/quic_test_utils.cc12
-rw-r--r--net/quic/test_tools/quic_test_utils.h7
-rw-r--r--net/socket/socket_test_util.cc1
-rw-r--r--net/tools/quic/end_to_end_test.cc85
-rw-r--r--net/tools/quic/quic_client.cc3
-rw-r--r--net/tools/quic/quic_client.h6
-rw-r--r--net/tools/quic/quic_client_session.cc4
-rw-r--r--net/tools/quic/quic_client_session_test.cc31
-rw-r--r--net/tools/quic/quic_epoll_connection_helper.h5
-rw-r--r--net/tools/quic/quic_epoll_connection_helper_test.cc16
-rw-r--r--net/tools/quic/quic_reliable_client_stream.h3
-rw-r--r--net/tools/quic/quic_reliable_client_stream_test.cc5
-rw-r--r--net/tools/quic/quic_server.cc9
-rw-r--r--net/tools/quic/quic_server_session.cc5
-rw-r--r--net/tools/quic/quic_socket_utils.cc2
-rw-r--r--net/tools/quic/test_tools/quic_client_peer.cc27
-rw-r--r--net/tools/quic/test_tools/quic_client_peer.h25
-rw-r--r--net/tools/quic/test_tools/quic_epoll_connection_helper_peer.cc21
-rw-r--r--net/tools/quic/test_tools/quic_epoll_connection_helper_peer.h31
-rw-r--r--net/tools/quic/test_tools/quic_test_client.cc3
-rw-r--r--net/tools/quic/test_tools/quic_test_utils.cc10
-rw-r--r--net/tools/quic/test_tools/quic_test_utils.h7
92 files changed, 1761 insertions, 585 deletions
diff --git a/net/base/ip_endpoint.cc b/net/base/ip_endpoint.cc
index 923596e..e86c457 100644
--- a/net/base/ip_endpoint.cc
+++ b/net/base/ip_endpoint.cc
@@ -35,15 +35,7 @@ IPEndPoint::IPEndPoint(const IPEndPoint& endpoint) {
}
AddressFamily IPEndPoint::GetFamily() const {
- switch (address_.size()) {
- case kIPv4AddressSize:
- return ADDRESS_FAMILY_IPV4;
- case kIPv6AddressSize:
- return ADDRESS_FAMILY_IPV6;
- default:
- NOTREACHED() << "Bad IP address";
- return ADDRESS_FAMILY_UNSPECIFIED;
- }
+ return GetAddressFamily(address_);
}
int IPEndPoint::GetSockAddrFamily() const {
diff --git a/net/base/net_util.cc b/net/base/net_util.cc
index a279293..3d4924a 100644
--- a/net/base/net_util.cc
+++ b/net/base/net_util.cc
@@ -2016,6 +2016,17 @@ bool HaveOnlyLoopbackAddresses() {
#endif // defined(various platforms)
}
+AddressFamily GetAddressFamily(const IPAddressNumber& address) {
+ switch (address.size()) {
+ case kIPv4AddressSize:
+ return ADDRESS_FAMILY_IPV4;
+ case kIPv6AddressSize:
+ return ADDRESS_FAMILY_IPV6;
+ default:
+ return ADDRESS_FAMILY_UNSPECIFIED;
+ }
+}
+
bool ParseIPLiteralToNumber(const std::string& ip_literal,
IPAddressNumber* ip_number) {
// |ip_literal| could be either a IPv4 or an IPv6 literal. If it contains
diff --git a/net/base/net_util.h b/net/base/net_util.h
index 5cfd1ea..e2519ba 100644
--- a/net/base/net_util.h
+++ b/net/base/net_util.h
@@ -22,6 +22,7 @@
#include "base/basictypes.h"
#include "base/string16.h"
+#include "net/base/address_family.h"
#include "net/base/escape.h"
#include "net/base/net_export.h"
#include "net/base/net_log.h"
@@ -458,6 +459,10 @@ NET_EXPORT IPv6SupportResult TestIPv6Support();
// Also returns false if it cannot determine this.
bool HaveOnlyLoopbackAddresses();
+// Returns AddressFamily of the address.
+NET_EXPORT_PRIVATE AddressFamily GetAddressFamily(
+ const IPAddressNumber& address);
+
// Parses an IP address literal (either IPv4 or IPv6) to its numeric value.
// Returns true on success and fills |ip_number| with the numeric value.
NET_EXPORT_PRIVATE bool ParseIPLiteralToNumber(const std::string& ip_literal,
diff --git a/net/base/net_util_unittest.cc b/net/base/net_util_unittest.cc
index 4ddafe6..a40ad79 100644
--- a/net/base/net_util_unittest.cc
+++ b/net/base/net_util_unittest.cc
@@ -3171,6 +3171,14 @@ TEST(NetUtilTest, GetHostOrSpecFromURL) {
GetHostOrSpecFromURL(GURL("file:///tmp/test.html")));
}
+TEST(NetUtilTest, GetAddressFamily) {
+ IPAddressNumber number;
+ EXPECT_TRUE(ParseIPLiteralToNumber("192.168.0.1", &number));
+ EXPECT_EQ(ADDRESS_FAMILY_IPV4, GetAddressFamily(number));
+ EXPECT_TRUE(ParseIPLiteralToNumber("1:abcd::3:4:ff", &number));
+ EXPECT_EQ(ADDRESS_FAMILY_IPV6, GetAddressFamily(number));
+}
+
// Test that invalid IP literals fail to parse.
TEST(NetUtilTest, ParseIPLiteralToNumber_FailParse) {
IPAddressNumber number;
diff --git a/net/net.gyp b/net/net.gyp
index 41775bd..6bdb387 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -1659,6 +1659,8 @@
'quic/test_tools/mock_crypto_client_stream_factory.h',
'quic/test_tools/mock_random.cc',
'quic/test_tools/mock_random.h',
+ 'quic/test_tools/quic_client_session_peer.cc',
+ 'quic/test_tools/quic_client_session_peer.h',
'quic/test_tools/quic_connection_peer.cc',
'quic/test_tools/quic_connection_peer.h',
'quic/test_tools/quic_framer_peer.cc',
@@ -1678,6 +1680,7 @@
'quic/quic_bandwidth_test.cc',
'quic/quic_client_session_test.cc',
'quic/quic_clock_test.cc',
+ 'quic/quic_config_test.cc',
'quic/quic_connection_helper_test.cc',
'quic/quic_connection_test.cc',
'quic/quic_crypto_client_stream_test.cc',
@@ -2685,6 +2688,10 @@
'tools/quic/test_tools/http_message_test_utils.h',
'tools/quic/test_tools/mock_epoll_server.cc',
'tools/quic/test_tools/mock_epoll_server.h',
+ 'tools/quic/test_tools/quic_client_peer.cc',
+ 'tools/quic/test_tools/quic_client_peer.h',
+ 'tools/quic/test_tools/quic_epoll_connection_helper_peer.cc',
+ 'tools/quic/test_tools/quic_epoll_connection_helper_peer.h',
'tools/quic/test_tools/quic_test_client.cc',
'tools/quic/test_tools/quic_test_client.h',
'tools/quic/test_tools/quic_test_utils.cc',
diff --git a/net/quic/congestion_control/hybrid_slow_start.cc b/net/quic/congestion_control/hybrid_slow_start.cc
index 62b28f8..8968dc9 100644
--- a/net/quic/congestion_control/hybrid_slow_start.cc
+++ b/net/quic/congestion_control/hybrid_slow_start.cc
@@ -41,7 +41,6 @@ void HybridSlowStart::Reset(QuicPacketSequenceNumber end_sequence_number) {
}
bool HybridSlowStart::EndOfRound(QuicPacketSequenceNumber ack) {
- // TODO(pwestin): do we need to handle wraparound?
return end_sequence_number_ <= ack;
}
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 78bd7d9..e6ed9d3 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -228,6 +228,7 @@ void TcpCubicSender::AckAccounting(QuicTime::Delta rtt) {
}
hybrid_slow_start_.Update(rtt, delay_min_);
if (hybrid_slow_start_.Exit()) {
+ DLOG(INFO) << "Set slowstart threshold:" << congestion_window_;
slowstart_threshold_ = congestion_window_;
}
}
diff --git a/net/quic/crypto/cert_compressor.cc b/net/quic/crypto/cert_compressor.cc
index 2f36c19..58d259a 100644
--- a/net/quic/crypto/cert_compressor.cc
+++ b/net/quic/crypto/cert_compressor.cc
@@ -20,7 +20,7 @@ namespace {
// kCommonCertSubstrings contains ~1500 bytes of common certificate substrings
// in order to help zlib. This was generated via a fairly dumb algorithm from
// the Alexa Top 5000 set - we could probably do better.
-static unsigned char kCommonCertSubstrings[] = {
+static const unsigned char kCommonCertSubstrings[] = {
0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04,
0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30,
@@ -176,7 +176,7 @@ struct CertEntry {
vector<CertEntry> MatchCerts(const vector<string>& certs,
StringPiece client_common_set_hashes,
StringPiece client_cached_cert_hashes,
- const CommonCertSets* common_set) {
+ const CommonCertSets* common_sets) {
vector<CertEntry> entries;
entries.reserve(certs.size());
@@ -214,8 +214,8 @@ vector<CertEntry> MatchCerts(const vector<string>& certs,
}
}
- if (common_set && common_set->MatchCert(*i, client_common_set_hashes,
- &entry.set_hash, &entry.index)) {
+ if (common_sets && common_sets->MatchCert(*i, client_common_set_hashes,
+ &entry.set_hash, &entry.index)) {
entry.type = CertEntry::COMMON;
entries.push_back(entry);
continue;
@@ -328,11 +328,11 @@ vector<uint64> HashCerts(const vector<string>& certs) {
// ParseEntries parses the serialised form of a vector of CertEntries from
// |in_out| and writes them to |out_entries|. CACHED and COMMON entries are
-// resolved using |cached_certs| and |common_set| and written to |out_certs|.
+// resolved using |cached_certs| and |common_sets| and written to |out_certs|.
// |in_out| is updated to contain the trailing data.
bool ParseEntries(StringPiece* in_out,
const vector<string>& cached_certs,
- const CommonCertSets* common_set,
+ const CommonCertSets* common_sets,
vector<CertEntry>* out_entries,
vector<string>* out_certs) {
StringPiece in = *in_out;
@@ -383,7 +383,7 @@ bool ParseEntries(StringPiece* in_out,
break;
}
case CertEntry::COMMON: {
- if (!common_set) {
+ if (!common_sets) {
return false;
}
if (in.size() < sizeof(uint64)) {
@@ -398,7 +398,7 @@ bool ParseEntries(StringPiece* in_out,
memcpy(&entry.index, in.data(), sizeof(uint32));
in.remove_prefix(sizeof(uint32));
- StringPiece cert = common_set->GetCert(entry.set_hash, entry.index);
+ StringPiece cert = common_sets->GetCert(entry.set_hash, entry.index);
if (cert.empty()) {
return false;
}
@@ -449,9 +449,9 @@ class ScopedZLib {
string CertCompressor::CompressChain(const vector<string>& certs,
StringPiece client_common_set_hashes,
StringPiece client_cached_cert_hashes,
- const CommonCertSets* common_set) {
+ const CommonCertSets* common_sets) {
const vector<CertEntry> entries = MatchCerts(
- certs, client_common_set_hashes, client_cached_cert_hashes, common_set);
+ certs, client_common_set_hashes, client_cached_cert_hashes, common_sets);
DCHECK_EQ(entries.size(), certs.size());
size_t uncompressed_size = 0;
@@ -549,10 +549,10 @@ string CertCompressor::CompressChain(const vector<string>& certs,
// static
bool CertCompressor::DecompressChain(StringPiece in,
const vector<string>& cached_certs,
- const CommonCertSets* common_set,
+ const CommonCertSets* common_sets,
vector<string>* out_certs) {
vector<CertEntry> entries;
- if (!ParseEntries(&in, cached_certs, common_set, &entries, out_certs)) {
+ if (!ParseEntries(&in, cached_certs, common_sets, &entries, out_certs)) {
return false;
}
DCHECK_EQ(entries.size(), out_certs->size());
diff --git a/net/quic/crypto/cert_compressor.h b/net/quic/crypto/cert_compressor.h
index 587684d..612bc529 100644
--- a/net/quic/crypto/cert_compressor.h
+++ b/net/quic/crypto/cert_compressor.h
@@ -22,31 +22,31 @@ namespace net {
// that they already have. In the event that one of them is to be
// compressed, it can be replaced with just the hash.
// 2) The peer may provide a number of hashes that represent sets of
-// pre-shared certificates (CommonCertSets). If one of those certificates
-// is to be compressed, and it's known to the given CommonCertSets, then it
-// can be replaced with a set hash and certificate index.
+// pre-shared certificates. If one of those certificates is to be
+// compressed, and it's known to the given CommonCertSets, then it can be
+// replaced with a set hash and certificate index.
// 3) Otherwise the certificates are compressed with zlib using a pre-shared
// dictionary that consists of the certificates handled with the above
// methods and a small chunk of common substrings.
class NET_EXPORT_PRIVATE CertCompressor {
public:
// CompressChain compresses the certificates in |certs| and returns a
- // compressed representation. |common_set| contains the common certificate
+ // compressed representation. |common_sets| contains the common certificate
// sets known locally and |client_common_set_hashes| contains the hashes of
- // the common sets known to the peer. |client_cached| contains 64-bit, FNV-1a
- // hashes of certificates that the peer already possesses.
+ // the common sets known to the peer. |client_cached_cert_hashes| contains
+ // 64-bit, FNV-1a hashes of certificates that the peer already possesses.
static std::string CompressChain(const std::vector<std::string>& certs,
base::StringPiece client_common_set_hashes,
base::StringPiece client_cached_cert_hashes,
- const CommonCertSets* common_set);
+ const CommonCertSets* common_sets);
// DecompressChain decompresses the result of |CompressChain|, given in |in|,
// into a series of certificates that are written to |out_certs|.
// |cached_certs| contains certificates that the peer may have omitted and
- // |common_set| contains the common certificate sets known locally.
+ // |common_sets| contains the common certificate sets known locally.
static bool DecompressChain(base::StringPiece in,
const std::vector<std::string>& cached_certs,
- const CommonCertSets* common_set,
+ const CommonCertSets* common_sets,
std::vector<std::string>* out_certs);
};
diff --git a/net/quic/crypto/cert_compressor_test.cc b/net/quic/crypto/cert_compressor_test.cc
index ef12ccc..5bfef8f 100644
--- a/net/quic/crypto/cert_compressor_test.cc
+++ b/net/quic/crypto/cert_compressor_test.cc
@@ -47,12 +47,12 @@ TEST(CertCompressor, Common) {
vector<string> chain;
chain.push_back("testcert");
static const uint64 set_hash = 42;
- scoped_ptr<CommonCertSets> common_set(
+ scoped_ptr<CommonCertSets> common_sets(
CryptoTestUtils::MockCommonCertSets(chain[0], set_hash, 1));
const string compressed = CertCompressor::CompressChain(
chain,
StringPiece(reinterpret_cast<const char*>(&set_hash), sizeof(set_hash)),
- StringPiece(), common_set.get());
+ StringPiece(), common_sets.get());
const string common("03" /* common */
"2A00000000000000" /* set hash 42 */
"01000000" /* index 1 */
@@ -62,7 +62,7 @@ TEST(CertCompressor, Common) {
vector<string> chain2, cached_certs;
ASSERT_TRUE(CertCompressor::DecompressChain(compressed, cached_certs,
- common_set.get(), &chain2));
+ common_sets.get(), &chain2));
EXPECT_EQ(chain.size(), chain2.size());
EXPECT_EQ(chain[0], chain2[0]);
}
@@ -124,7 +124,7 @@ TEST(CertCompressor, BadInputs) {
without_a_common_cert_set.size()),
cached_certs, NULL, &chain));
- scoped_ptr<CommonCertSets> common_set(
+ scoped_ptr<CommonCertSets> common_sets(
CryptoTestUtils::MockCommonCertSets("foo", 42, 1));
/* incorrect hash and index */
diff --git a/net/quic/crypto/common_cert_set.cc b/net/quic/crypto/common_cert_set.cc
index 78aa927..ee1ac67 100644
--- a/net/quic/crypto/common_cert_set.cc
+++ b/net/quic/crypto/common_cert_set.cc
@@ -53,17 +53,17 @@ StringPiece CommonCertSetsQUIC::GetCommonHashes() const {
}
StringPiece CommonCertSetsQUIC::GetCert(uint64 hash, uint32 index) const {
+ StringPiece cert;
for (size_t i = 0; i < arraysize(kSets); i++) {
if (kSets[i].hash == hash) {
- if (index >= kSets[i].num_certs) {
- return StringPiece();
+ if (index < kSets[i].num_certs) {
+ cert.set(kSets[i].certs[index], kSets[i].lens[index]);
}
- return StringPiece(reinterpret_cast<const char*>(kSets[i].certs[index]),
- kSets[i].lens[index]);
+ break;
}
}
- return StringPiece();
+ return cert;
}
// Compare returns a value less than, equal to or greater than zero if |a| is
@@ -110,11 +110,7 @@ bool CommonCertSetsQUIC::MatchCert(StringPiece cert,
// Binary search for a matching certificate.
size_t min = 0;
size_t max = kSets[j].num_certs - 1;
- for (;;) {
- if (max < min) {
- break;
- }
-
+ while (max >= min) {
size_t mid = min + ((max - min) / 2);
int n = Compare(cert, kSets[j].certs[mid], kSets[j].lens[mid]);
if (n < 0) {
diff --git a/net/quic/crypto/common_cert_set.h b/net/quic/crypto/common_cert_set.h
index 6972926..4f5d330 100644
--- a/net/quic/crypto/common_cert_set.h
+++ b/net/quic/crypto/common_cert_set.h
@@ -20,24 +20,26 @@ class NET_EXPORT_PRIVATE CommonCertSets {
virtual ~CommonCertSets();
// GetCommonHashes returns a StringPiece containing the hashes of common sets
- // supported by this object.
+ // supported by this object. The 64-bit hashes are concatenated in the
+ // StringPiece.
virtual base::StringPiece GetCommonHashes() const = 0;
- // GetCert returns a specific certificate in the common set identified by
- // |hash|. If no such certificate is known, an empty StringPiece is returned.
+ // GetCert returns a specific certificate (at index |index|) in the common
+ // set identified by |hash|. If no such certificate is known, an empty
+ // StringPiece is returned.
virtual base::StringPiece GetCert(uint64 hash, uint32 index) const = 0;
// MatchCert tries to find |cert| in one of the common certificate sets
- // identified by |common_set_hashes|. On success it puts the hash in
- // |out_hash|, the index in the set in |out_index| and returns true. Otherwise
- // it returns false.
+ // identified by |common_set_hashes|. On success it puts the hash of the
+ // set in |out_hash|, the index of |cert| in the set in |out_index| and
+ // returns true. Otherwise it returns false.
virtual bool MatchCert(base::StringPiece cert,
base::StringPiece common_set_hashes,
uint64* out_hash,
uint32* out_index) const = 0;
};
-// CommonCertSetsQUIC implements the CommonCertSet interface using the default
+// CommonCertSetsQUIC implements the CommonCertSets interface using the default
// certificate sets.
class NET_EXPORT_PRIVATE CommonCertSetsQUIC : public CommonCertSets {
public:
diff --git a/net/quic/crypto/common_cert_set_test.cc b/net/quic/crypto/common_cert_set_test.cc
index 51b41d8..57615c9 100644
--- a/net/quic/crypto/common_cert_set_test.cc
+++ b/net/quic/crypto/common_cert_set_test.cc
@@ -11,7 +11,7 @@ using base::StringPiece;
namespace net {
namespace test {
-static unsigned char kGIACertificate[] = {
+static const unsigned char kGIACertificate[] = {
0x30, 0x82, 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01,
0x02, 0x02, 0x03, 0x0b, 0x67, 0x71, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x4e, 0x31,
@@ -76,30 +76,30 @@ TEST(CommonCertSets, FindGIA) {
StringPiece gia(reinterpret_cast<const char*>(kGIACertificate),
sizeof(kGIACertificate));
- CommonCertSetsQUIC set;
+ CommonCertSetsQUIC sets;
const uint64 in_hash = GG_UINT64_C(0xde8086f914a3af54);
uint64 hash;
uint32 index;
- ASSERT_TRUE(set.MatchCert(
+ ASSERT_TRUE(sets.MatchCert(
gia,
StringPiece(reinterpret_cast<const char*>(&in_hash), sizeof(in_hash)),
&hash, &index));
EXPECT_EQ(in_hash, hash);
- StringPiece gia_copy = set.GetCert(hash, index);
+ StringPiece gia_copy = sets.GetCert(hash, index);
EXPECT_FALSE(gia_copy.empty());
ASSERT_EQ(gia.size(), gia_copy.size());
EXPECT_TRUE(0 == memcmp(gia.data(), gia_copy.data(), gia.size()));
}
TEST(CommonCertSets, NonMatch) {
- CommonCertSetsQUIC set;
+ CommonCertSetsQUIC sets;
StringPiece not_a_cert("hello");
const uint64 in_hash = GG_UINT64_C(0xde8086f914a3af54);
uint64 hash;
uint32 index;
- EXPECT_FALSE(set.MatchCert(
+ EXPECT_FALSE(sets.MatchCert(
not_a_cert,
StringPiece(reinterpret_cast<const char*>(&in_hash), sizeof(in_hash)),
&hash, &index));
diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc
index 16d32d6..3585eb5 100644
--- a/net/quic/crypto/crypto_handshake.cc
+++ b/net/quic/crypto/crypto_handshake.cc
@@ -107,7 +107,6 @@ QuicErrorCode CryptoHandshakeMessage::GetTaglist(QuicTag tag,
const QuicTag** out_tags,
size_t* out_len) const {
QuicTagValueMap::const_iterator it = tag_value_map_.find(tag);
- *out_len = 0;
QuicErrorCode ret = QUIC_NO_ERROR;
if (it == tag_value_map_.end()) {
@@ -221,40 +220,12 @@ QuicErrorCode CryptoHandshakeMessage::GetPOD(
return ret;
}
-// TagToString is a utility function for pretty-printing handshake messages
-// that converts a tag to a string. It will try to maintain the human friendly
-// name if possible (i.e. kABCD -> "ABCD"), or will just treat it as a number
-// if not.
-static string TagToString(QuicTag tag) {
- char chars[4];
- bool ascii = true;
- const QuicTag orig_tag = tag;
-
- for (size_t i = 0; i < sizeof(chars); i++) {
- chars[i] = tag;
- if (chars[i] == 0 && i == 3) {
- chars[i] = ' ';
- }
- if (!isprint(static_cast<unsigned char>(chars[i]))) {
- ascii = false;
- break;
- }
- tag >>= 8;
- }
-
- if (ascii) {
- return string(chars, sizeof(chars));
- }
-
- return base::UintToString(orig_tag);
-}
-
string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
- string ret = string(2 * indent, ' ') + TagToString(tag_) + "<\n";
+ string ret = string(2 * indent, ' ') + QuicUtils::TagToString(tag_) + "<\n";
++indent;
for (QuicTagValueMap::const_iterator it = tag_value_map_.begin();
it != tag_value_map_.end(); ++it) {
- ret += string(2 * indent, ' ') + TagToString(it->first) + ": ";
+ ret += string(2 * indent, ' ') + QuicUtils::TagToString(it->first) + ": ";
bool done = false;
switch (it->first) {
@@ -280,7 +251,7 @@ string CryptoHandshakeMessage::DebugStringInternal(size_t indent) const {
if (j > 0) {
ret += ",";
}
- ret += TagToString(tag);
+ ret += QuicUtils::TagToString(tag);
}
done = true;
}
@@ -331,7 +302,7 @@ const char QuicCryptoConfig::kForwardSecureLabel[] =
QuicCryptoConfig::QuicCryptoConfig()
: version(0),
- common_cert_set_(new CommonCertSetsQUIC) {
+ common_cert_sets(new CommonCertSetsQUIC) {
}
QuicCryptoConfig::~QuicCryptoConfig() {}
@@ -476,13 +447,19 @@ void QuicCryptoClientConfig::FillInchoateClientHello(
out->SetStringPiece(kSourceAddressTokenTag, cached->source_address_token());
}
- out->SetTaglist(kPDMD, kX509, 0);
+ if (proof_verifier_.get()) {
+ out->SetTaglist(kPDMD, kX509, 0);
+ }
- if (common_cert_set_.get()) {
- out->SetStringPiece(kCCS, common_cert_set_->GetCommonHashes());
+ if (common_cert_sets.get()) {
+ out->SetStringPiece(kCCS, common_cert_sets->GetCommonHashes());
}
const vector<string>& certs = cached->certs();
+ // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the
+ // client config is being used for multiple connections, another connection
+ // doesn't update the cached certificates and cause us to be unable to
+ // process the server's compressed certificate chain.
out_params->cached_certs = certs;
if (!certs.empty()) {
vector<uint64> hashes;
@@ -492,10 +469,6 @@ void QuicCryptoClientConfig::FillInchoateClientHello(
hashes.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size()));
}
out->SetVector(kCCRT, hashes);
- // We save |certs| in the QuicCryptoNegotiatedParameters so that, if the
- // client config is being used for multiple connections, another connection
- // doesn't update the cached certificates and cause us to be unable to
- // process the server's compressed certificate chain.
}
}
@@ -557,12 +530,12 @@ QuicErrorCode QuicCryptoClientConfig::FillClientHello(
}
size_t key_exchange_index;
- if (!CryptoUtils::FindMutualTag(aead, their_aeads, num_their_aeads,
- CryptoUtils::PEER_PRIORITY, &out_params->aead,
- NULL) ||
- !CryptoUtils::FindMutualTag(
+ if (!QuicUtils::FindMutualTag(aead, their_aeads, num_their_aeads,
+ QuicUtils::PEER_PRIORITY, &out_params->aead,
+ NULL) ||
+ !QuicUtils::FindMutualTag(
kexs, their_key_exchanges, num_their_key_exchanges,
- CryptoUtils::PEER_PRIORITY, &out_params->key_exchange,
+ QuicUtils::PEER_PRIORITY, &out_params->key_exchange,
&key_exchange_index)) {
*error_details = "Unsupported AEAD or KEXS";
return QUIC_CRYPTO_NO_SUPPORT;
@@ -667,7 +640,7 @@ QuicErrorCode QuicCryptoClientConfig::ProcessRejection(
rej.GetStringPiece(kCertificateTag, &cert_bytes)) {
vector<string> certs;
if (!CertCompressor::DecompressChain(cert_bytes, out_params->cached_certs,
- common_cert_set_.get(), &certs)) {
+ common_cert_sets.get(), &certs)) {
*error_details = "Certificate data invalid";
return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
}
diff --git a/net/quic/crypto/crypto_handshake.h b/net/quic/crypto/crypto_handshake.h
index 6b6c320..0774905 100644
--- a/net/quic/crypto/crypto_handshake.h
+++ b/net/quic/crypto/crypto_handshake.h
@@ -14,7 +14,6 @@
#include "net/base/net_export.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
namespace net {
@@ -188,7 +187,7 @@ class NET_EXPORT_PRIVATE QuicCryptoConfig {
// Authenticated encryption with associated data (AEAD) algorithms.
QuicTagVector aead;
- scoped_ptr<CommonCertSets> common_cert_set_;
+ scoped_ptr<CommonCertSets> common_cert_sets;
private:
DISALLOW_COPY_AND_ASSIGN(QuicCryptoConfig);
@@ -311,9 +310,9 @@ class NET_EXPORT_PRIVATE QuicCryptoClientConfig : public QuicCryptoConfig {
const ProofVerifier* proof_verifier() const;
// SetProofVerifier takes ownership of a |ProofVerifier| that clients are
- // free to use in order to verify certificate chains from servers. Setting a
- // |ProofVerifier| does not alter the behaviour of the
- // QuicCryptoClientConfig, it's just a place to store it.
+ // free to use in order to verify certificate chains from servers. If a
+ // ProofVerifier is set then the client will request a certificate chain from
+ // the server.
void SetProofVerifier(ProofVerifier* verifier);
private:
diff --git a/net/quic/crypto/crypto_handshake_test.cc b/net/quic/crypto/crypto_handshake_test.cc
index f3d86a5..e2e45f3 100644
--- a/net/quic/crypto/crypto_handshake_test.cc
+++ b/net/quic/crypto/crypto_handshake_test.cc
@@ -42,10 +42,9 @@ class QuicCryptoServerConfigPeer {
TEST(QuicCryptoServerConfigTest, ServerConfig) {
QuicCryptoServerConfig server("source address token secret");
MockClock clock;
- CryptoHandshakeMessage extra_tags;
scoped_ptr<CryptoHandshakeMessage>(
- server.AddDefaultConfig(QuicRandom::GetInstance(), &clock, extra_tags,
+ server.AddDefaultConfig(QuicRandom::GetInstance(), &clock,
QuicCryptoServerConfig::kDefaultExpiry));
}
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index 32ec7b1..c32884a 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -60,6 +60,7 @@ const QuicTag kCGST = TAG('C', 'G', 'S', 'T'); // Congestion control
const QuicTag kICSL = TAG('I', 'C', 'S', 'L'); // Idle connection state
// lifetime
const QuicTag kKATO = TAG('K', 'A', 'T', 'O'); // Keepalive timeout
+const QuicTag kMSPC = TAG('M', 'S', 'P', 'C'); // Max streams per connection.
const QuicTag kSNI = TAG('S', 'N', 'I', '\0'); // Server name
// indication
const QuicTag kPUBS = TAG('P', 'U', 'B', 'S'); // Public key values
diff --git a/net/quic/crypto/crypto_server_config.cc b/net/quic/crypto/crypto_server_config.cc
index e4ee400..d7eca6a 100644
--- a/net/quic/crypto/crypto_server_config.cc
+++ b/net/quic/crypto/crypto_server_config.cc
@@ -52,7 +52,11 @@ QuicCryptoServerConfig::QuicCryptoServerConfig(
// Salsa20+Poly1305).
: strike_register_lock_(),
source_address_token_encrypter_(new Aes128GcmEncrypter),
- source_address_token_decrypter_(new Aes128GcmDecrypter) {
+ source_address_token_decrypter_(new Aes128GcmDecrypter),
+ strike_register_max_entries_(1 << 10),
+ strike_register_window_secs_(600),
+ source_address_token_future_secs_(3600),
+ source_address_token_lifetime_secs_(86400) {
crypto::HKDF hkdf(source_address_token_secret, StringPiece() /* no salt */,
"QUIC source address token key",
source_address_token_encrypter_->GetKeySize(),
@@ -69,7 +73,6 @@ QuicCryptoServerConfig::~QuicCryptoServerConfig() {
QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig(
QuicRandom* rand,
const QuicClock* clock,
- const CryptoHandshakeMessage& extra_tags,
uint64 expiry_time) {
CryptoHandshakeMessage msg;
@@ -101,8 +104,6 @@ QuicServerConfigProtobuf* QuicCryptoServerConfig::DefaultConfig(
msg.SetTaglist(kAEAD, kAESG, 0);
msg.SetValue(kVERS, static_cast<uint16>(0));
msg.SetStringPiece(kPUBS, encoded_public_values);
- msg.Insert(extra_tags.tag_value_map().begin(),
- extra_tags.tag_value_map().end());
if (expiry_time == 0) {
const QuicWallTime now = clock->WallNow();
@@ -277,10 +278,9 @@ CryptoHandshakeMessage* QuicCryptoServerConfig::AddConfig(
CryptoHandshakeMessage* QuicCryptoServerConfig::AddDefaultConfig(
QuicRandom* rand,
const QuicClock* clock,
- const CryptoHandshakeMessage& extra_tags,
uint64 expiry_time) {
- scoped_ptr<QuicServerConfigProtobuf> config(DefaultConfig(
- rand, clock, extra_tags, expiry_time));
+ scoped_ptr<QuicServerConfigProtobuf> config(
+ DefaultConfig(rand, clock, expiry_time));
return AddConfig(config.get());
}
@@ -334,10 +334,10 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
if (strike_register_.get() == NULL) {
strike_register_.reset(new StrikeRegister(
- // TODO(agl): these magic numbers should come from config.
- 1024 /* max entries */,
+ strike_register_max_entries_,
static_cast<uint32>(now.ToUNIXSeconds()),
- 600 /* window secs */, config->orbit));
+ strike_register_window_secs_,
+ config->orbit));
}
unique_by_strike_register = strike_register_->Insert(
reinterpret_cast<const uint8*>(client_nonce.data()),
@@ -401,7 +401,7 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
const string compressed = CertCompressor::CompressChain(
*certs, their_common_set_hashes, their_cached_cert_hashes,
- config->common_cert_set_.get());
+ config->common_cert_sets.get());
// kMaxUnverifiedSize is the number of bytes that the certificate chain
// and signature can consume before we will demand a valid
@@ -433,12 +433,12 @@ QuicErrorCode QuicCryptoServerConfig::ProcessClientHello(
}
size_t key_exchange_index;
- if (!CryptoUtils::FindMutualTag(config->aead, their_aeads, num_their_aeads,
- CryptoUtils::LOCAL_PRIORITY, &params->aead,
- NULL) ||
- !CryptoUtils::FindMutualTag(
+ if (!QuicUtils::FindMutualTag(config->aead, their_aeads, num_their_aeads,
+ QuicUtils::LOCAL_PRIORITY, &params->aead,
+ NULL) ||
+ !QuicUtils::FindMutualTag(
config->kexs, their_key_exchanges, num_their_key_exchanges,
- CryptoUtils::LOCAL_PRIORITY, &params->key_exchange,
+ QuicUtils::LOCAL_PRIORITY, &params->key_exchange,
&key_exchange_index)) {
*error_details = "Unsupported AEAD or KEXS";
return QUIC_CRYPTO_NO_SUPPORT;
@@ -523,6 +523,28 @@ void QuicCryptoServerConfig::SetEphemeralKeySource(
ephemeral_key_source_.reset(ephemeral_key_source);
}
+void QuicCryptoServerConfig::set_strike_register_max_entries(
+ uint32 max_entries) {
+ DCHECK(!strike_register_.get());
+ strike_register_max_entries_ = max_entries;
+}
+
+void QuicCryptoServerConfig::set_strike_register_window_secs(
+ uint32 window_secs) {
+ DCHECK(!strike_register_.get());
+ strike_register_window_secs_ = window_secs;
+}
+
+void QuicCryptoServerConfig::set_source_address_token_future_secs(
+ uint32 future_secs) {
+ source_address_token_future_secs_ = future_secs;
+}
+
+void QuicCryptoServerConfig::set_source_address_token_lifetime_secs(
+ uint32 lifetime_secs) {
+ source_address_token_lifetime_secs_ = lifetime_secs;
+}
+
string QuicCryptoServerConfig::NewSourceAddressToken(
const IPEndPoint& ip,
QuicRandom* rand,
@@ -600,15 +622,13 @@ bool QuicCryptoServerConfig::ValidateSourceAddressToken(
QuicWallTime::FromUNIXSeconds(source_address_token.timestamp()));
const QuicTime::Delta delta(now.AbsoluteDifference(timestamp));
- // TODO(agl): consider whether and how these magic values should be moved to
- // a config.
- if (now.IsBefore(timestamp) && delta.ToSeconds() > 3600) {
- // We only allow timestamps to be from an hour in the future.
+ if (now.IsBefore(timestamp) &&
+ delta.ToSeconds() > source_address_token_future_secs_) {
return false;
}
- if (now.IsAfter(timestamp) && delta.ToSeconds() > 86400) {
- // We allow one day into the past.
+ if (now.IsAfter(timestamp) &&
+ delta.ToSeconds() > source_address_token_lifetime_secs_) {
return false;
}
diff --git a/net/quic/crypto/crypto_server_config.h b/net/quic/crypto/crypto_server_config.h
index 588d83d4..5c7d4da 100644
--- a/net/quic/crypto/crypto_server_config.h
+++ b/net/quic/crypto/crypto_server_config.h
@@ -54,14 +54,12 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
static const char TESTING[];
// DefaultConfig generates a QuicServerConfigProtobuf protobuf suitable for
- // using in tests. |extra_tags| contains additional key/value pairs that will
- // be inserted into the config. If |expiry_time| is non-zero then it's used
- // as the expiry for the server config in UNIX epoch seconds. Otherwise the
- // default expiry time is six months from now.
+ // using in tests. If |expiry_time| is non-zero then it's used as the expiry
+ // for the server config in UNIX epoch seconds. Otherwise the default expiry
+ // time is six months from now.
static QuicServerConfigProtobuf* DefaultConfig(
QuicRandom* rand,
const QuicClock* clock,
- const CryptoHandshakeMessage& extra_tags,
uint64 expiry_time);
// AddConfig adds a QuicServerConfigProtobuf to the availible configurations.
@@ -69,12 +67,12 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
// takes ownership of the CryptoHandshakeMessage.
CryptoHandshakeMessage* AddConfig(QuicServerConfigProtobuf* protobuf);
- // AddDefaultConfig creates a config and then calls AddConfig to add it. See
- // the comment for |DefaultConfig| for details of the arguments.
+ // AddDefaultConfig calls DefaultConfig to create a config and then calls
+ // AddConfig to add it. See the comment for |DefaultConfig| for details of
+ // the arguments.
CryptoHandshakeMessage* AddDefaultConfig(
QuicRandom* rand,
const QuicClock* clock,
- const CryptoHandshakeMessage& extra_tags,
uint64 expiry_time);
// ProcessClientHello processes |client_hello| and decides whether to accept
@@ -97,7 +95,7 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
QuicErrorCode ProcessClientHello(const CryptoHandshakeMessage& client_hello,
QuicGuid guid,
const IPEndPoint& client_ip,
- const QuicClock* now,
+ const QuicClock* clock,
QuicRandom* rand,
QuicCryptoNegotiatedParameters* params,
CryptoHandshakeMessage* out,
@@ -113,6 +111,27 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
// per-connection.
void SetEphemeralKeySource(EphemeralKeySource* ephemeral_key_source);
+ // set_strike_register_max_entries sets the maximum number of entries that
+ // the internal strike register will hold. If the strike register fills up
+ // then the oldest entries (by the client's clock) will be dropped.
+ void set_strike_register_max_entries(uint32 max_entries);
+
+ // set_strike_register_window_secs sets the number of seconds around the
+ // current time that the strike register will attempt to be authoritative
+ // for. Setting a larger value allows for greater client clock-skew, but
+ // means that the quiescent startup period must be longer.
+ void set_strike_register_window_secs(uint32 window_secs);
+
+ // set_source_address_token_future_secs sets the number of seconds into the
+ // future that source-address tokens will be accepted from. Since
+ // source-address tokens are authenticated, this should only happen if
+ // another, valid server has clock-skew.
+ void set_source_address_token_future_secs(uint32 future_secs);
+
+ // set_source_address_token_lifetime_secs sets the number of seconds that a
+ // source-address token will be valid for.
+ void set_source_address_token_lifetime_secs(uint32 lifetime_secs);
+
private:
friend class test::QuicCryptoServerConfigPeer;
@@ -177,6 +196,13 @@ class NET_EXPORT_PRIVATE QuicCryptoServerConfig {
// ephemeral_key_source_ contains an object that caches ephemeral keys for a
// short period of time.
scoped_ptr<EphemeralKeySource> ephemeral_key_source_;
+
+ // These fields store configuration values. See the comments for their
+ // respective setter functions.
+ uint32 strike_register_max_entries_;
+ uint32 strike_register_window_secs_;
+ uint32 source_address_token_future_secs_;
+ uint32 source_address_token_lifetime_secs_;
};
} // namespace net
diff --git a/net/quic/crypto/crypto_utils.cc b/net/quic/crypto/crypto_utils.cc
index bf1f4d2..a95ac42 100644
--- a/net/quic/crypto/crypto_utils.cc
+++ b/net/quic/crypto/crypto_utils.cc
@@ -17,53 +17,6 @@ using std::string;
namespace net {
-// static
-bool CryptoUtils::FindMutualTag(const QuicTagVector& our_tags_vector,
- const QuicTag* their_tags,
- size_t num_their_tags,
- Priority priority,
- QuicTag* out_result,
- size_t* out_index) {
- if (our_tags_vector.empty()) {
- return false;
- }
- const size_t num_our_tags = our_tags_vector.size();
- const QuicTag* our_tags = &our_tags_vector[0];
-
- size_t num_priority_tags, num_inferior_tags;
- const QuicTag* priority_tags;
- const QuicTag* inferior_tags;
- if (priority == LOCAL_PRIORITY) {
- num_priority_tags = num_our_tags;
- priority_tags = our_tags;
- num_inferior_tags = num_their_tags;
- inferior_tags = their_tags;
- } else {
- num_priority_tags = num_their_tags;
- priority_tags = their_tags;
- num_inferior_tags = num_our_tags;
- inferior_tags = our_tags;
- }
-
- for (size_t i = 0; i < num_priority_tags; i++) {
- for (size_t j = 0; j < num_inferior_tags; j++) {
- if (priority_tags[i] == inferior_tags[j]) {
- *out_result = priority_tags[i];
- if (out_index) {
- if (priority == LOCAL_PRIORITY) {
- *out_index = j;
- } else {
- *out_index = i;
- }
- }
- return true;
- }
- }
- }
-
- return false;
-}
-
void CryptoUtils::GenerateNonce(QuicWallTime now,
QuicRandom* random_generator,
StringPiece orbit,
diff --git a/net/quic/crypto/crypto_utils.h b/net/quic/crypto/crypto_utils.h
index 6c607a5..e516718 100644
--- a/net/quic/crypto/crypto_utils.h
+++ b/net/quic/crypto/crypto_utils.h
@@ -23,31 +23,11 @@ struct QuicCryptoNegotiatedParameters;
class NET_EXPORT_PRIVATE CryptoUtils {
public:
- enum Priority {
- LOCAL_PRIORITY,
- PEER_PRIORITY,
- };
-
enum Perspective {
SERVER,
CLIENT,
};
- // FindMutualTag sets |out_result| to the first tag in the priority list that
- // is also in the other list and returns true. If there is no intersection it
- // returns false.
- //
- // Which list has priority is determined by |priority|.
- //
- // If |out_index| is non-NULL and a match is found then the index of that
- // match in |their_tags| is written to |out_index|.
- static bool FindMutualTag(const QuicTagVector& our_tags,
- const QuicTag* their_tags,
- size_t num_their_tags,
- Priority priority,
- QuicTag* out_result,
- size_t* out_index);
-
// Generates the connection nonce. The nonce is formed as:
// <4 bytes> current time
// <8 bytes> |orbit| (or random if |orbit| is empty)
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index 30ca803..796fef6 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -24,9 +24,10 @@ QuicClientSession::QuicClientSession(
QuicStreamFactory* stream_factory,
QuicCryptoClientStreamFactory* crypto_client_stream_factory,
const string& server_hostname,
+ const QuicConfig& config,
QuicCryptoClientConfig* crypto_config,
NetLog* net_log)
- : QuicSession(connection, false),
+ : QuicSession(connection, config, false),
weak_factory_(this),
stream_factory_(stream_factory),
socket_(socket),
@@ -35,13 +36,12 @@ QuicClientSession::QuicClientSession(
num_total_streams_(0),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)),
logger_(net_log_) {
- config_.SetDefaults();
+ QuicSession::config()->SetDefaults();
crypto_stream_.reset(
crypto_client_stream_factory ?
crypto_client_stream_factory->CreateQuicCryptoClientStream(
- server_hostname, config_, this, crypto_config) :
- new QuicCryptoClientStream(
- server_hostname, config_, this, crypto_config));
+ server_hostname, this, crypto_config) :
+ new QuicCryptoClientStream(server_hostname, this, crypto_config));
connection->set_debug_visitor(&logger_);
// TODO(rch): pass in full host port proxy pair
diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h
index fbbbecf..2a63ca1 100644
--- a/net/quic/quic_client_session.h
+++ b/net/quic/quic_client_session.h
@@ -26,6 +26,10 @@ class QuicConnectionHelper;
class QuicCryptoClientStreamFactory;
class QuicStreamFactory;
+namespace test {
+class QuicClientSessionPeer;
+} // namespace test
+
class NET_EXPORT_PRIVATE QuicClientSession : public QuicSession {
public:
// Constructs a new session which will own |connection| and |helper|, but
@@ -36,6 +40,7 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicSession {
QuicStreamFactory* stream_factory,
QuicCryptoClientStreamFactory* crypto_client_stream_factory,
const std::string& server_hostname,
+ const QuicConfig& config,
QuicCryptoClientConfig* crypto_config,
NetLog* net_log);
@@ -70,13 +75,11 @@ class NET_EXPORT_PRIVATE QuicClientSession : public QuicSession {
QuicStreamId id) OVERRIDE;
private:
+ friend class test::QuicClientSessionPeer;
// A completion callback invoked when a read completes.
void OnReadComplete(int result);
base::WeakPtrFactory<QuicClientSession> weak_factory_;
- // config_ contains non-crypto configuration options negotiated in the crypto
- // handshake.
- QuicConfig config_;
scoped_ptr<QuicCryptoClientStream> crypto_stream_;
QuicStreamFactory* stream_factory_;
scoped_ptr<DatagramClientSocket> socket_;
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index 3883a05..cab44a7 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -13,6 +13,7 @@
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/test_tools/crypto_test_utils.h"
+#include "net/quic/test_tools/quic_client_session_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
using testing::_;
@@ -29,8 +30,9 @@ class QuicClientSessionTest : public ::testing::Test {
: guid_(1),
connection_(new PacketSavingConnection(guid_, IPEndPoint(), false)),
session_(connection_, NULL, NULL, NULL, kServerHostname,
- &crypto_config_, &net_log_) {
+ QuicConfig(), &crypto_config_, &net_log_) {
crypto_config_.SetDefaults();
+ QuicClientSessionPeer::SetMaxOpenStreams(&session_, 1, 1);
}
void CompleteCryptoHandshake() {
@@ -49,7 +51,6 @@ class QuicClientSessionTest : public ::testing::Test {
MockRandom random_;
QuicConnectionVisitorInterface* visitor_;
TestCompletionCallback callback_;
- QuicConfig* config_;
QuicCryptoClientConfig crypto_config_;
};
diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc
index 867cb6d..eacde84 100644
--- a/net/quic/quic_config.cc
+++ b/net/quic/quic_config.cc
@@ -4,126 +4,340 @@
#include "net/quic/quic_config.h"
+#include <algorithm>
+
+#include "base/logging.h"
+
using std::string;
namespace net {
-QuicNegotiatedParameters::QuicNegotiatedParameters()
- : idle_connection_state_lifetime(QuicTime::Delta::Zero()),
- keepalive_timeout(QuicTime::Delta::Zero()) {
+QuicNegotiableValue::QuicNegotiableValue(QuicTag tag, Presence presence)
+ : tag_(tag),
+ presence_(presence),
+ negotiated_(false) {
}
-QuicConfig::QuicConfig()
- : idle_connection_state_lifetime_(QuicTime::Delta::Zero()),
- keepalive_timeout_(QuicTime::Delta::Zero()) {
+QuicNegotiableUint32::QuicNegotiableUint32(QuicTag tag, Presence presence)
+ : QuicNegotiableValue(tag, presence) {
}
-QuicConfig::~QuicConfig() {
+void QuicNegotiableUint32::set(uint32 max, uint32 default_value) {
+ DCHECK_LE(default_value, max);
+ max_value_ = max;
+ default_value_ = default_value;
}
-void QuicConfig::SetDefaults() {
- idle_connection_state_lifetime_ = QuicTime::Delta::FromSeconds(300);
- keepalive_timeout_ = QuicTime::Delta::Zero();
- congestion_control_.clear();
- congestion_control_.push_back(kQBIC);
+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_);
+ }
}
-bool QuicConfig::SetFromHandshakeMessage(const CryptoHandshakeMessage& scfg) {
- const QuicTag* cgst;
- size_t num_cgst;
- QuicErrorCode error;
+QuicErrorCode QuicNegotiableUint32::ReadUint32(
+ const CryptoHandshakeMessage& msg,
+ uint32* out,
+ string* error_details) const {
+ DCHECK(error_details != NULL);
+ QuicErrorCode error = msg.GetUint32(tag_, out);
+ switch (error) {
+ case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
+ if (presence_ == QuicNegotiableValue::PRESENCE_REQUIRED) {
+ *error_details = "Missing " + QuicUtils::TagToString(tag_);
+ break;
+ }
+ error = QUIC_NO_ERROR;
+ *out = default_value_;
- error = scfg.GetTaglist(kCGST, &cgst, &num_cgst);
+ case QUIC_NO_ERROR:
+ break;
+ default:
+ *error_details = "Bad " + QuicUtils::TagToString(tag_);
+ break;
+ }
+ return error;
+}
+
+QuicErrorCode QuicNegotiableUint32::ProcessClientHello(
+ const CryptoHandshakeMessage& client_hello,
+ string* error_details) {
+ DCHECK(!negotiated_);
+ DCHECK(error_details != NULL);
+ uint32 value;
+ QuicErrorCode error = ReadUint32(client_hello, &value, error_details);
if (error != QUIC_NO_ERROR) {
- return false;
+ return error;
}
- congestion_control_.assign(cgst, cgst + num_cgst);
+ negotiated_ = true;
+ negotiated_value_ = std::min(value, max_value_);
- uint32 idle;
- error = scfg.GetUint32(kICSL, &idle);
+ 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, &value, error_details);
if (error != QUIC_NO_ERROR) {
- return false;
+ return error;
}
- idle_connection_state_lifetime_ = QuicTime::Delta::FromSeconds(idle);
-
- keepalive_timeout_ = QuicTime::Delta::Zero();
- uint32 keepalive;
- error = scfg.GetUint32(kKATO, &keepalive);
- // KATO is optional.
- if (error == QUIC_NO_ERROR) {
- keepalive_timeout_ = QuicTime::Delta::FromSeconds(keepalive);
+ if (value > max_value_) {
+ *error_details = "Invalid value received for " +
+ QuicUtils::TagToString(tag_);
+ return QUIC_INVALID_NEGOTIATED_VALUE;
}
- return true;
+ negotiated_ = true;
+ negotiated_value_ = value;
+ return QUIC_NO_ERROR;
}
-void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
- out->SetValue(
- kICSL, static_cast<uint32>(idle_connection_state_lifetime_.ToSeconds()));
- out->SetValue(kKATO, static_cast<uint32>(keepalive_timeout_.ToSeconds()));
- out->SetVector(kCGST, congestion_control_);
+QuicNegotiableTag::QuicNegotiableTag(QuicTag tag, Presence presence)
+ : QuicNegotiableValue(tag, presence) {
+}
+
+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_;
}
-QuicErrorCode QuicConfig::ProcessFinalPeerHandshake(
+void QuicNegotiableTag::ToHandshakeMessage(CryptoHandshakeMessage* out) const {
+ if (negotiated_) {
+ // Because of the way we serialize and parse handshake messages we can
+ // serialize this as value and still parse it as a vector.
+ out->SetValue(tag_, negotiated_tag_);
+ } else {
+ out->SetVector(tag_, possible_values_);
+ }
+}
+
+QuicErrorCode QuicNegotiableTag::ReadVector(
const CryptoHandshakeMessage& msg,
- CryptoUtils::Priority priority,
- QuicNegotiatedParameters* out_params,
+ 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_;
- const QuicTag* their_congestion_controls;
- size_t num_their_congestion_controls;
- QuicErrorCode error;
+ case QUIC_NO_ERROR:
+ break;
+ default:
+ *error_details = "Bad " + QuicUtils::TagToString(tag_);
+ break;
+ }
+ return error;
+}
- error = msg.GetTaglist(kCGST, &their_congestion_controls,
- &num_their_congestion_controls);
+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) {
- *error_details = "Missing CGST";
return error;
}
- if (!CryptoUtils::FindMutualTag(congestion_control_,
- their_congestion_controls,
- num_their_congestion_controls,
- priority,
- &out_params->congestion_control,
- NULL)) {
- *error_details = "Unsuported CGST";
+ 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;
}
- uint32 idle;
- error = msg.GetUint32(kICSL, &idle);
+ 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) {
- *error_details = "Missing ICSL";
return error;
}
- out_params->idle_connection_state_lifetime = QuicTime::Delta::FromSeconds(
- std::min(static_cast<uint32>(idle_connection_state_lifetime_.ToSeconds()),
- idle));
-
- uint32 keepalive;
- error = msg.GetUint32(kKATO, &keepalive);
- switch (error) {
- case QUIC_NO_ERROR:
- out_params->keepalive_timeout = QuicTime::Delta::FromSeconds(
- std::min(static_cast<uint32>(keepalive_timeout_.ToSeconds()),
- keepalive));
- break;
- case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND:
- // KATO is optional.
- out_params->keepalive_timeout = QuicTime::Delta::Zero();
- break;
- default:
- *error_details = "Bad KATO";
- 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;
}
+QuicConfig::QuicConfig() :
+ congestion_control_(kCGST, QuicNegotiableValue::PRESENCE_REQUIRED),
+ idle_connection_state_lifetime_seconds_(
+ kICSL, QuicNegotiableValue::PRESENCE_REQUIRED),
+ keepalive_timeout_seconds_(kKATO, QuicNegotiableValue::PRESENCE_OPTIONAL),
+ max_streams_per_connection_(kMSPC, QuicNegotiableValue::PRESENCE_REQUIRED) {
+ idle_connection_state_lifetime_seconds_.set(0, 0);
+ keepalive_timeout_seconds_.set(0, 0);
+}
+
+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_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();
+}
+
+bool QuicConfig::negotiated() {
+ return congestion_control_.negotiated() &&
+ idle_connection_state_lifetime_seconds_.negotiated() &&
+ keepalive_timeout_seconds_.negotiated() &&
+ max_streams_per_connection_.negotiated();
+}
+
+void QuicConfig::SetDefaults() {
+ congestion_control_.set(QuicTagVector(1, kQBIC), kQBIC);
+ idle_connection_state_lifetime_seconds_.set(kDefaultTimeoutSecs,
+ kDefaultTimeoutSecs);
+ // kKATO is optional. Return 0 if not negotiated.
+ keepalive_timeout_seconds_.set(0, 0);
+ max_streams_per_connection_.set(kDefaultMaxStreamsPerConnection,
+ kDefaultMaxStreamsPerConnection);
+}
+
+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);
+}
+
+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);
+ }
+ 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);
+ }
+ return error;
+}
+
} // namespace net
diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h
index 013a4f2..0f11493 100644
--- a/net/quic/quic_config.h
+++ b/net/quic/quic_config.h
@@ -7,21 +7,126 @@
#include <string>
+#include "base/basictypes.h"
#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/crypto/crypto_utils.h"
+#include "net/quic/quic_protocol.h"
#include "net/quic/quic_time.h"
+#include "net/quic/quic_utils.h"
namespace net {
-// QuicNegotiatedParameters contains non-crypto parameters that are agreed upon
-// during the crypto handshake.
-class NET_EXPORT_PRIVATE QuicNegotiatedParameters {
+class NET_EXPORT_PRIVATE QuicNegotiableValue {
public:
- QuicNegotiatedParameters();
+ enum Presence {
+ // This negotiable value can be absent from the handshake message. Default
+ // value is selected as the negotiated value in such a case.
+ PRESENCE_OPTIONAL,
+ // This negotiable value is required in the handshake message otherwise the
+ // Process*Hello function returns an error.
+ PRESENCE_REQUIRED,
+ };
- QuicTag congestion_control;
- QuicTime::Delta idle_connection_state_lifetime;
- QuicTime::Delta keepalive_timeout;
+ QuicNegotiableValue(QuicTag tag, Presence presence);
+
+ bool negotiated() const {
+ return negotiated_;
+ }
+
+ protected:
+ const QuicTag tag_;
+ const Presence presence_;
+ bool negotiated_;
+};
+
+class NET_EXPORT_PRIVATE QuicNegotiableUint32 : public QuicNegotiableValue {
+ public:
+ QuicNegotiableUint32(QuicTag name, Presence presence);
+
+ // Sets the maximum possible value that can be achieved after negotiation and
+ // also the default values to be assumed if PRESENCE_OPTIONAL and the *HLO msg
+ // doesn't contain a value corresponding to |name_|. |max| is serialised via
+ // ToHandshakeMessage call if |negotiated_| is false.
+ void set(uint32 max, uint32 default_value);
+
+ // Returns the value negotiated if |negotiated_| is true, otherwise returns
+ // default_value_ (used to set default values before negotiation finishes).
+ uint32 GetUint32() const;
+
+ // Serialises |name_| and value to |out|. If |negotiated_| is true then
+ // |negotiated_value_| is serialised, otherwise |max_value_| is serialised.
+ void ToHandshakeMessage(CryptoHandshakeMessage* out) const;
+
+ // Sets |negotiated_value_| to the minimum of |max_value_| and the
+ // corresponding value from |client_hello|. If the corresponding value is
+ // missing and PRESENCE_OPTIONAL then |negotiated_value_| is set to
+ // |default_value_|.
+ QuicErrorCode ProcessClientHello(const CryptoHandshakeMessage& client_hello,
+ std::string* error_details);
+
+ // Sets the |negotiated_value_| to the corresponding value from
+ // |server_hello|. Returns error if the value received in |server_hello| is
+ // greater than |max_value_|. If the corresponding value is missing and
+ // PRESENCE_OPTIONAL then |negotiated_value_| is set to |0|,
+ QuicErrorCode ProcessServerHello(const CryptoHandshakeMessage& server_hello,
+ std::string* error_details);
+
+ private:
+ // Reads the value corresponding to |name_| from |msg| into |out|. If the
+ // |name_| is absent in |msg| and |presence_| is set to OPTIONAL |out| is set
+ // to |max_value_|.
+ QuicErrorCode ReadUint32(const CryptoHandshakeMessage& msg,
+ uint32* out,
+ std::string* error_details) const;
+
+ uint32 max_value_;
+ uint32 default_value_;
+ uint32 negotiated_value_;
+};
+
+class NET_EXPORT_PRIVATE QuicNegotiableTag : public QuicNegotiableValue {
+ public:
+ QuicNegotiableTag(QuicTag name, Presence presence);
+ ~QuicNegotiableTag();
+
+ // Sets the possible values that |negotiated_tag_| can take after negotiation
+ // and the default value that |negotiated_tag_| takes if OPTIONAL and *HLO
+ // msg doesn't contain tag |name_|.
+ void set(const QuicTagVector& possible_values, QuicTag default_value);
+
+ // Returns the negotiated tag if |negotiated_| is true, otherwise returns
+ // |default_value_| (used to set default values before negotiation finishes).
+ QuicTag GetTag() const;
+
+ // Serialises |name_| and vector (either possible or negotiated) to |out|. If
+ // |negotiated_| is true then |negotiated_tag_| is serialised, otherwise
+ // |possible_values_| is serialised.
+ void ToHandshakeMessage(CryptoHandshakeMessage* out) const;
+
+ // Selects the tag common to both tags in |client_hello| for |name_| and
+ // |possible_values_| with preference to tag in |possible_values_|. The
+ // selected tag is set as |negotiated_tag_|.
+ QuicErrorCode ProcessClientHello(const CryptoHandshakeMessage& client_hello,
+ std::string* error_details);
+
+ // Sets the value for |name_| tag in |server_hello| as |negotiated_value_|.
+ // Returns error if the value received in |server_hello| isn't present in
+ // |possible_values_|.
+ QuicErrorCode ProcessServerHello(const CryptoHandshakeMessage& server_hello,
+ std::string* error_details);
+
+ private:
+ // Reads the vector corresponding to |name_| from |msg| into |out|. If the
+ // |name_| is absent in |msg| and |presence_| is set to OPTIONAL |out| is set
+ // to |possible_values_|.
+ QuicErrorCode ReadVector(const CryptoHandshakeMessage& msg,
+ const QuicTag** out,
+ size_t* out_length,
+ std::string* error_details) const;
+
+ QuicTag negotiated_tag_;
+ QuicTagVector possible_values_;
+ QuicTag default_value_;
};
// QuicConfig contains non-crypto configuration options that are negotiated in
@@ -31,39 +136,52 @@ class NET_EXPORT_PRIVATE QuicConfig {
QuicConfig();
~QuicConfig();
+ void set_congestion_control(const QuicTagVector& congestion_control,
+ QuicTag default_congestion_control);
+
+ QuicTag congestion_control() const;
+
void set_idle_connection_state_lifetime(
- QuicTime::Delta idle_connection_state_lifetime) {
- idle_connection_state_lifetime_ = idle_connection_state_lifetime;
- }
+ QuicTime::Delta max_idle_connection_state_lifetime,
+ QuicTime::Delta default_idle_conection_state_lifetime);
+
+ QuicTime::Delta idle_connection_state_lifetime() const;
+
+ QuicTime::Delta keepalive_timeout() const;
+
+ void set_max_streams_per_connection(size_t max_streams,
+ size_t default_streams);
+
+ uint32 max_streams_per_connection() const;
+
+ bool negotiated();
// SetDefaults sets the members to sensible, default values.
void SetDefaults();
- // SetFromMessage extracts the non-crypto configuration from |msg| and sets
- // the members of this object to match. This is expected to be called in the
- // case of a server which is loading a server config. The server config
- // contains the non-crypto parameters and so the server will need to keep its
- // QuicConfig in sync with the server config that it'll be sending to
- // clients.
- bool SetFromHandshakeMessage(const CryptoHandshakeMessage& scfg);
-
// ToHandshakeMessage serializes the settings in this object as a series of
// tags /value pairs and adds them to |out|.
void ToHandshakeMessage(CryptoHandshakeMessage* out) const;
- QuicErrorCode ProcessFinalPeerHandshake(
- const CryptoHandshakeMessage& peer_handshake,
- CryptoUtils::Priority priority,
- QuicNegotiatedParameters* out_params,
- std::string* error_details) const;
+ // Calls ProcessClientHello on each negotiable parameter. On failure returns
+ // the corresponding QuicErrorCode and sets detailed error in |error_details|.
+ QuicErrorCode ProcessClientHello(const CryptoHandshakeMessage& client_hello,
+ std::string* error_details);
+
+ // Calls ProcessServerHello on each negotiable parameter. On failure returns
+ // the corresponding QuicErrorCode and sets detailed error in |error_details|.
+ QuicErrorCode ProcessServerHello(const CryptoHandshakeMessage& server_hello,
+ std::string* error_details);
private:
// Congestion control feedback type.
- QuicTagVector congestion_control_;
+ QuicNegotiableTag congestion_control_;
// Idle connection state lifetime
- QuicTime::Delta idle_connection_state_lifetime_;
+ QuicNegotiableUint32 idle_connection_state_lifetime_seconds_;
// Keepalive timeout, or 0 to turn off keepalive probes
- QuicTime::Delta keepalive_timeout_;
+ QuicNegotiableUint32 keepalive_timeout_seconds_;
+ // Maximum number of streams that the connection can support.
+ QuicNegotiableUint32 max_streams_per_connection_;
};
} // namespace net
diff --git a/net/quic/quic_config_test.cc b/net/quic/quic_config_test.cc
new file mode 100644
index 0000000..eeaa97d
--- /dev/null
+++ b/net/quic/quic_config_test.cc
@@ -0,0 +1,167 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/quic_config.h"
+
+#include "net/quic/crypto/crypto_handshake.h"
+#include "net/quic/crypto/crypto_protocol.h"
+#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+
+namespace net {
+namespace test {
+namespace {
+
+class QuicConfigTest : public ::testing::Test {
+ protected:
+ QuicConfigTest() {
+ config_.SetDefaults();
+ }
+
+ QuicConfig config_;
+};
+
+TEST_F(QuicConfigTest, ToHandshakeMessage) {
+ config_.set_idle_connection_state_lifetime(QuicTime::Delta::FromSeconds(5),
+ QuicTime::Delta::FromSeconds(2));
+ config_.set_max_streams_per_connection(4, 2);
+ CryptoHandshakeMessage msg;
+ config_.ToHandshakeMessage(&msg);
+
+ uint32 value;
+ QuicErrorCode error = msg.GetUint32(kICSL, &value);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ EXPECT_EQ(5u, value);
+
+ error = msg.GetUint32(kMSPC, &value);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ EXPECT_EQ(4u, value);
+
+ const QuicTag* out;
+ size_t out_len;
+ error = msg.GetTaglist(kCGST, &out, &out_len);
+ EXPECT_EQ(1u, out_len);
+ EXPECT_EQ(kQBIC, *out);
+}
+
+TEST_F(QuicConfigTest, ProcessClientHello) {
+ QuicConfig client_config;
+ QuicTagVector cgst;
+ cgst.push_back(kINAR);
+ cgst.push_back(kQBIC);
+ client_config.set_congestion_control(cgst, kQBIC);
+ client_config.set_idle_connection_state_lifetime(
+ QuicTime::Delta::FromSeconds(2 * kDefaultTimeoutSecs),
+ QuicTime::Delta::FromSeconds(kDefaultTimeoutSecs));
+ client_config.set_max_streams_per_connection(
+ 2 * kDefaultMaxStreamsPerConnection, kDefaultMaxStreamsPerConnection);
+
+ CryptoHandshakeMessage msg;
+ client_config.ToHandshakeMessage(&msg);
+ string error_details;
+ const QuicErrorCode error = config_.ProcessClientHello(msg, &error_details);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ EXPECT_TRUE(config_.negotiated());
+ EXPECT_EQ(kQBIC, config_.congestion_control());
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(kDefaultTimeoutSecs),
+ config_.idle_connection_state_lifetime());
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection,
+ config_.max_streams_per_connection());
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(0), config_.keepalive_timeout());
+}
+
+TEST_F(QuicConfigTest, ProcessServerHello) {
+ QuicConfig server_config;
+ QuicTagVector cgst;
+ cgst.push_back(kQBIC);
+ server_config.set_congestion_control(cgst, kQBIC);
+ server_config.set_idle_connection_state_lifetime(
+ QuicTime::Delta::FromSeconds(kDefaultTimeoutSecs / 2),
+ QuicTime::Delta::FromSeconds(kDefaultTimeoutSecs / 2));
+ server_config.set_max_streams_per_connection(
+ kDefaultMaxStreamsPerConnection / 2,
+ kDefaultMaxStreamsPerConnection / 2);
+
+ CryptoHandshakeMessage msg;
+ server_config.ToHandshakeMessage(&msg);
+ string error_details;
+ const QuicErrorCode error = config_.ProcessServerHello(msg, &error_details);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
+ EXPECT_TRUE(config_.negotiated());
+ EXPECT_EQ(kQBIC, config_.congestion_control());
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(kDefaultTimeoutSecs / 2),
+ config_.idle_connection_state_lifetime());
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection / 2,
+ config_.max_streams_per_connection());
+ EXPECT_EQ(QuicTime::Delta::FromSeconds(0), config_.keepalive_timeout());
+}
+
+TEST_F(QuicConfigTest, MissingValueInCHLO) {
+ CryptoHandshakeMessage msg;
+ msg.SetValue(kICSL, 1);
+ msg.SetVector(kCGST, QuicTagVector(1, kQBIC));
+ // Missing kMSPC. KATO is optional.
+ string error_details;
+ const QuicErrorCode error = config_.ProcessClientHello(msg, &error_details);
+ EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, error);
+}
+
+TEST_F(QuicConfigTest, MissingValueInSHLO) {
+ CryptoHandshakeMessage msg;
+ msg.SetValue(kICSL, 1);
+ msg.SetValue(kMSPC, 3);
+ // Missing CGST. KATO is optional.
+ string error_details;
+ const QuicErrorCode error = config_.ProcessServerHello(msg, &error_details);
+ EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, error);
+}
+
+TEST_F(QuicConfigTest, OutOfBoundSHLO) {
+ QuicConfig server_config;
+ server_config.set_idle_connection_state_lifetime(
+ QuicTime::Delta::FromSeconds(2 * kDefaultTimeoutSecs),
+ QuicTime::Delta::FromSeconds(2 * kDefaultTimeoutSecs));
+
+ CryptoHandshakeMessage msg;
+ server_config.ToHandshakeMessage(&msg);
+ string error_details;
+ const QuicErrorCode error = config_.ProcessServerHello(msg, &error_details);
+ EXPECT_EQ(QUIC_INVALID_NEGOTIATED_VALUE, error);
+}
+
+TEST_F(QuicConfigTest, MultipleNegotiatedValuesInVectorTag) {
+ QuicConfig server_config;
+ QuicTagVector cgst;
+ cgst.push_back(kQBIC);
+ cgst.push_back(kINAR);
+ server_config.set_congestion_control(cgst, kQBIC);
+
+ CryptoHandshakeMessage msg;
+ server_config.ToHandshakeMessage(&msg);
+ string error_details;
+ const QuicErrorCode error = config_.ProcessServerHello(msg, &error_details);
+ EXPECT_EQ(QUIC_INVALID_NEGOTIATED_VALUE, error);
+}
+
+TEST_F(QuicConfigTest, NoOverLapInCGST) {
+ QuicConfig server_config;
+ server_config.SetDefaults();
+ QuicTagVector cgst;
+ cgst.push_back(kINAR);
+ server_config.set_congestion_control(cgst, kINAR);
+
+ CryptoHandshakeMessage msg;
+ string error_details;
+ server_config.ToHandshakeMessage(&msg);
+ const QuicErrorCode error = config_.ProcessClientHello(msg, &error_details);
+ LOG(INFO) << QuicUtils::ErrorToString(error);
+ EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP, error);
+}
+
+} // namespace
+} // namespace test
+} // namespace net
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 481fca9..51319ff 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -30,17 +30,6 @@ namespace {
// This will likely have to be tuned.
const QuicPacketSequenceNumber kMaxPacketGap = 5000;
-// The maximum number of nacks which can be transmitted in a single ack packet
-// without exceeding kMaxPacketSize.
-// TODO(satyamshekhar): Get rid of magic numbers and move this to protocol.h
-// 16 - Min ack frame size.
-// 16 - Crypto hash for integrity. Not a static value. Use
-// QuicEncrypter::GetMaxPlaintextSize.
-size_t GetMaxUnackedPackets(bool include_version) {
- return (kMaxPacketSize - GetPacketHeaderSize(include_version) - 16 - 16) /
- kSequenceNumberSize;
-}
-
// We want to make sure if we get a large nack packet, we don't queue up too
// many packets at once. 10 is arbitrary.
const int kMaxRetransmissionsPerAck = 10;
@@ -58,7 +47,11 @@ const int kMaxPacketsToSerializeAtOnce = 6;
// Limit the number of packets we send per retransmission-alarm so we
// eventually cede. 10 is arbitrary.
-const int kMaxPacketsPerRetransmissionAlarm = 10;
+const size_t kMaxPacketsPerRetransmissionAlarm = 10;
+
+// Limit the number of FEC groups to two. If we get enough out of order packets
+// that this becomes limiting, we can revisit.
+const size_t kMaxFecGroups = 2;
bool Near(QuicPacketSequenceNumber a, QuicPacketSequenceNumber b) {
QuicPacketSequenceNumber delta = (a > b) ? a - b : b - a;
@@ -91,20 +84,20 @@ QuicConnection::QuicConnection(QuicGuid guid,
debug_visitor_(NULL),
packet_creator_(guid_, &framer_, random_generator_, is_server),
packet_generator_(this, &packet_creator_),
- timeout_(QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs)),
+ timeout_(QuicTime::Delta::FromSeconds(kDefaultInitialTimeoutSecs)),
time_of_last_received_packet_(clock_->ApproximateNow()),
time_of_last_sent_packet_(clock_->ApproximateNow()),
time_largest_observed_(QuicTime::Zero()),
congestion_manager_(clock_, kTCP),
version_negotiation_state_(START_NEGOTIATION),
quic_version_(kQuicVersion1),
+ max_packets_per_retransmission_alarm_(kMaxPacketsPerRetransmissionAlarm),
is_server_(is_server),
connected_(true),
received_truncated_ack_(false),
- send_ack_in_response_to_packet_(false) {
+ send_ack_in_response_to_packet_(false),
+ address_migrating_(false) {
helper_->SetConnection(this);
- // TODO(satyamshekhar): Have a smaller timeout till version is negotiated and
- // connection is established (CHLO fully processed).
helper_->SetTimeoutAlarm(timeout_);
framer_.set_visitor(this);
framer_.set_entropy_calculator(&entropy_manager_);
@@ -160,10 +153,6 @@ void QuicConnection::OnPacket() {
time_of_last_received_packet_ = clock_->Now();
DVLOG(1) << "time of last received packet: "
<< time_of_last_received_packet_.ToDebuggingValue();
-
- // TODO(alyssar, rch) handle migration!
- self_address_ = last_self_address_;
- peer_address_ = last_peer_address_;
}
void QuicConnection::OnPublicResetPacket(
@@ -175,6 +164,12 @@ void QuicConnection::OnPublicResetPacket(
}
bool QuicConnection::OnProtocolVersionMismatch(QuicTag received_version) {
+ if (address_migrating_) {
+ SendConnectionCloseWithDetails(
+ QUIC_ERROR_MIGRATING_ADDRESS,
+ "Address migration is not yet a supported feature");
+ }
+
// TODO(satyamshekhar): Implement no server state in this mode.
if (!is_server_) {
LOG(DFATAL) << "Framer called OnProtocolVersionMismatch for server. "
@@ -226,6 +221,11 @@ bool QuicConnection::OnProtocolVersionMismatch(QuicTag received_version) {
// Handles version negotiation for client connection.
void QuicConnection::OnVersionNegotiationPacket(
const QuicVersionNegotiationPacket& packet) {
+ if (address_migrating_) {
+ SendConnectionCloseWithDetails(
+ QUIC_ERROR_MIGRATING_ADDRESS,
+ "Address migration is not yet a supported feature");
+ }
if (is_server_) {
LOG(DFATAL) << "Framer parsed VersionNegotiationPacket for server."
<< "Closing connection.";
@@ -268,6 +268,13 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
debug_visitor_->OnPacketHeader(header);
}
+ if (address_migrating_) {
+ SendConnectionCloseWithDetails(
+ QUIC_ERROR_MIGRATING_ADDRESS,
+ "Address migration is not yet a supported feature");
+ return false;
+ }
+
// Will be decrement below if we fall through to return true;
++stats_.packets_dropped;
@@ -281,7 +288,8 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
last_header_.packet_sequence_number)) {
DLOG(INFO) << ENDPOINT << "Packet " << header.packet_sequence_number
<< " out of bounds. Discarding";
- // TODO(alyssar) close the connection entirely.
+ SendConnectionCloseWithDetails(QUIC_INVALID_PACKET_HEADER,
+ "Packet sequence number out of bounds");
return false;
}
@@ -326,7 +334,9 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) {
void QuicConnection::OnFecProtectedPayload(StringPiece payload) {
DCHECK_NE(0u, last_header_.fec_group);
QuicFecGroup* group = GetFecGroup();
- group->Update(last_header_, payload);
+ if (group != NULL) {
+ group->Update(last_header_, payload);
+ }
}
bool QuicConnection::OnStreamFrame(const QuicStreamFrame& frame) {
@@ -356,16 +366,9 @@ bool QuicConnection::OnAckFrame(const QuicAckFrame& incoming_ack) {
return false;
}
- // TODO(satyamshekhar): Not true if missing_packets.size() was actually
- // kMaxUnackedPackets. This can result in a dead connection if all the
- // missing packets get lost during retransmission. Now the new packets(or the
- // older packets) will not be retransmitted due to RTO
- // since received_truncated_ack_ is true and their sequence_number is >
- // peer_largest_observed_packet. Fix either by resetting it in
- // MaybeRetransmitPacketForRTO or keeping an explicit flag for ack truncation.
received_truncated_ack_ =
incoming_ack.received_info.missing_packets.size() >=
- GetMaxUnackedPackets(last_header_.public_header.version_flag);
+ QuicFramer::GetMaxUnackedPackets(last_header_.public_header.version_flag);
UpdatePacketInformationReceivedByPeer(incoming_ack);
UpdatePacketInformationSentByPeer(incoming_ack);
@@ -422,7 +425,8 @@ bool QuicConnection::ValidateAckFrame(const QuicAckFrame& incoming_ack) {
// We can't have too many unacked packets, or our ack frames go over
// kMaxPacketSize.
DCHECK_LE(incoming_ack.received_info.missing_packets.size(),
- GetMaxUnackedPackets(last_header_.public_header.version_flag));
+ QuicFramer::GetMaxUnackedPackets(
+ last_header_.public_header.version_flag));
if (incoming_ack.sent_info.least_unacked < peer_least_packet_awaiting_ack_) {
DLOG(ERROR) << ENDPOINT << "Peer's sent low least_unacked: "
@@ -581,8 +585,10 @@ void QuicConnection::UpdatePacketInformationSentByPeer(
void QuicConnection::OnFecData(const QuicFecData& fec) {
DCHECK_NE(0u, last_header_.fec_group);
QuicFecGroup* group = GetFecGroup();
- group->UpdateFec(last_header_.packet_sequence_number,
- last_header_.fec_entropy_flag, fec);
+ if (group != NULL) {
+ group->UpdateFec(last_header_.packet_sequence_number,
+ last_header_.fec_entropy_flag, fec);
+ }
}
bool QuicConnection::OnRstStreamFrame(const QuicRstStreamFrame& frame) {
@@ -618,8 +624,12 @@ bool QuicConnection::OnGoAwayFrame(const QuicGoAwayFrame& frame) {
}
void QuicConnection::OnPacketComplete() {
- // TODO(satyamshekhar): Don't do anything if this packet closed the
- // connection.
+ // Don't do anything if this packet closed the connection.
+ if (!connected_) {
+ last_stream_frames_.clear();
+ return;
+ }
+
if (!last_packet_revived_) {
DLOG(INFO) << ENDPOINT << "Got packet "
<< last_header_.packet_sequence_number
@@ -717,8 +727,19 @@ void QuicConnection::ProcessUdpPacket(const IPEndPoint& self_address,
}
last_packet_revived_ = false;
last_size_ = packet.length();
- last_self_address_ = self_address;
- last_peer_address_ = peer_address;
+
+ address_migrating_ = false;
+
+ if (peer_address_.address().empty()) {
+ peer_address_ = peer_address;
+ }
+ if (self_address_.address().empty()) {
+ self_address_ = self_address;
+ }
+
+ if (!(peer_address == peer_address_) && (self_address == self_address_)) {
+ address_migrating_ = true;
+ }
stats_.bytes_received += packet.length();
++stats_.packets_received;
@@ -826,12 +847,18 @@ bool QuicConnection::MaybeRetransmitPacketForRTO(
return true;
}
+ RetransmissionMap::iterator retransmission_it =
+ retransmission_map_.find(sequence_number);
// If the packet hasn't been acked and we're getting truncated acks, ignore
// any RTO for packets larger than the peer's largest observed packet; it may
// have been received by the peer and just wasn't acked due to the ack frame
// running out of space.
if (received_truncated_ack_ &&
- sequence_number > peer_largest_observed_packet_) {
+ sequence_number > peer_largest_observed_packet_ &&
+ // We allow retransmission of already retransmitted packets so that we
+ // retransmit packets that were retransmissions of the packet with
+ // sequence number < the largest observed field of the truncated ack.
+ retransmission_it->second.number_retransmissions == 0) {
return false;
} else {
++stats_.rto_count;
@@ -901,8 +928,7 @@ bool QuicConnection::CanWrite(Retransmission retransmission,
QuicTime::Delta delay = congestion_manager_.TimeUntilSend(
now, retransmission, retransmittable);
if (delay.IsInfinite()) {
- // TODO(pwestin): should be false but trigger other bugs see b/8350327.
- return true;
+ return false;
}
// If the scheduler requires a delay, then we can not send this packet now.
@@ -983,20 +1009,23 @@ bool QuicConnection::WritePacket(EncryptionLevel level,
int error;
QuicTime now = clock_->Now();
- int rv = helper_->WritePacketToWire(*encrypted, &error);
- if (rv == -1 && helper_->IsWriteBlocked(error)) {
- // TODO(satyashekhar): It might be more efficient (fewer system calls), if
- // all connections share this variable i.e this becomes a part of
- // PacketWriterInterface.
- write_blocked_ = true;
- // If the socket buffers the the data, then the packet should not
- // be queued and sent again, which would result in an unnecessary duplicate
- // packet being sent.
- return helper_->IsWriteBlockedDataBuffered();
+ if (helper_->WritePacketToWire(*encrypted, &error) == -1) {
+ if (helper_->IsWriteBlocked(error)) {
+ // TODO(satyashekhar): It might be more efficient (fewer system calls), if
+ // all connections share this variable i.e this becomes a part of
+ // PacketWriterInterface.
+ write_blocked_ = true;
+ // If the socket buffers the the data, then the packet should not
+ // be queued and sent again, which would result in an unnecessary
+ // duplicate packet being sent.
+ return helper_->IsWriteBlockedDataBuffered();
+ }
+ // We can't send an error as the socket is presumably borked.
+ CloseConnection(QUIC_PACKET_WRITE_ERROR, false);
+ return false;
}
time_of_last_sent_packet_ = now;
DVLOG(1) << "time of last sent packet: " << now.ToDebuggingValue();
- // TODO(wtc): Is it correct to continue if the write failed.
// Set the retransmit alarm only when we have sent the packet to the client
// and not when it goes to the pending queue, otherwise we will end up adding
@@ -1113,7 +1142,7 @@ QuicTime QuicConnection::OnRetransmissionTimeout() {
// want to set it to the RTO of B when we return from this function.
handling_retransmission_timeout_ = true;
- for (int i = 0; i < kMaxPacketsPerRetransmissionAlarm &&
+ for (size_t i = 0; i < max_packets_per_retransmission_alarm_ &&
!retransmission_timeouts_.empty(); ++i) {
RetransmissionInfo retransmission_info = retransmission_timeouts_.top();
DCHECK(retransmission_info.scheduled_time.IsInitialized());
@@ -1206,7 +1235,16 @@ QuicFecGroup* QuicConnection::GetFecGroup() {
return NULL;
}
if (group_map_.count(fec_group_num) == 0) {
- // TODO(rch): limit the number of active FEC groups.
+ if (group_map_.size() >= kMaxFecGroups) { // Too many groups
+ if (fec_group_num < group_map_.begin()->first) {
+ // The group being requested is a group we've seen before and deleted.
+ // Don't recreate it.
+ return NULL;
+ }
+ // Clear the lowest group number.
+ delete group_map_.begin()->second;
+ group_map_.erase(group_map_.begin());
+ }
group_map_[fec_group_num] = new QuicFecGroup();
}
return group_map_[fec_group_num];
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index ce3a263..dab64ee 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -503,7 +503,8 @@ class NET_EXPORT_PRIVATE QuicConnection
void MaybeSendAckInResponseToPacket();
- // Get the FEC group associate with the last processed packet.
+ // Get the FEC group associate with the last processed packet or NULL, if the
+ // group has already been deleted.
QuicFecGroup* GetFecGroup();
// Closes any FEC groups protecting packets before |sequence_number|.
@@ -519,10 +520,6 @@ class NET_EXPORT_PRIVATE QuicConnection
// client.
IPEndPoint self_address_;
IPEndPoint peer_address_;
- // Address on the last(currently being processed) packet received. Not
- // verified/authenticated.
- IPEndPoint last_self_address_;
- IPEndPoint last_peer_address_;
bool last_packet_revived_; // True if the last packet was revived from FEC.
size_t last_size_; // Size of the last received packet.
@@ -606,6 +603,8 @@ class NET_EXPORT_PRIVATE QuicConnection
// The version of the protocol this connection is using.
QuicTag quic_version_;
+ size_t max_packets_per_retransmission_alarm_;
+
// Tracks if the connection was created by the server.
bool is_server_;
@@ -619,6 +618,10 @@ class NET_EXPORT_PRIVATE QuicConnection
bool send_ack_in_response_to_packet_;
+ // Set to true if the udp packet headers have a new self or peer address.
+ // This is checked later on validating a data or version negotiation packet.
+ bool address_migrating_;
+
DISALLOW_COPY_AND_ASSIGN(QuicConnection);
};
diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc
index 0c81722..fa7484a 100644
--- a/net/quic/quic_connection_helper_test.cc
+++ b/net/quic/quic_connection_helper_test.cc
@@ -23,7 +23,7 @@ namespace net {
namespace test {
const char kData[] = "foo";
-const bool kHasData = true;
+const bool kFromPeer = true;
class TestConnection : public QuicConnection {
public:
@@ -328,7 +328,7 @@ TEST_F(QuicConnectionHelperTest, InitialTimeout) {
// Verify that a single task was posted.
ASSERT_EQ(1u, runner_->GetPostedTasks().size());
- EXPECT_EQ(base::TimeDelta::FromMicroseconds(kDefaultTimeoutUs),
+ EXPECT_EQ(base::TimeDelta::FromSeconds(kDefaultInitialTimeoutSecs),
runner_->GetPostedTasks().front().delay);
EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
@@ -336,8 +336,8 @@ TEST_F(QuicConnectionHelperTest, InitialTimeout) {
EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
runner_->RunNextTask();
- EXPECT_EQ(QuicTime::Zero().Add(
- QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs)),
+ EXPECT_EQ(QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(
+ kDefaultInitialTimeoutSecs)),
clock_.ApproximateNow());
EXPECT_FALSE(connection_->connected());
EXPECT_TRUE(AtEof());
@@ -374,7 +374,8 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) {
EXPECT_TRUE(connection_->connected());
QuicTime start = clock_.ApproximateNow();
- // When we send a packet, the timeout will change to 5000 + kDefaultTimeout.
+ // When we send a packet, the timeout will change to 5000 +
+ // kDefaultInitialTimeoutSecs.
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(5000));
EXPECT_EQ(5000u, clock_.ApproximateNow().Subtract(start).ToMicroseconds());
EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
@@ -386,17 +387,18 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) {
// network event at t=5000. The alarm will reregister.
runner_->RunNextTask();
- EXPECT_EQ(QuicTime::Zero().Add(
- QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs)),
+ EXPECT_EQ(QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(
+ kDefaultInitialTimeoutSecs)),
clock_.ApproximateNow());
EXPECT_TRUE(connection_->connected());
// This time, we should time out.
- EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
+ EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, !kFromPeer));
EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, NOT_RETRANSMISSION));
runner_->RunNextTask();
- EXPECT_EQ(kDefaultTimeoutUs + 5000, clock_.ApproximateNow().Subtract(
- QuicTime::Zero()).ToMicroseconds());
+ EXPECT_EQ(kDefaultInitialTimeoutSecs * 1000000 + 5000,
+ clock_.ApproximateNow().Subtract(
+ QuicTime::Zero()).ToMicroseconds());
EXPECT_FALSE(connection_->connected());
EXPECT_TRUE(AtEof());
}
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 826681a..b761aaf 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -756,10 +756,8 @@ TEST_F(QuicConnectionTest, PacketsOutOfOrderWithAdditionsAndLeastAwaiting) {
TEST_F(QuicConnectionTest, RejectPacketTooFarOut) {
// Call ProcessDataPacket rather than ProcessPacket, as we should not get a
// packet call to the visitor.
+ EXPECT_CALL(visitor_, ConnectionClose(QUIC_INVALID_PACKET_HEADER, false));
ProcessDataPacket(6000, 0, !kEntropyFlag);
-
- SendAckPacketToPeer(); // Packet 2
- EXPECT_EQ(0u, outgoing_ack()->received_info.largest_observed);
}
TEST_F(QuicConnectionTest, TruncatedAck) {
@@ -1119,6 +1117,45 @@ TEST_F(QuicConnectionTest, RetransmitNackedLargestObserved) {
ProcessAckPacket(&frame);
}
+TEST_F(QuicConnectionTest, RetransmitNackedPacketsOnTruncatedAck) {
+ for (int i = 0; i < 200; ++i) {
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(1);
+ connection_.SendStreamData(1, "foo", i * 3, !kFin);
+ }
+
+ // Make a truncated ack frame.
+ QuicAckFrame frame(0, QuicTime::Zero(), 1);
+ frame.received_info.largest_observed = 192;
+ InsertMissingPacketsBetween(&frame.received_info, 1, 192);
+ frame.received_info.entropy_hash =
+ QuicConnectionPeer::GetSentEntropyHash(&connection_, 192) ^
+ QuicConnectionPeer::GetSentEntropyHash(&connection_, 191);
+
+
+ EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1);
+ EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
+ EXPECT_CALL(visitor_, OnAck(_)).Times(1);
+ ProcessAckPacket(&frame);
+ EXPECT_TRUE(QuicConnectionPeer::GetReceivedTruncatedAck(&connection_));
+
+ QuicConnectionPeer::SetMaxPacketsPerRetransmissionAlarm(&connection_, 200);
+ const QuicTime::Delta kDefaultRetransmissionTime =
+ QuicTime::Delta::FromMilliseconds(500);
+ clock_.AdvanceTime(kDefaultRetransmissionTime);
+ // Only packets that are less than largest observed should be retransmitted.
+ EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(191);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(191);
+ connection_.OnRetransmissionTimeout();
+
+ clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(
+ 2 * kDefaultRetransmissionTime.ToMicroseconds()));
+ // Retransmit already retransmitted packets event though the sequence number
+ // greater than the largest observed.
+ EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(191);
+ EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(191);
+ connection_.OnRetransmissionTimeout();
+}
+
TEST_F(QuicConnectionTest, LimitPacketsPerNack) {
EXPECT_CALL(*send_algorithm_, OnIncomingAck(12, _, _)).Times(1);
EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
@@ -1487,11 +1524,12 @@ TEST_F(QuicConnectionTest, InitialTimeout) {
EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
QuicTime default_timeout = clock_.ApproximateNow().Add(
- QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs));
+ QuicTime::Delta::FromSeconds(kDefaultInitialTimeoutSecs));
EXPECT_EQ(default_timeout, helper_->timeout_alarm());
// Simulate the timeout alarm firing
- clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs));
+ clock_.AdvanceTime(
+ QuicTime::Delta::FromSeconds(kDefaultInitialTimeoutSecs));
EXPECT_TRUE(connection_.CheckForTimeout());
EXPECT_FALSE(connection_.connected());
}
@@ -1500,9 +1538,10 @@ TEST_F(QuicConnectionTest, TimeoutAfterSend) {
EXPECT_TRUE(connection_.connected());
QuicTime default_timeout = clock_.ApproximateNow().Add(
- QuicTime::Delta::FromMicroseconds(kDefaultTimeoutUs));
+ QuicTime::Delta::FromSeconds(kDefaultInitialTimeoutSecs));
- // When we send a packet, the timeout will change to 5000 + kDefaultTimeout.
+ // When we send a packet, the timeout will change to 5000 +
+ // kDefaultInitialTimeoutSecs.
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
// Send an ack so we don't set the retransimission alarm.
@@ -1512,7 +1551,7 @@ TEST_F(QuicConnectionTest, TimeoutAfterSend) {
// The original alarm will fire. We should not time out because we had a
// network event at t=5000. The alarm will reregister.
clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(
- kDefaultTimeoutUs - 5000));
+ kDefaultInitialTimeoutSecs * 1000000 - 5000));
EXPECT_EQ(default_timeout, clock_.ApproximateNow());
EXPECT_FALSE(connection_.CheckForTimeout());
EXPECT_TRUE(connection_.connected());
@@ -1993,6 +2032,60 @@ TEST_F(QuicConnectionTest, CheckReceiveStats) {
EXPECT_EQ(1u, stats.packets_dropped);
}
+TEST_F(QuicConnectionTest, TestFecGroupLimits) {
+ // Create and return a group for 1
+ ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 1) != NULL);
+
+ // Create and return a group for 2
+ ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 2) != NULL);
+
+ // Create and return a group for 4. This should remove 1 but not 2.
+ ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 4) != NULL);
+ ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 1) == NULL);
+ ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 2) != NULL);
+
+ // Create and return a group for 3. This will kill off 2.
+ ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 3) != NULL);
+ ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 2) == NULL);
+
+ // Verify that adding 5 kills off 3, despite 4 being created before 3.
+ ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 5) != NULL);
+ ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 4) != NULL);
+ ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 3) == NULL);
+}
+
+TEST_F(QuicConnectionTest, DontProcessFramesIfPacketClosedConnection) {
+ // Construct a packet with stream frame and connection close frame.
+ header_.public_header.guid = guid_;
+ header_.packet_sequence_number = 1;
+ header_.public_header.reset_flag = false;
+ header_.public_header.version_flag = false;
+ header_.entropy_flag = false;
+ header_.fec_flag = false;
+ header_.fec_entropy_flag = false;
+ header_.fec_group = 0;
+
+ QuicConnectionCloseFrame qccf;
+ qccf.error_code = QUIC_PEER_GOING_AWAY;
+ qccf.ack_frame = QuicAckFrame(0, QuicTime::Zero(), 1);
+ QuicFrame close_frame(&qccf);
+ QuicFrame stream_frame(&frame1_);
+
+ QuicFrames frames;
+ frames.push_back(stream_frame);
+ frames.push_back(close_frame);
+ scoped_ptr<QuicPacket> packet(
+ framer_.ConstructFrameDataPacket(header_, frames).packet);
+ EXPECT_TRUE(NULL != packet.get());
+ scoped_ptr<QuicEncryptedPacket> encrypted(framer_.EncryptPacket(
+ ENCRYPTION_NONE, 1, *packet));
+
+ EXPECT_CALL(visitor_, ConnectionClose(QUIC_PEER_GOING_AWAY, true));
+ EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).Times(0);
+
+ connection_.ProcessUdpPacket(IPEndPoint(), IPEndPoint(), *encrypted);
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index e6322a8..80d298e 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -15,13 +15,11 @@ namespace net {
QuicCryptoClientStream::QuicCryptoClientStream(
const string& server_hostname,
- const QuicConfig& config,
QuicSession* session,
QuicCryptoClientConfig* crypto_config)
: QuicCryptoStream(session),
next_state_(STATE_IDLE),
num_client_hellos_(0),
- config_(config),
crypto_config_(crypto_config),
server_hostname_(server_hostname) {
}
@@ -82,8 +80,7 @@ void QuicCryptoClientStream::DoHandshakeLoop(
SendHandshakeMessage(out);
return;
}
- const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
- config_.ToHandshakeMessage(&out);
+ session()->config()->ToHandshakeMessage(&out);
error = crypto_config_->FillClientHello(
server_hostname_,
session()->connection()->guid(),
@@ -97,13 +94,6 @@ void QuicCryptoClientStream::DoHandshakeLoop(
CloseConnectionWithDetails(error, error_details);
return;
}
- error = config_.ProcessFinalPeerHandshake(
- *scfg, CryptoUtils::PEER_PRIORITY, &negotiated_params_,
- &error_details);
- if (error != QUIC_NO_ERROR) {
- CloseConnectionWithDetails(error, error_details);
- return;
- }
next_state_ = STATE_RECV_SHLO;
DLOG(INFO) << "Client Sending: " << out.DebugString();
SendHandshakeMessage(out);
@@ -214,6 +204,12 @@ void QuicCryptoClientStream::DoHandshakeLoop(
error, "Server hello invalid: " + error_details);
return;
}
+ error = session()->config()->ProcessServerHello(*in, &error_details);
+ if (error != QUIC_NO_ERROR) {
+ CloseConnectionWithDetails(
+ error, "Server hello invalid: " + error_details);
+ return;
+ }
CrypterPair* crypters =
&crypto_negotiated_params_.forward_secure_crypters;
// TODO(agl): we don't currently latch this decrypter because the idea
diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h
index 041d11c..e85a764 100644
--- a/net/quic/quic_crypto_client_stream.h
+++ b/net/quic/quic_crypto_client_stream.h
@@ -13,7 +13,6 @@
namespace net {
-class QuicConfig;
class QuicSession;
namespace test {
@@ -23,7 +22,6 @@ class CryptoTestUtils;
class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream {
public:
QuicCryptoClientStream(const string& server_hostname,
- const QuicConfig& config,
QuicSession* session,
QuicCryptoClientConfig* crypto_config);
virtual ~QuicCryptoClientStream();
@@ -61,7 +59,6 @@ class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream {
// connection has sent.
int num_client_hellos_;
- const QuicConfig& config_;
QuicCryptoClientConfig* const crypto_config_;
// Client's connection nonce (4-byte timestamp + 28 random bytes)
diff --git a/net/quic/quic_crypto_client_stream_factory.h b/net/quic/quic_crypto_client_stream_factory.h
index 4d0eb1e..4fa5f57 100644
--- a/net/quic/quic_crypto_client_stream_factory.h
+++ b/net/quic/quic_crypto_client_stream_factory.h
@@ -22,7 +22,6 @@ class NET_EXPORT QuicCryptoClientStreamFactory {
virtual QuicCryptoClientStream* CreateQuicCryptoClientStream(
const string& server_hostname,
- const QuicConfig& config,
QuicSession* session,
QuicCryptoClientConfig* crypto_config) = 0;
};
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index c913964..90b9122 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -8,6 +8,7 @@
#include "net/quic/crypto/aes_128_gcm_encrypter.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
+#include "net/quic/quic_protocol.h"
#include "net/quic/test_tools/crypto_test_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/simple_quic_framer.h"
@@ -50,10 +51,10 @@ class QuicCryptoClientStreamTest : public ::testing::Test {
QuicCryptoClientStreamTest()
: addr_(),
connection_(new PacketSavingConnection(1, addr_, true)),
- session_(connection_, true),
- stream_(kServerHostname, config_, &session_, &crypto_config_) {
+ session_(connection_, QuicConfig(), true),
+ stream_(kServerHostname, &session_, &crypto_config_) {
session_.SetCryptoStream(&stream_);
- config_.SetDefaults();
+ session_.config()->SetDefaults();
crypto_config_.SetDefaults();
}
@@ -73,7 +74,6 @@ class QuicCryptoClientStreamTest : public ::testing::Test {
QuicCryptoClientStream stream_;
CryptoHandshakeMessage message_;
scoped_ptr<QuicData> message_data_;
- QuicConfig config_;
QuicCryptoClientConfig crypto_config_;
};
@@ -137,10 +137,13 @@ TEST_F(QuicCryptoClientStreamTest, NegotiatedParameters) {
CompleteCryptoHandshake();
- const QuicNegotiatedParameters& params(stream_.negotiated_params());
- EXPECT_EQ(kQBIC, params.congestion_control);
- EXPECT_EQ(300, params.idle_connection_state_lifetime.ToSeconds());
- EXPECT_EQ(0, params.keepalive_timeout.ToSeconds());
+ const QuicConfig* config = session_.config();
+ EXPECT_EQ(kQBIC, config->congestion_control());
+ EXPECT_EQ(kDefaultTimeoutSecs,
+ config->idle_connection_state_lifetime().ToSeconds());
+ EXPECT_EQ(kDefaultMaxStreamsPerConnection,
+ config->max_streams_per_connection());
+ EXPECT_EQ(0, config->keepalive_timeout().ToSeconds());
const QuicCryptoNegotiatedParameters& crypto_params(
stream_.crypto_negotiated_params());
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index 57c1076..c87c6d5 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -14,11 +14,9 @@
namespace net {
QuicCryptoServerStream::QuicCryptoServerStream(
- const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
QuicSession* session)
: QuicCryptoStream(session),
- config_(config),
crypto_config_(crypto_config) {
}
@@ -58,14 +56,15 @@ void QuicCryptoServerStream::OnHandshakeMessage(
}
// If we are returning a SHLO then we accepted the handshake.
- error = config_.ProcessFinalPeerHandshake(
- message, CryptoUtils::LOCAL_PRIORITY, &negotiated_params_,
- &error_details);
+ QuicConfig* config = session()->config();
+ error = config->ProcessClientHello(message, &error_details);
if (error != QUIC_NO_ERROR) {
CloseConnectionWithDetails(error, error_details);
return;
}
+ config->ToHandshakeMessage(&reply);
+
// Receiving a full CHLO implies the client is prepared to decrypt with
// the new server write key. We can start to encrypt with the new server
// write key.
diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h
index 47c1478..1c7ac06 100644
--- a/net/quic/quic_crypto_server_stream.h
+++ b/net/quic/quic_crypto_server_stream.h
@@ -15,7 +15,6 @@ namespace net {
class CryptoHandshakeMessage;
class QuicCryptoServerConfig;
-class QuicNegotiatedParameters;
class QuicSession;
namespace test {
@@ -24,8 +23,7 @@ class CryptoTestUtils;
class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream {
public:
- QuicCryptoServerStream(const QuicConfig& config,
- const QuicCryptoServerConfig& crypto_config,
+ QuicCryptoServerStream(const QuicCryptoServerConfig& crypto_config,
QuicSession* session);
explicit QuicCryptoServerStream(QuicSession* session);
virtual ~QuicCryptoServerStream();
@@ -37,9 +35,6 @@ class NET_EXPORT_PRIVATE QuicCryptoServerStream : public QuicCryptoStream {
private:
friend class test::CryptoTestUtils;
- // config_ contains non-crypto parameters that are negotiated in the crypto
- // handshake.
- const QuicConfig& config_;
// crypto_config_ contains crypto parameters for the handshake.
const QuicCryptoServerConfig& crypto_config_;
};
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc
index d12597b..73469db 100644
--- a/net/quic/quic_crypto_server_stream_test.cc
+++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -61,9 +61,10 @@ class QuicCryptoServerStreamTest : public ::testing::Test {
addr_(ParseIPLiteralToNumber("192.0.2.33", &ip_) ?
ip_ : IPAddressNumber(), 1),
connection_(new PacketSavingConnection(guid_, addr_, true)),
- session_(connection_, true),
+ session_(connection_, QuicConfig(), true),
crypto_config_(QuicCryptoServerConfig::TESTING),
- stream_(config_, crypto_config_, &session_) {
+ stream_(crypto_config_, &session_) {
+ session_.config()->SetDefaults();
session_.SetCryptoStream(&stream_);
// We advance the clock initially because the default time is zero and the
// strike register worries that we've just overflowed a uint32 time.
@@ -72,8 +73,8 @@ class QuicCryptoServerStreamTest : public ::testing::Test {
// crypto_config_.SetProofSource(CryptoTestUtils::ProofSourceForTesting());
CryptoTestUtils::SetupCryptoServerConfigForTest(
- connection_->clock(), connection_->random_generator(), &config_,
- &crypto_config_);
+ connection_->clock(), connection_->random_generator(),
+ session_.config(), &crypto_config_);
}
void ConstructHandshakeMessage() {
@@ -82,7 +83,8 @@ class QuicCryptoServerStreamTest : public ::testing::Test {
}
int CompleteCryptoHandshake() {
- return CryptoTestUtils::HandshakeWithFakeClient(connection_, &stream_);
+ return CryptoTestUtils::HandshakeWithFakeClient(connection_, &stream_,
+ client_options_);
}
protected:
@@ -96,6 +98,7 @@ class QuicCryptoServerStreamTest : public ::testing::Test {
QuicCryptoServerStream stream_;
CryptoHandshakeMessage message_;
scoped_ptr<QuicData> message_data_;
+ CryptoTestUtils::FakeClientOptions client_options_;
};
TEST_F(QuicCryptoServerStreamTest, NotInitiallyConected) {
@@ -144,18 +147,15 @@ TEST_F(QuicCryptoServerStreamTest, ZeroRTT) {
client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(100000));
server_conn->AdvanceTime(QuicTime::Delta::FromSeconds(100000));
- scoped_ptr<TestSession> client_session(new TestSession(client_conn, true));
- scoped_ptr<TestSession> server_session(new TestSession(server_conn, true));
-
QuicConfig client_config;
+ scoped_ptr<TestSession> client_session(
+ new TestSession(client_conn, client_config, false));
+ client_session->config()->SetDefaults();
QuicCryptoClientConfig client_crypto_config;
-
- client_config.SetDefaults();
client_crypto_config.SetDefaults();
scoped_ptr<QuicCryptoClientStream> client(new QuicCryptoClientStream(
- "test.example.com", client_config, client_session.get(),
- &client_crypto_config));
+ "test.example.com", client_session.get(), &client_crypto_config));
client_session->SetCryptoStream(client.get());
// Do a first handshake in order to prime the client config with the server's
@@ -163,9 +163,11 @@ TEST_F(QuicCryptoServerStreamTest, ZeroRTT) {
CHECK(client->CryptoConnect());
CHECK_EQ(1u, client_conn->packets_.size());
+ scoped_ptr<TestSession> server_session(
+ new TestSession(server_conn, config_, true));
+ server_session->config()->SetDefaults();
scoped_ptr<QuicCryptoServerStream> server(
- new QuicCryptoServerStream(config_, crypto_config_,
- server_session.get()));
+ new QuicCryptoServerStream(crypto_config_, server_session.get()));
server_session->SetCryptoStream(server.get());
CryptoTestUtils::CommunicateHandshakeMessages(
@@ -185,14 +187,15 @@ TEST_F(QuicCryptoServerStreamTest, ZeroRTT) {
// This causes the client's nonce to be different and thus stops the
// strike-register from rejecting the repeated nonce.
client_conn->random_generator()->Reseed(NULL, 0);
- client_session.reset(new TestSession(client_conn, true));
- server_session.reset(new TestSession(server_conn, true));
+ client_session.reset(new TestSession(client_conn, client_config, false));
+ client_session->config()->SetDefaults();
+ server_session.reset(new TestSession(server_conn, config_, true));
+ server_session->config()->SetDefaults();
client.reset(new QuicCryptoClientStream(
- "test.example.com", client_config, client_session.get(),
- &client_crypto_config));
+ "test.example.com", client_session.get(), &client_crypto_config));
client_session->SetCryptoStream(client.get());
- server.reset(new QuicCryptoServerStream(config_, crypto_config_,
+ server.reset(new QuicCryptoServerStream(crypto_config_,
server_session.get()));
server_session->SetCryptoStream(server.get());
@@ -230,6 +233,22 @@ TEST_F(QuicCryptoServerStreamTest, BadMessageType) {
stream_.ProcessData(message_data_->data(), message_data_->length());
}
+TEST_F(QuicCryptoServerStreamTest, WithoutCertificates) {
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
+ crypto_config_.SetProofSource(NULL);
+ client_options_.dont_verify_certs = true;
+
+ // Only 2 client hellos need to be sent in the no-certs case: one to get the
+ // source-address token and the second to finish.
+ EXPECT_EQ(2, CompleteCryptoHandshake());
+ EXPECT_TRUE(stream_.encryption_established());
+ EXPECT_TRUE(stream_.handshake_confirmed());
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/quic_crypto_stream.cc b/net/quic/quic_crypto_stream.cc
index 70bf4d3..2f06e3b 100644
--- a/net/quic/quic_crypto_stream.cc
+++ b/net/quic/quic_crypto_stream.cc
@@ -57,11 +57,6 @@ void QuicCryptoStream::SendHandshakeMessage(
WriteData(string(data.data(), data.length()), false);
}
-const QuicNegotiatedParameters&
-QuicCryptoStream::negotiated_params() const {
- return negotiated_params_;
-}
-
const QuicCryptoNegotiatedParameters&
QuicCryptoStream::crypto_negotiated_params() const {
return crypto_negotiated_params_;
diff --git a/net/quic/quic_crypto_stream.h b/net/quic/quic_crypto_stream.h
index 1352f2e..bdae59e 100644
--- a/net/quic/quic_crypto_stream.h
+++ b/net/quic/quic_crypto_stream.h
@@ -46,7 +46,6 @@ class NET_EXPORT_PRIVATE QuicCryptoStream
bool encryption_established() { return encryption_established_; }
bool handshake_confirmed() { return handshake_confirmed_; }
- const QuicNegotiatedParameters& negotiated_params() const;
const QuicCryptoNegotiatedParameters& crypto_negotiated_params() const;
protected:
@@ -57,7 +56,6 @@ class NET_EXPORT_PRIVATE QuicCryptoStream
bool encryption_established_;
bool handshake_confirmed_;
- QuicNegotiatedParameters negotiated_params_;
QuicCryptoNegotiatedParameters crypto_negotiated_params_;
private:
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index 67a376e..0e56382 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -102,6 +102,14 @@ size_t QuicFramer::GetMinGoAwayFrameSize() {
kQuicStreamIdSize;
}
+// static
+// TODO(satyamshekhar): 16 - Crypto hash for integrity. Not a static value. Use
+// QuicEncrypter::GetMaxPlaintextSize.
+size_t QuicFramer::GetMaxUnackedPackets(bool include_version) {
+ return (kMaxPacketSize - GetPacketHeaderSize(include_version) -
+ GetMinAckFrameSize() - 16) / kSequenceNumberSize;
+}
+
bool QuicFramer::IsSupportedVersion(QuicTag version) {
return version == kQuicVersion1;
}
@@ -313,6 +321,8 @@ QuicEncryptedPacket* QuicFramer::ConstructVersionNegotiationPacket(
}
bool QuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) {
+ // TODO(satyamshekhar): Don't RaiseError (and close the connection) for
+ // invalid (unauthenticated) packets.
DCHECK(!reader_.get());
reader_.reset(new QuicDataReader(packet.data(), packet.length()));
@@ -409,15 +419,14 @@ bool QuicFramer::ProcessPublicResetPacket(
const QuicPacketPublicHeader& public_header) {
QuicPublicResetPacket packet(public_header);
if (!reader_->ReadUInt64(&packet.nonce_proof)) {
- // TODO(satyamshekhar): Raise error.
set_detailed_error("Unable to read nonce proof.");
- return false;
+ return RaiseError(QUIC_INVALID_PUBLIC_RST_PACKET);
}
// TODO(satyamshekhar): validate nonce to protect against DoS.
if (!reader_->ReadUInt48(&packet.rejected_sequence_number)) {
set_detailed_error("Unable to read rejected sequence number.");
- return false;
+ return RaiseError(QUIC_INVALID_PUBLIC_RST_PACKET);
}
visitor_->OnPublicResetPacket(packet);
return true;
@@ -431,8 +440,9 @@ bool QuicFramer::ProcessRevivedPacket(QuicPacketHeader* header,
header->entropy_hash = GetPacketEntropyHash(*header);
- // TODO(satyamshekhar): Don't process if the visitor refuses the header.
- visitor_->OnPacketHeader(*header);
+ if (!visitor_->OnPacketHeader(*header)) {
+ return true;
+ }
if (payload.length() > kMaxPacketSize) {
set_detailed_error("Revived packet too large.");
@@ -704,6 +714,13 @@ bool QuicFramer::ProcessFrameData() {
if (!ProcessConnectionCloseFrame(&frame)) {
return RaiseError(QUIC_INVALID_CONNECTION_CLOSE_DATA);
}
+
+ if (!visitor_->OnAckFrame(frame.ack_frame)) {
+ DLOG(INFO) << "Visitor asked to stopped further processing.";
+ // Returning true since there was no parsing error.
+ return true;
+ }
+
if (!visitor_->OnConnectionCloseFrame(frame)) {
DLOG(INFO) << "Visitor asked to stopped further processing.";
// Returning true since there was no parsing error.
@@ -988,12 +1005,6 @@ bool QuicFramer::ProcessConnectionCloseFrame(QuicConnectionCloseFrame* frame) {
return false;
}
- if (!visitor_->OnAckFrame(frame->ack_frame)) {
- DLOG(INFO) << "Visitor asked to stopped further processing.";
- // Returning true since there was no parsing error.
- return true;
- }
-
return true;
}
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h
index 8286844..b13a257 100644
--- a/net/quic/quic_framer.h
+++ b/net/quic/quic_framer.h
@@ -231,6 +231,9 @@ class NET_EXPORT_PRIVATE QuicFramer {
static size_t GetMinConnectionCloseFrameSize();
// Size in bytes of all GoAway frame fields without the reason phrase.
static size_t GetMinGoAwayFrameSize();
+ // The maximum number of nacks which can be transmitted in a single ack packet
+ // without exceeding kMaxPacketSize.
+ static size_t GetMaxUnackedPackets(bool include_version);
// Size in bytes required for a serialized version negotiation packet
size_t GetVersionNegotiationPacketSize(size_t number_versions);
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index 6986443..701e2bb 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -572,7 +572,7 @@ TEST_F(QuicFramerTest, PacketHeaderWithVersionFlag) {
// public flags (version)
0x01,
// version tag
- 'Q', '0', '0', '1',
+ 'Q', '0', '0', '2',
// packet sequence number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
@@ -817,7 +817,7 @@ TEST_F(QuicFramerTest, StreamFrameWithVersion) {
// public flags (version)
0x01,
// version tag
- 'Q', '0', '0', '1',
+ 'Q', '0', '0', '2',
// packet sequence number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
@@ -1608,14 +1608,21 @@ TEST_F(QuicFramerTest, PublicResetPacket) {
DLOG(INFO) << "iteration: " << i;
if (i < kPublicFlagsOffset) {
expected_error = "Unable to read GUID.";
+ CheckProcessingFails(packet, i, expected_error,
+ QUIC_INVALID_PACKET_HEADER);
} else if (i < kPublicResetPacketNonceProofOffset) {
expected_error = "Unable to read public flags.";
+ CheckProcessingFails(packet, i, expected_error,
+ QUIC_INVALID_PACKET_HEADER);
} else if (i < kPublicResetPacketRejectedSequenceNumberOffset) {
expected_error = "Unable to read nonce proof.";
+ CheckProcessingFails(packet, i, expected_error,
+ QUIC_INVALID_PUBLIC_RST_PACKET);
} else {
expected_error = "Unable to read rejected sequence number.";
+ CheckProcessingFails(packet, i, expected_error,
+ QUIC_INVALID_PUBLIC_RST_PACKET);
}
- CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER);
}
}
@@ -1626,7 +1633,7 @@ TEST_F(QuicFramerTest, VersionNegotiationPacket) {
// public flags (version)
0x01,
// version tag
- 'Q', '0', '0', '1',
+ 'Q', '0', '0', '2',
'Q', '2', '.', '0',
};
@@ -1825,7 +1832,7 @@ TEST_F(QuicFramerTest, ConstructStreamFramePacketWithVersionFlag) {
// public flags (version)
0x01,
// version tag
- 'Q', '0', '0', '1',
+ 'Q', '0', '0', '2',
// packet sequence number
0xBC, 0x9A, 0x78, 0x56,
0x34, 0x12,
@@ -1873,7 +1880,7 @@ TEST_F(QuicFramerTest, ConstructVersionNegotiationPacket) {
// public flags (version)
0x01,
// version tag
- 'Q', '0', '0', '1',
+ 'Q', '0', '0', '2',
'Q', '2', '.', '0',
};
@@ -2801,5 +2808,65 @@ TEST_F(QuicFramerTest, StopPacketProcessing) {
EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
}
+TEST_F(QuicFramerTest, ConnectionCloseWithInvalidAck) {
+ unsigned char packet[] = {
+ // guid
+ 0x10, 0x32, 0x54, 0x76,
+ 0x98, 0xBA, 0xDC, 0xFE,
+ // public flags
+ 0x00,
+ // packet sequence number
+ 0xBC, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // private flags
+ 0x00,
+ // first fec protected packet offset
+ 0xFF,
+
+ // frame type (connection close frame)
+ 0x05,
+ // error code
+ 0x11, 0x00, 0x00, 0x00,
+ // error details length
+ 0x0d, 0x00,
+ // error details
+ 'b', 'e', 'c', 'a',
+ 'u', 's', 'e', ' ',
+ 'I', ' ', 'c', 'a',
+ 'n',
+
+ // Ack frame.
+ // entropy hash of sent packets till least awaiting - 1.
+ 0xE0,
+ // least packet sequence number awaiting an ack
+ 0xA0, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // entropy hash of all received packets.
+ 0x43,
+ // largest observed packet sequence number
+ 0xBF, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ // Infinite delta time.
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ // num missing packets
+ 0x01,
+ // missing packet
+ 0xBE, 0x9A, 0x78, 0x56,
+ 0x34, 0x12,
+ };
+
+ MockFramerVisitor visitor;
+ framer_.set_visitor(&visitor);
+ EXPECT_CALL(visitor, OnPacket());
+ EXPECT_CALL(visitor, OnPacketHeader(_));
+ EXPECT_CALL(visitor, OnAckFrame(_)).WillOnce(Return(false));
+ EXPECT_CALL(visitor, OnConnectionCloseFrame(_)).Times(0);
+ EXPECT_CALL(visitor, OnPacketComplete());
+
+ QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
+ EXPECT_TRUE(framer_.ProcessPacket(encrypted));
+ EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index d7fafe0..ff82ab4 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -179,8 +179,8 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
crypto_config_.SetDefaults();
session_.reset(new QuicClientSession(connection_, socket, NULL,
&crypto_client_stream_factory_,
- "www.google.com", &crypto_config_,
- NULL));
+ "www.google.com", QuicConfig(),
+ &crypto_config_, NULL));
session_->GetCryptoStream()->CryptoConnect();
EXPECT_TRUE(session_->IsCryptoHandshakeConfirmed());
QuicReliableClientStream* stream =
@@ -265,7 +265,6 @@ class QuicHttpStreamTest : public ::testing::TestWithParam<bool> {
testing::StrictMock<MockConnectionVisitor> visitor_;
scoped_ptr<QuicHttpStream> stream_;
scoped_ptr<QuicClientSession> session_;
- QuicConfig* config_;
QuicCryptoClientConfig crypto_config_;
TestCompletionCallback callback_;
HttpRequestInfo request_;
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 31fab86..f4c5e95 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -93,7 +93,10 @@ const QuicStreamId kCryptoStreamId = 1;
// Value which indicates this packet is not FEC protected.
const uint8 kNoFecOffset = 0xFF;
-const int64 kDefaultTimeoutUs = 600000000; // 10 minutes.
+// This is the default network timeout a for connection till the crypto
+// handshake succeeds and the negotiated timeout from the handshake is received.
+const int64 kDefaultInitialTimeoutSecs = 30; // 30 secs.
+const int64 kDefaultTimeoutSecs = 60 * 10; // 10 minutes.
enum Retransmission {
NOT_RETRANSMISSION,
@@ -173,6 +176,8 @@ enum QuicErrorCode {
QUIC_INVALID_ACK_DATA,
// Version negotiation packet is malformed.
QUIC_INVALID_VERSION_NEGOTIATION_PACKET,
+ // Public RST packet is malformed.
+ QUIC_INVALID_PUBLIC_RST_PACKET,
// There was an error decrypting.
QUIC_DECRYPTION_FAILURE,
// There was an error encrypting.
@@ -195,9 +200,17 @@ enum QuicErrorCode {
QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED,
// The Header ID for a stream was too far from the previous.
QUIC_INVALID_HEADER_ID,
-
+ // Negotiable parameter received during handshake had invalid value.
+ QUIC_INVALID_NEGOTIATED_VALUE,
+ // There was an error decompressing data.
+ QUIC_DECOMPRESSION_FAILURE,
// We hit our prenegotiated (or default) timeout
QUIC_CONNECTION_TIMED_OUT,
+ // There was an error encountered migrating addresses
+ QUIC_ERROR_MIGRATING_ADDRESS,
+ // There was an error while writing the packet.
+ QUIC_PACKET_WRITE_ERROR,
+
// Crypto errors.
@@ -258,7 +271,7 @@ const QuicTag kUnsupportedVersion = -1;
// Each time the wire format changes, this need needs to be incremented.
// At some point, we will actually freeze the wire format and make an official
// version number, but this works for now.
-const QuicTag kQuicVersion1 = TAG('Q', '0', '0', '1');
+const QuicTag kQuicVersion1 = TAG('Q', '0', '0', '2');
#undef TAG
// MakeQuicTag returns a value given the four bytes. For example:
diff --git a/net/quic/quic_reliable_client_stream_test.cc b/net/quic/quic_reliable_client_stream_test.cc
index 2517bac..12402fd 100644
--- a/net/quic/quic_reliable_client_stream_test.cc
+++ b/net/quic/quic_reliable_client_stream_test.cc
@@ -42,7 +42,6 @@ class QuicReliableClientStreamTest : public ::testing::Test {
testing::StrictMock<MockDelegate> delegate_;
MockSession session_;
QuicReliableClientStream stream_;
- QuicConfig config_;
QuicCryptoClientConfig crypto_config_;
};
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 66879300..5d5df18 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -64,9 +64,12 @@ class VisitorShim : public QuicConnectionVisitorInterface {
QuicSession* session_;
};
-QuicSession::QuicSession(QuicConnection* connection, bool is_server)
+QuicSession::QuicSession(QuicConnection* connection,
+ const QuicConfig& config,
+ bool is_server)
: connection_(connection),
visitor_shim_(new VisitorShim(this)),
+ config_(config),
max_open_streams_(kDefaultMaxStreamsPerConnection),
next_stream_id_(is_server ? 2 : 3),
is_server_(is_server),
@@ -214,11 +217,17 @@ bool QuicSession::IsCryptoHandshakeConfirmed() {
void QuicSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
if (event == QuicSession::HANDSHAKE_CONFIRMED) {
- connection_->SetConnectionTimeout(
- GetCryptoStream()->negotiated_params().idle_connection_state_lifetime);
+ LOG_IF(DFATAL, !config_.negotiated())
+ << "Handshake confirmed without parameter negotiation.";
+ connection_->SetConnectionTimeout(config_.idle_connection_state_lifetime());
+ max_open_streams_ = config_.max_streams_per_connection();
}
}
+QuicConfig* QuicSession::config() {
+ return &config_;
+}
+
void QuicSession::ActivateStream(ReliableQuicStream* stream) {
DLOG(INFO) << "num_streams: " << stream_map_.size()
<< ". activating " << stream->id();
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index eff0546..00003d4 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -50,7 +50,9 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
HANDSHAKE_CONFIRMED,
};
- QuicSession(QuicConnection* connection, bool is_server);
+ QuicSession(QuicConnection* connection,
+ const QuicConfig& config,
+ bool is_server);
virtual ~QuicSession();
@@ -102,6 +104,8 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
// Servers will simply call it once with HANDSHAKE_CONFIRMED.
virtual void OnCryptoHandshakeEvent(CryptoHandshakeEvent event);
+ virtual QuicConfig* config();
+
// Returns true if the stream existed previously and has been closed.
// Returns false if the stream is still active or if the stream has
// not yet been created.
@@ -176,6 +180,10 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
return max_open_streams_;
}
+ void set_max_open_streams(size_t max_open_streams) {
+ max_open_streams_ = max_open_streams;
+ }
+
private:
friend class test::QuicSessionPeer;
friend class VisitorShim;
@@ -195,8 +203,10 @@ class NET_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface {
QuicSpdyDecompressor decompressor_;
QuicSpdyCompressor compressor_;
+ QuicConfig config_;
+
// Returns the maximum number of streams this connection can open.
- const size_t max_open_streams_;
+ size_t max_open_streams_;
// Map from StreamId to pointers to streams that are owned by the caller.
ReliableStreamMap stream_map_;
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index 02b9853..338caed 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -3,12 +3,14 @@
// found in the LICENSE file.
#include "net/quic/quic_session.h"
-#include "net/quic/quic_connection.h"
#include <set>
#include "base/hash_tables.h"
#include "net/quic/crypto/crypto_handshake.h"
+#include "net/quic/quic_connection.h"
+#include "net/quic/quic_protocol.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -32,6 +34,12 @@ class TestCryptoStream : public QuicCryptoStream {
const CryptoHandshakeMessage& message) OVERRIDE {
encryption_established_ = true;
handshake_confirmed_ = true;
+ CryptoHandshakeMessage msg;
+ string error_details;
+ session()->config()->ToHandshakeMessage(&msg);
+ const QuicErrorCode error = session()->config()->ProcessClientHello(
+ msg, &error_details);
+ EXPECT_EQ(QUIC_NO_ERROR, error);
session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
}
};
@@ -52,8 +60,9 @@ class TestStream : public ReliableQuicStream {
class TestSession : public QuicSession {
public:
TestSession(QuicConnection* connection, bool is_server)
- : QuicSession(connection, is_server),
+ : QuicSession(connection, QuicConfig(), is_server),
crypto_stream_(this) {
+ config()->SetDefaults();
}
virtual QuicCryptoStream* GetCryptoStream() OVERRIDE {
@@ -84,6 +93,7 @@ class TestSession : public QuicSession {
}
TestCryptoStream crypto_stream_;
+ QuicConfig config_;
};
class QuicSessionTest : public ::testing::Test {
@@ -166,6 +176,16 @@ TEST_F(QuicSessionTest, StreamIdTooLarge) {
session_.GetIncomingReliableStream(105);
}
+TEST_F(QuicSessionTest, DecompressionError) {
+ ReliableQuicStream* stream = session_.GetIncomingReliableStream(3);
+ EXPECT_CALL(*connection_, SendConnectionClose(QUIC_DECOMPRESSION_FAILURE));
+ const char data[] =
+ "\1\0\0\0" // headers id
+ "\0\0\0\4" // length
+ "abcd"; // invalid compressed data
+ stream->ProcessRawData(data, arraysize(data));
+}
+
TEST_F(QuicSessionTest, OnCanWrite) {
TestStream* stream2 = session_.CreateOutgoingReliableStream();
TestStream* stream4 = session_.CreateOutgoingReliableStream();
@@ -213,6 +233,15 @@ TEST_F(QuicSessionTest, SendGoAway) {
EXPECT_FALSE(session_.GetIncomingReliableStream(3u));
}
+TEST_F(QuicSessionTest, IncreasedTimeoutAfterCryptoHandshake) {
+ EXPECT_EQ(kDefaultInitialTimeoutSecs,
+ QuicConnectionPeer::GetTimeout(connection_).ToSeconds());
+ CryptoHandshakeMessage msg;
+ session_.crypto_stream_.OnHandshakeMessage(msg);
+ EXPECT_EQ(kDefaultTimeoutSecs,
+ QuicConnectionPeer::GetTimeout(connection_).ToSeconds());
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/quic_spdy_compressor.cc b/net/quic/quic_spdy_compressor.cc
index 4497c59..4f67e26 100644
--- a/net/quic/quic_spdy_compressor.cc
+++ b/net/quic/quic_spdy_compressor.cc
@@ -12,7 +12,7 @@ using std::string;
namespace net {
QuicSpdyCompressor::QuicSpdyCompressor()
- : spdy_framer_(3),
+ : spdy_framer_(kSpdyVersion3),
header_sequence_id_(1) {
spdy_framer_.set_enable_compression(true);
}
diff --git a/net/quic/quic_spdy_decompressor.cc b/net/quic/quic_spdy_decompressor.cc
index f96e846..0d58937 100644
--- a/net/quic/quic_spdy_decompressor.cc
+++ b/net/quic/quic_spdy_decompressor.cc
@@ -75,7 +75,7 @@ bool SpdyFramerVisitor::OnControlFrameHeaderData(SpdyStreamId stream_id,
}
QuicSpdyDecompressor::QuicSpdyDecompressor()
- : spdy_framer_(3),
+ : spdy_framer_(kSpdyVersion3),
spdy_visitor_(new SpdyFramerVisitor(NULL)),
current_header_id_(1),
has_current_compressed_size_(false),
@@ -116,9 +116,11 @@ size_t QuicSpdyDecompressor::DecompressData(StringPiece data,
min(current_compressed_size_ - compressed_bytes_consumed_,
static_cast<uint32>(data.length()));
if (bytes_to_consume > 0) {
- bool success = spdy_framer_.IncrementallyDecompressControlFrameHeaderData(
- current_header_id_, data.data(), bytes_to_consume);
- DCHECK(success);
+ if (!spdy_framer_.IncrementallyDecompressControlFrameHeaderData(
+ current_header_id_, data.data(), bytes_to_consume)) {
+ visitor->OnDecompressionError();
+ return bytes_consumed;
+ }
compressed_bytes_consumed_ += bytes_to_consume;
bytes_consumed += bytes_to_consume;
}
diff --git a/net/quic/quic_spdy_decompressor.h b/net/quic/quic_spdy_decompressor.h
index 3fd50783..a56c479 100644
--- a/net/quic/quic_spdy_decompressor.h
+++ b/net/quic/quic_spdy_decompressor.h
@@ -27,6 +27,7 @@ class NET_EXPORT_PRIVATE QuicSpdyDecompressor {
public:
virtual ~Visitor() {}
virtual bool OnDecompressedData(base::StringPiece data) = 0;
+ virtual void OnDecompressionError() = 0;
};
QuicSpdyDecompressor();
diff --git a/net/quic/quic_spdy_decompressor_test.cc b/net/quic/quic_spdy_decompressor_test.cc
index b2fbb37..1e63396 100644
--- a/net/quic/quic_spdy_decompressor_test.cc
+++ b/net/quic/quic_spdy_decompressor_test.cc
@@ -52,6 +52,22 @@ TEST_F(QuicSpdyDecompressorTest, DecompressAndIgnoreTrailingData) {
EXPECT_EQ(SpdyUtils::SerializeUncompressedHeaders(headers), visitor_.data());
}
+TEST_F(QuicSpdyDecompressorTest, DecompressError) {
+ SpdyHeaderBlock headers;
+ headers[":host"] = "www.google.com";
+ headers[":path"] = "/index.hml";
+ headers[":scheme"] = "https";
+
+ EXPECT_EQ(1u, decompressor_.current_header_id());
+ string compressed_headers = compressor_.CompressHeaders(headers).substr(4);
+ compressed_headers[compressed_headers.length() - 1] ^= 0x01;
+ EXPECT_NE(compressed_headers.length(),
+ decompressor_.DecompressData(compressed_headers, &visitor_));
+
+ EXPECT_TRUE(visitor_.error());
+ EXPECT_EQ("", visitor_.data());
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 5ac6bf58..007fc88 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -372,7 +372,6 @@ QuicClientSession* QuicStreamFactory::CreateSession(
DatagramSocket::DEFAULT_BIND, base::Bind(&base::RandInt),
net_log.net_log(), net_log.source());
socket->Connect(addr);
- socket->GetLocalAddress(&addr);
QuicConnectionHelper* helper = new QuicConnectionHelper(
MessageLoop::current()->message_loop_proxy(),
@@ -387,7 +386,7 @@ QuicClientSession* QuicStreamFactory::CreateSession(
QuicClientSession* session =
new QuicClientSession(connection, socket, this,
quic_crypto_client_stream_factory_,
- host_port_proxy_pair.first.host(),
+ host_port_proxy_pair.first.host(), QuicConfig(),
crypto_config, net_log.net_log());
all_sessions_.insert(session); // owning pointer
return session;
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index 228b796..a42993c 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -4,8 +4,13 @@
#include "net/quic/quic_utils.h"
+#include <ctype.h>
+
#include "base/logging.h"
#include "base/port.h"
+#include "base/strings/string_number_conversions.h"
+
+using std::string;
namespace net {
@@ -49,6 +54,53 @@ uint128 QuicUtils::FNV1a_128_Hash(const char* data, int len) {
}
// static
+bool QuicUtils::FindMutualTag(const QuicTagVector& our_tags_vector,
+ const QuicTag* their_tags,
+ size_t num_their_tags,
+ Priority priority,
+ QuicTag* out_result,
+ size_t* out_index) {
+ if (our_tags_vector.empty()) {
+ return false;
+ }
+ const size_t num_our_tags = our_tags_vector.size();
+ const QuicTag* our_tags = &our_tags_vector[0];
+
+ size_t num_priority_tags, num_inferior_tags;
+ const QuicTag* priority_tags;
+ const QuicTag* inferior_tags;
+ if (priority == LOCAL_PRIORITY) {
+ num_priority_tags = num_our_tags;
+ priority_tags = our_tags;
+ num_inferior_tags = num_their_tags;
+ inferior_tags = their_tags;
+ } else {
+ num_priority_tags = num_their_tags;
+ priority_tags = their_tags;
+ num_inferior_tags = num_our_tags;
+ inferior_tags = our_tags;
+ }
+
+ for (size_t i = 0; i < num_priority_tags; i++) {
+ for (size_t j = 0; j < num_inferior_tags; j++) {
+ if (priority_tags[i] == inferior_tags[j]) {
+ *out_result = priority_tags[i];
+ if (out_index) {
+ if (priority == LOCAL_PRIORITY) {
+ *out_index = j;
+ } else {
+ *out_index = i;
+ }
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+// static
void QuicUtils::SerializeUint128(uint128 v, uint8* out) {
const uint64 lo = Uint128Low64(v);
const uint64 hi = Uint128High64(v);
@@ -100,6 +152,7 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_INVALID_GOAWAY_DATA);
RETURN_STRING_LITERAL(QUIC_INVALID_ACK_DATA);
RETURN_STRING_LITERAL(QUIC_INVALID_VERSION_NEGOTIATION_PACKET);
+ RETURN_STRING_LITERAL(QUIC_INVALID_PUBLIC_RST_PACKET);
RETURN_STRING_LITERAL(QUIC_DECRYPTION_FAILURE);
RETURN_STRING_LITERAL(QUIC_ENCRYPTION_FAILURE);
RETURN_STRING_LITERAL(QUIC_PACKET_TOO_LARGE);
@@ -124,7 +177,11 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
RETURN_STRING_LITERAL(QUIC_INVALID_VERSION);
RETURN_STRING_LITERAL(QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED);
RETURN_STRING_LITERAL(QUIC_INVALID_HEADER_ID);
+ RETURN_STRING_LITERAL(QUIC_INVALID_NEGOTIATED_VALUE);
+ RETURN_STRING_LITERAL(QUIC_DECOMPRESSION_FAILURE);
RETURN_STRING_LITERAL(QUIC_CONNECTION_TIMED_OUT);
+ RETURN_STRING_LITERAL(QUIC_ERROR_MIGRATING_ADDRESS);
+ RETURN_STRING_LITERAL(QUIC_PACKET_WRITE_ERROR);
RETURN_STRING_LITERAL(QUIC_PROOF_INVALID);
RETURN_STRING_LITERAL(QUIC_CRYPTO_DUPLICATE_TAG);
RETURN_STRING_LITERAL(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT);
@@ -139,4 +196,29 @@ const char* QuicUtils::ErrorToString(QuicErrorCode error) {
return "INVALID_ERROR_CODE";
}
+// static
+string QuicUtils::TagToString(QuicTag tag) {
+ char chars[4];
+ bool ascii = true;
+ const QuicTag orig_tag = tag;
+
+ for (size_t i = 0; i < sizeof(chars); i++) {
+ chars[i] = tag;
+ if (chars[i] == 0 && i == 3) {
+ chars[i] = ' ';
+ }
+ if (!isprint(static_cast<unsigned char>(chars[i]))) {
+ ascii = false;
+ break;
+ }
+ tag >>= 8;
+ }
+
+ if (ascii) {
+ return string(chars, sizeof(chars));
+ }
+
+ return base::UintToString(orig_tag);
+}
+
} // namespace net
diff --git a/net/quic/quic_utils.h b/net/quic/quic_utils.h
index 14345eb..e866a07 100644
--- a/net/quic/quic_utils.h
+++ b/net/quic/quic_utils.h
@@ -15,6 +15,11 @@ namespace net {
class NET_EXPORT_PRIVATE QuicUtils {
public:
+ enum Priority {
+ LOCAL_PRIORITY,
+ PEER_PRIORITY,
+ };
+
// returns the 64 bit FNV1a hash of the data. See
// http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param
static uint64 FNV1a_64_Hash(const char* data, int len);
@@ -23,6 +28,21 @@ class NET_EXPORT_PRIVATE QuicUtils {
// http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param
static uint128 FNV1a_128_Hash(const char* data, int len);
+ // FindMutualTag sets |out_result| to the first tag in the priority list that
+ // is also in the other list and returns true. If there is no intersection it
+ // returns false.
+ //
+ // Which list has priority is determined by |priority|.
+ //
+ // If |out_index| is non-NULL and a match is found then the index of that
+ // match in |their_tags| is written to |out_index|.
+ static bool FindMutualTag(const QuicTagVector& our_tags,
+ const QuicTag* their_tags,
+ size_t num_their_tags,
+ Priority priority,
+ QuicTag* out_result,
+ size_t* out_index);
+
// SerializeUint128 writes |v| in little-endian form to |out|.
static void SerializeUint128(uint128 v, uint8* out);
@@ -34,6 +54,12 @@ class NET_EXPORT_PRIVATE QuicUtils {
// Returns the name of the QuicErrorCode as a char*
static const char* ErrorToString(QuicErrorCode error);
+
+ // TagToString is a utility function for pretty-printing handshake messages
+ // that converts a tag to a string. It will try to maintain the human friendly
+ // name if possible (i.e. kABCD -> "ABCD"), or will just treat it as a number
+ // if not.
+ static std::string TagToString(QuicTag tag);
};
} // namespace net
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc
index cadbe9a..c293eed 100644
--- a/net/quic/reliable_quic_stream.cc
+++ b/net/quic/reliable_quic_stream.cc
@@ -365,6 +365,11 @@ bool ReliableQuicStream::OnDecompressedData(StringPiece data) {
return true;
}
+void ReliableQuicStream::OnDecompressionError() {
+ session_->connection()->SendConnectionClose(QUIC_DECOMPRESSION_FAILURE);
+}
+
+
void ReliableQuicStream::CloseWriteSide() {
if (write_side_closed_) {
return;
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h
index 726cc9c..a22f90d 100644
--- a/net/quic/reliable_quic_stream.h
+++ b/net/quic/reliable_quic_stream.h
@@ -76,6 +76,7 @@ class NET_EXPORT_PRIVATE ReliableQuicStream : public
virtual uint32 ProcessData(const char* data, uint32 data_len) = 0;
virtual bool OnDecompressedData(base::StringPiece data) OVERRIDE;
+ virtual void OnDecompressionError() OVERRIDE;
// Called to close the stream from this end.
virtual void Close(QuicRstStreamErrorCode error);
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index 058157e..4e285ad 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -102,6 +102,10 @@ void MovePackets(PacketSavingConnection* source_conn,
} // anonymous namespace
+CryptoTestUtils::FakeClientOptions::FakeClientOptions()
+ : dont_verify_certs(false) {
+}
+
// static
void CryptoTestUtils::CommunicateHandshakeMessages(
PacketSavingConnection* a_conn,
@@ -135,16 +139,15 @@ int CryptoTestUtils::HandshakeWithFakeServer(
IPEndPoint addr = IPEndPoint(ip, 1);
PacketSavingConnection* server_conn =
new PacketSavingConnection(guid, addr, true);
- TestSession server_session(server_conn, true);
+ TestSession server_session(server_conn, QuicConfig(), true);
- QuicConfig config;
QuicCryptoServerConfig crypto_config(QuicCryptoServerConfig::TESTING);
SetupCryptoServerConfigForTest(
server_session.connection()->clock(),
server_session.connection()->random_generator(),
- &config, &crypto_config);
+ server_session.config(), &crypto_config);
- QuicCryptoServerStream server(config, crypto_config, &server_session);
+ QuicCryptoServerStream server(crypto_config, &server_session);
server_session.SetCryptoStream(&server);
// The client's handshake must have been started already.
@@ -160,22 +163,24 @@ int CryptoTestUtils::HandshakeWithFakeServer(
// static
int CryptoTestUtils::HandshakeWithFakeClient(
PacketSavingConnection* server_conn,
- QuicCryptoServerStream* server) {
+ QuicCryptoServerStream* server,
+ const FakeClientOptions& options) {
QuicGuid guid(1);
IPAddressNumber ip;
CHECK(ParseIPLiteralToNumber("192.0.2.33", &ip));
IPEndPoint addr = IPEndPoint(ip, 1);
PacketSavingConnection* client_conn =
new PacketSavingConnection(guid, addr, false);
- TestSession client_session(client_conn, true);
- QuicConfig config;
+ TestSession client_session(client_conn, QuicConfig(), false);
QuicCryptoClientConfig crypto_config;
- config.SetDefaults();
+ client_session.config()->SetDefaults();
crypto_config.SetDefaults();
// TODO(rtenneti): Enable testing of ProofVerifier.
- // crypto_config.SetProofVerifier(ProofVerifierForTesting());
- QuicCryptoClientStream client("test.example.com", config, &client_session,
+ // if (!options.dont_verify_certs) {
+ // crypto_config.SetProofVerifier(ProofVerifierForTesting());
+ // }
+ QuicCryptoClientStream client("test.example.com", &client_session,
&crypto_config);
client_session.SetCryptoStream(&client);
@@ -196,15 +201,9 @@ void CryptoTestUtils::SetupCryptoServerConfigForTest(
QuicConfig* config,
QuicCryptoServerConfig* crypto_config) {
config->SetDefaults();
- CryptoHandshakeMessage extra_tags;
- config->ToHandshakeMessage(&extra_tags);
-
scoped_ptr<CryptoHandshakeMessage> scfg(
crypto_config->AddDefaultConfig(
- rand, clock, extra_tags, QuicCryptoServerConfig::kDefaultExpiry));
- if (!config->SetFromHandshakeMessage(*scfg)) {
- CHECK(false) << "Crypto config could not be parsed by QuicConfig.";
- }
+ rand, clock, QuicCryptoServerConfig::kDefaultExpiry));
}
// static
@@ -274,8 +273,8 @@ class MockCommonCertSets : public CommonCertSets {
};
CommonCertSets* CryptoTestUtils::MockCommonCertSets(StringPiece cert,
- uint64 hash,
- uint32 index) {
+ uint64 hash,
+ uint32 index) {
return new class MockCommonCertSets(cert, hash, index);
}
diff --git a/net/quic/test_tools/crypto_test_utils.h b/net/quic/test_tools/crypto_test_utils.h
index 62748a3..3a4fdd4 100644
--- a/net/quic/test_tools/crypto_test_utils.h
+++ b/net/quic/test_tools/crypto_test_utils.h
@@ -32,13 +32,24 @@ class PacketSavingConnection;
class CryptoTestUtils {
public:
+ // FakeClientOptions bundles together a number of options for configuring
+ // HandshakeWithFakeClient.
+ struct FakeClientOptions {
+ FakeClientOptions();
+
+ // If dont_verify_certs is true then no ProofVerifier is set on the client.
+ // Thus no certificates will be requested or checked.
+ bool dont_verify_certs;
+ };
+
// returns: the number of client hellos that the client sent.
static int HandshakeWithFakeServer(PacketSavingConnection* client_conn,
QuicCryptoClientStream* client);
// returns: the number of client hellos that the client sent.
static int HandshakeWithFakeClient(PacketSavingConnection* server_conn,
- QuicCryptoServerStream* server);
+ QuicCryptoServerStream* server,
+ const FakeClientOptions& options);
// SetupCryptoServerConfigForTest configures |config| and |crypto_config|
// with sensible defaults for testing.
diff --git a/net/quic/test_tools/mock_crypto_client_stream.cc b/net/quic/test_tools/mock_crypto_client_stream.cc
index afaa570..dda5965 100644
--- a/net/quic/test_tools/mock_crypto_client_stream.cc
+++ b/net/quic/test_tools/mock_crypto_client_stream.cc
@@ -8,11 +8,10 @@ namespace net {
MockCryptoClientStream::MockCryptoClientStream(
const string& server_hostname,
- const QuicConfig& config,
QuicSession* session,
QuicCryptoClientConfig* crypto_config,
HandshakeMode handshake_mode)
- : QuicCryptoClientStream(server_hostname, config, session, crypto_config),
+ : QuicCryptoClientStream(server_hostname, session, crypto_config),
handshake_mode_(handshake_mode) {
}
diff --git a/net/quic/test_tools/mock_crypto_client_stream.h b/net/quic/test_tools/mock_crypto_client_stream.h
index 4546d23..3351dec 100644
--- a/net/quic/test_tools/mock_crypto_client_stream.h
+++ b/net/quic/test_tools/mock_crypto_client_stream.h
@@ -34,7 +34,6 @@ class MockCryptoClientStream : public QuicCryptoClientStream {
MockCryptoClientStream(
const string& server_hostname,
- const QuicConfig& config,
QuicSession* session,
QuicCryptoClientConfig* crypto_config,
HandshakeMode handshake_mode);
diff --git a/net/quic/test_tools/mock_crypto_client_stream_factory.cc b/net/quic/test_tools/mock_crypto_client_stream_factory.cc
index 20926ce..7578790 100644
--- a/net/quic/test_tools/mock_crypto_client_stream_factory.cc
+++ b/net/quic/test_tools/mock_crypto_client_stream_factory.cc
@@ -18,11 +18,10 @@ MockCryptoClientStreamFactory::MockCryptoClientStreamFactory()
QuicCryptoClientStream*
MockCryptoClientStreamFactory::CreateQuicCryptoClientStream(
const string& server_hostname,
- const QuicConfig& config,
QuicSession* session,
QuicCryptoClientConfig* crypto_config) {
- return new MockCryptoClientStream(server_hostname, config, session,
- crypto_config, handshake_mode_);
+ return new MockCryptoClientStream(server_hostname, session, crypto_config,
+ handshake_mode_);
}
} // namespace net
diff --git a/net/quic/test_tools/mock_crypto_client_stream_factory.h b/net/quic/test_tools/mock_crypto_client_stream_factory.h
index 01d0c75..e3f2a4a 100644
--- a/net/quic/test_tools/mock_crypto_client_stream_factory.h
+++ b/net/quic/test_tools/mock_crypto_client_stream_factory.h
@@ -22,7 +22,6 @@ class MockCryptoClientStreamFactory : public QuicCryptoClientStreamFactory {
virtual QuicCryptoClientStream* CreateQuicCryptoClientStream(
const string& server_hostname,
- const QuicConfig& config,
QuicSession* session,
QuicCryptoClientConfig* crypto_config) OVERRIDE;
diff --git a/net/quic/test_tools/quic_client_session_peer.cc b/net/quic/test_tools/quic_client_session_peer.cc
new file mode 100644
index 0000000..e88da49
--- /dev/null
+++ b/net/quic/test_tools/quic_client_session_peer.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/test_tools/quic_client_session_peer.h"
+
+#include "net/quic/quic_client_session.h"
+
+namespace net {
+namespace test {
+
+// static
+void QuicClientSessionPeer::SetMaxOpenStreams(QuicClientSession* session,
+ size_t max_streams,
+ size_t default_streams) {
+ session->config()->set_max_streams_per_connection(max_streams,
+ default_streams);
+}
+
+} // namespace test
+} // namespace net
diff --git a/net/quic/test_tools/quic_client_session_peer.h b/net/quic/test_tools/quic_client_session_peer.h
new file mode 100644
index 0000000..7217d9d
--- /dev/null
+++ b/net/quic/test_tools/quic_client_session_peer.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_TEST_TOOLS_QUIC_CLIENT_SESSION_PEER_H_
+#define NET_QUIC_TEST_TOOLS_QUIC_CLIENT_SESSION_PEER_H_
+
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+
+class QuicClientSession;
+
+namespace test {
+
+class QuicClientSessionPeer {
+ public:
+ static void SetMaxOpenStreams(QuicClientSession* session,
+ size_t max_streams,
+ size_t default_streams);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicClientSessionPeer);
+};
+
+} // namespace test
+} // namespace net
+
+#endif // NET_QUIC_TEST_TOOLS_QUIC_CLIENT_SESSION_PEER_H_
diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc
index 6816e54..4f2b500 100644
--- a/net/quic/test_tools/quic_connection_peer.cc
+++ b/net/quic/test_tools/quic_connection_peer.cc
@@ -63,6 +63,11 @@ size_t QuicConnectionPeer::GetNumRetransmissionTimeouts(
}
// static
+QuicTime::Delta QuicConnectionPeer::GetTimeout(QuicConnection* connection) {
+ return connection->timeout_;
+}
+
+// static
bool QuicConnectionPeer::IsSavedForRetransmission(
QuicConnection* connection,
QuicPacketSequenceNumber sequence_number) {
@@ -121,5 +126,24 @@ void QuicConnectionPeer::SwapCrypters(QuicConnection* connection,
framer->SwapCryptersForTest(&connection->framer_);
}
+// static
+void QuicConnectionPeer:: SetMaxPacketsPerRetransmissionAlarm(
+ QuicConnection* connection,
+ int max_packets) {
+ connection->max_packets_per_retransmission_alarm_ = max_packets;
+}
+
+// static
+QuicConnectionHelperInterface* QuicConnectionPeer::GetHelper(
+ QuicConnection* connection) {
+ return connection->helper_.get();
+}
+
+QuicFecGroup* QuicConnectionPeer::GetFecGroup(QuicConnection* connection,
+ int fec_group) {
+ connection->last_header_.fec_group = fec_group;
+ return connection->GetFecGroup();
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h
index 89c6482..e2b4ff9 100644
--- a/net/quic/test_tools/quic_connection_peer.h
+++ b/net/quic/test_tools/quic_connection_peer.h
@@ -12,8 +12,11 @@
namespace net {
struct QuicAckFrame;
+struct QuicPacketHeader;
class QuicConnection;
+class QuicConnectionHelperInterface;
class QuicConnectionVisitorInterface;
+class QuicFecGroup;
class QuicFramer;
class QuicPacketCreator;
class ReceiveAlgorithmInterface;
@@ -43,6 +46,8 @@ class QuicConnectionPeer {
static size_t GetNumRetransmissionTimeouts(QuicConnection* connection);
+ static QuicTime::Delta GetTimeout(QuicConnection* connection);
+
static bool IsSavedForRetransmission(
QuicConnection* connection,
QuicPacketSequenceNumber sequence_number);
@@ -70,6 +75,14 @@ class QuicConnectionPeer {
static void SwapCrypters(QuicConnection* connection, QuicFramer* framer);
+ static void SetMaxPacketsPerRetransmissionAlarm(QuicConnection* connection,
+ int max_packets);
+
+ static QuicConnectionHelperInterface* GetHelper(QuicConnection* connection);
+
+ // Set last_header_->fec_group = fec_group and return connection->GetFecGroup
+ static QuicFecGroup* GetFecGroup(QuicConnection* connection, int fec_group);
+
private:
DISALLOW_COPY_AND_ASSIGN(QuicConnectionPeer);
};
diff --git a/net/quic/test_tools/quic_session_peer.cc b/net/quic/test_tools/quic_session_peer.cc
index 16b5c41..0a81ca9 100644
--- a/net/quic/test_tools/quic_session_peer.cc
+++ b/net/quic/test_tools/quic_session_peer.cc
@@ -10,9 +10,15 @@ namespace net {
namespace test {
// static
-void QuicSessionPeer::SetNextStreamId(QuicStreamId id, QuicSession* session) {
+void QuicSessionPeer::SetNextStreamId(QuicSession* session, QuicStreamId id) {
session->next_stream_id_ = id;
}
+// static
+void QuicSessionPeer::SetMaxOpenStreams(QuicSession* session,
+ uint32 max_streams) {
+ session->max_open_streams_ = max_streams;
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/test_tools/quic_session_peer.h b/net/quic/test_tools/quic_session_peer.h
index 16b0c21..9aff659 100644
--- a/net/quic/test_tools/quic_session_peer.h
+++ b/net/quic/test_tools/quic_session_peer.h
@@ -15,7 +15,8 @@ namespace test {
class QuicSessionPeer {
public:
- static void SetNextStreamId(QuicStreamId id, QuicSession* session);
+ static void SetNextStreamId(QuicSession* session, QuicStreamId id);
+ static void SetMaxOpenStreams(QuicSession* session, uint32 max_streams);
private:
DISALLOW_COPY_AND_ASSIGN(QuicSessionPeer);
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index c987277..8821387 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -235,7 +235,7 @@ bool PacketSavingConnection::SendOrQueuePacket(
}
MockSession::MockSession(QuicConnection* connection, bool is_server)
- : QuicSession(connection, is_server) {
+ : QuicSession(connection, QuicConfig(), is_server) {
ON_CALL(*this, WriteData(_, _, _, _))
.WillByDefault(testing::Return(QuicConsumedData(0, false)));
}
@@ -243,8 +243,10 @@ MockSession::MockSession(QuicConnection* connection, bool is_server)
MockSession::~MockSession() {
}
-TestSession::TestSession(QuicConnection* connection, bool is_server)
- : QuicSession(connection, is_server),
+TestSession::TestSession(QuicConnection* connection,
+ const QuicConfig& config,
+ bool is_server)
+ : QuicSession(connection, config, is_server),
crypto_stream_(NULL) {
}
@@ -404,5 +406,9 @@ bool TestDecompressorVisitor::OnDecompressedData(StringPiece data) {
return true;
}
+void TestDecompressorVisitor::OnDecompressionError() {
+ error_ = true;
+}
+
} // namespace test
} // namespace net
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 5ea2a78..8fbf054 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -295,7 +295,9 @@ class MockSession : public QuicSession {
class TestSession : public QuicSession {
public:
- TestSession(QuicConnection* connection, bool is_server);
+ TestSession(QuicConnection* connection,
+ const QuicConfig& config,
+ bool is_server);
virtual ~TestSession();
MOCK_METHOD1(CreateIncomingReliableStream,
@@ -351,11 +353,14 @@ class TestDecompressorVisitor : public QuicSpdyDecompressor::Visitor {
public:
virtual ~TestDecompressorVisitor() {}
virtual bool OnDecompressedData(base::StringPiece data) OVERRIDE;
+ virtual void OnDecompressionError() OVERRIDE;
string data() { return data_; }
+ bool error() { return error_; }
private:
string data_;
+ bool error_;
};
} // namespace test
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index 06cb5f9..aa92856 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -1498,6 +1498,7 @@ const BoundNetLog& MockUDPClientSocket::NetLog() const {
int MockUDPClientSocket::Connect(const IPEndPoint& address) {
connected_ = true;
+ peer_addr_ = address;
return OK;
}
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index c03f9d8..01e9181 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -17,16 +17,22 @@
#include "net/quic/quic_framer.h"
#include "net/quic/quic_packet_creator.h"
#include "net/quic/quic_protocol.h"
+#include "net/quic/test_tools/quic_connection_peer.h"
#include "net/quic/test_tools/quic_session_peer.h"
#include "net/quic/test_tools/reliable_quic_stream_peer.h"
+#include "net/tools/quic/quic_epoll_connection_helper.h"
#include "net/tools/quic/quic_in_memory_cache.h"
#include "net/tools/quic/quic_server.h"
+#include "net/tools/quic/quic_socket_utils.h"
#include "net/tools/quic/test_tools/http_message_test_utils.h"
+#include "net/tools/quic/test_tools/quic_client_peer.h"
+#include "net/tools/quic/test_tools/quic_epoll_connection_helper_peer.h"
#include "net/tools/quic/test_tools/quic_test_client.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::StringPiece;
using base::WaitableEvent;
+using net::test::QuicConnectionPeer;
using net::test::QuicSessionPeer;
using net::test::ReliableQuicStreamPeer;
using std::string;
@@ -209,7 +215,7 @@ TEST_F(EndToEndTest, SimpleRequestResponse) {
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
- EXPECT_EQ(200ul, client_->response_headers()->parsed_response_code());
+ EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
}
TEST_F(EndToEndTest, SimpleRequestResponsev6) {
@@ -220,12 +226,12 @@ TEST_F(EndToEndTest, SimpleRequestResponsev6) {
}
IPAddressNumber ip;
- CHECK(net::ParseIPLiteralToNumber("::", &ip));
+ CHECK(net::ParseIPLiteralToNumber("::1", &ip));
server_address_ = IPEndPoint(ip, server_address_.port());
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
- EXPECT_EQ(200ul, client_->response_headers()->parsed_response_code());
+ EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
}
TEST_F(EndToEndTest, SeparateFinPacket) {
@@ -247,7 +253,7 @@ TEST_F(EndToEndTest, SeparateFinPacket) {
client_->WaitForResponse();
EXPECT_EQ(kFooResponseBody, client_->response_body());
- EXPECT_EQ(200ul, client_->response_headers()->parsed_response_code());
+ EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
request.AddBody("foo", true);
@@ -255,7 +261,7 @@ TEST_F(EndToEndTest, SeparateFinPacket) {
client_->SendData(std::string(), true);
client_->WaitForResponse();
EXPECT_EQ(kFooResponseBody, client_->response_body());
- EXPECT_EQ(200ul, client_->response_headers()->parsed_response_code());
+ EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
}
TEST_F(EndToEndTest, MultipleRequestResponse) {
@@ -268,9 +274,9 @@ TEST_F(EndToEndTest, MultipleRequestResponse) {
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
- EXPECT_EQ(200ul, client_->response_headers()->parsed_response_code());
+ EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar"));
- EXPECT_EQ(200ul, client_->response_headers()->parsed_response_code());
+ EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
}
TEST_F(EndToEndTest, MultipleClients) {
@@ -294,12 +300,12 @@ TEST_F(EndToEndTest, MultipleClients) {
client_->SendData("bar", true);
client_->WaitForResponse();
EXPECT_EQ(kFooResponseBody, client_->response_body());
- EXPECT_EQ(200ul, client_->response_headers()->parsed_response_code());
+ EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
client2->SendData("eep", true);
client2->WaitForResponse();
EXPECT_EQ(kFooResponseBody, client2->response_body());
- EXPECT_EQ(200ul, client2->response_headers()->parsed_response_code());
+ EXPECT_EQ(200u, client2->response_headers()->parsed_response_code());
}
TEST_F(EndToEndTest, RequestOverMultiplePackets) {
@@ -329,7 +335,7 @@ TEST_F(EndToEndTest, RequestOverMultiplePackets) {
// Make sure our request is too large to fit in one packet.
EXPECT_GT(strlen(kLargeRequest), min_payload_size);
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest(kLargeRequest));
- EXPECT_EQ(200ul, client_->response_headers()->parsed_response_code());
+ EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
}
TEST_F(EndToEndTest, MultipleFramesRandomOrder) {
@@ -360,7 +366,7 @@ TEST_F(EndToEndTest, MultipleFramesRandomOrder) {
// Make sure our request is too large to fit in one packet.
EXPECT_GT(strlen(kLargeRequest), min_payload_size);
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest(kLargeRequest));
- EXPECT_EQ(200ul, client_->response_headers()->parsed_response_code());
+ EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
}
TEST_F(EndToEndTest, PostMissingBytes) {
@@ -382,7 +388,7 @@ TEST_F(EndToEndTest, PostMissingBytes) {
// triggering an error response.
client_->SendCustomSynchronousRequest(request);
EXPECT_EQ("bad", client_->response_body());
- EXPECT_EQ(500ul, client_->response_headers()->parsed_response_code());
+ EXPECT_EQ(500u, client_->response_headers()->parsed_response_code());
}
TEST_F(EndToEndTest, LargePost) {
@@ -460,7 +466,7 @@ TEST_F(EndToEndTest, InvalidStream) {
request.AddBody(body, true);
// Force the client to write with a stream ID belonging to a nonexistant
// server-side stream.
- QuicSessionPeer::SetNextStreamId(2, client_->client()->session());
+ QuicSessionPeer::SetNextStreamId(client_->client()->session(), 2);
client_->SendCustomSynchronousRequest(request);
// EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
@@ -505,6 +511,7 @@ TEST_F(EndToEndTest, MultipleTermination) {
/*TEST_F(EndToEndTest, Timeout) {
config_.set_idle_connection_state_lifetime(
+ QuicTime::Delta::FromMicroseconds(500),
QuicTime::Delta::FromMicroseconds(500));
// Note: we do NOT ASSERT_TRUE: we may time out during initial handshake:
// that's enough to validate timeout in this case.
@@ -524,10 +531,58 @@ TEST_F(EndToEndTest, ResetConnection) {
ASSERT_TRUE(Initialize());
EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
- EXPECT_EQ(200ul, client_->response_headers()->parsed_response_code());
+ EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
client_->ResetConnection();
EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar"));
- EXPECT_EQ(200ul, client_->response_headers()->parsed_response_code());
+ EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
+}
+
+class WrongAddressWriter : public QuicPacketWriter {
+ public:
+ explicit WrongAddressWriter(int fd) : fd_(fd) {
+ IPAddressNumber ip;
+ CHECK(net::ParseIPLiteralToNumber("127.0.0.2", &ip));
+ self_address_ = IPEndPoint(ip, 0);
+ }
+
+ virtual int WritePacket(const char* buffer, size_t buf_len,
+ const IPAddressNumber& real_self_address,
+ const IPEndPoint& peer_address,
+ QuicBlockedWriterInterface* blocked_writer,
+ int* error) OVERRIDE {
+ return QuicSocketUtils::WritePacket(fd_, buffer, buf_len,
+ self_address_.address(), peer_address,
+ error);
+ }
+
+ IPEndPoint self_address_;
+ int fd_;
+};
+
+TEST_F(EndToEndTest, ConnectionMigration) {
+ // TODO(rtenneti): Delete this when NSS is supported.
+ if (!Aes128GcmEncrypter::IsSupported()) {
+ LOG(INFO) << "AES GCM not supported. Test skipped.";
+ return;
+ }
+
+ ASSERT_TRUE(Initialize());
+
+ EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
+ EXPECT_EQ(200u, client_->response_headers()->parsed_response_code());
+
+ WrongAddressWriter writer(QuicClientPeer::GetFd(client_->client()));
+ QuicEpollConnectionHelper* helper =
+ reinterpret_cast<QuicEpollConnectionHelper*>(
+ QuicConnectionPeer::GetHelper(
+ client_->client()->session()->connection()));
+ QuicEpollConnectionHelperPeer::SetWriter(helper, &writer);
+
+ client_->SendSynchronousRequest("/bar");
+ QuicEpollConnectionHelperPeer::SetWriter(helper, NULL);
+
+ EXPECT_EQ(QUIC_STREAM_CONNECTION_ERROR, client_->stream_error());
+ EXPECT_EQ(QUIC_ERROR_MIGRATING_ADDRESS, client_->connection_error());
}
} // namespace
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc
index 0206c3f..9ca70a3 100644
--- a/net/tools/quic/quic_client.cc
+++ b/net/tools/quic/quic_client.cc
@@ -63,6 +63,8 @@ QuicClient::~QuicClient() {
}
bool QuicClient::Initialize() {
+ DCHECK(!initialized_);
+
epoll_server_.set_timeout_in_us(50 * 1000);
crypto_config_.SetDefaults();
int address_family = server_address_.GetSockAddrFamily();
@@ -167,6 +169,7 @@ void QuicClient::Disconnect() {
epoll_server_.UnregisterFD(fd_);
close(fd_);
fd_ = -1;
+ initialized_ = false;
}
void QuicClient::SendRequestsAndWaitForResponse(int argc, char *argv[]) {
diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h
index 9cfaa3e..0ce9104 100644
--- a/net/tools/quic/quic_client.h
+++ b/net/tools/quic/quic_client.h
@@ -24,6 +24,10 @@
namespace net {
namespace tools {
+namespace test {
+class QuicClientPeer;
+} // namespace test
+
class QuicClient : public EpollCallbackInterface {
public:
QuicClient(IPEndPoint server_address, const std::string& server_hostname);
@@ -108,6 +112,8 @@ class QuicClient : public EpollCallbackInterface {
int fd() { return fd_; }
private:
+ friend class net::tools::test::QuicClientPeer;
+
// Read a UDP packet and hand it to the framer.
bool ReadAndProcessPacket();
diff --git a/net/tools/quic/quic_client_session.cc b/net/tools/quic/quic_client_session.cc
index e3394d3..c41df67 100644
--- a/net/tools/quic/quic_client_session.cc
+++ b/net/tools/quic/quic_client_session.cc
@@ -19,8 +19,8 @@ QuicClientSession::QuicClientSession(
const QuicConfig& config,
QuicConnection* connection,
QuicCryptoClientConfig* crypto_config)
- : QuicSession(connection, false),
- crypto_stream_(server_hostname, config, this, crypto_config) {
+ : QuicSession(connection, config, false),
+ crypto_stream_(server_hostname, this, crypto_config) {
}
QuicClientSession::~QuicClientSession() {
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc
index 39543db..0b9603c 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -27,22 +27,23 @@ class QuicClientSessionTest : public ::testing::Test {
protected:
QuicClientSessionTest()
: guid_(1),
- connection_(new PacketSavingConnection(guid_, IPEndPoint(), false)),
- session_(kServerHostname, config_, connection_, &crypto_config_) {
- config_.SetDefaults();
+ connection_(new PacketSavingConnection(guid_, IPEndPoint(), false)) {
crypto_config_.SetDefaults();
+ session_.reset(new QuicClientSession(kServerHostname, QuicConfig(),
+ connection_, &crypto_config_));
+ session_->config()->SetDefaults();
+ session_->config()->set_max_streams_per_connection(1, 1);
}
void CompleteCryptoHandshake() {
- ASSERT_TRUE(session_.CryptoConnect());
+ ASSERT_TRUE(session_->CryptoConnect());
CryptoTestUtils::HandshakeWithFakeServer(
- connection_, session_.GetCryptoStream());
+ connection_, session_->GetCryptoStream());
}
QuicGuid guid_;
PacketSavingConnection* connection_;
- QuicClientSession session_;
- QuicConfig config_;
+ scoped_ptr<QuicClientSession> session_;
QuicCryptoClientConfig crypto_config_;
};
@@ -56,28 +57,28 @@ TEST_F(QuicClientSessionTest, DISABLED_MaxNumConnections) {
CompleteCryptoHandshake();
QuicReliableClientStream* stream =
- session_.CreateOutgoingReliableStream();
+ session_->CreateOutgoingReliableStream();
ASSERT_TRUE(stream);
- EXPECT_FALSE(session_.CreateOutgoingReliableStream());
+ EXPECT_FALSE(session_->CreateOutgoingReliableStream());
// Close a stream and ensure I can now open a new one.
- session_.CloseStream(stream->id());
- stream = session_.CreateOutgoingReliableStream();
+ session_->CloseStream(stream->id());
+ stream = session_->CreateOutgoingReliableStream();
EXPECT_TRUE(stream);
}
TEST_F(QuicClientSessionTest, GoAwayReceived) {
// Initialize crypto before the client session will create a stream.
- ASSERT_TRUE(session_.CryptoConnect());
+ ASSERT_TRUE(session_->CryptoConnect());
// Simulate the server crypto handshake.
CryptoHandshakeMessage server_message;
server_message.set_tag(kSHLO);
- session_.GetCryptoStream()->OnHandshakeMessage(server_message);
+ session_->GetCryptoStream()->OnHandshakeMessage(server_message);
// After receiving a GoAway, I should no longer be able to create outgoing
// streams.
- session_.OnGoAway(QuicGoAwayFrame(QUIC_PEER_GOING_AWAY, 1u, "Going away."));
- EXPECT_EQ(NULL, session_.CreateOutgoingReliableStream());
+ session_->OnGoAway(QuicGoAwayFrame(QUIC_PEER_GOING_AWAY, 1u, "Going away."));
+ EXPECT_EQ(NULL, session_->CreateOutgoingReliableStream());
}
} // namespace
diff --git a/net/tools/quic/quic_epoll_connection_helper.h b/net/tools/quic/quic_epoll_connection_helper.h
index edf5615..9ddef2f 100644
--- a/net/tools/quic/quic_epoll_connection_helper.h
+++ b/net/tools/quic/quic_epoll_connection_helper.h
@@ -30,6 +30,10 @@ class RetransmissionAlarm;
class SendAlarm;
class TimeoutAlarm;
+namespace test {
+class QuicEpollConnectionHelperPeer;
+} // namespace test
+
class QuicEpollConnectionHelper : public QuicConnectionHelperInterface {
public:
QuicEpollConnectionHelper(int fd, EpollServer* eps);
@@ -56,6 +60,7 @@ class QuicEpollConnectionHelper : public QuicConnectionHelperInterface {
private:
friend class QuicConnectionPeer;
+ friend class net::tools::test::QuicEpollConnectionHelperPeer;
QuicPacketWriter* writer_; // Not owned
EpollServer* epoll_server_; // Not owned.
diff --git a/net/tools/quic/quic_epoll_connection_helper_test.cc b/net/tools/quic/quic_epoll_connection_helper_test.cc
index 91fafa0..5f5dc1b 100644
--- a/net/tools/quic/quic_epoll_connection_helper_test.cc
+++ b/net/tools/quic/quic_epoll_connection_helper_test.cc
@@ -29,7 +29,7 @@ namespace test {
namespace {
const char data1[] = "foo";
-const bool kHasData = true;
+const bool kFromPeer = true;
class TestConnectionHelper : public QuicEpollConnectionHelper {
public:
@@ -141,17 +141,18 @@ TEST_F(QuicConnectionHelperTest, InitialTimeout) {
EXPECT_TRUE(connection_.connected());
EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
- EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, !kHasData));
+ EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, !kFromPeer));
epoll_server_.WaitForEventsAndExecuteCallbacks();
EXPECT_FALSE(connection_.connected());
- EXPECT_EQ(kDefaultTimeoutUs, epoll_server_.NowInUsec());
+ EXPECT_EQ(kDefaultInitialTimeoutSecs * 1000000, epoll_server_.NowInUsec());
}
TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) {
EXPECT_TRUE(connection_.connected());
EXPECT_EQ(0, epoll_server_.NowInUsec());
- // When we send a packet, the timeout will change to 5000 + kDefaultTimeout.
+ // When we send a packet, the timeout will change to 5000 +
+ // kDefaultInitialTimeoutSecs.
epoll_server_.AdvanceBy(5000);
EXPECT_EQ(5000, epoll_server_.NowInUsec());
@@ -162,13 +163,14 @@ TEST_F(QuicConnectionHelperTest, TimeoutAfterSend) {
// The original alarm will fire. We should not time out because we had a
// network event at t=5000. The alarm will reregister.
epoll_server_.WaitForEventsAndExecuteCallbacks();
- EXPECT_EQ(kDefaultTimeoutUs, epoll_server_.NowInUsec());
+ EXPECT_EQ(kDefaultInitialTimeoutSecs * 1000000, epoll_server_.NowInUsec());
// This time, we should time out.
- EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, false));
+ EXPECT_CALL(visitor_, ConnectionClose(QUIC_CONNECTION_TIMED_OUT, !kFromPeer));
EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, NOT_RETRANSMISSION));
epoll_server_.WaitForEventsAndExecuteCallbacks();
- EXPECT_EQ(kDefaultTimeoutUs + 5000, epoll_server_.NowInUsec());
+ EXPECT_EQ(kDefaultInitialTimeoutSecs * 1000000 + 5000,
+ epoll_server_.NowInUsec());
EXPECT_FALSE(connection_.connected());
}
diff --git a/net/tools/quic/quic_reliable_client_stream.h b/net/tools/quic/quic_reliable_client_stream.h
index c46420b..10b60c2 100644
--- a/net/tools/quic/quic_reliable_client_stream.h
+++ b/net/tools/quic/quic_reliable_client_stream.h
@@ -49,8 +49,6 @@ class QuicReliableClientStream : public ReliableQuicStream {
// Returns whatever headers have been received for this stream.
const BalsaHeaders& headers() { return headers_; }
- bool closed() { return closed_; }
-
protected:
std::string* mutable_data() { return &data_; }
BalsaHeaders* mutable_headers() { return &headers_; }
@@ -58,7 +56,6 @@ class QuicReliableClientStream : public ReliableQuicStream {
private:
BalsaHeaders headers_;
std::string data_;
- bool closed_;
DISALLOW_COPY_AND_ASSIGN(QuicReliableClientStream);
};
diff --git a/net/tools/quic/quic_reliable_client_stream_test.cc b/net/tools/quic/quic_reliable_client_stream_test.cc
index 8020c33..1f1eb54 100644
--- a/net/tools/quic/quic_reliable_client_stream_test.cc
+++ b/net/tools/quic/quic_reliable_client_stream_test.cc
@@ -25,11 +25,11 @@ namespace {
class QuicClientStreamTest : public ::testing::Test {
public:
QuicClientStreamTest()
- : session_("localhost", config_,
+ : session_("localhost", QuicConfig(),
new MockConnection(1, IPEndPoint(), 0, &eps_, false),
&crypto_config_),
body_("hello world") {
- config_.SetDefaults();
+ session_.config()->SetDefaults();
crypto_config_.SetDefaults();
headers_.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "Ok");
@@ -45,7 +45,6 @@ class QuicClientStreamTest : public ::testing::Test {
BalsaHeaders headers_;
string headers_string_;
string body_;
- QuicConfig config_;
QuicCryptoClientConfig crypto_config_;
};
diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc
index 7319c67..a92c4ba 100644
--- a/net/tools/quic/quic_server.cc
+++ b/net/tools/quic/quic_server.cc
@@ -46,19 +46,12 @@ QuicServer::QuicServer()
// Use hardcoded crypto parameters for now.
config_.SetDefaults();
- CryptoHandshakeMessage extra_tags;
- config_.ToHandshakeMessage(&extra_tags);
QuicEpollClock clock(&epoll_server_);
scoped_ptr<CryptoHandshakeMessage> scfg(
crypto_config_.AddDefaultConfig(
- QuicRandom::GetInstance(), &clock, extra_tags,
+ QuicRandom::GetInstance(), &clock,
QuicCryptoServerConfig::kDefaultExpiry));
- // If we were using the same config in many servers then we would have to
- // parse a QuicConfig from config_tags here.
- if (!config_.SetFromHandshakeMessage(*scfg)) {
- CHECK(false) << "Crypto config could not be parsed by QuicConfig.";
- }
}
QuicServer::~QuicServer() {
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index f692332..330c307 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -16,9 +16,10 @@ QuicServerSession::QuicServerSession(
const QuicCryptoServerConfig& crypto_config,
QuicConnection* connection,
QuicSessionOwner* owner)
- : QuicSession(connection, true),
- crypto_stream_(config, crypto_config, this),
+ : QuicSession(connection, config, true),
+ crypto_stream_(crypto_config, this),
owner_(owner) {
+ set_max_open_streams(config.max_streams_per_connection());
}
QuicServerSession::~QuicServerSession() {
diff --git a/net/tools/quic/quic_socket_utils.cc b/net/tools/quic/quic_socket_utils.cc
index 1798b04..329217a 100644
--- a/net/tools/quic/quic_socket_utils.cc
+++ b/net/tools/quic/quic_socket_utils.cc
@@ -149,7 +149,7 @@ int QuicSocketUtils::WritePacket(int fd, const char* buffer, size_t buf_len,
if (self_address.empty()) {
hdr.msg_control = 0;
hdr.msg_controllen = 0;
- } else if (self_address.size() == sizeof(sockaddr_in)) {
+ } else if (GetAddressFamily(self_address) == ADDRESS_FAMILY_IPV4) {
cmsghdr *cmsg = reinterpret_cast<cmsghdr*>(cbuf);
hdr.msg_control = cmsg;
hdr.msg_controllen = CMSG_SPACE(sizeof(in_pktinfo));
diff --git a/net/tools/quic/test_tools/quic_client_peer.cc b/net/tools/quic/test_tools/quic_client_peer.cc
new file mode 100644
index 0000000..8583594
--- /dev/null
+++ b/net/tools/quic/test_tools/quic_client_peer.cc
@@ -0,0 +1,27 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/tools/quic/test_tools/quic_client_peer.h"
+
+#include "net/tools/quic/quic_client.h"
+
+namespace net {
+namespace tools {
+namespace test {
+
+// static
+void QuicClientPeer::Reinitialize(QuicClient* client) {
+ client->initialized_ = false;
+ client->epoll_server_.UnregisterFD(client->fd_);
+ client->Initialize();
+}
+
+// static
+int QuicClientPeer::GetFd(QuicClient* client) {
+ return client->fd_;
+}
+
+} // namespace test
+} // namespace tools
+} // namespace net
diff --git a/net/tools/quic/test_tools/quic_client_peer.h b/net/tools/quic/test_tools/quic_client_peer.h
new file mode 100644
index 0000000..8eaa17e
--- /dev/null
+++ b/net/tools/quic/test_tools/quic_client_peer.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_TOOLS_QUIC_TEST_TOOLS_QUIC_CLIENT_PEER_H_
+#define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_CLIENT_PEER_H_
+
+namespace net {
+namespace tools {
+
+class QuicClient;
+
+namespace test {
+
+class QuicClientPeer {
+ public:
+ static void Reinitialize(QuicClient* client);
+ static int GetFd(QuicClient* client);
+};
+
+} // namespace test
+} // namespace tools
+} // namespace net
+
+#endif // NET_TOOLS_QUIC_TEST_TOOLS_QUIC_CLIENT_PEER_H_
diff --git a/net/tools/quic/test_tools/quic_epoll_connection_helper_peer.cc b/net/tools/quic/test_tools/quic_epoll_connection_helper_peer.cc
new file mode 100644
index 0000000..e358273
--- /dev/null
+++ b/net/tools/quic/test_tools/quic_epoll_connection_helper_peer.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/tools/quic/test_tools/quic_epoll_connection_helper_peer.h"
+
+#include "net/tools/quic/quic_epoll_connection_helper.h"
+
+namespace net {
+namespace tools {
+namespace test {
+
+// static
+void QuicEpollConnectionHelperPeer::SetWriter(QuicEpollConnectionHelper* helper,
+ QuicPacketWriter* writer) {
+ helper->writer_ = writer;
+}
+
+} // namespace test
+} // namespace tools
+} // namespace net
diff --git a/net/tools/quic/test_tools/quic_epoll_connection_helper_peer.h b/net/tools/quic/test_tools/quic_epoll_connection_helper_peer.h
new file mode 100644
index 0000000..72085df
--- /dev/null
+++ b/net/tools/quic/test_tools/quic_epoll_connection_helper_peer.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_TOOLS_QUIC_TEST_TOOLS_QUIC_EPOLL_CONNECTION_HELPER_PEER_H_
+#define NET_TOOLS_QUIC_TEST_TOOLS_QUIC_EPOLL_CONNECTION_HELPER_PEER_H_
+
+#include "base/basictypes.h"
+
+namespace net {
+namespace tools {
+
+class QuicPacketWriter;
+class QuicEpollConnectionHelper;
+
+namespace test {
+
+class QuicEpollConnectionHelperPeer {
+ public:
+ static void SetWriter(QuicEpollConnectionHelper* helper,
+ QuicPacketWriter* writer);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuicEpollConnectionHelperPeer);
+};
+
+} // namespace test
+} // namespace tools
+} // namespace net
+
+#endif // NET_TOOLS_QUIC_TEST_TOOLS_QUIC_EPOLL_CONNECTION_HELPER_PEER_H_
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index c6c921e8..1a7539f 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -182,6 +182,9 @@ size_t QuicTestClient::bytes_written() const {
}
void QuicTestClient::OnClose(ReliableQuicStream* stream) {
+ if (stream_ != stream) {
+ return;
+ }
response_ = stream_->data();
headers_.CopyFrom(stream_->headers());
stream_error_ = stream_->stream_error();
diff --git a/net/tools/quic/test_tools/quic_test_utils.cc b/net/tools/quic/test_tools/quic_test_utils.cc
index a5c22ea6..05c3a57 100644
--- a/net/tools/quic/test_tools/quic_test_utils.cc
+++ b/net/tools/quic/test_tools/quic_test_utils.cc
@@ -54,8 +54,14 @@ bool TestDecompressorVisitor::OnDecompressedData(StringPiece data) {
return true;
}
-TestSession::TestSession(QuicConnection* connection, bool is_server)
- : QuicSession(connection, is_server),
+void TestDecompressorVisitor::OnDecompressionError() {
+ error_ = true;
+}
+
+TestSession::TestSession(QuicConnection* connection,
+ const QuicConfig& config,
+ bool is_server)
+ : QuicSession(connection, config, is_server),
crypto_stream_(NULL) {
}
diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h
index fd69a1d..68f4de4 100644
--- a/net/tools/quic/test_tools/quic_test_utils.h
+++ b/net/tools/quic/test_tools/quic_test_utils.h
@@ -75,16 +75,21 @@ class TestDecompressorVisitor : public QuicSpdyDecompressor::Visitor {
public:
virtual ~TestDecompressorVisitor() {}
virtual bool OnDecompressedData(base::StringPiece data) OVERRIDE;
+ virtual void OnDecompressionError() OVERRIDE;
std::string data() { return data_; }
+ bool error() { return error_; }
private:
std::string data_;
+ bool error_;
};
class TestSession : public QuicSession {
public:
- TestSession(QuicConnection* connection, bool is_server);
+ TestSession(QuicConnection* connection,
+ const QuicConfig& config,
+ bool is_server);
virtual ~TestSession();
MOCK_METHOD1(CreateIncomingReliableStream,