Skip to content

Instantly share code, notes, and snippets.

@nus
Last active November 19, 2017 14:53
Show Gist options
  • Save nus/ebeaa10427bbba34963642a8e6237e5c to your computer and use it in GitHub Desktop.
Save nus/ebeaa10427bbba34963642a8e6237e5c to your computer and use it in GitHub Desktop.
Quic memo. バックアップ用とのため実装は中途半端。https://github.com/google/proto-quic 1694fa55a19d7e03103f65d69360bd7ff05389c8
#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();
}
#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