#include "net/quic/crypto/quic_crypto_server_config.h"
#include "net/quic/crypto/quic_random.h"
#include "net/quic/quic_crypto_stream.h"
+#include "net/quic/quic_flags.h"
+#include "net/quic/quic_utils.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/quic/quic_packet_writer_wrapper.h"
using base::StringPiece;
using net::EpollServer;
+using net::test::ConstructEncryptedPacket;
using net::test::MockSession;
+using net::test::ValueRestore;
using net::tools::test::MockConnection;
using std::make_pair;
-using testing::_;
using testing::DoAll;
-using testing::Invoke;
using testing::InSequence;
-using testing::Return;
+using testing::Invoke;
using testing::WithoutArgs;
+using testing::_;
namespace net {
namespace tools {
explicit TestDispatcher(const QuicConfig& config,
const QuicCryptoServerConfig& crypto_config,
EpollServer* eps)
- : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), eps) {
+ : QuicDispatcher(config,
+ crypto_config,
+ QuicSupportedVersions(),
+ new QuicDispatcher::DefaultPacketWriterFactory(),
+ eps) {
}
MOCK_METHOD3(CreateQuicSession, QuicSession*(
- QuicGuid guid,
+ QuicConnectionId connection_id,
const IPEndPoint& server_address,
const IPEndPoint& client_address));
- using QuicDispatcher::write_blocked_list;
+
+ using QuicDispatcher::current_server_address;
+ using QuicDispatcher::current_client_address;
};
// A Connection class which unregisters the session from the dispatcher
// involve a lot more mocking.
class MockServerConnection : public MockConnection {
public:
- MockServerConnection(QuicGuid guid,
+ MockServerConnection(QuicConnectionId connection_id,
QuicDispatcher* dispatcher)
- : MockConnection(guid, true),
+ : MockConnection(connection_id, true),
dispatcher_(dispatcher) {}
void UnregisterOnConnectionClosed() {
- LOG(ERROR) << "Unregistering " << guid();
- dispatcher_->OnConnectionClosed(guid(), QUIC_NO_ERROR);
+ LOG(ERROR) << "Unregistering " << connection_id();
+ dispatcher_->OnConnectionClosed(connection_id(), QUIC_NO_ERROR);
}
private:
QuicDispatcher* dispatcher_;
};
QuicSession* CreateSession(QuicDispatcher* dispatcher,
- QuicGuid guid,
- const IPEndPoint& addr,
+ QuicConnectionId connection_id,
+ const IPEndPoint& client_address,
MockSession** session) {
- MockServerConnection* connection = new MockServerConnection(guid, dispatcher);
+ MockServerConnection* connection =
+ new MockServerConnection(connection_id, dispatcher);
*session = new MockSession(connection);
ON_CALL(*connection, SendConnectionClose(_)).WillByDefault(
WithoutArgs(Invoke(
connection, &MockServerConnection::UnregisterOnConnectionClosed)));
EXPECT_CALL(*reinterpret_cast<MockConnection*>((*session)->connection()),
- ProcessUdpPacket(_, addr, _));
+ ProcessUdpPacket(_, client_address, _));
return *session;
}
: crypto_config_(QuicCryptoServerConfig::TESTING,
QuicRandom::GetInstance()),
dispatcher_(config_, crypto_config_, &eps_),
- session1_(NULL),
- session2_(NULL) {
+ session1_(nullptr),
+ session2_(nullptr) {
dispatcher_.Initialize(1);
}
- virtual ~QuicDispatcherTest() {}
+ ~QuicDispatcherTest() override {}
MockConnection* connection1() {
return reinterpret_cast<MockConnection*>(session1_->connection());
return reinterpret_cast<MockConnection*>(session2_->connection());
}
- QuicEncryptedPacket* ConstructEncryptedPacket(
- QuicGuid guid,
- bool version_flag,
- bool reset_flag,
- QuicPacketSequenceNumber sequence_number,
- const string& data) {
- QuicPacketHeader header;
- header.public_header.guid = guid;
- header.public_header.guid_length = PACKET_8BYTE_GUID;
- header.public_header.version_flag = version_flag;
- header.public_header.reset_flag = reset_flag;
- header.public_header.sequence_number_length = PACKET_6BYTE_SEQUENCE_NUMBER;
- header.packet_sequence_number = sequence_number;
- header.entropy_flag = false;
- header.entropy_hash = 0;
- header.fec_flag = false;
- header.is_in_fec_group = NOT_IN_FEC_GROUP;
- header.fec_group = 0;
- QuicStreamFrame stream_frame(1, false, 0, MakeIOVector(data));
- QuicFrame frame(&stream_frame);
- QuicFrames frames;
- frames.push_back(frame);
- QuicFramer framer(QuicSupportedVersions(), QuicTime::Zero(), false);
- scoped_ptr<QuicPacket> packet(
- framer.BuildUnsizedDataPacket(header, frames).packet);
- EXPECT_TRUE(packet != NULL);
- QuicEncryptedPacket* encrypted = framer.EncryptPacket(ENCRYPTION_NONE,
- sequence_number,
- *packet);
- EXPECT_TRUE(encrypted != NULL);
- data_ = string(encrypted->data(), encrypted->length());
- return encrypted;
- }
-
- void ProcessPacket(IPEndPoint addr,
- QuicGuid guid,
+ void ProcessPacket(IPEndPoint client_address,
+ QuicConnectionId connection_id,
bool has_version_flag,
const string& data) {
- scoped_ptr<QuicEncryptedPacket> packet(
- ConstructEncryptedPacket(guid, has_version_flag, false, 1, data));
- dispatcher_.ProcessPacket(IPEndPoint(), addr, *packet.get());
+ scoped_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket(
+ connection_id, has_version_flag, false, 1, data));
+ data_ = string(packet->data(), packet->length());
+ dispatcher_.ProcessPacket(server_address_, client_address, *packet);
}
void ValidatePacket(const QuicEncryptedPacket& packet) {
EpollServer eps_;
QuicConfig config_;
QuicCryptoServerConfig crypto_config_;
+ IPEndPoint server_address_;
TestDispatcher dispatcher_;
MockSession* session1_;
MockSession* session2_;
};
TEST_F(QuicDispatcherTest, ProcessPackets) {
- IPEndPoint addr(net::test::Loopback4(), 1);
+ IPEndPoint client_address(net::test::Loopback4(), 1);
+ IPAddressNumber any4;
+ CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4));
+ server_address_ = IPEndPoint(any4, 5);
- EXPECT_CALL(dispatcher_, CreateQuicSession(1, _, addr))
+ EXPECT_CALL(dispatcher_, CreateQuicSession(1, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, 1, addr, &session1_)));
- ProcessPacket(addr, 1, true, "foo");
+ &dispatcher_, 1, client_address, &session1_)));
+ ProcessPacket(client_address, 1, true, "foo");
+ EXPECT_EQ(client_address, dispatcher_.current_client_address());
+ EXPECT_EQ(server_address_, dispatcher_.current_server_address());
+
- EXPECT_CALL(dispatcher_, CreateQuicSession(2, _, addr))
+ EXPECT_CALL(dispatcher_, CreateQuicSession(2, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, 2, addr, &session2_)));
- ProcessPacket(addr, 2, true, "bar");
+ &dispatcher_, 2, client_address, &session2_)));
+ ProcessPacket(client_address, 2, true, "bar");
EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()),
ProcessUdpPacket(_, _, _)).Times(1).
WillOnce(testing::WithArgs<2>(Invoke(
this, &QuicDispatcherTest::ValidatePacket)));
- ProcessPacket(addr, 1, false, "eep");
+ ProcessPacket(client_address, 1, false, "eep");
}
TEST_F(QuicDispatcherTest, Shutdown) {
- IPEndPoint addr(net::test::Loopback4(), 1);
+ IPEndPoint client_address(net::test::Loopback4(), 1);
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, addr))
+ EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, 1, addr, &session1_)));
+ &dispatcher_, 1, client_address, &session1_)));
- ProcessPacket(addr, 1, true, "foo");
+ ProcessPacket(client_address, 1, true, "foo");
EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()),
SendConnectionClose(QUIC_PEER_GOING_AWAY));
: QuicTimeWaitListManager(writer, visitor, eps, QuicSupportedVersions()) {
}
- MOCK_METHOD4(ProcessPacket, void(const IPEndPoint& server_address,
+ MOCK_METHOD5(ProcessPacket, void(const IPEndPoint& server_address,
const IPEndPoint& client_address,
- QuicGuid guid,
- QuicPacketSequenceNumber sequence_number));
+ QuicConnectionId connection_id,
+ QuicPacketSequenceNumber sequence_number,
+ const QuicEncryptedPacket& packet));
};
TEST_F(QuicDispatcherTest, TimeWaitListManager) {
QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_,
time_wait_list_manager);
// Create a new session.
- IPEndPoint addr(net::test::Loopback4(), 1);
- QuicGuid guid = 1;
- EXPECT_CALL(dispatcher_, CreateQuicSession(guid, _, addr))
+ IPEndPoint client_address(net::test::Loopback4(), 1);
+ QuicConnectionId connection_id = 1;
+ EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, guid, addr, &session1_)));
- ProcessPacket(addr, guid, true, "foo");
+ &dispatcher_, connection_id, client_address, &session1_)));
+ ProcessPacket(client_address, connection_id, true, "foo");
// Close the connection by sending public reset packet.
QuicPublicResetPacket packet;
- packet.public_header.guid = guid;
+ packet.public_header.connection_id = connection_id;
packet.public_header.reset_flag = true;
packet.public_header.version_flag = false;
packet.rejected_sequence_number = 19191;
.WillOnce(Invoke(
reinterpret_cast<MockConnection*>(session1_->connection()),
&MockConnection::ReallyProcessUdpPacket));
- dispatcher_.ProcessPacket(IPEndPoint(), addr, *encrypted);
- EXPECT_TRUE(time_wait_list_manager->IsGuidInTimeWait(guid));
-
- // Dispatcher forwards subsequent packets for this guid to the time wait list
- // manager.
- EXPECT_CALL(*time_wait_list_manager, ProcessPacket(_, _, guid, _)).Times(1);
- ProcessPacket(addr, guid, true, "foo");
+ dispatcher_.ProcessPacket(IPEndPoint(), client_address, *encrypted);
+ EXPECT_TRUE(time_wait_list_manager->IsConnectionIdInTimeWait(connection_id));
+
+ // Dispatcher forwards subsequent packets for this connection_id to the time
+ // wait list manager.
+ EXPECT_CALL(*time_wait_list_manager,
+ ProcessPacket(_, _, connection_id, _, _)).Times(1);
+ ProcessPacket(client_address, connection_id, true, "foo");
}
TEST_F(QuicDispatcherTest, StrayPacketToTimeWaitListManager) {
QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_,
time_wait_list_manager);
- IPEndPoint addr(net::test::Loopback4(), 1);
- QuicGuid guid = 1;
- // Dispatcher forwards all packets for this guid to the time wait list
- // manager.
+ IPEndPoint client_address(net::test::Loopback4(), 1);
+ QuicConnectionId connection_id = 1;
+ // Dispatcher forwards all packets for this connection_id to the time wait
+ // list manager.
EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, _)).Times(0);
- EXPECT_CALL(*time_wait_list_manager, ProcessPacket(_, _, guid, _)).Times(1);
+ EXPECT_CALL(*time_wait_list_manager,
+ ProcessPacket(_, _, connection_id, _, _)).Times(1);
string data = "foo";
- ProcessPacket(addr, guid, false, "foo");
+ ProcessPacket(client_address, connection_id, false, "foo");
}
class BlockingWriter : public QuicPacketWriterWrapper {
public:
BlockingWriter() : write_blocked_(false) {}
- virtual bool IsWriteBlocked() const OVERRIDE { return write_blocked_; }
- virtual void SetWritable() OVERRIDE { write_blocked_ = false; }
-
- virtual WriteResult WritePacket(
- const char* buffer,
- size_t buf_len,
- const IPAddressNumber& self_address,
- const IPEndPoint& peer_address,
- QuicBlockedWriterInterface* blocked_writer) OVERRIDE {
- if (write_blocked_) {
- return WriteResult(WRITE_STATUS_BLOCKED, EAGAIN);
- } else {
- return QuicPacketWriterWrapper::WritePacket(
- buffer, buf_len, self_address, peer_address, blocked_writer);
- }
+ bool IsWriteBlocked() const override { return write_blocked_; }
+ void SetWritable() override { write_blocked_ = false; }
+
+ WriteResult WritePacket(const char* buffer,
+ size_t buf_len,
+ const IPAddressNumber& self_client_address,
+ const IPEndPoint& peer_client_address) override {
+ // It would be quite possible to actually implement this method here with
+ // the fake blocked status, but it would be significantly more work in
+ // Chromium, and since it's not called anyway, don't bother.
+ LOG(DFATAL) << "Not supported";
+ return WriteResult();
}
bool write_blocked_;
class QuicDispatcherWriteBlockedListTest : public QuicDispatcherTest {
public:
- virtual void SetUp() {
+ void SetUp() override {
writer_ = new BlockingWriter;
+ QuicDispatcherPeer::SetPacketWriterFactory(&dispatcher_,
+ new TestWriterFactory());
QuicDispatcherPeer::UseWriter(&dispatcher_, writer_);
- IPEndPoint addr(net::test::Loopback4(), 1);
+ IPEndPoint client_address(net::test::Loopback4(), 1);
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, addr))
+ EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, 1, addr, &session1_)));
- ProcessPacket(addr, 1, true, "foo");
+ &dispatcher_, 1, client_address, &session1_)));
+ ProcessPacket(client_address, 1, true, "foo");
- EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, addr))
+ EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address))
.WillOnce(testing::Return(CreateSession(
- &dispatcher_, 2, addr, &session2_)));
- ProcessPacket(addr, 2, true, "bar");
+ &dispatcher_, 2, client_address, &session2_)));
+ ProcessPacket(client_address, 2, true, "bar");
- blocked_list_ = dispatcher_.write_blocked_list();
+ blocked_list_ = QuicDispatcherPeer::GetWriteBlockedList(&dispatcher_);
}
- virtual void TearDown() {
+ void TearDown() override {
EXPECT_CALL(*connection1(), SendConnectionClose(QUIC_PEER_GOING_AWAY));
EXPECT_CALL(*connection2(), SendConnectionClose(QUIC_PEER_GOING_AWAY));
dispatcher_.Shutdown();
}
- bool SetBlocked() {
+ void SetBlocked() {
+ writer_->write_blocked_ = true;
+ }
+
+ void BlockConnection2() {
writer_->write_blocked_ = true;
- return true;
+ dispatcher_.OnWriteBlocked(connection2());
}
protected:
// It should get only one notification.
EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
- EXPECT_FALSE(dispatcher_.OnCanWrite());
+ dispatcher_.OnCanWrite();
+ EXPECT_FALSE(dispatcher_.HasPendingWrites());
}
TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteOrder) {
SetBlocked();
dispatcher_.OnWriteBlocked(connection1());
dispatcher_.OnWriteBlocked(connection2());
- EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce(Return(true));
- EXPECT_CALL(*connection2(), OnCanWrite()).WillOnce(Return(false));
+ EXPECT_CALL(*connection1(), OnCanWrite());
+ EXPECT_CALL(*connection2(), OnCanWrite()).WillOnce(
+ Invoke(this, &QuicDispatcherWriteBlockedListTest::BlockConnection2));
dispatcher_.OnCanWrite();
+ EXPECT_TRUE(dispatcher_.HasPendingWrites());
// Now call OnCanWrite again, and connection1 should get its second chance
- EXPECT_CALL(*connection1(), OnCanWrite());
+ EXPECT_CALL(*connection2(), OnCanWrite());
dispatcher_.OnCanWrite();
+ EXPECT_FALSE(dispatcher_.HasPendingWrites());
}
TEST_F(QuicDispatcherWriteBlockedListTest, TestWriteLimits) {
Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked));
EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
dispatcher_.OnCanWrite();
+ EXPECT_TRUE(dispatcher_.HasPendingWrites());
// And we'll resume where we left off when we get another call.
EXPECT_CALL(*connection2(), OnCanWrite());
dispatcher_.OnCanWrite();
+ EXPECT_FALSE(dispatcher_.HasPendingWrites());
}
} // namespace