Windows should animate when they are about to get docked at screen edges.
[chromium-blink-merge.git] / net / tools / quic / quic_server.cc
blobd18525f634fcbb9c601a85427e3cce7aa5f9ed72
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_in_memory_cache.h"
22 #include "net/tools/quic/quic_socket_utils.h"
24 #define MMSG_MORE 0
26 #ifndef SO_RXQ_OVFL
27 #define SO_RXQ_OVFL 40
28 #endif
30 const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET;
31 const int kNumPacketsPerReadCall = 5; // Arbitrary
32 static const char kSourceAddressTokenSecret[] = "secret";
34 namespace net {
35 namespace tools {
37 QuicServer::QuicServer()
38 : port_(0),
39 packets_dropped_(0),
40 overflow_supported_(false),
41 use_recvmmsg_(false),
42 crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()) {
43 // Use hardcoded crypto parameters for now.
44 config_.SetDefaults();
45 Initialize();
48 QuicServer::QuicServer(const QuicConfig& config)
49 : port_(0),
50 packets_dropped_(0),
51 overflow_supported_(false),
52 use_recvmmsg_(false),
53 config_(config),
54 crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()) {
55 Initialize();
58 void QuicServer::Initialize() {
59 #if MMSG_MORE
60 use_recvmmsg_ = true;
61 #endif
62 epoll_server_.set_timeout_in_us(50 * 1000);
63 // Initialize the in memory cache now.
64 QuicInMemoryCache::GetInstance();
66 QuicEpollClock clock(&epoll_server_);
68 scoped_ptr<CryptoHandshakeMessage> scfg(
69 crypto_config_.AddDefaultConfig(
70 QuicRandom::GetInstance(), &clock,
71 QuicCryptoServerConfig::ConfigOptions()));
74 QuicServer::~QuicServer() {
77 bool QuicServer::Listen(const IPEndPoint& address) {
78 port_ = address.port();
79 int address_family = address.GetSockAddrFamily();
80 fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP);
81 if (fd_ < 0) {
82 LOG(ERROR) << "CreateSocket() failed: " << strerror(errno);
83 return false;
86 int rc = QuicSocketUtils::SetGetAddressInfo(fd_, address_family);
88 if (rc < 0) {
89 LOG(ERROR) << "IP detection not supported" << strerror(errno);
90 return false;
93 int get_overflow = 1;
94 rc = setsockopt(
95 fd_, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow, sizeof(get_overflow));
97 if (rc < 0) {
98 DLOG(WARNING) << "Socket overflow detection not supported";
99 } else {
100 overflow_supported_ = true;
103 // Enable the socket option that allows the local address to be
104 // returned if the socket is bound to more than on address.
105 int get_local_ip = 1;
106 rc = setsockopt(fd_, IPPROTO_IP, IP_PKTINFO,
107 &get_local_ip, sizeof(get_local_ip));
108 if (rc == 0 && address_family == AF_INET6) {
109 rc = setsockopt(fd_, IPPROTO_IPV6, IPV6_RECVPKTINFO,
110 &get_local_ip, sizeof(get_local_ip));
112 if (rc != 0) {
113 LOG(ERROR) << "Failed to set required socket options";
114 return false;
117 sockaddr_storage raw_addr;
118 socklen_t raw_addr_len = sizeof(raw_addr);
119 CHECK(address.ToSockAddr(reinterpret_cast<sockaddr*>(&raw_addr),
120 &raw_addr_len));
121 rc = bind(fd_,
122 reinterpret_cast<const sockaddr*>(&raw_addr),
123 sizeof(raw_addr));
124 if (rc < 0) {
125 LOG(ERROR) << "Bind failed: " << strerror(errno);
126 return false;
129 LOG(INFO) << "Listening on " << address.ToString();
130 if (port_ == 0) {
131 SockaddrStorage storage;
132 IPEndPoint server_address;
133 if (getsockname(fd_, storage.addr, &storage.addr_len) != 0 ||
134 !server_address.FromSockAddr(storage.addr, storage.addr_len)) {
135 LOG(ERROR) << "Unable to get self address. Error: " << strerror(errno);
136 return false;
138 port_ = server_address.port();
139 LOG(INFO) << "Kernel assigned port is " << port_;
142 epoll_server_.RegisterFD(fd_, this, kEpollFlags);
143 dispatcher_.reset(new QuicDispatcher(config_, crypto_config_, fd_,
144 &epoll_server_));
146 return true;
149 void QuicServer::WaitForEvents() {
150 epoll_server_.WaitForEventsAndExecuteCallbacks();
153 void QuicServer::Shutdown() {
154 // Before we shut down the epoll server, give all active sessions a chance to
155 // notify clients that they're closing.
156 dispatcher_->Shutdown();
159 void QuicServer::OnEvent(int fd, EpollEvent* event) {
160 DCHECK_EQ(fd, fd_);
161 event->out_ready_mask = 0;
163 if (event->in_events & EPOLLIN) {
164 LOG(ERROR) << "EPOLLIN";
165 bool read = true;
166 while (read) {
167 read = ReadAndDispatchSinglePacket(
168 fd_, port_, dispatcher_.get(),
169 overflow_supported_ ? &packets_dropped_ : NULL);
172 if (event->in_events & EPOLLOUT) {
173 bool can_write_more = dispatcher_->OnCanWrite();
174 if (can_write_more) {
175 event->out_ready_mask |= EPOLLOUT;
178 if (event->in_events & EPOLLERR) {
182 /* static */
183 void QuicServer::MaybeDispatchPacket(QuicDispatcher* dispatcher,
184 const QuicEncryptedPacket& packet,
185 const IPEndPoint& server_address,
186 const IPEndPoint& client_address) {
187 QuicGuid guid;
188 if (!QuicFramer::ReadGuidFromPacket(packet, &guid)) {
189 return;
192 dispatcher->ProcessPacket(server_address, client_address, guid, packet);
195 bool QuicServer::ReadAndDispatchSinglePacket(int fd,
196 int port,
197 QuicDispatcher* dispatcher,
198 int* packets_dropped) {
199 // Allocate some extra space so we can send an error if the client goes over
200 // the limit.
201 char buf[2 * kMaxPacketSize];
203 IPEndPoint client_address;
204 IPAddressNumber server_ip;
205 int bytes_read =
206 QuicSocketUtils::ReadPacket(fd, buf, arraysize(buf),
207 packets_dropped,
208 &server_ip, &client_address);
210 if (bytes_read < 0) {
211 return false; // We failed to read.
214 QuicEncryptedPacket packet(buf, bytes_read, false);
216 IPEndPoint server_address(server_ip, port);
217 MaybeDispatchPacket(dispatcher, packet, server_address, client_address);
219 return true;
222 } // namespace tools
223 } // namespace net