| // 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 |