diff options
-rw-r--r-- | net/net.gyp | 9 | ||||
-rw-r--r-- | net/quic/quic_client_session.cc | 50 | ||||
-rw-r--r-- | net/quic/quic_client_session.h | 42 | ||||
-rw-r--r-- | net/quic/quic_client_session_test.cc | 70 | ||||
-rw-r--r-- | net/quic/quic_crypto_client_stream.cc | 34 | ||||
-rw-r--r-- | net/quic/quic_crypto_client_stream.h | 29 | ||||
-rw-r--r-- | net/quic/quic_crypto_client_stream_test.cc | 67 | ||||
-rw-r--r-- | net/quic/quic_reliable_client_stream.cc | 39 | ||||
-rw-r--r-- | net/quic/quic_reliable_client_stream.h | 75 | ||||
-rw-r--r-- | net/quic/quic_reliable_client_stream_test.cc | 70 |
10 files changed, 485 insertions, 0 deletions
diff --git a/net/net.gyp b/net/net.gyp index d2cbb7307..98bc7ad 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -655,6 +655,10 @@ 'quic/crypto/quic_decrypter.cc', 'quic/crypto/quic_encrypter.h', 'quic/crypto/quic_encrypter.cc', + 'quic/quic_client_session.cc', + 'quic/quic_client_session.h', + 'quic/quic_crypto_client_stream.cc', + 'quic/quic_crypto_client_stream.h', 'quic/quic_crypto_stream.cc', 'quic/quic_crypto_stream.h', 'quic/quic_clock.cc', @@ -673,6 +677,8 @@ 'quic/quic_packet_creator.h', 'quic/quic_protocol.cc', 'quic/quic_protocol.h', + 'quic/quic_reliable_client_stream.cc', + 'quic/quic_reliable_client_stream.h', 'quic/quic_session.cc', 'quic/quic_session.h', 'quic/quic_stream_sequencer.cc', @@ -1415,11 +1421,14 @@ 'quic/test_tools/mock_clock.h', 'quic/test_tools/quic_test_utils.cc', 'quic/test_tools/quic_test_utils.h', + 'quic/quic_client_session_test.cc', 'quic/quic_connection_test.cc', + 'quic/quic_crypto_client_stream_test.cc', 'quic/quic_crypto_stream_test.cc', 'quic/quic_fec_group_test.cc', 'quic/quic_framer_test.cc', 'quic/quic_packet_creator_test.cc', + 'quic/quic_reliable_client_stream_test.cc', 'quic/quic_session_test.cc', 'quic/quic_stream_sequencer_test.cc', 'socket/buffered_write_stream_socket_unittest.cc', diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc new file mode 100644 index 0000000..cf101c6 --- /dev/null +++ b/net/quic/quic_client_session.cc @@ -0,0 +1,50 @@ +// Copyright (c) 2012 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_client_session.h" + +namespace net { + +QuicClientSession::QuicClientSession(QuicConnection* connection) + : QuicSession(connection, false), + crypto_stream_(this) { +} + +QuicClientSession::~QuicClientSession() { +} + +QuicReliableClientStream* QuicClientSession::CreateOutgoingReliableStream() { + if (!crypto_stream_.handshake_complete()) { + DLOG(INFO) << "Crypto handshake not complete, no outgoing stream created."; + return NULL; + } + if (GetNumOpenStreams() >= get_max_open_streams()) { + DLOG(INFO) << "Failed to create a new outgoing stream. " + << "Already " << GetNumOpenStreams() << " open."; + return NULL; + } + QuicReliableClientStream* stream = + new QuicReliableClientStream(GetNextStreamId(), this); + + ActivateStream(stream); + return stream; +} + +QuicCryptoClientStream* QuicClientSession::GetCryptoStream() { + return &crypto_stream_; +}; + +void QuicClientSession::CryptoConnect() { + CryptoHandshakeMessage message; + message.tag = kCHLO; + crypto_stream_.SendHandshakeMessage(message); +} + +ReliableQuicStream* QuicClientSession::CreateIncomingReliableStream( + QuicStreamId id) { + DLOG(ERROR) << "Server push not supported"; + return NULL; +} + +} // namespace net diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h new file mode 100644 index 0000000..08e6c65 --- /dev/null +++ b/net/quic/quic_client_session.h @@ -0,0 +1,42 @@ +// Copyright (c) 2012 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. +// +// A client specific QuicSession subclass. + +#ifndef NET_QUIC_QUIC_CLIENT_SESSION_H_ +#define NET_QUIC_QUIC_CLIENT_SESSION_H_ + +#include "net/quic/quic_crypto_client_stream.h" +#include "net/quic/quic_reliable_client_stream.h" +#include "net/quic/quic_session.h" + +namespace net { + +class NET_EXPORT_PRIVATE QuicClientSession : public QuicSession { + public: + explicit QuicClientSession(QuicConnection* connection); + + virtual ~QuicClientSession(); + + // QuicSession methods: + virtual QuicReliableClientStream* CreateOutgoingReliableStream() OVERRIDE; + virtual QuicCryptoClientStream* GetCryptoStream() OVERRIDE; + + // Perform a crypto handshake with the server. + void CryptoConnect(); + + protected: + // QuicSession methods: + virtual ReliableQuicStream* CreateIncomingReliableStream( + QuicStreamId id) OVERRIDE; + + private: + QuicCryptoClientStream crypto_stream_; + + DISALLOW_COPY_AND_ASSIGN(QuicClientSession); +}; + +} // namespace net + +#endif // NET_QUIC_QUIC_CLIENT_SESSION_H_ diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc new file mode 100644 index 0000000..3f3ad04 --- /dev/null +++ b/net/quic/quic_client_session_test.cc @@ -0,0 +1,70 @@ +// Copyright (c) 2012 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_client_session.h" + +#include <vector> + +#include "base/stl_util.h" +#include "net/quic/crypto/crypto_protocol.h" +#include "net/quic/test_tools/quic_test_utils.h" + +using testing::_; + +namespace net { +namespace test { +namespace { + +class QuicClientSessionTest : public ::testing::Test { + protected: + QuicClientSessionTest() + : guid_(1), + connection_(new PacketSavingConnection(guid_, IPEndPoint())), + session_(connection_) { + } + + protected: + QuicGuid guid_; + PacketSavingConnection* connection_; + QuicClientSession session_; + QuicConnectionVisitorInterface* visitor_; +}; + +TEST_F(QuicClientSessionTest, CryptoConnect) { + session_.CryptoConnect(); + ASSERT_EQ(1u, connection_->packets_.size()); + scoped_ptr<QuicPacket> chlo(ConstructHandshakePacket(guid_, kCHLO)); + CompareQuicDataWithHexError("CHLO", connection_->packets_[0], chlo.get()); +} + +TEST_F(QuicClientSessionTest, MaxNumConnections) { + // Initialize crypto before the client session will create a stream. + session_.CryptoConnect(); + ASSERT_EQ(1u, connection_->packets_.size()); + scoped_ptr<QuicPacket> chlo(ConstructHandshakePacket(guid_, kCHLO)); + CompareQuicDataWithHexError("CHLO", connection_->packets_[0], chlo.get()); + // Simulate the server crypto handshake. + CryptoHandshakeMessage server_message; + server_message.tag = kSHLO; + session_.GetCryptoStream()->OnHandshakeMessage(server_message); + + std::vector<QuicReliableClientStream*> streams; + for (size_t i = 0; i < kDefaultMaxStreamsPerConnection; i++) { + QuicReliableClientStream* stream = session_.CreateOutgoingReliableStream(); + streams.push_back(stream); + EXPECT_TRUE(stream); + } + EXPECT_FALSE(session_.CreateOutgoingReliableStream()); + + // Close a stream and ensure I can now open a new one. + session_.CloseStream(streams[0]->id()); + scoped_ptr<QuicReliableClientStream> stream( + session_.CreateOutgoingReliableStream()); + EXPECT_TRUE(stream.get()); + STLDeleteElements(&streams); +} + +} // namespace +} // namespace test +} // namespace net diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc new file mode 100644 index 0000000..d0ace80 --- /dev/null +++ b/net/quic/quic_crypto_client_stream.cc @@ -0,0 +1,34 @@ +// Copyright (c) 2012 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_crypto_client_stream.h" + +#include "net/quic/quic_session.h" + +namespace net { + +QuicCryptoClientStream::QuicCryptoClientStream(QuicSession* session) + : QuicCryptoStream(session) { +} + + +void QuicCryptoClientStream::OnHandshakeMessage( + const CryptoHandshakeMessage& message) { + // Do not process handshake messages after the handshake is complete. + if (handshake_complete()) { + CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE); + return; + } + + if (message.tag != kSHLO) { + CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE); + return; + } + + // TODO(rch): correctly validate the message + set_handshake_complete(true); + return; +} + +} // namespace net diff --git a/net/quic/quic_crypto_client_stream.h b/net/quic/quic_crypto_client_stream.h new file mode 100644 index 0000000..8f94884 --- /dev/null +++ b/net/quic/quic_crypto_client_stream.h @@ -0,0 +1,29 @@ +// Copyright (c) 2012 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_QUIC_CRYPTO_CLIENT_STREAM_H_ +#define NET_QUIC_QUIC_CRYPTO_CLIENT_STREAM_H_ + +#include "net/quic/quic_crypto_stream.h" + +namespace net { + +class QuicSession; + +class NET_EXPORT_PRIVATE QuicCryptoClientStream : public QuicCryptoStream { + + public: + explicit QuicCryptoClientStream(QuicSession* session); + + // CryptoFramerVisitorInterface implementation + virtual void OnHandshakeMessage( + const CryptoHandshakeMessage& message) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(QuicCryptoClientStream); +}; + +} // namespace net + +#endif // NET_QUIC_QUIC_CRYPTO_CLIENT_STREAM_H_ diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc new file mode 100644 index 0000000..2dfa430 --- /dev/null +++ b/net/quic/quic_crypto_client_stream_test.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2012 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_crypto_client_stream.h" + +#include "net/quic/quic_utils.h" +#include "net/quic/test_tools/quic_test_utils.h" + +namespace net { +namespace test { +namespace { + +class QuicCryptoClientStreamTest : public ::testing::Test { + public: + QuicCryptoClientStreamTest() + : connection_(new MockConnection(1, addr_)), + session_(connection_, true), + stream_(&session_) { + message_.tag = kSHLO; + message_.tag_value_map[1] = "abc"; + message_.tag_value_map[2] = "def"; + ConstructHandshakeMessage(); + } + + void ConstructHandshakeMessage() { + CryptoFramer framer; + message_data_.reset(framer.ConstructHandshakeMessage(message_)); + } + + IPEndPoint addr_; + MockConnection* connection_; + MockSession session_; + QuicCryptoClientStream stream_; + CryptoHandshakeMessage message_; + scoped_ptr<QuicData> message_data_; +}; + +TEST_F(QuicCryptoClientStreamTest, NotInitiallyConected) { + EXPECT_FALSE(stream_.handshake_complete()); +} + +TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) { + stream_.ProcessData(message_data_->data(), message_data_->length()); + EXPECT_TRUE(stream_.handshake_complete()); +} + +TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) { + stream_.ProcessData(message_data_->data(), message_data_->length()); + + EXPECT_CALL(*connection_, SendConnectionClose( + QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE)); + stream_.ProcessData(message_data_->data(), message_data_->length()); +} + +TEST_F(QuicCryptoClientStreamTest, BadMessageType) { + message_.tag = kCHLO; + ConstructHandshakeMessage(); + + EXPECT_CALL(*connection_, + SendConnectionClose(QUIC_INVALID_CRYPTO_MESSAGE_TYPE)); + stream_.ProcessData(message_data_->data(), message_data_->length()); +} + +} // namespace +} // namespace test +} // namespace net diff --git a/net/quic/quic_reliable_client_stream.cc b/net/quic/quic_reliable_client_stream.cc new file mode 100644 index 0000000..09fb01e --- /dev/null +++ b/net/quic/quic_reliable_client_stream.cc @@ -0,0 +1,39 @@ +// Copyright (c) 2012 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_reliable_client_stream.h" + +#include "net/base/net_errors.h" + +namespace net { + +QuicReliableClientStream::QuicReliableClientStream(QuicStreamId id, + QuicSession* session) + : ReliableQuicStream(id, session) { +} + +QuicReliableClientStream::~QuicReliableClientStream() { +} + +uint32 QuicReliableClientStream::ProcessData(const char* data, + uint32 data_len) { + int rv = delegate_->OnDataReceived(data, data_len); + if (rv != OK) { + DLOG(ERROR) << "Delegate refused data, rv: " << rv; + Close(QUIC_BAD_APPLICATION_PAYLOAD); + return 0; + } + return data_len; +} + +void QuicReliableClientStream::TerminateFromPeer(bool half_close) { + delegate_->OnClose(error()); +} + +void QuicReliableClientStream::SetDelegate( + QuicReliableClientStream::Delegate* delegate) { + delegate_ = delegate; +} + +} // namespace net diff --git a/net/quic/quic_reliable_client_stream.h b/net/quic/quic_reliable_client_stream.h new file mode 100644 index 0000000..7c5986d --- /dev/null +++ b/net/quic/quic_reliable_client_stream.h @@ -0,0 +1,75 @@ +// Copyright (c) 2012 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. +// +// NOTE: This code is not shared between Google and Chrome. + +#ifndef NET_QUIC_QUIC_RELIABLE_CLIENT_STREAM_H_ +#define NET_QUIC_QUIC_RELIABLE_CLIENT_STREAM_H_ + +#include "net/base/upload_data_stream.h" +#include "net/http/http_request_info.h" +#include "net/http/http_response_info.h" +#include "net/http/http_stream.h" +#include "net/quic/reliable_quic_stream.h" + +namespace net { + +class QuicClientSession; + +class NET_EXPORT_PRIVATE QuicReliableClientStream : public ReliableQuicStream { + public: + // Delegate handles protocol specific behavior of a quic stream. + class Delegate { + public: + Delegate() {} + + // Called when stream is ready to send data. + // Returns network error code. OK when it successfully sent data. + // ERR_IO_PENDING when performing operation asynchronously. + virtual int OnSendData() = 0; + + // Called when data has been sent. |status| indicates network error + // or number of bytes that has been sent. On return, |eof| is set to true + // if no more data is available to send. + // Returns network error code. OK when it successfully sent data. + virtual int OnSendDataComplete(int status, bool* eof) = 0; + + // Called when data is received. + // Returns network error code. OK when it successfully receives data. + virtual int OnDataReceived(const char* data, int length) = 0; + + // Called when the stream is closed by the peer. + virtual void OnClose(QuicErrorCode error) = 0; + + protected: + virtual ~Delegate() {} + + private: + DISALLOW_COPY_AND_ASSIGN(Delegate); + }; + + QuicReliableClientStream(QuicStreamId id, + QuicSession* session); + + virtual ~QuicReliableClientStream(); + + // ReliableQuicStream + virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE; + virtual void TerminateFromPeer(bool half_close) OVERRIDE; + + // Set new |delegate|. |delegate| must not be NULL. + // If this stream has already received data, OnDataReceived() will be + // called on the delegate. + void SetDelegate(Delegate* delegate); + Delegate* GetDelegate() { return delegate_; } + + private: + Delegate* delegate_; + + DISALLOW_COPY_AND_ASSIGN(QuicReliableClientStream); +}; + +} // namespace net + +#endif // NET_QUIC_QUIC_RELIABLE_CLIENT_STREAM_H_ diff --git a/net/quic/quic_reliable_client_stream_test.cc b/net/quic/quic_reliable_client_stream_test.cc new file mode 100644 index 0000000..66c3bb7 --- /dev/null +++ b/net/quic/quic_reliable_client_stream_test.cc @@ -0,0 +1,70 @@ +// Copyright (c) 2012 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_reliable_client_stream.h" + +#include "net/base/net_errors.h" +#include "net/quic/quic_client_session.h" +#include "net/quic/quic_utils.h" +#include "net/quic/test_tools/quic_test_utils.h" +#include "testing/gmock/include/gmock/gmock.h" + +using testing::Return; +using testing::StrEq; + +namespace net { +namespace test { +namespace { + +class MockDelegate : public QuicReliableClientStream::Delegate { + public: + MockDelegate() {} + + MOCK_METHOD0(OnSendData, int()); + MOCK_METHOD2(OnSendDataComplete, int(int, bool*)); + MOCK_METHOD2(OnDataReceived, int(const char*, int)); + MOCK_METHOD1(OnClose, void(QuicErrorCode)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockDelegate); +}; + +class QuicReliableClientStreamTest : public ::testing::Test { + public: + QuicReliableClientStreamTest() + : session_(new MockConnection(1, IPEndPoint()), false), + stream_(1, &session_) { + stream_.SetDelegate(&delegate_); + } + + testing::StrictMock<MockDelegate> delegate_; + MockSession session_; + QuicReliableClientStream stream_; +}; + +TEST_F(QuicReliableClientStreamTest, TerminateFromPeer) { + EXPECT_CALL(delegate_, OnClose(QUIC_NO_ERROR)); + + stream_.TerminateFromPeer(true); +} + +TEST_F(QuicReliableClientStreamTest, ProcessData) { + const char data[] = "hello world!"; + EXPECT_CALL(delegate_, OnDataReceived(StrEq(data), arraysize(data))); + + EXPECT_EQ(arraysize(data), stream_.ProcessData(data, arraysize(data))); +} + +TEST_F(QuicReliableClientStreamTest, ProcessDataWithError) { + const char data[] = "hello world!"; + EXPECT_CALL(delegate_, + OnDataReceived(StrEq(data), + arraysize(data))).WillOnce(Return(ERR_UNEXPECTED)); + + EXPECT_EQ(0u, stream_.ProcessData(data, arraysize(data))); +} + +} // namespace +} // namespace test +} // namespace net |