Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / tools / quic / quic_server.cc
blob5d551e68762f0045771189cef84fd11ed81abbdd
1 // Copyright (c) 2012 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_server.h"
7 #include <errno.h>
8 #include <features.h>
9 #include <netinet/in.h>
10 #include <string.h>
11 #include <sys/epoll.h>
12 #include <sys/socket.h>
14 #include "net/base/ip_endpoint.h"
15 #include "net/quic/crypto/crypto_handshake.h"
16 #include "net/quic/crypto/quic_random.h"
17 #include "net/quic/quic_clock.h"
18 #include "net/quic/quic_crypto_stream.h"
19 #include "net/quic/quic_data_reader.h"
20 #include "net/quic/quic_protocol.h"
21 #include "net/tools/quic/quic_dispatcher.h"
22 #include "net/tools/quic/quic_epoll_clock.h"
23 #include "net/tools/quic/quic_epoll_connection_helper.h"
24 #include "net/tools/quic/quic_in_memory_cache.h"
25 #include "net/tools/quic/quic_packet_reader.h"
26 #include "net/tools/quic/quic_socket_utils.h"
28 // TODO(rtenneti): Add support for MMSG_MORE.
29 #define MMSG_MORE 0
31 #ifndef SO_RXQ_OVFL
32 #define SO_RXQ_OVFL 40
33 #endif
35 namespace net {
36 namespace tools {
37 namespace {
39 // Specifies the directory used during QuicInMemoryCache
40 // construction to seed the cache. Cache directory can be
41 // generated using `wget -p --save-headers <url>`
42 std::string FLAGS_quic_in_memory_cache_dir = "";
44 const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
45 const char kSourceAddressTokenSecret[] = "secret";
47 } // namespace
49 QuicServer::QuicServer()
50 : port_(0),
51 fd_(-1),
52 packets_dropped_(0),
53 overflow_supported_(false),
54 use_recvmmsg_(false),
55 crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()),
56 supported_versions_(QuicSupportedVersions()),
57 packet_reader_(new QuicPacketReader()) {
58 Initialize();
61 QuicServer::QuicServer(const QuicConfig& config,
62 const QuicVersionVector& supported_versions)
63 : port_(0),
64 fd_(-1),
65 packets_dropped_(0),
66 overflow_supported_(false),
67 use_recvmmsg_(false),
68 config_(config),
69 crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()),
70 supported_versions_(supported_versions),
71 packet_reader_(new QuicPacketReader()) {
72 Initialize();
75 void QuicServer::Initialize() {
76 #if MMSG_MORE
77 use_recvmmsg_ = true;
78 #endif
80 // If an initial flow control window has not explicitly been set, then use a
81 // sensible value for a server: 1 MB for session, 64 KB for each stream.
82 const uint32 kInitialSessionFlowControlWindow = 1 * 1024 * 1024; // 1 MB
83 const uint32 kInitialStreamFlowControlWindow = 64 * 1024; // 64 KB
84 if (config_.GetInitialStreamFlowControlWindowToSend() ==
85 kMinimumFlowControlSendWindow) {
86 config_.SetInitialStreamFlowControlWindowToSend(
87 kInitialStreamFlowControlWindow);
89 if (config_.GetInitialSessionFlowControlWindowToSend() ==
90 kMinimumFlowControlSendWindow) {
91 config_.SetInitialSessionFlowControlWindowToSend(
92 kInitialSessionFlowControlWindow);
95 epoll_server_.set_timeout_in_us(50 * 1000);
97 if (!FLAGS_quic_in_memory_cache_dir.empty()) {
98 QuicInMemoryCache::GetInstance()->InitializeFromDirectory(
99 FLAGS_quic_in_memory_cache_dir);
102 QuicEpollClock clock(&epoll_server_);
104 scoped_ptr<CryptoHandshakeMessage> scfg(
105 crypto_config_.AddDefaultConfig(
106 QuicRandom::GetInstance(), &clock,
107 QuicCryptoServerConfig::ConfigOptions()));
110 QuicServer::~QuicServer() {
113 bool QuicServer::Listen(const IPEndPoint& address) {
114 port_ = address.port();
115 int address_family = address.GetSockAddrFamily();
116 fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
117 if (fd_ < 0) {
118 LOG(ERROR) << "CreateSocket() failed: " << strerror(errno);
119 return false;
122 // Enable the socket option that allows the local address to be
123 // returned if the socket is bound to more than one address.
124 int rc = QuicSocketUtils::SetGetAddressInfo(fd_, address_family);
126 if (rc < 0) {
127 LOG(ERROR) << "IP detection not supported" << strerror(errno);
128 return false;
131 int get_overflow = 1;
132 rc = setsockopt(
133 fd_, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow, sizeof(get_overflow));
135 if (rc < 0) {
136 DLOG(WARNING) << "Socket overflow detection not supported";
137 } else {
138 overflow_supported_ = true;
141 // These send and receive buffer sizes are sized for a single connection,
142 // because the default usage of QuicServer is as a test server with one or
143 // two clients. Adjust higher for use with many clients.
144 if (!QuicSocketUtils::SetReceiveBufferSize(fd_,
145 kDefaultSocketReceiveBuffer)) {
146 return false;
149 if (!QuicSocketUtils::SetSendBufferSize(fd_, kDefaultSocketReceiveBuffer)) {
150 return false;
153 sockaddr_storage raw_addr;
154 socklen_t raw_addr_len = sizeof(raw_addr);
155 CHECK(address.ToSockAddr(reinterpret_cast<sockaddr*>(&raw_addr),
156 &raw_addr_len));
157 rc = bind(fd_,
158 reinterpret_cast<const sockaddr*>(&raw_addr),
159 sizeof(raw_addr));
160 if (rc < 0) {
161 LOG(ERROR) << "Bind failed: " << strerror(errno);
162 return false;
165 DVLOG(1) << "Listening on " << address.ToString();
166 if (port_ == 0) {
167 SockaddrStorage storage;
168 IPEndPoint server_address;
169 if (getsockname(fd_, storage.addr, &storage.addr_len) != 0 ||
170 !server_address.FromSockAddr(storage.addr, storage.addr_len)) {
171 LOG(ERROR) << "Unable to get self address. Error: " << strerror(errno);
172 return false;
174 port_ = server_address.port();
175 DVLOG(1) << "Kernel assigned port is " << port_;
178 epoll_server_.RegisterFD(fd_, this, kEpollFlags);
179 dispatcher_.reset(CreateQuicDispatcher());
180 dispatcher_->InitializeWithWriter(CreateWriter(fd_));
182 return true;
185 QuicDefaultPacketWriter* QuicServer::CreateWriter(int fd) {
186 return new QuicDefaultPacketWriter(fd);
189 QuicDispatcher* QuicServer::CreateQuicDispatcher() {
190 return new QuicDispatcher(
191 config_,
192 &crypto_config_,
193 supported_versions_,
194 new QuicDispatcher::DefaultPacketWriterFactory(),
195 new QuicEpollConnectionHelper(&epoll_server_));
198 void QuicServer::WaitForEvents() {
199 epoll_server_.WaitForEventsAndExecuteCallbacks();
202 void QuicServer::Shutdown() {
203 // Before we shut down the epoll server, give all active sessions a chance to
204 // notify clients that they're closing.
205 dispatcher_->Shutdown();
207 close(fd_);
208 fd_ = -1;
211 void QuicServer::OnEvent(int fd, EpollEvent* event) {
212 DCHECK_EQ(fd, fd_);
213 event->out_ready_mask = 0;
215 if (event->in_events & EPOLLIN) {
216 DVLOG(1) << "EPOLLIN";
217 bool read = true;
218 while (read) {
219 if (use_recvmmsg_) {
220 read = packet_reader_->ReadAndDispatchPackets(
221 fd_, port_, dispatcher_.get(),
222 overflow_supported_ ? &packets_dropped_ : nullptr);
223 } else {
224 read = QuicPacketReader::ReadAndDispatchSinglePacket(
225 fd_, port_, dispatcher_.get(),
226 overflow_supported_ ? &packets_dropped_ : nullptr);
230 if (event->in_events & EPOLLOUT) {
231 dispatcher_->OnCanWrite();
232 if (dispatcher_->HasPendingWrites()) {
233 event->out_ready_mask |= EPOLLOUT;
236 if (event->in_events & EPOLLERR) {
240 } // namespace tools
241 } // namespace net