| // Copyright 2014 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_simple_server.h" | |
| #include <string.h> | |
| #include "base/location.h" | |
| #include "base/single_thread_task_runner.h" | |
| #include "base/threading/thread_task_runner_handle.h" | |
| #include "net/base/ip_endpoint.h" | |
| #include "net/base/net_errors.h" | |
| #include "net/log/net_log_source.h" | |
| #include "net/socket/udp_server_socket.h" | |
| #include "net/third_party/quic/core/crypto/crypto_handshake.h" | |
| #include "net/third_party/quic/core/crypto/quic_random.h" | |
| #include "net/third_party/quic/core/quic_crypto_stream.h" | |
| #include "net/third_party/quic/core/quic_data_reader.h" | |
| #include "net/third_party/quic/core/quic_packets.h" | |
| #include "net/third_party/quic/core/tls_server_handshaker.h" | |
| #include "net/third_party/quic/tools/quic_simple_dispatcher.h" | |
| #include "net/tools/quic/quic_simple_per_connection_packet_writer.h" | |
| #include "net/tools/quic/quic_simple_server_packet_writer.h" | |
| #include "net/tools/quic/quic_simple_server_session_helper.h" | |
| #include "starboard/types.h" | |
| namespace net { | |
| 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 * quic::kMaxPacketSize; | |
| } // namespace | |
| QuicSimpleServer::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) | |
| : version_manager_(supported_versions), | |
| helper_( | |
| new QuicChromiumConnectionHelper(&clock_, | |
| quic::QuicRandom::GetInstance())), | |
| alarm_factory_(new QuicChromiumAlarmFactory( | |
| base::ThreadTaskRunnerHandle::Get().get(), | |
| &clock_)), | |
| config_(config), | |
| crypto_config_options_(crypto_config_options), | |
| crypto_config_(kSourceAddressTokenSecret, | |
| quic::QuicRandom::GetInstance(), | |
| std::move(proof_source), | |
| quic::KeyExchangeSource::Default(), | |
| quic::TlsServerHandshaker::CreateSslCtx()), | |
| read_pending_(false), | |
| synchronous_read_count_(0), | |
| read_buffer_(base::MakeRefCounted<IOBufferWithSize>(kReadBufferSize)), | |
| quic_simple_server_backend_(quic_simple_server_backend), | |
| weak_factory_(this) { | |
| Initialize(); | |
| } | |
| void QuicSimpleServer::Initialize() { | |
| #if MMSG_MORE | |
| use_recvmmsg_ = true; | |
| #endif | |
| // 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() == | |
| quic::kMinimumFlowControlSendWindow) { | |
| config_.SetInitialStreamFlowControlWindowToSend( | |
| kInitialStreamFlowControlWindow); | |
| } | |
| if (config_.GetInitialSessionFlowControlWindowToSend() == | |
| quic::kMinimumFlowControlSendWindow) { | |
| config_.SetInitialSessionFlowControlWindowToSend( | |
| kInitialSessionFlowControlWindow); | |
| } | |
| std::unique_ptr<quic::CryptoHandshakeMessage> scfg( | |
| crypto_config_.AddDefaultConfig(helper_->GetRandomGenerator(), | |
| helper_->GetClock(), | |
| crypto_config_options_)); | |
| } | |
| QuicSimpleServer::~QuicSimpleServer() = default; | |
| int QuicSimpleServer::Listen(const IPEndPoint& address) { | |
| std::unique_ptr<UDPServerSocket> socket( | |
| new UDPServerSocket(&net_log_, NetLogSource())); | |
| socket->AllowAddressReuse(); | |
| int rc = socket->Listen(address); | |
| if (rc < 0) { | |
| LOG(ERROR) << "Listen() failed: " << ErrorToString(rc); | |
| 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>(quic::kDefaultSocketReceiveBuffer)); | |
| if (rc < 0) { | |
| LOG(ERROR) << "SetReceiveBufferSize() failed: " << ErrorToString(rc); | |
| return rc; | |
| } | |
| rc = socket->SetSendBufferSize(20 * quic::kMaxPacketSize); | |
| if (rc < 0) { | |
| LOG(ERROR) << "SetSendBufferSize() failed: " << ErrorToString(rc); | |
| return rc; | |
| } | |
| rc = socket->GetLocalAddress(&server_address_); | |
| if (rc < 0) { | |
| LOG(ERROR) << "GetLocalAddress() failed: " << ErrorToString(rc); | |
| return rc; | |
| } | |
| DVLOG(1) << "Listening on " << server_address_.ToString(); | |
| socket_.swap(socket); | |
| dispatcher_.reset(new quic::QuicSimpleDispatcher( | |
| #if defined(COBALT_QUIC46) | |
| &config_, &crypto_config_, &version_manager_, | |
| #else | |
| config_, &crypto_config_, &version_manager_, | |
| #endif | |
| std::unique_ptr<quic::QuicConnectionHelperInterface>(helper_), | |
| std::unique_ptr<quic::QuicCryptoServerStream::Helper>( | |
| new QuicSimpleServerSessionHelper(quic::QuicRandom::GetInstance())), | |
| std::unique_ptr<quic::QuicAlarmFactory>(alarm_factory_), | |
| quic_simple_server_backend_)); | |
| QuicSimpleServerPacketWriter* writer = | |
| new QuicSimpleServerPacketWriter(socket_.get(), dispatcher_.get()); | |
| dispatcher_->InitializeWithWriter(writer); | |
| StartReading(); | |
| return OK; | |
| } | |
| void QuicSimpleServer::Shutdown() { | |
| // Before we shut down the epoll server, give all active sessions a chance to | |
| // notify clients that they're closing. | |
| dispatcher_->Shutdown(); | |
| if (!socket_) { | |
| return; | |
| } | |
| socket_->Close(); | |
| socket_.reset(); | |
| } | |
| void QuicSimpleServer::StartReading() { | |
| if (synchronous_read_count_ == 0) { | |
| // Only process buffered packets once per message loop. | |
| dispatcher_->ProcessBufferedChlos(kNumSessionsToCreatePerSocketEvent); | |
| } | |
| if (read_pending_) { | |
| return; | |
| } | |
| read_pending_ = true; | |
| int result = socket_->RecvFrom( | |
| read_buffer_.get(), read_buffer_->size(), &client_address_, | |
| base::Bind(&QuicSimpleServer::OnReadComplete, base::Unretained(this))); | |
| if (result == 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(&QuicSimpleServer::StartReading, | |
| weak_factory_.GetWeakPtr())); | |
| } | |
| return; | |
| } | |
| if (++synchronous_read_count_ > 32) { | |
| synchronous_read_count_ = 0; | |
| // 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(&QuicSimpleServer::OnReadComplete, | |
| weak_factory_.GetWeakPtr(), result)); | |
| } else { | |
| OnReadComplete(result); | |
| } | |
| } | |
| void QuicSimpleServer::OnReadComplete(int result) { | |
| read_pending_ = false; | |
| if (result == 0) | |
| result = ERR_CONNECTION_CLOSED; | |
| if (result < 0) { | |
| LOG(ERROR) << "QuicSimpleServer read failed: " << ErrorToString(result); | |
| Shutdown(); | |
| return; | |
| } | |
| quic::QuicReceivedPacket packet(read_buffer_->data(), result, | |
| helper_->GetClock()->Now(), false); | |
| dispatcher_->ProcessPacket( | |
| quic::QuicSocketAddress(quic::QuicSocketAddressImpl(server_address_)), | |
| quic::QuicSocketAddress(quic::QuicSocketAddressImpl(client_address_)), | |
| packet); | |
| StartReading(); | |
| } | |
| } // namespace net |