Last active
November 19, 2017 14:53
-
-
Save nus/ebeaa10427bbba34963642a8e6237e5c to your computer and use it in GitHub Desktop.
Quic memo. バックアップ用とのため実装は中途半端。https://github.com/google/proto-quic 1694fa55a19d7e03103f65d69360bd7ff05389c8
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "base/at_exit.h" | |
#include "base/message_loop/message_loop.h" | |
#include "base/threading/thread_task_runner_handle.h" | |
#include "net/cert/cert_verifier.h" | |
#include "net/cert/ct_known_logs.h" | |
#include "net/cert/ct_policy_enforcer.h" | |
#include "net/cert/multi_log_ct_verifier.h" | |
#include "net/http/transport_security_state.h" | |
#include "net/tools/quic/quic_client_base.h" | |
#include "net/tools/quic/quic_client_message_loop_network_helper.h" | |
#include "net/quic/chromium/quic_chromium_alarm_factory.h" | |
#include "net/quic/chromium/quic_chromium_connection_helper.h" | |
#include "net/quic/core/quic_config.h" // net::QuicConfig | |
#include "net/quic/platform/api/quic_ptr_util.h" | |
#include "net/quic/platform/api/quic_str_cat.h" | |
#include "net/quic/platform/impl/quic_chromium_clock.h" | |
#include "base/at_exit.h" | |
#include "base/command_line.h" | |
#include "base/logging.h" | |
#include "base/message_loop/message_loop.h" | |
#include "net/base/net_errors.h" | |
#include "net/base/privacy_mode.h" | |
#include "net/cert/cert_verifier.h" | |
#include "net/cert/ct_known_logs.h" | |
#include "net/cert/ct_log_verifier.h" | |
#include "net/cert/multi_log_ct_verifier.h" | |
#include "net/http/transport_security_state.h" | |
#include "net/quic/chromium/crypto/proof_verifier_chromium.h" | |
#include "net/quic/core/quic_error_codes.h" | |
#include "net/quic/core/quic_packets.h" | |
#include "net/quic/core/quic_server_id.h" | |
#include "net/quic/platform/api/quic_socket_address.h" | |
#include "net/quic/platform/api/quic_str_cat.h" | |
#include "net/quic/platform/api/quic_string_piece.h" | |
#include "net/quic/platform/api/quic_text_utils.h" | |
#include "net/spdy/chromium/spdy_http_utils.h" | |
#include "net/spdy/core/spdy_header_block.h" | |
#include "net/tools/quic/quic_simple_client.h" | |
#include "net/tools/quic/synchronous_host_resolver.h" | |
#include "url/gurl.h" | |
#include <iostream> | |
using namespace std; | |
namespace { | |
class FakeProofVerifier : public net::ProofVerifier { | |
public: | |
net::QuicAsyncStatus VerifyProof( | |
const string& /*hostname*/, | |
const uint16_t /*port*/, | |
const string& /*server_config*/, | |
net::QuicVersion /*quic_version*/, | |
net::QuicStringPiece /*chlo_hash*/, | |
const std::vector<string>& /*certs*/, | |
const string& /*cert_sct*/, | |
const string& /*signature*/, | |
const net::ProofVerifyContext* /*context*/, | |
string* /*error_details*/, | |
std::unique_ptr<net::ProofVerifyDetails>* /*details*/, | |
std::unique_ptr<net::ProofVerifierCallback> /*callback*/) override { | |
return net::QUIC_SUCCESS; | |
} | |
net::QuicAsyncStatus VerifyCertChain( | |
const std::string& /*hostname*/, | |
const std::vector<std::string>& /*certs*/, | |
const net::ProofVerifyContext* /*verify_context*/, | |
std::string* /*error_details*/, | |
std::unique_ptr<net::ProofVerifyDetails>* /*verify_details*/, | |
std::unique_ptr<net::ProofVerifierCallback> /*callback*/) override { | |
return net::QUIC_SUCCESS; | |
} | |
}; | |
#if 0 | |
class QCQuicCryptoStream : public net::QuicCryptoStream { | |
public: | |
explicit QCQuicCryptoStream(net::QuicSession* session); | |
~QCQuicCryptoStream() override; | |
bool encryption_established() const override; | |
bool handshake_confirmed() const override; | |
const net::QuicCryptoNegotiatedParameters& crypto_negotiated_params() | |
const override; | |
net::CryptoMessageParser* crypto_message_parser() override; | |
private: | |
net::QuicReferenceCountedPointer<net::QuicCryptoNegotiatedParameters> params_; | |
net::CryptoFramer crypto_framer_; | |
}; | |
QCQuicCryptoStream::QCQuicCryptoStream(net::QuicSession* session) | |
: QuicCryptoStream(session), params_(new net::QuicCryptoNegotiatedParameters) {} | |
QCQuicCryptoStream::~QCQuicCryptoStream() {} | |
bool QCQuicCryptoStream::encryption_established() const { | |
cout << "encryption_established" << endl; | |
return true; | |
} | |
bool QCQuicCryptoStream::handshake_confirmed() const { | |
cout << "handshake_confirmed" << endl; | |
return false; | |
} | |
const net::QuicCryptoNegotiatedParameters& | |
QCQuicCryptoStream::crypto_negotiated_params() const { | |
cout << "crypto_negotiated_params" << endl; | |
return *params_; | |
} | |
net::CryptoMessageParser* QCQuicCryptoStream::crypto_message_parser() { | |
cout << "crypto_message_parser" << endl; | |
return &crypto_framer_; | |
} | |
#endif | |
class QCQuicStream : public net::QuicStream { | |
public: | |
QCQuicStream(net::QuicStreamId id, net::QuicSession* session) | |
: net::QuicStream(id, session) { | |
} | |
// Called when new data is available from the sequencer. Subclasses must | |
// actively retrieve the data using the sequencer's Readv() or | |
// GetReadableRegions() method. | |
void OnDataAvailable() override { | |
cout << "OnDataAvailable" << endl; | |
} | |
}; | |
class QCQuicSession | |
: public net::QuicSession, | |
public net::QuicCryptoClientStream::ProofHandler { | |
public: | |
QCQuicSession(net::QuicConnection* connection, | |
net::QuicSession::Visitor* owner, | |
const net::QuicConfig& config, | |
const net::QuicServerId& server_id, | |
net::QuicCryptoClientConfig* crypto_config); | |
// Creates a new stream to handle a peer-initiated stream. | |
// Caller does not own the returned stream. | |
// Returns nullptr and does error handling if the stream can not be created. | |
net::QuicStream* CreateIncomingDynamicStream(net::QuicStreamId id) override { | |
cout << "CreateIncomingDynamicStream" << endl; | |
return nullptr; | |
} | |
// Create a new stream to handle a locally-initiated stream. | |
// Caller does not own the returned stream. | |
// Returns nullptr if max streams have already been opened. | |
net::QuicStream* CreateOutgoingDynamicStream(net::SpdyPriority priority) override { | |
cout << "CreateOutgoingDynamicStream" << endl; | |
return CreateAndActivateStream(GetNextOutgoingStreamId()); | |
} | |
// Return the reserved crypto stream. | |
net::QuicCryptoStream* GetMutableCryptoStream() override { | |
cout << "GetMutableCryptoStream" << endl; | |
return crypto_stream_.get(); | |
} | |
// Return the reserved crypto stream as a constant pointer. | |
const net::QuicCryptoStream* GetCryptoStream() const override { | |
cout << "GetCryptoStream" << endl; | |
//home/yota/github/proto-quic/src/net/quic/core/quic_crypto_client_stream.cc | |
// を参考に返す。 | |
return crypto_stream_.get(); | |
} | |
// Unconditionally creates a stream. Subclasses should use this to | |
// provide streams appropriately subclassed from |QuicStream|, | |
// e.g. |QuicSpdySession::CreateStream()| creates a |QuicSpdyStream|. | |
// net/quic/core/quic_spdy_session.cc | |
std::unique_ptr<net::QuicStream> CreateStream(net::QuicStreamId id) override { | |
cout << "CreateStream" << endl; | |
auto stream = net::QuicMakeUnique<QCQuicStream>(id, this); | |
if (!stream) { | |
cerr << "CreateStream() failed." << endl; | |
} | |
return stream; | |
} | |
// ProofHandler | |
// net/quic/quartc/quartc_session.cc を参考にした | |
void OnProofValid( | |
const net::QuicCryptoClientConfig::CachedState& cached) override { | |
// TODO: Handle the proof verification. | |
} | |
void OnProofVerifyDetailsAvailable( | |
const net::ProofVerifyDetails& verify_details) override { | |
// TODO: Handle the proof verification. | |
} | |
private: | |
std::unique_ptr<net::QuicCryptoStream> crypto_stream_; | |
}; | |
QCQuicSession::QCQuicSession(net::QuicConnection* connection, | |
net::QuicSession::Visitor* owner, | |
const net::QuicConfig& config, | |
const net::QuicServerId& server_id, | |
net::QuicCryptoClientConfig* crypto_config) : | |
net::QuicSession(connection, owner, config) { | |
cout << "sever_id " << server_id.ToString() << endl; | |
net::QuicCryptoClientStream *s = new net::QuicCryptoClientStream(server_id, this, new net::ProofVerifyContext(), crypto_config, this); | |
crypto_stream_.reset(s); | |
QuicSession::Initialize(); | |
s->CryptoConnect(); | |
} | |
class QuicClient : public net::QuicClientBase { | |
public: | |
QuicClient(net::QuicSocketAddress server_address, | |
const net::QuicServerId& server_id, | |
const net::QuicVersionVector& supported_versions, | |
std::unique_ptr<net::ProofVerifier> proof_verifier); | |
~QuicClient() override; | |
bool SendRequestAndWaitForResponse(); | |
protected: | |
int GetNumSentClientHellosFromSession() override { | |
cout << "GetNumSentClientHellosFromSession" << endl; | |
return 0; | |
} | |
int GetNumReceivedServerConfigUpdatesFromSession() override { | |
cout << "GetNumReceivedServerConfigUpdatesFromSession" << endl; | |
return 0; | |
} | |
// If this client supports buffering data, resend it. | |
void ResendSavedData() override { | |
cout << "ResendSavedData" << endl; | |
} | |
// If this client supports buffering data, clear it. | |
void ClearDataToResend() override { | |
cout << "ClearDataToResend" << endl; | |
} | |
// Takes ownership of |connection|. If you override this function, | |
// you probably want to call ResetSession() in your destructor. | |
// TODO(rch): Change the connection parameter to take in a | |
// std::unique_ptr<QuicConnection> instead. | |
std::unique_ptr<net::QuicSession> CreateQuicClientSession( | |
net::QuicConnection* connection) override { | |
cout << "CreateQuicClientSession" << endl; | |
return net::QuicMakeUnique<QCQuicSession>(connection, nullptr, *config(), server_id(), crypto_config()); | |
} | |
private: | |
void SendRequest(const std::string body); | |
QCQuicSession* client_session(); | |
private: | |
net::QuicChromiumClock clock_; | |
}; | |
QuicClient::QuicClient(net::QuicSocketAddress server_address, | |
const net::QuicServerId& server_id, | |
const net::QuicVersionVector& supported_versions, | |
std::unique_ptr<net::ProofVerifier> proof_verifier) | |
: QuicClientBase( | |
server_id, | |
supported_versions, | |
net::QuicConfig(), | |
new net::QuicChromiumConnectionHelper(&clock_, net::QuicRandom::GetInstance()), | |
new net::QuicChromiumAlarmFactory(base::ThreadTaskRunnerHandle::Get().get(), &clock_), | |
net::QuicWrapUnique(new net::QuicClientMessageLooplNetworkHelper(&clock_, this)), | |
std::move(proof_verifier)) { | |
set_server_address(server_address); | |
} | |
QuicClient::~QuicClient() { | |
// TODO Close session. | |
ResetSession(); | |
} | |
bool QuicClient::SendRequestAndWaitForResponse() { | |
std::string body = "hello"; | |
SendRequest(body); | |
while(WaitForEvents()) { | |
cout << "Waint for events." << endl; | |
} | |
return true; | |
} | |
void QuicClient::SendRequest(const std::string body) { | |
if (!connected()) { | |
return; | |
} | |
auto* stream = static_cast<net::QuicCryptoClientStream*>(client_session()->CreateOutgoingDynamicStream(3)); | |
if (stream == nullptr) { | |
cout << "stream is null" << endl; | |
return; | |
} | |
stream->WriteOrBufferData(body, true /* fin */, nullptr /* ack_listener */); | |
} | |
QCQuicSession* QuicClient::client_session() { | |
return static_cast<QCQuicSession*>(QuicClientBase::session()); | |
} | |
} // namespace | |
int main() { | |
base::AtExitManager exit_manager; | |
base::MessageLoopForIO message_loop; | |
// Determine IP address to connect to from supplied hostname. | |
std::string host = "127.0.0.1"; | |
net::QuicIpAddress ip_addr; | |
if (!ip_addr.FromString(host)) { | |
cerr << "ip_addr.FromString failed." << endl; | |
} | |
int port = 6121; | |
string host_port = net::QuicStrCat(ip_addr.ToString(), ":", port); | |
cout << "Resolved " << host << " to " << host_port << endl; | |
std::string url_host = "www.example.org"; | |
int url_port = 443; | |
net::QuicServerId server_id(url_host, url_port, | |
net::PRIVACY_MODE_DISABLED); | |
net::QuicVersionVector versions = net::AllSupportedVersions(); | |
#if 0 | |
std::unique_ptr<net::CertVerifier> cert_verifier(net::CertVerifier::CreateDefault()); | |
std::unique_ptr<net::TransportSecurityState> transport_security_state( | |
new net::TransportSecurityState); | |
std::unique_ptr<net::MultiLogCTVerifier> ct_verifier(new net::MultiLogCTVerifier()); | |
ct_verifier->AddLogs(net::ct::CreateLogVerifiersForKnownLogs()); | |
std::unique_ptr<net::CTPolicyEnforcer> ct_policy_enforcer(new net::CTPolicyEnforcer()); | |
#endif | |
std::unique_ptr<net::ProofVerifier> proof_verifier; | |
proof_verifier.reset(new FakeProofVerifier()); | |
QuicClient client(net::QuicSocketAddress(ip_addr, port), server_id, | |
versions, std::move(proof_verifier)); | |
client.set_initial_max_packet_length(net::kDefaultMaxPacketSize); | |
if (!client.Initialize()) { | |
cerr << "Failed to initialize client." << endl; | |
return 1; | |
} | |
if (!client.Connect()) { | |
cerr << "Failed to connect." << endl; | |
return 1; | |
} | |
cout << "Connected" << endl; | |
client.SendRequestAndWaitForResponse(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "base/at_exit.h" | |
#include "base/message_loop/message_loop.h" | |
#include "base/threading/thread_task_runner_handle.h" | |
#include "net/cert/cert_verifier.h" | |
#include "net/cert/ct_known_logs.h" | |
#include "net/cert/ct_policy_enforcer.h" | |
#include "net/cert/multi_log_ct_verifier.h" | |
#include "net/http/transport_security_state.h" | |
#include "net/tools/quic/quic_client_base.h" | |
#include "net/tools/quic/quic_client_message_loop_network_helper.h" | |
#include "net/quic/chromium/quic_chromium_alarm_factory.h" | |
#include "net/quic/chromium/quic_chromium_connection_helper.h" | |
#include "net/quic/core/quic_config.h" // net::QuicConfig | |
#include "net/quic/platform/api/quic_ptr_util.h" | |
#include "net/quic/platform/api/quic_str_cat.h" | |
#include "net/quic/platform/impl/quic_chromium_clock.h" | |
#include "base/at_exit.h" | |
#include "base/command_line.h" | |
#include "base/logging.h" | |
#include "base/message_loop/message_loop.h" | |
#include "net/base/net_errors.h" | |
#include "net/base/privacy_mode.h" | |
#include "net/cert/cert_verifier.h" | |
#include "net/cert/ct_known_logs.h" | |
#include "net/cert/ct_log_verifier.h" | |
#include "net/cert/multi_log_ct_verifier.h" | |
#include "net/http/transport_security_state.h" | |
#include "net/quic/chromium/crypto/proof_verifier_chromium.h" | |
#include "net/quic/core/quic_error_codes.h" | |
#include "net/quic/core/quic_packets.h" | |
#include "net/quic/core/quic_server_id.h" | |
#include "net/quic/platform/api/quic_socket_address.h" | |
#include "net/quic/platform/api/quic_str_cat.h" | |
#include "net/quic/platform/api/quic_string_piece.h" | |
#include "net/quic/platform/api/quic_text_utils.h" | |
#include "net/spdy/chromium/spdy_http_utils.h" | |
#include "net/spdy/core/spdy_header_block.h" | |
#include "net/tools/quic/quic_simple_client.h" | |
#include "net/tools/quic/synchronous_host_resolver.h" | |
#include "url/gurl.h" | |
#include <iostream> | |
#include <string> | |
#include "base/at_exit.h" | |
#include "base/command_line.h" | |
#include "base/logging.h" | |
#include "base/message_loop/message_loop.h" | |
#include "base/run_loop.h" | |
#include "base/strings/string_number_conversions.h" | |
#include "net/base/ip_address.h" | |
#include "net/base/ip_endpoint.h" | |
#include "net/quic/chromium/crypto/proof_source_chromium.h" | |
#include "net/quic/core/quic_packets.h" | |
#include "net/tools/quic/quic_http_response_cache.h" | |
#include "net/tools/quic/quic_simple_server.h" | |
#include "net/socket/udp_server_socket.h" | |
#include "net/quic/core/quic_constants.h" | |
#include "net/quic/chromium/quic_chromium_connection_helper.h" | |
#include "net/tools/quic/quic_simple_server_session_helper.h" | |
#include "net/base/net_errors.h" | |
#include "net/tools/quic/quic_dispatcher.h" | |
#include "net/tools/quic/quic_simple_server_packet_writer.h" | |
using namespace std; | |
namespace { | |
const char kSourceAddressTokenSecret[] = "secret"; | |
const size_t kNumSessionsToCreatePerSocketEvent = 16; | |
// Allocate some extra space so we can send an error if the client goes over | |
// the limit. | |
const int kReadBufferSize = 2 * net::kMaxPacketSize; | |
std::unique_ptr<net::ProofSource> CreateProofSource( | |
const base::FilePath& cert_path, | |
const base::FilePath& key_path) { | |
std::unique_ptr<net::ProofSourceChromium> proof_source( | |
new net::ProofSourceChromium()); | |
CHECK(proof_source->Initialize(cert_path, key_path, base::FilePath())); | |
return std::move(proof_source); | |
} | |
class QCQuicStream : public net::QuicStream { | |
public: | |
QCQuicStream(net::QuicStreamId id, net::QuicSession* session) | |
: net::QuicStream(id, session) { | |
} | |
// Called when new data is available from the sequencer. Subclasses must | |
// actively retrieve the data using the sequencer's Readv() or | |
// GetReadableRegions() method. | |
void OnDataAvailable() override { | |
cout << "OnDataAvailable" << endl; | |
struct iovec iov; | |
while (sequencer()->GetReadableRegions(&iov, 1) == 1) { | |
string buf(static_cast<char *>(iov.iov_base), iov.iov_len); | |
cout << "while: " << buf << endl; | |
sequencer()->MarkConsumed(iov.iov_len); | |
} | |
if (sequencer()->IsClosed()) { | |
OnFinRead(); | |
cout << "OnDataAvailable finished" << endl; | |
} | |
} | |
}; | |
class QuartcCryptoServerStreamHelper : public net::QuicCryptoServerStream::Helper { | |
public: | |
net::QuicConnectionId GenerateConnectionIdForReject( | |
net::QuicConnectionId connection_id) const override; | |
bool CanAcceptClientHello(const net::CryptoHandshakeMessage& message, | |
const net::QuicSocketAddress& self_address, | |
std::string* error_details) const override; | |
}; | |
net::QuicConnectionId QuartcCryptoServerStreamHelper::GenerateConnectionIdForReject( | |
net::QuicConnectionId connection_id) const { | |
return 0; | |
} | |
bool QuartcCryptoServerStreamHelper::CanAcceptClientHello( | |
const net::CryptoHandshakeMessage& message, | |
const net::QuicSocketAddress& self_address, | |
string* error_details) const { | |
return true; | |
} | |
class QSQuicSession | |
: public net::QuicSession { | |
public: | |
QSQuicSession( | |
net::QuicConnection* connection, | |
net::QuicSession::Visitor* owner, | |
const net::QuicConfig& config, | |
const net::QuicCryptoServerConfig* crypto_config); | |
~QSQuicSession() override; | |
// Creates a new stream to handle a peer-initiated stream. | |
// Caller does not own the returned stream. | |
// Returns nullptr and does error handling if the stream can not be created. | |
net::QuicStream* CreateIncomingDynamicStream(net::QuicStreamId id) override { | |
cout << "CreateIncomingDynamicStream" << endl; | |
return CreateAndActivateStream(id); | |
} | |
// Create a new stream to handle a locally-initiated stream. | |
// Caller does not own the returned stream. | |
// Returns nullptr if max streams have already been opened. | |
net::QuicStream* CreateOutgoingDynamicStream(net::SpdyPriority priority) override { | |
cout << "CreateOutgoingDynamicStream" << endl; | |
return CreateAndActivateStream(GetNextOutgoingStreamId()); | |
} | |
// Return the reserved crypto stream. | |
net::QuicCryptoStream* GetMutableCryptoStream() override { | |
cout << "GetMutableCryptoStream" << endl; | |
return crypto_stream_.get(); | |
} | |
// Return the reserved crypto stream as a constant pointer. | |
const net::QuicCryptoStream* GetCryptoStream() const override { | |
cout << "GetCryptoStream" << endl; | |
//home/yota/github/proto-quic/src/net/quic/core/quic_crypto_client_stream.cc | |
// を参考に返す。 | |
return crypto_stream_.get(); | |
} | |
// Unconditionally creates a stream. Subclasses should use this to | |
// provide streams appropriately subclassed from |QuicStream|, | |
// e.g. |QuicSpdySession::CreateStream()| creates a |QuicSpdyStream|. | |
// net/quic/core/quic_spdy_session.cc | |
std::unique_ptr<net::QuicStream> CreateStream(net::QuicStreamId id) override { | |
cout << "CreateStream" << endl; | |
auto stream = net::QuicMakeUnique<QCQuicStream>(id, this); | |
if (!stream) { | |
cerr << "CreateStream() failed." << endl; | |
} | |
return stream; | |
} | |
private: | |
std::unique_ptr<net::QuicCryptoStream> crypto_stream_; | |
std::unique_ptr<net::QuicCompressedCertsCache> quic_compressed_certs_cache_; | |
QuartcCryptoServerStreamHelper stream_helper_; | |
}; | |
QSQuicSession::QSQuicSession( | |
net::QuicConnection* connection, | |
net::QuicSession::Visitor* owner, | |
const net::QuicConfig& config, | |
const net::QuicCryptoServerConfig* crypto_config) : | |
net::QuicSession(connection, owner, config) { | |
quic_compressed_certs_cache_.reset(new net::QuicCompressedCertsCache( | |
net::QuicCompressedCertsCache::kQuicCompressedCertsCacheSize)); | |
bool use_stateless_rejects_if_peer_supported = false; | |
net::QuicCryptoServerStream *s = new net::QuicCryptoServerStream( | |
crypto_config, | |
quic_compressed_certs_cache_.get(), | |
use_stateless_rejects_if_peer_supported, | |
this, | |
&stream_helper_); | |
crypto_stream_.reset(s); | |
QuicSession::Initialize(); | |
} | |
QSQuicSession::~QSQuicSession() { | |
delete connection(); | |
} | |
class QuicDispatcher : public net::QuicDispatcher { | |
public: | |
QuicDispatcher( | |
const net::QuicConfig& config, | |
const net::QuicCryptoServerConfig* crypto_config, | |
net::QuicVersionManager* version_manager, | |
std::unique_ptr<net::QuicConnectionHelperInterface> helper, | |
std::unique_ptr<net::QuicCryptoServerStream::Helper> session_helper, | |
std::unique_ptr<net::QuicAlarmFactory> alarm_factory); | |
~QuicDispatcher() override; | |
net::QuicSession* CreateQuicSession( | |
net::QuicConnectionId connection_id, | |
const net::QuicSocketAddress& client_address, | |
net::QuicStringPiece alpn) override; | |
void OnRstStreamReceived(const net::QuicRstStreamFrame& frame) override; | |
}; | |
QuicDispatcher::QuicDispatcher( | |
const net::QuicConfig& config, | |
const net::QuicCryptoServerConfig* crypto_config, | |
net::QuicVersionManager* version_manager, | |
std::unique_ptr<net::QuicConnectionHelperInterface> helper, | |
std::unique_ptr<net::QuicCryptoServerStream::Helper> session_helper, | |
std::unique_ptr<net::QuicAlarmFactory> alarm_factory) | |
: net::QuicDispatcher(config, | |
crypto_config, | |
version_manager, | |
std::move(helper), | |
std::move(session_helper), | |
std::move(alarm_factory)) { | |
} | |
QuicDispatcher::~QuicDispatcher() { | |
} | |
net::QuicSession* QuicDispatcher::CreateQuicSession( | |
net::QuicConnectionId connection_id, | |
const net::QuicSocketAddress& client_address, | |
net::QuicStringPiece alpn) { | |
cout << "QuicDispatcher::CreateQuicSession" << endl; | |
net::QuicConnection* connection = new net::QuicConnection( | |
connection_id, client_address, helper(), alarm_factory(), | |
CreatePerConnectionWriter(), | |
/* owns_writer= */ true, net::Perspective::IS_SERVER, GetSupportedVersions()); | |
QSQuicSession *session = new QSQuicSession(connection, | |
nullptr, | |
config(), | |
crypto_config()); | |
return session; | |
} | |
void QuicDispatcher::OnRstStreamReceived(const net::QuicRstStreamFrame& frame) { | |
cout << "QuicDispatcher::OnRstStreamReceived" << endl; | |
net::QuicDispatcher::OnRstStreamReceived(frame); | |
} | |
class QuicServer { | |
public: | |
QuicServer( | |
std::unique_ptr<net::ProofSource> proof_source, | |
const net::QuicConfig config, | |
const net::QuicCryptoServerConfig::ConfigOptions& crypto_config_options, | |
const net::QuicVersionVector& supported_versions); | |
~QuicServer(); | |
int Listen(const net::IPEndPoint& address); | |
void Shutdown(); | |
void OnReadComplete(int result); | |
private: | |
std::unique_ptr<net::UDPServerSocket> socket_; | |
// config_ contains non-crypto parameters that are negotiated in the crypto | |
// handshake. | |
net::QuicConfig config_; | |
// crypto_config_ contains crypto parameters that are negotiated in the crypto | |
// handshake. | |
net::QuicCryptoServerConfig::ConfigOptions crypto_config_options_; | |
// crypto_config_ contains crypto parameters for the handshake. | |
net::QuicCryptoServerConfig crypto_config_; | |
net::QuicVersionManager version_manager_; | |
// Used by the helper_ to time alarms. | |
net::QuicChromiumClock clock_; | |
// Used to manage the message loop. Owned by dispatcher_. | |
net::QuicChromiumConnectionHelper* helper_; | |
// Used to manage the message loop. Owned by dispatcher_. | |
net::QuicChromiumAlarmFactory* alarm_factory_; | |
// The log to use for the socket. | |
net::NetLog net_log_; | |
// The address that the server listens on. | |
net::IPEndPoint server_address_; | |
// The source address of the current read. | |
net::IPEndPoint client_address_; | |
std::unique_ptr<QuicDispatcher> dispatcher_; | |
// Keeps track of whether a read is currently in flight, after which | |
// OnReadComplete will be called. | |
bool read_pending_; | |
int synchronous_read_count_; | |
// The target buffer of the current read. | |
scoped_refptr<net::IOBufferWithSize> read_buffer_; | |
base::WeakPtrFactory<QuicServer> weak_factory_; | |
void Initialize(); | |
void StartReading(); | |
}; | |
QuicServer::QuicServer( | |
std::unique_ptr<net::ProofSource> proof_source, | |
const net::QuicConfig config, | |
const net::QuicCryptoServerConfig::ConfigOptions& crypto_config_options, | |
const net::QuicVersionVector& supported_versions) | |
: config_(config) | |
, crypto_config_options_(crypto_config_options) | |
, crypto_config_(kSourceAddressTokenSecret, | |
net::QuicRandom::GetInstance(), | |
std::move(proof_source)) | |
, version_manager_(supported_versions) | |
, helper_( | |
new net::QuicChromiumConnectionHelper(&clock_, net::QuicRandom::GetInstance())) | |
, alarm_factory_(new net::QuicChromiumAlarmFactory( | |
base::ThreadTaskRunnerHandle::Get().get(), | |
&clock_)) | |
, read_pending_(false) | |
, synchronous_read_count_(0) | |
, read_buffer_(new net::IOBufferWithSize(kReadBufferSize)) | |
, weak_factory_(this) { | |
Initialize(); | |
} | |
QuicServer::~QuicServer() {} | |
int QuicServer::Listen(const net::IPEndPoint& address) { | |
std::unique_ptr<net::UDPServerSocket> socket( | |
new net::UDPServerSocket(&net_log_, net::NetLogSource())); | |
socket->AllowAddressReuse(); | |
int rc = socket->Listen(address); | |
if (rc < 0) { | |
cerr << "Listen() failed: " << net::ErrorToString(rc) << endl; | |
return rc; | |
} | |
// These send and receive buffer sizes are sized for a single connection, | |
// because the default usage of QuicSimpleServer is as a test server with | |
// one or two clients. Adjust higher for use with many clients. | |
rc = socket->SetReceiveBufferSize( | |
static_cast<int32_t>(net::kDefaultSocketReceiveBuffer)); | |
if (rc < 0) { | |
cerr << "SetReceiveBufferSize() failed: " << net::ErrorToString(rc) << endl; | |
return rc; | |
} | |
rc = socket->SetSendBufferSize(20 * net::kMaxPacketSize); | |
if (rc < 0) { | |
cerr << "SetSendBufferSize() failed: " << net::ErrorToString(rc) << endl; | |
return rc; | |
} | |
rc = socket->GetLocalAddress(&server_address_); | |
if (rc < 0) { | |
cerr << "GetLocalAddress() failed: " << net::ErrorToString(rc) << endl; | |
return rc; | |
} | |
cout << "Listening on " << server_address_.ToString() << endl;; | |
socket_.swap(socket); | |
dispatcher_.reset(new QuicDispatcher( | |
config_, &crypto_config_, &version_manager_, | |
std::unique_ptr<net::QuicConnectionHelperInterface>(helper_), | |
std::unique_ptr<net::QuicCryptoServerStream::Helper>( | |
new net::QuicSimpleServerSessionHelper(net::QuicRandom::GetInstance())), | |
std::unique_ptr<net::QuicAlarmFactory>(alarm_factory_))); | |
net::QuicSimpleServerPacketWriter* writer = | |
new net::QuicSimpleServerPacketWriter(socket_.get(), dispatcher_.get()); | |
dispatcher_->InitializeWithWriter(writer); | |
StartReading(); | |
return net::OK; | |
} | |
void QuicServer::Shutdown() { | |
dispatcher_->Shutdown(); | |
socket_->Close(); | |
socket_.reset(); | |
} | |
void QuicServer::OnReadComplete(int result) { | |
cout << "QuicServer::OnReadComplete: " << result << endl; | |
read_pending_ = false; | |
if (result == 0) | |
result = net::ERR_CONNECTION_CLOSED; | |
if (result < 0) { | |
cerr << "QuicSimpleServer read failed: " << net::ErrorToString(result) << endl; | |
Shutdown(); | |
return; | |
} | |
net::QuicReceivedPacket packet(read_buffer_->data(), result, | |
helper_->GetClock()->Now(), false); | |
dispatcher_->ProcessPacket( | |
net::QuicSocketAddress(net::QuicSocketAddressImpl(server_address_)), | |
net::QuicSocketAddress(net::QuicSocketAddressImpl(client_address_)), packet); | |
StartReading(); | |
} | |
void QuicServer::Initialize() { | |
// If an initial flow control window has not explicitly been set, then use a | |
// sensible value for a server: 1 MB for session, 64 KB for each stream. | |
const uint32_t kInitialSessionFlowControlWindow = 1 * 1024 * 1024; // 1 MB | |
const uint32_t kInitialStreamFlowControlWindow = 64 * 1024; // 64 KB | |
if (config_.GetInitialStreamFlowControlWindowToSend() == | |
net::kMinimumFlowControlSendWindow) { | |
config_.SetInitialStreamFlowControlWindowToSend( | |
kInitialStreamFlowControlWindow); | |
} | |
if (config_.GetInitialSessionFlowControlWindowToSend() == | |
net::kMinimumFlowControlSendWindow) { | |
config_.SetInitialSessionFlowControlWindowToSend( | |
kInitialSessionFlowControlWindow); | |
} | |
std::unique_ptr<net::CryptoHandshakeMessage> scfg(crypto_config_.AddDefaultConfig( | |
helper_->GetRandomGenerator(), helper_->GetClock(), | |
crypto_config_options_)); | |
} | |
void QuicServer::StartReading() { | |
cout << "QuicServer::StartReading 1" << endl; | |
if (synchronous_read_count_ == 0) { | |
// Only process buffered packets once per message loop. | |
dispatcher_->ProcessBufferedChlos(kNumSessionsToCreatePerSocketEvent); | |
cout << "QuicServer::StartReading 2" << endl; | |
} | |
cout << "QuicServer::StartReading 3" << endl; | |
if (read_pending_) { | |
cout << "QuicServer::StartReading 4" << endl; | |
return; | |
} | |
read_pending_ = true; | |
int result = socket_->RecvFrom( | |
read_buffer_.get(), read_buffer_->size(), &client_address_, | |
base::Bind(&QuicServer::OnReadComplete, base::Unretained(this))); | |
if (result == net::ERR_IO_PENDING) { | |
synchronous_read_count_ = 0; | |
if (dispatcher_->HasChlosBuffered()) { | |
// No more packets to read, so yield before processing buffered packets. | |
base::ThreadTaskRunnerHandle::Get()->PostTask( | |
FROM_HERE, base::Bind(&QuicServer::StartReading, | |
weak_factory_.GetWeakPtr())); | |
cout << "QuicServer::StartReading 5" << endl; | |
} | |
cout << "QuicServer::StartReading 6" << endl; | |
return; | |
} | |
if (++synchronous_read_count_ > 32) { | |
synchronous_read_count_ = 0; | |
cout << "QuicServer::StartReading 7" << endl; | |
// Schedule the processing through the message loop to 1) prevent infinite | |
// recursion and 2) avoid blocking the thread for too long. | |
base::ThreadTaskRunnerHandle::Get()->PostTask( | |
FROM_HERE, base::Bind(&QuicServer::OnReadComplete, | |
weak_factory_.GetWeakPtr(), result)); | |
cout << "QuicServer::StartReading 8" << endl; | |
} else { | |
cout << "QuicServer::StartReading 9" << endl; | |
OnReadComplete(result); | |
} | |
} | |
} // namespace | |
int main() { | |
base::AtExitManager exit_manager; | |
base::MessageLoopForIO message_loop; | |
net::QuicConfig config; | |
QuicServer server( | |
CreateProofSource( | |
base::FilePath("net/tools/quic/certs/out/leaf_cert.pem"), | |
base::FilePath("net/tools/quic/certs/out/leaf_cert.pkcs8")), | |
config, | |
net::QuicCryptoServerConfig::ConfigOptions(), | |
net::AllSupportedVersions()); | |
net::IPAddress ip = net::IPAddress::IPv6AllZeros(); | |
int port = 6121; | |
int rc = server.Listen(net::IPEndPoint(ip, port)); | |
if (rc < 0) { | |
return 1; | |
} | |
base::RunLoop().Run(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment