Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / tools / quic / quic_simple_server.cc
blobf7fc9427d102b95ec19cf5b4b68bd726a54954f7
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/tools/quic/quic_simple_server.h"
7 #include <string.h>
9 #include "base/location.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "net/base/ip_endpoint.h"
13 #include "net/base/net_errors.h"
14 #include "net/quic/crypto/crypto_handshake.h"
15 #include "net/quic/crypto/quic_random.h"
16 #include "net/quic/quic_crypto_stream.h"
17 #include "net/quic/quic_data_reader.h"
18 #include "net/quic/quic_protocol.h"
19 #include "net/tools/quic/quic_dispatcher.h"
20 #include "net/tools/quic/quic_simple_per_connection_packet_writer.h"
21 #include "net/tools/quic/quic_simple_server_packet_writer.h"
22 #include "net/udp/udp_server_socket.h"
24 namespace net {
25 namespace tools {
27 namespace {
29 const char kSourceAddressTokenSecret[] = "secret";
31 // Allocate some extra space so we can send an error if the client goes over
32 // the limit.
33 const int kReadBufferSize = 2 * kMaxPacketSize;
35 // A packet writer factory which wraps a shared QuicSimpleServerPacketWriter
36 // inside of a QuicPerConnectionPacketWriter. Instead of checking that
37 // the shared_writer is the expected writer, this could instead cast
38 // from QuicPacketWriter to QuicSimpleServerPacketWriter.
39 class CustomPacketWriterFactory : public QuicDispatcher::PacketWriterFactory {
40 public:
41 ~CustomPacketWriterFactory() override {}
43 QuicPacketWriter* Create(QuicPacketWriter* writer,
44 QuicConnection* connection) override {
45 if (writer == nullptr) {
46 LOG(DFATAL) << "shared_writer not initialized";
47 return nullptr;
49 if (writer != shared_writer_) {
50 LOG(DFATAL) << "writer mismatch";
51 return nullptr;
53 return new QuicSimplePerConnectionPacketWriter(shared_writer_, connection);
56 void set_shared_writer(QuicSimpleServerPacketWriter* shared_writer) {
57 shared_writer_ = shared_writer;
60 private:
61 QuicSimpleServerPacketWriter* shared_writer_; // Not owned.
64 } // namespace
66 QuicSimpleServer::QuicSimpleServer(const QuicConfig& config,
67 const QuicVersionVector& supported_versions)
68 : helper_(base::ThreadTaskRunnerHandle::Get().get(),
69 &clock_,
70 QuicRandom::GetInstance()),
71 config_(config),
72 crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()),
73 supported_versions_(supported_versions),
74 read_pending_(false),
75 synchronous_read_count_(0),
76 read_buffer_(new IOBufferWithSize(kReadBufferSize)),
77 weak_factory_(this) {
78 Initialize();
81 void QuicSimpleServer::Initialize() {
82 #if MMSG_MORE
83 use_recvmmsg_ = true;
84 #endif
86 // If an initial flow control window has not explicitly been set, then use a
87 // sensible value for a server: 1 MB for session, 64 KB for each stream.
88 const uint32 kInitialSessionFlowControlWindow = 1 * 1024 * 1024; // 1 MB
89 const uint32 kInitialStreamFlowControlWindow = 64 * 1024; // 64 KB
90 if (config_.GetInitialStreamFlowControlWindowToSend() ==
91 kMinimumFlowControlSendWindow) {
92 config_.SetInitialStreamFlowControlWindowToSend(
93 kInitialStreamFlowControlWindow);
95 if (config_.GetInitialSessionFlowControlWindowToSend() ==
96 kMinimumFlowControlSendWindow) {
97 config_.SetInitialSessionFlowControlWindowToSend(
98 kInitialSessionFlowControlWindow);
101 scoped_ptr<CryptoHandshakeMessage> scfg(
102 crypto_config_.AddDefaultConfig(
103 helper_.GetRandomGenerator(), helper_.GetClock(),
104 QuicCryptoServerConfig::ConfigOptions()));
107 QuicSimpleServer::~QuicSimpleServer() {
110 int QuicSimpleServer::Listen(const IPEndPoint& address) {
111 scoped_ptr<UDPServerSocket> socket(
112 new UDPServerSocket(&net_log_, NetLog::Source()));
114 socket->AllowAddressReuse();
116 int rc = socket->Listen(address);
117 if (rc < 0) {
118 LOG(ERROR) << "Listen() failed: " << ErrorToString(rc);
119 return rc;
122 // These send and receive buffer sizes are sized for a single connection,
123 // because the default usage of QuicSimpleServer is as a test server with
124 // one or two clients. Adjust higher for use with many clients.
125 rc = socket->SetReceiveBufferSize(
126 static_cast<int32>(kDefaultSocketReceiveBuffer));
127 if (rc < 0) {
128 LOG(ERROR) << "SetReceiveBufferSize() failed: " << ErrorToString(rc);
129 return rc;
132 rc = socket->SetSendBufferSize(20 * kMaxPacketSize);
133 if (rc < 0) {
134 LOG(ERROR) << "SetSendBufferSize() failed: " << ErrorToString(rc);
135 return rc;
138 rc = socket->GetLocalAddress(&server_address_);
139 if (rc < 0) {
140 LOG(ERROR) << "GetLocalAddress() failed: " << ErrorToString(rc);
141 return rc;
144 DVLOG(1) << "Listening on " << server_address_.ToString();
146 socket_.swap(socket);
148 CustomPacketWriterFactory* factory = new CustomPacketWriterFactory();
149 dispatcher_.reset(
150 new QuicDispatcher(config_,
151 &crypto_config_,
152 supported_versions_,
153 factory,
154 &helper_));
155 QuicSimpleServerPacketWriter* writer = new QuicSimpleServerPacketWriter(
156 socket_.get(),
157 dispatcher_.get());
158 factory->set_shared_writer(writer);
159 dispatcher_->InitializeWithWriter(writer);
161 StartReading();
163 return OK;
166 void QuicSimpleServer::Shutdown() {
167 // Before we shut down the epoll server, give all active sessions a chance to
168 // notify clients that they're closing.
169 dispatcher_->Shutdown();
171 socket_->Close();
172 socket_.reset();
175 void QuicSimpleServer::StartReading() {
176 if (read_pending_) {
177 return;
179 read_pending_ = true;
181 int result = socket_->RecvFrom(
182 read_buffer_.get(),
183 read_buffer_->size(),
184 &client_address_,
185 base::Bind(&QuicSimpleServer::OnReadComplete, base::Unretained(this)));
187 if (result == ERR_IO_PENDING) {
188 synchronous_read_count_ = 0;
189 return;
192 if (++synchronous_read_count_ > 32) {
193 synchronous_read_count_ = 0;
194 // Schedule the processing through the message loop to 1) prevent infinite
195 // recursion and 2) avoid blocking the thread for too long.
196 base::ThreadTaskRunnerHandle::Get()->PostTask(
197 FROM_HERE, base::Bind(&QuicSimpleServer::OnReadComplete,
198 weak_factory_.GetWeakPtr(), result));
199 } else {
200 OnReadComplete(result);
204 void QuicSimpleServer::OnReadComplete(int result) {
205 read_pending_ = false;
206 if (result == 0)
207 result = ERR_CONNECTION_CLOSED;
209 if (result < 0) {
210 LOG(ERROR) << "QuicSimpleServer read failed: " << ErrorToString(result);
211 Shutdown();
212 return;
215 QuicEncryptedPacket packet(read_buffer_->data(), result, false);
216 dispatcher_->ProcessPacket(server_address_, client_address_, packet);
218 StartReading();
221 } // namespace tools
222 } // namespace net