Various formatting changes to shared QUIC server code found while syning with interna...
[chromium-blink-merge.git] / net / tools / quic / quic_dispatcher.cc
blob448e5ce71d6bfb02c5fa3ca94f4f9cdd8a2ee04b
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_dispatcher.h"
7 #include <utility>
9 #include "base/debug/stack_trace.h"
10 #include "base/logging.h"
11 #include "base/stl_util.h"
12 #include "net/quic/quic_utils.h"
13 #include "net/tools/quic/quic_per_connection_packet_writer.h"
14 #include "net/tools/quic/quic_time_wait_list_manager.h"
16 namespace net {
18 namespace tools {
20 using base::StringPiece;
22 namespace {
24 // An alarm that informs the QuicDispatcher to delete old sessions.
25 class DeleteSessionsAlarm : public QuicAlarm::Delegate {
26 public:
27 explicit DeleteSessionsAlarm(QuicDispatcher* dispatcher)
28 : dispatcher_(dispatcher) {
31 QuicTime OnAlarm() override {
32 dispatcher_->DeleteSessions();
33 // Let the dispatcher register the alarm at appropriate time.
34 return QuicTime::Zero();
37 private:
38 // Not owned.
39 QuicDispatcher* dispatcher_;
41 DISALLOW_COPY_AND_ASSIGN(DeleteSessionsAlarm);
44 } // namespace
46 class QuicDispatcher::QuicFramerVisitor : public QuicFramerVisitorInterface {
47 public:
48 explicit QuicFramerVisitor(QuicDispatcher* dispatcher)
49 : dispatcher_(dispatcher),
50 connection_id_(0) {}
52 // QuicFramerVisitorInterface implementation
53 void OnPacket() override {}
54 bool OnUnauthenticatedPublicHeader(
55 const QuicPacketPublicHeader& header) override {
56 connection_id_ = header.connection_id;
57 return dispatcher_->OnUnauthenticatedPublicHeader(header);
59 bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override {
60 dispatcher_->OnUnauthenticatedHeader(header);
61 return false;
63 void OnError(QuicFramer* framer) override {
64 DVLOG(1) << QuicUtils::ErrorToString(framer->error());
67 bool OnProtocolVersionMismatch(QuicVersion /*received_version*/) override {
68 if (dispatcher_->time_wait_list_manager()->IsConnectionIdInTimeWait(
69 connection_id_)) {
70 // Keep processing after protocol mismatch - this will be dealt with by
71 // the TimeWaitListManager.
72 return true;
73 } else {
74 DLOG(DFATAL) << "Version mismatch, connection ID (" << connection_id_
75 << ") not in time wait list.";
76 return false;
80 // The following methods should never get called because we always return
81 // false from OnUnauthenticatedHeader(). As a result, we never process the
82 // payload of the packet.
83 void OnPublicResetPacket(const QuicPublicResetPacket& /*packet*/) override {
84 DCHECK(false);
86 void OnVersionNegotiationPacket(
87 const QuicVersionNegotiationPacket& /*packet*/) override {
88 DCHECK(false);
90 void OnDecryptedPacket(EncryptionLevel level) override { DCHECK(false); }
91 bool OnPacketHeader(const QuicPacketHeader& /*header*/) override {
92 DCHECK(false);
93 return false;
95 void OnRevivedPacket() override { DCHECK(false); }
96 void OnFecProtectedPayload(StringPiece /*payload*/) override {
97 DCHECK(false);
99 bool OnStreamFrame(const QuicStreamFrame& /*frame*/) override {
100 DCHECK(false);
101 return false;
103 bool OnAckFrame(const QuicAckFrame& /*frame*/) override {
104 DCHECK(false);
105 return false;
107 bool OnStopWaitingFrame(const QuicStopWaitingFrame& /*frame*/) override {
108 DCHECK(false);
109 return false;
111 bool OnPingFrame(const QuicPingFrame& /*frame*/) override {
112 DCHECK(false);
113 return false;
115 bool OnRstStreamFrame(const QuicRstStreamFrame& /*frame*/) override {
116 DCHECK(false);
117 return false;
119 bool OnConnectionCloseFrame(
120 const QuicConnectionCloseFrame& /*frame*/) override {
121 DCHECK(false);
122 return false;
124 bool OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) override {
125 DCHECK(false);
126 return false;
128 bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& /*frame*/) override {
129 DCHECK(false);
130 return false;
132 bool OnBlockedFrame(const QuicBlockedFrame& frame) override {
133 DCHECK(false);
134 return false;
136 void OnFecData(const QuicFecData& /*fec*/) override { DCHECK(false); }
137 void OnPacketComplete() override { DCHECK(false); }
139 private:
140 QuicDispatcher* dispatcher_;
142 // Latched in OnUnauthenticatedPublicHeader for use later.
143 QuicConnectionId connection_id_;
146 QuicPacketWriter* QuicDispatcher::DefaultPacketWriterFactory::Create(
147 QuicPacketWriter* writer,
148 QuicConnection* connection) {
149 return new QuicPerConnectionPacketWriter(writer, connection);
152 QuicDispatcher::PacketWriterFactoryAdapter::PacketWriterFactoryAdapter(
153 QuicDispatcher* dispatcher)
154 : dispatcher_(dispatcher) {}
156 QuicDispatcher::PacketWriterFactoryAdapter::~PacketWriterFactoryAdapter() {}
158 QuicPacketWriter* QuicDispatcher::PacketWriterFactoryAdapter::Create(
159 QuicConnection* connection) const {
160 return dispatcher_->packet_writer_factory_->Create(
161 dispatcher_->writer_.get(),
162 connection);
165 QuicDispatcher::QuicDispatcher(const QuicConfig& config,
166 const QuicCryptoServerConfig& crypto_config,
167 const QuicVersionVector& supported_versions,
168 PacketWriterFactory* packet_writer_factory,
169 QuicConnectionHelperInterface* helper)
170 : config_(config),
171 crypto_config_(crypto_config),
172 helper_(helper),
173 delete_sessions_alarm_(
174 helper_->CreateAlarm(new DeleteSessionsAlarm(this))),
175 packet_writer_factory_(packet_writer_factory),
176 connection_writer_factory_(this),
177 supported_versions_(supported_versions),
178 current_packet_(nullptr),
179 framer_(supported_versions,
180 /*unused*/ QuicTime::Zero(),
181 Perspective::IS_SERVER),
182 framer_visitor_(new QuicFramerVisitor(this)) {
183 framer_.set_visitor(framer_visitor_.get());
186 QuicDispatcher::~QuicDispatcher() {
187 STLDeleteValues(&session_map_);
188 STLDeleteElements(&closed_session_list_);
191 void QuicDispatcher::InitializeWithWriter(QuicPacketWriter* writer) {
192 DCHECK(writer_ == nullptr);
193 writer_.reset(writer);
194 time_wait_list_manager_.reset(CreateQuicTimeWaitListManager());
197 void QuicDispatcher::ProcessPacket(const IPEndPoint& server_address,
198 const IPEndPoint& client_address,
199 const QuicEncryptedPacket& packet) {
200 current_server_address_ = server_address;
201 current_client_address_ = client_address;
202 current_packet_ = &packet;
203 // ProcessPacket will cause the packet to be dispatched in
204 // OnUnauthenticatedPublicHeader, or sent to the time wait list manager
205 // in OnAuthenticatedHeader.
206 framer_.ProcessPacket(packet);
207 // TODO(rjshade): Return a status describing if/why a packet was dropped,
208 // and log somehow. Maybe expose as a varz.
211 bool QuicDispatcher::OnUnauthenticatedPublicHeader(
212 const QuicPacketPublicHeader& header) {
213 // Port zero is only allowed for unidirectional UDP, so is disallowed by QUIC.
214 // Given that we can't even send a reply rejecting the packet, just black hole
215 // it.
216 if (current_client_address_.port() == 0) {
217 return false;
220 // The session that we have identified as the one to which this packet
221 // belongs.
222 QuicServerSession* session = nullptr;
223 QuicConnectionId connection_id = header.connection_id;
224 SessionMap::iterator it = session_map_.find(connection_id);
225 if (it == session_map_.end()) {
226 if (time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)) {
227 return HandlePacketForTimeWait(header);
230 // The packet has an unknown connection ID.
231 // If the packet is a public reset, there is nothing we must do or can do.
232 if (header.reset_flag) {
233 return false;
236 // All packets within a connection sent by a client before receiving a
237 // response from the server are required to have the version negotiation
238 // flag set. Since this may be a client continuing a connection we lost
239 // track of via server restart, send a rejection to fast-fail the
240 // connection.
241 if (!header.version_flag) {
242 DVLOG(1) << "Packet without version arrived for unknown connection ID "
243 << connection_id;
244 // Add this connection_id fo the time-wait state, to safely reject future
245 // packets.
246 QuicVersion version = supported_versions_.front();
247 time_wait_list_manager_->AddConnectionIdToTimeWait(connection_id, version,
248 nullptr);
249 DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
250 return HandlePacketForTimeWait(header);
253 session = AdditionalValidityChecksThenCreateSession(header, connection_id);
254 if (session == nullptr) {
255 return false;
257 } else {
258 session = it->second;
261 session->connection()->ProcessUdpPacket(
262 current_server_address_, current_client_address_, *current_packet_);
264 // Do not parse the packet further. The session methods called above have
265 // processed it completely.
266 return false;
269 QuicServerSession* QuicDispatcher::AdditionalValidityChecksThenCreateSession(
270 const QuicPacketPublicHeader& header,
271 QuicConnectionId connection_id) {
272 QuicServerSession* session = CreateQuicSession(
273 connection_id, current_server_address_, current_client_address_);
275 if (session == nullptr) {
276 DVLOG(1) << "Failed to create session for " << connection_id;
278 if (!framer_.IsSupportedVersion(header.versions.front())) {
279 // TODO(ianswett): Produce packet saying "no supported version".
280 return nullptr;
283 // Add this connection_id to the time-wait state, to safely reject future
284 // packets.
285 QuicVersion version = header.versions.front();
286 time_wait_list_manager_->AddConnectionIdToTimeWait(connection_id, version,
287 nullptr);
288 DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
289 HandlePacketForTimeWait(header);
291 return nullptr;
294 DVLOG(1) << "Created new session for connection ID " << connection_id;
295 session_map_.insert(std::make_pair(connection_id, session));
297 return session;
300 void QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
301 DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(
302 header.public_header.connection_id));
303 time_wait_list_manager_->ProcessPacket(current_server_address_,
304 current_client_address_,
305 header.public_header.connection_id,
306 header.packet_sequence_number,
307 *current_packet_);
310 void QuicDispatcher::CleanUpSession(SessionMap::iterator it) {
311 QuicConnection* connection = it->second->connection();
312 QuicEncryptedPacket* connection_close_packet =
313 connection->ReleaseConnectionClosePacket();
314 write_blocked_list_.erase(connection);
315 time_wait_list_manager_->AddConnectionIdToTimeWait(it->first,
316 connection->version(),
317 connection_close_packet);
318 session_map_.erase(it);
321 void QuicDispatcher::DeleteSessions() {
322 STLDeleteElements(&closed_session_list_);
325 void QuicDispatcher::OnCanWrite() {
326 // We got an EPOLLOUT: the socket should not be blocked.
327 writer_->SetWritable();
329 // Give all the blocked writers one chance to write, until we're blocked again
330 // or there's no work left.
331 while (!write_blocked_list_.empty() && !writer_->IsWriteBlocked()) {
332 QuicBlockedWriterInterface* blocked_writer =
333 write_blocked_list_.begin()->first;
334 write_blocked_list_.erase(write_blocked_list_.begin());
335 blocked_writer->OnCanWrite();
339 bool QuicDispatcher::HasPendingWrites() const {
340 return !write_blocked_list_.empty();
343 void QuicDispatcher::Shutdown() {
344 while (!session_map_.empty()) {
345 QuicServerSession* session = session_map_.begin()->second;
346 session->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
347 // Validate that the session removes itself from the session map on close.
348 DCHECK(session_map_.empty() || session_map_.begin()->second != session);
350 DeleteSessions();
353 void QuicDispatcher::OnConnectionClosed(QuicConnectionId connection_id,
354 QuicErrorCode error) {
355 SessionMap::iterator it = session_map_.find(connection_id);
356 if (it == session_map_.end()) {
357 LOG(DFATAL) << "ConnectionId " << connection_id
358 << " does not exist in the session map. "
359 << "Error: " << QuicUtils::ErrorToString(error);
360 LOG(DFATAL) << base::debug::StackTrace().ToString();
361 return;
364 DVLOG_IF(1, error != QUIC_NO_ERROR) << "Closing connection ("
365 << connection_id
366 << ") due to error: "
367 << QuicUtils::ErrorToString(error);
369 if (closed_session_list_.empty()) {
370 delete_sessions_alarm_->Cancel();
371 delete_sessions_alarm_->Set(helper()->GetClock()->ApproximateNow());
373 closed_session_list_.push_back(it->second);
374 CleanUpSession(it);
377 void QuicDispatcher::OnWriteBlocked(
378 QuicBlockedWriterInterface* blocked_writer) {
379 if (!writer_->IsWriteBlocked()) {
380 LOG(DFATAL) <<
381 "QuicDispatcher::OnWriteBlocked called when the writer is not blocked.";
382 // Return without adding the connection to the blocked list, to avoid
383 // infinite loops in OnCanWrite.
384 return;
386 write_blocked_list_.insert(std::make_pair(blocked_writer, true));
389 void QuicDispatcher::OnConnectionAddedToTimeWaitList(
390 QuicConnectionId connection_id) {
391 DVLOG(1) << "Connection " << connection_id << " added to time wait list.";
394 void QuicDispatcher::OnConnectionRemovedFromTimeWaitList(
395 QuicConnectionId connection_id) {
396 DVLOG(1) << "Connection " << connection_id << " removed from time wait list.";
399 QuicServerSession* QuicDispatcher::CreateQuicSession(
400 QuicConnectionId connection_id,
401 const IPEndPoint& server_address,
402 const IPEndPoint& client_address) {
403 // The QuicServerSession takes ownership of |connection| below.
404 QuicConnection* connection = new QuicConnection(
405 connection_id, client_address, helper_.get(), connection_writer_factory_,
406 /* owns_writer= */ true, Perspective::IS_SERVER,
407 crypto_config_.HasProofSource(), supported_versions_);
409 QuicServerSession* session = new QuicServerSession(config_, connection, this);
410 session->InitializeSession(&crypto_config_);
411 return session;
414 QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() {
415 return new QuicTimeWaitListManager(
416 writer_.get(), this, helper_.get(), supported_versions());
419 bool QuicDispatcher::HandlePacketForTimeWait(
420 const QuicPacketPublicHeader& header) {
421 if (header.reset_flag) {
422 // Public reset packets do not have sequence numbers, so ignore the packet.
423 return false;
426 // Switch the framer to the correct version, so that the sequence number can
427 // be parsed correctly.
428 framer_.set_version(time_wait_list_manager_->GetQuicVersionFromConnectionId(
429 header.connection_id));
431 // Continue parsing the packet to extract the sequence number. Then
432 // send it to the time wait manager in OnUnathenticatedHeader.
433 return true;
436 } // namespace tools
437 } // namespace net