xref: /aosp_15_r20/external/cronet/net/tools/quic/quic_simple_server.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/tools/quic/quic_simple_server.h"
6 
7 #include <string.h>
8 
9 #include <memory>
10 
11 #include "base/functional/bind.h"
12 #include "base/location.h"
13 #include "base/run_loop.h"
14 #include "base/task/single_thread_task_runner.h"
15 #include "net/base/ip_endpoint.h"
16 #include "net/base/net_errors.h"
17 #include "net/log/net_log_source.h"
18 #include "net/quic/address_utils.h"
19 #include "net/socket/udp_server_socket.h"
20 #include "net/third_party/quiche/src/quiche/quic/core/crypto/crypto_handshake.h"
21 #include "net/third_party/quiche/src/quiche/quic/core/crypto/quic_random.h"
22 #include "net/third_party/quiche/src/quiche/quic/core/quic_crypto_stream.h"
23 #include "net/third_party/quiche/src/quiche/quic/core/quic_data_reader.h"
24 #include "net/third_party/quiche/src/quiche/quic/core/quic_packets.h"
25 #include "net/third_party/quiche/src/quiche/quic/tools/quic_simple_dispatcher.h"
26 #include "net/tools/quic/quic_simple_server_packet_writer.h"
27 #include "net/tools/quic/quic_simple_server_session_helper.h"
28 #include "net/tools/quic/quic_simple_server_socket.h"
29 
30 namespace net {
31 
32 namespace {
33 
34 const char kSourceAddressTokenSecret[] = "secret";
35 const size_t kNumSessionsToCreatePerSocketEvent = 16;
36 
37 // Allocate some extra space so we can send an error if the client goes over
38 // the limit.
39 const int kReadBufferSize = 2 * quic::kMaxIncomingPacketSize;
40 
41 }  // namespace
42 
QuicSimpleServer(std::unique_ptr<quic::ProofSource> proof_source,const quic::QuicConfig & config,const quic::QuicCryptoServerConfig::ConfigOptions & crypto_config_options,const quic::ParsedQuicVersionVector & supported_versions,quic::QuicSimpleServerBackend * quic_simple_server_backend)43 QuicSimpleServer::QuicSimpleServer(
44     std::unique_ptr<quic::ProofSource> proof_source,
45     const quic::QuicConfig& config,
46     const quic::QuicCryptoServerConfig::ConfigOptions& crypto_config_options,
47     const quic::ParsedQuicVersionVector& supported_versions,
48     quic::QuicSimpleServerBackend* quic_simple_server_backend)
49     : version_manager_(supported_versions),
50       helper_(
51           new QuicChromiumConnectionHelper(&clock_,
52                                            quic::QuicRandom::GetInstance())),
53       alarm_factory_(new QuicChromiumAlarmFactory(
54           base::SingleThreadTaskRunner::GetCurrentDefault().get(),
55           &clock_)),
56       config_(config),
57       crypto_config_options_(crypto_config_options),
58       crypto_config_(kSourceAddressTokenSecret,
59                      quic::QuicRandom::GetInstance(),
60                      std::move(proof_source),
61                      quic::KeyExchangeSource::Default()),
62       read_buffer_(base::MakeRefCounted<IOBufferWithSize>(kReadBufferSize)),
63       quic_simple_server_backend_(quic_simple_server_backend),
64       connection_id_generator_(quic::kQuicDefaultConnectionIdLength) {
65   DCHECK(quic_simple_server_backend);
66   Initialize();
67 }
68 
Initialize()69 void QuicSimpleServer::Initialize() {
70   // If an initial flow control window has not explicitly been set, then use a
71   // sensible value for a server: 1 MB for session, 64 KB for each stream.
72   const uint32_t kInitialSessionFlowControlWindow = 1 * 1024 * 1024;  // 1 MB
73   const uint32_t kInitialStreamFlowControlWindow = 64 * 1024;         // 64 KB
74   if (config_.GetInitialStreamFlowControlWindowToSend() ==
75       quic::kMinimumFlowControlSendWindow) {
76     config_.SetInitialStreamFlowControlWindowToSend(
77         kInitialStreamFlowControlWindow);
78   }
79   if (config_.GetInitialSessionFlowControlWindowToSend() ==
80       quic::kMinimumFlowControlSendWindow) {
81     config_.SetInitialSessionFlowControlWindowToSend(
82         kInitialSessionFlowControlWindow);
83   }
84 
85   std::unique_ptr<quic::CryptoHandshakeMessage> scfg(
86       crypto_config_.AddDefaultConfig(helper_->GetRandomGenerator(),
87                                       helper_->GetClock(),
88                                       crypto_config_options_));
89 }
90 
91 QuicSimpleServer::~QuicSimpleServer() = default;
92 
CreateUDPSocketAndListen(const quic::QuicSocketAddress & address)93 bool QuicSimpleServer::CreateUDPSocketAndListen(
94     const quic::QuicSocketAddress& address) {
95   return Listen(ToIPEndPoint(address));
96 }
97 
HandleEventsForever()98 void QuicSimpleServer::HandleEventsForever() {
99   base::RunLoop().Run();
100 }
101 
Listen(const IPEndPoint & address)102 bool QuicSimpleServer::Listen(const IPEndPoint& address) {
103   socket_ = CreateQuicSimpleServerSocket(address, &server_address_);
104   if (socket_ == nullptr)
105     return false;
106 
107   dispatcher_ = std::make_unique<quic::QuicSimpleDispatcher>(
108       &config_, &crypto_config_, &version_manager_,
109       std::unique_ptr<quic::QuicConnectionHelperInterface>(helper_),
110       std::make_unique<QuicSimpleServerSessionHelper>(
111           quic::QuicRandom::GetInstance()),
112       std::unique_ptr<quic::QuicAlarmFactory>(alarm_factory_),
113       quic_simple_server_backend_, quic::kQuicDefaultConnectionIdLength,
114       connection_id_generator_);
115   QuicSimpleServerPacketWriter* writer =
116       new QuicSimpleServerPacketWriter(socket_.get(), dispatcher_.get());
117   dispatcher_->InitializeWithWriter(writer);
118 
119   StartReading();
120 
121   return true;
122 }
123 
Shutdown()124 void QuicSimpleServer::Shutdown() {
125   DVLOG(1) << "QuicSimpleServer is shutting down";
126   // Before we shut down the epoll server, give all active sessions a chance to
127   // notify clients that they're closing.
128   dispatcher_->Shutdown();
129 
130   if (!socket_) {
131     return;
132   }
133   socket_->Close();
134   socket_.reset();
135 }
136 
StartReading()137 void QuicSimpleServer::StartReading() {
138   if (synchronous_read_count_ == 0) {
139     // Only process buffered packets once per message loop.
140     dispatcher_->ProcessBufferedChlos(kNumSessionsToCreatePerSocketEvent);
141   }
142 
143   if (read_pending_) {
144     return;
145   }
146   read_pending_ = true;
147 
148   int result = socket_->RecvFrom(
149       read_buffer_.get(), read_buffer_->size(), &client_address_,
150       base::BindOnce(&QuicSimpleServer::OnReadComplete,
151                      base::Unretained(this)));
152 
153   if (result == ERR_IO_PENDING) {
154     synchronous_read_count_ = 0;
155     if (dispatcher_->HasChlosBuffered()) {
156       // No more packets to read, so yield before processing buffered packets.
157       base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
158           FROM_HERE, base::BindOnce(&QuicSimpleServer::StartReading,
159                                     weak_factory_.GetWeakPtr()));
160     }
161     return;
162   }
163 
164   if (++synchronous_read_count_ > 32) {
165     synchronous_read_count_ = 0;
166     // Schedule the processing through the message loop to 1) prevent infinite
167     // recursion and 2) avoid blocking the thread for too long.
168     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
169         FROM_HERE, base::BindOnce(&QuicSimpleServer::OnReadComplete,
170                                   weak_factory_.GetWeakPtr(), result));
171   } else {
172     OnReadComplete(result);
173   }
174 }
175 
OnReadComplete(int result)176 void QuicSimpleServer::OnReadComplete(int result) {
177   read_pending_ = false;
178 
179   if (result > 0) {
180     quic::QuicReceivedPacket packet(read_buffer_->data(), result,
181                                     helper_->GetClock()->Now(), false);
182     dispatcher_->ProcessPacket(ToQuicSocketAddress(server_address_),
183                                ToQuicSocketAddress(client_address_), packet);
184   } else {
185     LOG(ERROR) << "QuicSimpleServer read failed: " << ErrorToString(result);
186     // Do not act on ERR_MSG_TOO_BIG as that indicates that we received a UDP
187     // packet whose payload is larger than our receive buffer. Do not act on 0
188     // as that indicates that we received a UDP packet with an empty payload.
189     // In both cases, the socket should still be usable.
190     // Also do not act on ERR_CONNECTION_RESET as this is happening when the
191     // network service restarts on Windows.
192     if (result != ERR_MSG_TOO_BIG && result != ERR_CONNECTION_RESET &&
193         result != 0) {
194       Shutdown();
195       return;
196     }
197   }
198 
199   StartReading();
200 }
201 
202 }  // namespace net
203