Commit c6e8e367 authored by Victor Vasiliev's avatar Victor Vasiliev Committed by Commit Bot

Add quic_transport_simple_server

quic_transport_simple_server is a simple QuicTransport server that can
discard or echo back all of the traffic it receives, depending on how
it's configured.

Note that I've not tested the functionality of this server fully (as I
don't have a corresponding client binary), but it does correctly parse
ALPN and reject HTTP/3 when offered.

R=rch@chromium.org

Change-Id: I6396e95d180a41a9afdb185f0891c787d0c67c36
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1903958
Commit-Queue: Victor Vasiliev <vasilvv@chromium.org>
Reviewed-by: default avatarRyan Hamilton <rch@chromium.org>
Cr-Commit-Position: refs/heads/master@{#714007}
parent 9c9eb002
...@@ -3568,6 +3568,8 @@ source_set("simple_quic_tools") { ...@@ -3568,6 +3568,8 @@ source_set("simple_quic_tools") {
"tools/quic/quic_simple_server_session_helper.h", "tools/quic/quic_simple_server_session_helper.h",
"tools/quic/quic_simple_server_socket.cc", "tools/quic/quic_simple_server_socket.cc",
"tools/quic/quic_simple_server_socket.h", "tools/quic/quic_simple_server_socket.h",
"tools/quic/quic_transport_simple_server.cc",
"tools/quic/quic_transport_simple_server.h",
"tools/quic/synchronous_host_resolver.cc", "tools/quic/synchronous_host_resolver.cc",
"tools/quic/synchronous_host_resolver.h", "tools/quic/synchronous_host_resolver.h",
] ]
...@@ -3613,6 +3615,19 @@ if (!is_ios) { ...@@ -3613,6 +3615,19 @@ if (!is_ios) {
"//third_party/protobuf:protobuf_lite", "//third_party/protobuf:protobuf_lite",
] ]
} }
executable("quic_transport_simple_server") {
sources = [
"tools/quic/quic_transport_simple_server_bin.cc",
]
deps = [
":net",
":simple_quic_tools",
"//base",
"//build/win:default_exe_manifest",
"//third_party/boringssl",
"//third_party/protobuf:protobuf_lite",
]
}
executable("quic_packet_printer") { executable("quic_packet_printer") {
sources = [ sources = [
"third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc", "third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc",
......
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/tools/quic/quic_transport_simple_server.h"
#include <stdlib.h>
#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/net_errors.h"
#include "net/quic/address_utils.h"
#include "net/quic/platform/impl/quic_chromium_clock.h"
#include "net/quic/quic_chromium_alarm_factory.h"
#include "net/quic/quic_chromium_connection_helper.h"
#include "net/socket/udp_server_socket.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h"
#include "net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.h"
#include "net/tools/quic/quic_simple_server_packet_writer.h"
#include "net/tools/quic/quic_simple_server_socket.h"
namespace net {
namespace {
using quic::CryptoHandshakeMessage;
using quic::ParsedQuicVersion;
using quic::PROTOCOL_TLS1_3;
using quic::QUIC_VERSION_99;
using quic::QuicChromiumClock;
using quic::QuicCryptoServerStream;
using quic::QuicSocketAddress;
using quic::QuicTransportSimpleServerSession;
constexpr char kSourceAddressTokenSecret[] = "test";
constexpr size_t kMaxReadsPerEvent = 32;
constexpr size_t kMaxNewConnectionsPerEvent = 32;
constexpr int kReadBufferSize = 2 * quic::kMaxIncomingPacketSize;
} // namespace
class QuicTransportSimpleServerSessionHelper
: public QuicCryptoServerStream::Helper {
public:
bool CanAcceptClientHello(const CryptoHandshakeMessage& /*message*/,
const QuicSocketAddress& /*client_address*/,
const QuicSocketAddress& /*peer_address*/,
const QuicSocketAddress& /*self_address*/,
std::string* /*error_details*/) const override {
return true;
}
};
QuicTransportSimpleServer::QuicTransportSimpleServer(
int port,
QuicTransportSimpleServerSession::Mode mode,
std::vector<url::Origin> accepted_origins)
: port_(port),
version_manager_({ParsedQuicVersion{PROTOCOL_TLS1_3, QUIC_VERSION_99}}),
clock_(QuicChromiumClock::GetInstance()),
crypto_config_(kSourceAddressTokenSecret,
quic::QuicRandom::GetInstance(),
quic::CreateDefaultProofSource(),
quic::KeyExchangeSource::Default()),
dispatcher_(&config_,
&crypto_config_,
&version_manager_,
std::make_unique<QuicChromiumConnectionHelper>(
clock_,
quic::QuicRandom::GetInstance()),
std::make_unique<QuicTransportSimpleServerSessionHelper>(),
std::make_unique<QuicChromiumAlarmFactory>(
base::ThreadTaskRunnerHandle::Get().get(),
clock_),
quic::kQuicDefaultConnectionIdLength,
mode,
accepted_origins),
read_buffer_(base::MakeRefCounted<IOBufferWithSize>(kReadBufferSize)) {}
QuicTransportSimpleServer::~QuicTransportSimpleServer() {}
int QuicTransportSimpleServer::Run() {
socket_ = CreateQuicSimpleServerSocket(
IPEndPoint{IPAddress::IPv6AllZeros(), port_}, &server_address_);
if (socket_ == nullptr)
return EXIT_FAILURE;
dispatcher_.InitializeWithWriter(
new QuicSimpleServerPacketWriter(socket_.get(), &dispatcher_));
ScheduleReadPackets();
base::RunLoop().Run();
return EXIT_SUCCESS;
}
void QuicTransportSimpleServer::ScheduleReadPackets() {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&QuicTransportSimpleServer::ReadPackets,
weak_factory_.GetWeakPtr()));
}
void QuicTransportSimpleServer::ReadPackets() {
dispatcher_.ProcessBufferedChlos(kMaxNewConnectionsPerEvent);
for (size_t i = 0; i < kMaxReadsPerEvent; i++) {
int result = socket_->RecvFrom(
read_buffer_.get(), read_buffer_->size(), &client_address_,
base::BindOnce(&QuicTransportSimpleServer::OnReadComplete,
base::Unretained(this)));
if (result == ERR_IO_PENDING)
return;
ProcessReadPacket(result);
}
ScheduleReadPackets();
}
void QuicTransportSimpleServer::OnReadComplete(int result) {
ProcessReadPacket(result);
ReadPackets();
}
void QuicTransportSimpleServer::ProcessReadPacket(int result) {
if (result == 0)
result = ERR_CONNECTION_CLOSED;
if (result < 0) {
LOG(ERROR) << "QuicTransportSimpleServer read failed: "
<< ErrorToString(result);
dispatcher_.Shutdown();
exit(EXIT_FAILURE);
return;
}
quic::QuicReceivedPacket packet(read_buffer_->data(), /*length=*/result,
clock_->Now(), /*owns_buffer=*/false);
dispatcher_.ProcessPacket(ToQuicSocketAddress(server_address_),
ToQuicSocketAddress(client_address_), packet);
}
} // namespace net
// Copyright (c) 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_TOOLS_QUIC_QUIC_TRANSPORT_SIMPLE_SERVER_H_
#define NET_TOOLS_QUIC_QUIC_TRANSPORT_SIMPLE_SERVER_H_
#include "base/memory/weak_ptr.h"
#include "net/base/io_buffer.h"
#include "net/base/ip_endpoint.h"
#include "net/quic/platform/impl/quic_chromium_clock.h"
#include "net/socket/udp_server_socket.h"
#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
#include "net/third_party/quiche/src/quic/core/quic_config.h"
#include "net/third_party/quiche/src/quic/core/quic_version_manager.h"
#include "net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.h"
#include "net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h"
#include "url/origin.h"
namespace net {
// Server for QuicTransportSimpleSession. This class is responsible for
// creating a UDP server socket, listening on it and passing the packets
// received to the dispatcher.
class QuicTransportSimpleServer {
public:
QuicTransportSimpleServer(int port,
quic::QuicTransportSimpleServerSession::Mode mode,
std::vector<url::Origin> accepted_origins);
~QuicTransportSimpleServer();
int Run();
private:
// Schedules a ReadPackets() call on the next iteration of the event loop.
void ScheduleReadPackets();
// Reads a fixed number of packets and then reschedules itself.
void ReadPackets();
// Called when an asynchronous read from the socket is complete.
void OnReadComplete(int result);
// Passes the most recently read packet into the dispatcher.
void ProcessReadPacket(int result);
const int port_;
quic::QuicVersionManager version_manager_;
quic::QuicChromiumClock* clock_; // Not owned.
quic::QuicConfig config_;
quic::QuicCryptoServerConfig crypto_config_;
quic::QuicTransportSimpleServerDispatcher dispatcher_;
std::unique_ptr<UDPServerSocket> socket_;
IPEndPoint server_address_;
// Results of the potentially asynchronous read operation.
scoped_refptr<IOBufferWithSize> read_buffer_;
IPEndPoint client_address_;
base::WeakPtrFactory<QuicTransportSimpleServer> weak_factory_{this};
};
} // namespace net
#endif // NET_TOOLS_QUIC_QUIC_TRANSPORT_SIMPLE_SERVER_H_
// Copyright (c) 2019 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 "base/strings/string_split.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_system_event_loop.h"
#include "net/tools/quic/quic_transport_simple_server.h"
#include "url/gurl.h"
DEFINE_QUIC_COMMAND_LINE_FLAG(int, port, 20557, "The port to listen on.");
DEFINE_QUIC_COMMAND_LINE_FLAG(
std::string,
mode,
"discard",
"The mode used by the SimpleServer. Can be \"echo\" or \"discard\".");
DEFINE_QUIC_COMMAND_LINE_FLAG(std::string,
accepted_origins,
"",
"Comma-separated list of accepted origins");
int main(int argc, char** argv) {
const char* usage = "quic_transport_simple_server";
QuicSystemEventLoop event_loop("quic_transport_simple_server");
std::vector<std::string> non_option_args =
quic::QuicParseCommandLineFlags(usage, argc, argv);
if (!non_option_args.empty()) {
quic::QuicPrintCommandLineFlagHelp(usage);
return 0;
}
std::string mode_text = GetQuicFlag(FLAGS_mode);
quic::QuicTransportSimpleServerSession::Mode mode;
if (mode_text == "discard") {
mode = quic::QuicTransportSimpleServerSession::DISCARD;
} else if (mode_text == "echo") {
mode = quic::QuicTransportSimpleServerSession::ECHO;
} else {
LOG(ERROR) << "Invalid mode specified: " << mode_text;
return 1;
}
std::string accepted_origins_text = GetQuicFlag(FLAGS_accepted_origins);
std::vector<url::Origin> accepted_origins;
for (const base::StringPiece& origin :
base::SplitStringPiece(accepted_origins_text, ",", base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY)) {
GURL url{origin};
if (!url.is_valid()) {
LOG(ERROR) << "Failed to parse origin specified: " << origin;
return 1;
}
accepted_origins.push_back(url::Origin::Create(url));
}
net::QuicTransportSimpleServer server(GetQuicFlag(FLAGS_port), mode,
accepted_origins);
return server.Run();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment