Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/tools/quic/quic_server.h" | 5 #include "net/quic/quic_server.h" |
| 6 | 6 |
| 7 #include <errno.h> | |
| 8 #include <features.h> | |
| 9 #include <netinet/in.h> | |
| 10 #include <string.h> | 7 #include <string.h> |
| 11 #include <sys/epoll.h> | |
| 12 #include <sys/socket.h> | |
| 13 | 8 |
| 14 #include "net/base/ip_endpoint.h" | 9 #include "net/base/ip_endpoint.h" |
| 10 #include "net/base/net_errors.h" | |
| 15 #include "net/quic/congestion_control/tcp_receiver.h" | 11 #include "net/quic/congestion_control/tcp_receiver.h" |
| 16 #include "net/quic/crypto/crypto_handshake.h" | 12 #include "net/quic/crypto/crypto_handshake.h" |
| 17 #include "net/quic/crypto/quic_random.h" | 13 #include "net/quic/crypto/quic_random.h" |
| 18 #include "net/quic/quic_clock.h" | |
| 19 #include "net/quic/quic_crypto_stream.h" | 14 #include "net/quic/quic_crypto_stream.h" |
| 20 #include "net/quic/quic_data_reader.h" | 15 #include "net/quic/quic_data_reader.h" |
| 16 #include "net/quic/quic_dispatcher.h" | |
| 17 #include "net/quic/quic_in_memory_cache.h" | |
| 21 #include "net/quic/quic_protocol.h" | 18 #include "net/quic/quic_protocol.h" |
| 22 #include "net/tools/quic/quic_in_memory_cache.h" | 19 #include "net/quic/quic_server_packet_writer.h" |
| 23 #include "net/tools/quic/quic_socket_utils.h" | 20 #include "net/tools/quic/quic_socket_utils.h" |
| 24 | 21 |
| 25 #define MMSG_MORE 0 | |
| 26 | |
| 27 #ifndef SO_RXQ_OVFL | |
| 28 #define SO_RXQ_OVFL 40 | |
| 29 #endif | |
| 30 | |
| 31 const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET; | |
| 32 static const char kSourceAddressTokenSecret[] = "secret"; | |
| 33 const uint32 kServerInitialFlowControlWindow = 100 * net::kMaxPacketSize; | |
| 34 | 22 |
| 35 namespace net { | 23 namespace net { |
| 36 namespace tools { | |
| 37 | 24 |
| 38 QuicServer::QuicServer() | 25 static const char kSourceAddressTokenSecret[] = "secret"; |
| 39 : port_(0), | 26 |
| 40 fd_(-1), | 27 // Allocate some extra space so we can send an error if the client goes over |
| 41 packets_dropped_(0), | 28 // the limit. |
| 42 overflow_supported_(false), | 29 static const int kReadBufferSize = 2 * net::kMaxPacketSize; |
|
Ryan Hamilton
2014/06/18 23:59:51
This seems too small. Why 2 (vs, say 100 from the
dmz
2014/06/19 17:46:24
This is actually a different constant (the size of
| |
| 43 use_recvmmsg_(false), | |
| 44 crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()), | |
| 45 supported_versions_(QuicSupportedVersions()), | |
| 46 server_initial_flow_control_receive_window_( | |
| 47 kServerInitialFlowControlWindow) { | |
| 48 // Use hardcoded crypto parameters for now. | |
| 49 config_.SetDefaults(); | |
| 50 Initialize(); | |
| 51 } | |
| 52 | 30 |
| 53 QuicServer::QuicServer(const QuicConfig& config, | 31 QuicServer::QuicServer(const QuicConfig& config, |
| 54 const QuicVersionVector& supported_versions, | 32 const QuicVersionVector& supported_versions, |
| 55 uint32 server_initial_flow_control_receive_window) | 33 uint32 server_initial_flow_control_receive_window) |
| 56 : port_(0), | 34 : helper_(new QuicConnectionHelper( |
| 57 fd_(-1), | 35 base::MessageLoop::current()->message_loop_proxy().get(), |
| 58 packets_dropped_(0), | 36 &clock_, |
| 59 overflow_supported_(false), | 37 QuicRandom::GetInstance())), |
| 60 use_recvmmsg_(false), | |
| 61 config_(config), | 38 config_(config), |
| 62 crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()), | 39 crypto_config_(kSourceAddressTokenSecret, QuicRandom::GetInstance()), |
| 63 supported_versions_(supported_versions), | 40 supported_versions_(supported_versions), |
| 64 server_initial_flow_control_receive_window_( | 41 server_initial_flow_control_receive_window_( |
| 65 server_initial_flow_control_receive_window) { | 42 server_initial_flow_control_receive_window), |
| 43 read_pending_(false), | |
| 44 synchronous_read_count_(0), | |
| 45 read_buffer_(new IOBufferWithSize(kReadBufferSize)), | |
| 46 weak_factory_(this) { | |
| 66 Initialize(); | 47 Initialize(); |
| 67 } | 48 } |
| 68 | 49 |
| 69 void QuicServer::Initialize() { | 50 void QuicServer::Initialize() { |
| 70 #if MMSG_MORE | |
| 71 use_recvmmsg_ = true; | |
| 72 #endif | |
| 73 epoll_server_.set_timeout_in_us(50 * 1000); | |
| 74 // Initialize the in memory cache now. | 51 // Initialize the in memory cache now. |
| 75 QuicInMemoryCache::GetInstance(); | 52 QuicInMemoryCache::GetInstance(); |
| 76 | 53 |
| 77 QuicEpollClock clock(&epoll_server_); | |
| 78 | |
| 79 scoped_ptr<CryptoHandshakeMessage> scfg( | 54 scoped_ptr<CryptoHandshakeMessage> scfg( |
| 80 crypto_config_.AddDefaultConfig( | 55 crypto_config_.AddDefaultConfig(QuicRandom::GetInstance(), |
| 81 QuicRandom::GetInstance(), &clock, | 56 helper_->GetClock(), |
| 82 QuicCryptoServerConfig::ConfigOptions())); | 57 QuicCryptoServerConfig::ConfigOptions())); |
| 83 } | 58 } |
| 84 | 59 |
| 85 QuicServer::~QuicServer() { | 60 QuicServer::~QuicServer() { |
| 86 } | 61 } |
| 87 | 62 |
| 88 bool QuicServer::Listen(const IPEndPoint& address) { | 63 int QuicServer::Listen(const IPEndPoint& address) { |
| 89 port_ = address.port(); | 64 scoped_ptr<UDPServerSocket> socket( |
| 90 int address_family = address.GetSockAddrFamily(); | 65 new UDPServerSocket(NULL, NetLog::Source())); |
| 91 fd_ = socket(address_family, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); | |
| 92 if (fd_ < 0) { | |
| 93 LOG(ERROR) << "CreateSocket() failed: " << strerror(errno); | |
| 94 return false; | |
| 95 } | |
| 96 | 66 |
| 97 int rc = QuicSocketUtils::SetGetAddressInfo(fd_, address_family); | 67 // TODO(dmz): socket->AllowBroadcast()? socket->SetMulticastInterface? |
| 68 socket->AllowAddressReuse(); | |
| 98 | 69 |
| 70 int rc = socket->Listen(address); | |
| 99 if (rc < 0) { | 71 if (rc < 0) { |
| 100 LOG(ERROR) << "IP detection not supported" << strerror(errno); | 72 LOG(ERROR) << "Listen() failed: " << strerror(errno); |
| 101 return false; | 73 return rc; |
| 102 } | |
| 103 | |
| 104 int get_overflow = 1; | |
| 105 rc = setsockopt( | |
| 106 fd_, SOL_SOCKET, SO_RXQ_OVFL, &get_overflow, sizeof(get_overflow)); | |
| 107 | |
| 108 if (rc < 0) { | |
| 109 DLOG(WARNING) << "Socket overflow detection not supported"; | |
| 110 } else { | |
| 111 overflow_supported_ = true; | |
| 112 } | 74 } |
| 113 | 75 |
| 114 // These send and receive buffer sizes are sized for a single connection, | 76 // These send and receive buffer sizes are sized for a single connection, |
| 115 // because the default usage of QuicServer is as a test server with one or | 77 // because the default usage of QuicServer is as a test server with one or |
| 116 // two clients. Adjust higher for use with many clients. | 78 // two clients. Adjust higher for use with many clients. |
| 117 if (!QuicSocketUtils::SetReceiveBufferSize(fd_, | 79 rc = socket->SetReceiveBufferSize(TcpReceiver::kReceiveWindowTCP); |
| 118 TcpReceiver::kReceiveWindowTCP)) { | 80 if (rc < 0) { |
| 119 return false; | 81 LOG(ERROR) << "SetReceiveBufferSize() failed: " << strerror(errno); |
| 82 return rc; | |
| 120 } | 83 } |
| 121 | 84 |
| 122 if (!QuicSocketUtils::SetSendBufferSize(fd_, | 85 rc = socket->SetSendBufferSize(TcpReceiver::kReceiveWindowTCP); |
|
Ryan Hamilton
2014/06/18 23:59:51
Seems surprising to set the send buffer to the *re
dmz
2014/06/19 17:46:24
I agree -- although this is unchanged from the ori
Ryan Hamilton
2014/06/19 19:21:29
Let's do what we do in the QuicStreamFactory:
net
dmz
2014/06/19 20:06:28
Done.
| |
| 123 TcpReceiver::kReceiveWindowTCP)) { | 86 if (rc < 0) { |
| 124 return false; | 87 LOG(ERROR) << "SetSendBufferSize() failed: " << strerror(errno); |
| 88 return rc; | |
| 125 } | 89 } |
| 126 | 90 |
| 127 // Enable the socket option that allows the local address to be | |
| 128 // returned if the socket is bound to more than on address. | |
| 129 int get_local_ip = 1; | |
| 130 rc = setsockopt(fd_, IPPROTO_IP, IP_PKTINFO, | |
| 131 &get_local_ip, sizeof(get_local_ip)); | |
| 132 if (rc == 0 && address_family == AF_INET6) { | |
| 133 rc = setsockopt(fd_, IPPROTO_IPV6, IPV6_RECVPKTINFO, | |
| 134 &get_local_ip, sizeof(get_local_ip)); | |
| 135 } | |
| 136 if (rc != 0) { | |
| 137 LOG(ERROR) << "Failed to set required socket options"; | |
| 138 return false; | |
| 139 } | |
| 140 | 91 |
| 141 sockaddr_storage raw_addr; | 92 socket->GetLocalAddress(&server_address_); |
| 142 socklen_t raw_addr_len = sizeof(raw_addr); | |
| 143 CHECK(address.ToSockAddr(reinterpret_cast<sockaddr*>(&raw_addr), | |
| 144 &raw_addr_len)); | |
| 145 rc = bind(fd_, | |
| 146 reinterpret_cast<const sockaddr*>(&raw_addr), | |
| 147 sizeof(raw_addr)); | |
| 148 if (rc < 0) { | |
| 149 LOG(ERROR) << "Bind failed: " << strerror(errno); | |
| 150 return false; | |
| 151 } | |
| 152 | 93 |
| 153 DVLOG(1) << "Listening on " << address.ToString(); | 94 DVLOG(1) << "Listening on " << server_address_.ToString(); |
| 154 if (port_ == 0) { | |
| 155 SockaddrStorage storage; | |
| 156 IPEndPoint server_address; | |
| 157 if (getsockname(fd_, storage.addr, &storage.addr_len) != 0 || | |
| 158 !server_address.FromSockAddr(storage.addr, storage.addr_len)) { | |
| 159 LOG(ERROR) << "Unable to get self address. Error: " << strerror(errno); | |
| 160 return false; | |
| 161 } | |
| 162 port_ = server_address.port(); | |
| 163 DVLOG(1) << "Kernel assigned port is " << port_; | |
| 164 } | |
| 165 | 95 |
| 166 epoll_server_.RegisterFD(fd_, this, kEpollFlags); | 96 socket_.swap(socket); |
| 167 dispatcher_.reset(new QuicDispatcher( | |
| 168 config_, | |
| 169 crypto_config_, | |
| 170 supported_versions_, | |
| 171 &epoll_server_, | |
| 172 server_initial_flow_control_receive_window_)); | |
| 173 dispatcher_->Initialize(fd_); | |
| 174 | 97 |
| 175 return true; | 98 dispatcher_.reset( |
| 176 } | 99 new QuicDispatcher(config_, |
| 100 crypto_config_, | |
| 101 supported_versions_, | |
| 102 helper_, | |
| 103 server_initial_flow_control_receive_window_)); | |
| 104 QuicServerPacketWriter* writer = new QuicServerPacketWriter(socket_.get()); | |
| 105 writer->SetWriterToUnblock(dispatcher_.get()); | |
| 106 dispatcher_->Initialize(writer); | |
| 177 | 107 |
| 178 void QuicServer::WaitForEvents() { | 108 StartReading(); |
| 179 epoll_server_.WaitForEventsAndExecuteCallbacks(); | 109 |
| 110 return OK; | |
| 180 } | 111 } |
| 181 | 112 |
| 182 void QuicServer::Shutdown() { | 113 void QuicServer::Shutdown() { |
| 183 // Before we shut down the epoll server, give all active sessions a chance to | 114 // Before we shut down the epoll server, give all active sessions a chance to |
| 184 // notify clients that they're closing. | 115 // notify clients that they're closing. |
| 185 dispatcher_->Shutdown(); | 116 dispatcher_->Shutdown(); |
| 186 | 117 |
| 187 close(fd_); | 118 socket_->Close(); |
| 188 fd_ = -1; | |
| 189 } | 119 } |
| 190 | 120 |
| 191 void QuicServer::OnEvent(int fd, EpollEvent* event) { | 121 void QuicServer::OnReadComplete(int result) { |
|
Ryan Hamilton
2014/06/18 23:59:51
Please move this method below StartReading();
dmz
2014/06/19 17:46:24
Done.
Ryan Hamilton
2014/06/19 19:21:29
Still looks to be above StartReading()?
dmz
2014/06/19 20:06:28
Not in the newest patch set -- looks like you stil
| |
| 192 DCHECK_EQ(fd, fd_); | 122 read_pending_ = false; |
| 193 event->out_ready_mask = 0; | 123 if (result == 0) |
| 124 result = ERR_CONNECTION_CLOSED; // TODO(dmz): correct for server? | |
| 194 | 125 |
| 195 if (event->in_events & EPOLLIN) { | 126 if (result < 0) { |
| 196 DVLOG(1) << "EPOLLIN"; | 127 // TODO(dmz) how to handle error? probably just DVLOG, ignore, & continue? |
| 197 bool read = true; | 128 return; |
|
Ryan Hamilton
2014/06/19 19:21:29
I'd recommend closing connections and exiting.
dmz
2014/06/19 20:06:28
Done.
| |
| 198 while (read) { | |
| 199 read = ReadAndDispatchSinglePacket( | |
| 200 fd_, port_, dispatcher_.get(), | |
| 201 overflow_supported_ ? &packets_dropped_ : NULL); | |
| 202 } | |
| 203 } | 129 } |
| 204 if (event->in_events & EPOLLOUT) { | 130 |
| 205 dispatcher_->OnCanWrite(); | 131 QuicEncryptedPacket packet(read_buffer_->data(), result, false); |
| 206 if (dispatcher_->HasPendingWrites()) { | 132 dispatcher_->ProcessPacket(server_address_, read_addr_, packet); |
| 207 event->out_ready_mask |= EPOLLOUT; | 133 |
| 208 } | 134 StartReading(); |
| 135 } | |
| 136 | |
| 137 void QuicServer::StartReading() { | |
| 138 if (read_pending_) { | |
| 139 return; | |
| 209 } | 140 } |
| 210 if (event->in_events & EPOLLERR) { | 141 |
| 142 int result = socket_->RecvFrom( | |
| 143 read_buffer_.get(), | |
| 144 read_buffer_->size(), | |
| 145 &read_addr_, | |
| 146 base::Bind(&QuicServer::OnReadComplete, base::Unretained(this))); | |
| 147 | |
| 148 if (result == ERR_IO_PENDING) { | |
| 149 read_pending_ = true; | |
| 150 return; | |
| 151 } | |
| 152 | |
| 153 if (++synchronous_read_count_ > 32) { | |
| 154 synchronous_read_count_ = 0; | |
| 155 // Schedule the processing through the message loop to 1) prevent infinite | |
| 156 // recursion and 2) avoid blocking the thread for too long. | |
| 157 base::MessageLoop::current()->PostTask( | |
| 158 FROM_HERE, | |
| 159 base::Bind(&QuicServer::OnReadComplete, | |
| 160 weak_factory_.GetWeakPtr(), | |
| 161 result)); | |
| 162 } else { | |
| 163 OnReadComplete(result); | |
| 211 } | 164 } |
| 212 } | 165 } |
| 213 | 166 |
| 214 /* static */ | |
| 215 bool QuicServer::ReadAndDispatchSinglePacket(int fd, | |
| 216 int port, | |
| 217 QuicDispatcher* dispatcher, | |
| 218 uint32* packets_dropped) { | |
| 219 // Allocate some extra space so we can send an error if the client goes over | |
| 220 // the limit. | |
| 221 char buf[2 * kMaxPacketSize]; | |
| 222 | |
| 223 IPEndPoint client_address; | |
| 224 IPAddressNumber server_ip; | |
| 225 int bytes_read = | |
| 226 QuicSocketUtils::ReadPacket(fd, buf, arraysize(buf), | |
| 227 packets_dropped, | |
| 228 &server_ip, &client_address); | |
| 229 | |
| 230 if (bytes_read < 0) { | |
| 231 return false; // We failed to read. | |
| 232 } | |
| 233 | |
| 234 QuicEncryptedPacket packet(buf, bytes_read, false); | |
| 235 | |
| 236 IPEndPoint server_address(server_ip, port); | |
| 237 dispatcher->ProcessPacket(server_address, client_address, packet); | |
| 238 | |
| 239 return true; | |
| 240 } | |
| 241 | |
| 242 } // namespace tools | |
| 243 } // namespace net | 167 } // namespace net |
| OLD | NEW |