Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / net / tools / quic / quic_dispatcher.cc
bloba4efa69f730ed4669a3d92a132b75b69693fe7dd
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_flags.h"
13 #include "net/quic/quic_utils.h"
14 #include "net/tools/quic/quic_per_connection_packet_writer.h"
15 #include "net/tools/quic/quic_time_wait_list_manager.h"
17 namespace net {
19 namespace tools {
21 using std::make_pair;
22 using base::StringPiece;
24 // The threshold size for the session map, over which the dispatcher will start
25 // sending stateless rejects (SREJ), rather than stateful rejects (REJ) to
26 // clients who support them. If -1, stateless rejects will not be sent. If 0,
27 // the server will only send stateless rejects to clients who support them.
28 int32 FLAGS_quic_session_map_threshold_for_stateless_rejects = -1;
30 namespace {
32 // An alarm that informs the QuicDispatcher to delete old sessions.
33 class DeleteSessionsAlarm : public QuicAlarm::Delegate {
34 public:
35 explicit DeleteSessionsAlarm(QuicDispatcher* dispatcher)
36 : dispatcher_(dispatcher) {
39 QuicTime OnAlarm() override {
40 dispatcher_->DeleteSessions();
41 // Let the dispatcher register the alarm at appropriate time.
42 return QuicTime::Zero();
45 private:
46 // Not owned.
47 QuicDispatcher* dispatcher_;
49 DISALLOW_COPY_AND_ASSIGN(DeleteSessionsAlarm);
52 } // namespace
54 class QuicDispatcher::QuicFramerVisitor : public QuicFramerVisitorInterface {
55 public:
56 explicit QuicFramerVisitor(QuicDispatcher* dispatcher)
57 : dispatcher_(dispatcher),
58 connection_id_(0) {}
60 // QuicFramerVisitorInterface implementation
61 void OnPacket() override {}
62 bool OnUnauthenticatedPublicHeader(
63 const QuicPacketPublicHeader& header) override {
64 connection_id_ = header.connection_id;
65 return dispatcher_->OnUnauthenticatedPublicHeader(header);
67 bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override {
68 dispatcher_->OnUnauthenticatedHeader(header);
69 return false;
71 void OnError(QuicFramer* framer) override {
72 QuicErrorCode error = framer->error();
73 dispatcher_->SetLastError(error);
74 DVLOG(1) << QuicUtils::ErrorToString(error);
77 bool OnProtocolVersionMismatch(QuicVersion /*received_version*/) override {
78 DVLOG(1) << "Version mismatch, connection ID " << connection_id_;
79 // Keep processing after protocol mismatch - this will be dealt with by the
80 // time wait list or connection that we will create.
81 return true;
84 // The following methods should never get called because
85 // OnUnauthenticatedPublicHeader() or OnUnauthenticatedHeader() (whichever was
86 // called last), will return false and prevent a subsequent invocation of
87 // these methods. Thus, the payload of the packet is never processed in the
88 // dispatcher.
89 void OnPublicResetPacket(const QuicPublicResetPacket& /*packet*/) override {
90 DCHECK(false);
92 void OnVersionNegotiationPacket(
93 const QuicVersionNegotiationPacket& /*packet*/) override {
94 DCHECK(false);
96 void OnDecryptedPacket(EncryptionLevel level) override { DCHECK(false); }
97 bool OnPacketHeader(const QuicPacketHeader& /*header*/) override {
98 DCHECK(false);
99 return false;
101 void OnRevivedPacket() override { DCHECK(false); }
102 void OnFecProtectedPayload(StringPiece /*payload*/) override {
103 DCHECK(false);
105 bool OnStreamFrame(const QuicStreamFrame& /*frame*/) override {
106 DCHECK(false);
107 return false;
109 bool OnAckFrame(const QuicAckFrame& /*frame*/) override {
110 DCHECK(false);
111 return false;
113 bool OnStopWaitingFrame(const QuicStopWaitingFrame& /*frame*/) override {
114 DCHECK(false);
115 return false;
117 bool OnPingFrame(const QuicPingFrame& /*frame*/) override {
118 DCHECK(false);
119 return false;
121 bool OnRstStreamFrame(const QuicRstStreamFrame& /*frame*/) override {
122 DCHECK(false);
123 return false;
125 bool OnConnectionCloseFrame(
126 const QuicConnectionCloseFrame& /*frame*/) override {
127 DCHECK(false);
128 return false;
130 bool OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) override {
131 DCHECK(false);
132 return false;
134 bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& /*frame*/) override {
135 DCHECK(false);
136 return false;
138 bool OnBlockedFrame(const QuicBlockedFrame& frame) override {
139 DCHECK(false);
140 return false;
142 void OnFecData(const QuicFecData& /*fec*/) override { DCHECK(false); }
143 void OnPacketComplete() override { DCHECK(false); }
145 private:
146 QuicDispatcher* dispatcher_;
148 // Latched in OnUnauthenticatedPublicHeader for use later.
149 QuicConnectionId connection_id_;
152 QuicPacketWriter* QuicDispatcher::DefaultPacketWriterFactory::Create(
153 QuicPacketWriter* writer,
154 QuicConnection* connection) {
155 return new QuicPerConnectionPacketWriter(writer, connection);
158 QuicDispatcher::PacketWriterFactoryAdapter::PacketWriterFactoryAdapter(
159 QuicDispatcher* dispatcher)
160 : dispatcher_(dispatcher) {}
162 QuicDispatcher::PacketWriterFactoryAdapter::~PacketWriterFactoryAdapter() {}
164 QuicPacketWriter* QuicDispatcher::PacketWriterFactoryAdapter::Create(
165 QuicConnection* connection) const {
166 return dispatcher_->packet_writer_factory_->Create(
167 dispatcher_->writer_.get(),
168 connection);
171 QuicDispatcher::QuicDispatcher(const QuicConfig& config,
172 const QuicCryptoServerConfig* crypto_config,
173 const QuicVersionVector& supported_versions,
174 PacketWriterFactory* packet_writer_factory,
175 QuicConnectionHelperInterface* helper)
176 : config_(config),
177 crypto_config_(crypto_config),
178 helper_(helper),
179 delete_sessions_alarm_(
180 helper_->CreateAlarm(new DeleteSessionsAlarm(this))),
181 packet_writer_factory_(packet_writer_factory),
182 connection_writer_factory_(this),
183 supported_versions_(supported_versions),
184 current_packet_(nullptr),
185 framer_(supported_versions,
186 /*unused*/ QuicTime::Zero(),
187 Perspective::IS_SERVER),
188 framer_visitor_(new QuicFramerVisitor(this)),
189 last_error_(QUIC_NO_ERROR) {
190 framer_.set_visitor(framer_visitor_.get());
193 QuicDispatcher::~QuicDispatcher() {
194 STLDeleteValues(&session_map_);
195 STLDeleteElements(&closed_session_list_);
198 void QuicDispatcher::InitializeWithWriter(QuicPacketWriter* writer) {
199 DCHECK(writer_ == nullptr);
200 writer_.reset(writer);
201 time_wait_list_manager_.reset(CreateQuicTimeWaitListManager());
204 void QuicDispatcher::ProcessPacket(const IPEndPoint& server_address,
205 const IPEndPoint& client_address,
206 const QuicEncryptedPacket& packet) {
207 current_server_address_ = server_address;
208 current_client_address_ = client_address;
209 current_packet_ = &packet;
210 // ProcessPacket will cause the packet to be dispatched in
211 // OnUnauthenticatedPublicHeader, or sent to the time wait list manager
212 // in OnAuthenticatedHeader.
213 framer_.ProcessPacket(packet);
214 // TODO(rjshade): Return a status describing if/why a packet was dropped,
215 // and log somehow. Maybe expose as a varz.
218 bool QuicDispatcher::OnUnauthenticatedPublicHeader(
219 const QuicPacketPublicHeader& header) {
220 // Port zero is only allowed for unidirectional UDP, so is disallowed by QUIC.
221 // Given that we can't even send a reply rejecting the packet, just drop the
222 // packet.
223 if (current_client_address_.port() == 0) {
224 return false;
227 // Stopgap test: The code does not construct full-length connection IDs
228 // correctly from truncated connection ID fields. Prevent this from causing
229 // the connection ID lookup to error by dropping any packet with a short
230 // connection ID.
231 if (header.connection_id_length != PACKET_8BYTE_CONNECTION_ID) {
232 return false;
235 // Packets with connection IDs for active connections are processed
236 // immediately.
237 QuicConnectionId connection_id = header.connection_id;
238 SessionMap::iterator it = session_map_.find(connection_id);
239 if (it != session_map_.end()) {
240 it->second->connection()->ProcessUdpPacket(
241 current_server_address_, current_client_address_, *current_packet_);
242 return false;
245 // If the packet is a public reset for a connection ID that is not active,
246 // there is nothing we must do or can do.
247 if (header.reset_flag) {
248 return false;
251 if (time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)) {
252 // Set the framer's version based on the recorded version for this
253 // connection and continue processing for non-public-reset packets.
254 return HandlePacketForTimeWait(header);
257 // The packet has an unknown connection ID.
259 // Unless the packet provides a version, assume that we can continue
260 // processing using our preferred version.
261 QuicVersion version = supported_versions_.front();
262 if (header.version_flag) {
263 QuicVersion packet_version = header.versions.front();
264 if (framer_.IsSupportedVersion(packet_version)) {
265 version = packet_version;
266 } else {
267 // Packets set to be processed but having an unsupported version will
268 // cause a connection to be created. The connection will handle
269 // sending a version negotiation packet.
270 // TODO(ianswett): This will malfunction if the full header of the packet
271 // causes a parsing error when parsed using the server's preferred
272 // version.
275 // Set the framer's version and continue processing.
276 framer_.set_version(version);
277 return true;
280 void QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
281 QuicConnectionId connection_id = header.public_header.connection_id;
283 if (time_wait_list_manager_->IsConnectionIdInTimeWait(
284 header.public_header.connection_id)) {
285 // This connection ID is already in time-wait state.
286 time_wait_list_manager_->ProcessPacket(
287 current_server_address_, current_client_address_,
288 header.public_header.connection_id, header.packet_packet_number,
289 *current_packet_);
290 return;
293 // Packet's connection ID is unknown.
294 // Apply the validity checks.
295 QuicPacketFate fate = ValidityChecks(header);
296 switch (fate) {
297 case kFateProcess: {
298 // Create a session and process the packet.
299 QuicServerSession* session = CreateQuicSession(
300 connection_id, current_server_address_, current_client_address_);
301 DVLOG(1) << "Created new session for " << connection_id;
302 session_map_.insert(make_pair(connection_id, session));
303 session->connection()->ProcessUdpPacket(
304 current_server_address_, current_client_address_, *current_packet_);
306 if (FLAGS_enable_quic_stateless_reject_support &&
307 session->UsingStatelessRejectsIfPeerSupported() &&
308 session->PeerSupportsStatelessRejects() &&
309 !session->IsCryptoHandshakeConfirmed()) {
310 DVLOG(1) << "Removing new session for " << connection_id
311 << " because the session is in stateless reject mode and"
312 << " encryption has not been established.";
313 session->connection()->CloseConnection(
314 QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, /* from_peer */ false);
316 break;
318 case kFateTimeWait:
319 // Add this connection_id to the time-wait state, to safely reject
320 // future packets.
321 DVLOG(1) << "Adding connection ID " << connection_id
322 << "to time-wait list.";
323 time_wait_list_manager_->AddConnectionIdToTimeWait(
324 connection_id, framer_.version(),
325 /*connection_rejected_statelessly=*/false, nullptr);
326 DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(
327 header.public_header.connection_id));
328 time_wait_list_manager_->ProcessPacket(
329 current_server_address_, current_client_address_,
330 header.public_header.connection_id, header.packet_packet_number,
331 *current_packet_);
332 break;
333 case kFateDrop:
334 // Do nothing with the packet.
335 break;
339 QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks(
340 const QuicPacketHeader& header) {
341 // To have all the checks work properly without tears, insert any new check
342 // into the framework of this method in the section for checks that return the
343 // check's fate value. The sections for checks must be ordered with the
344 // highest priority fate first.
346 // Checks that return kFateDrop.
348 // Checks that return kFateTimeWait.
350 // All packets within a connection sent by a client before receiving a
351 // response from the server are required to have the version negotiation flag
352 // set. Since this may be a client continuing a connection we lost track of
353 // via server restart, send a rejection to fast-fail the connection.
354 if (!header.public_header.version_flag) {
355 DVLOG(1) << "Packet without version arrived for unknown connection ID "
356 << header.public_header.connection_id;
357 return kFateTimeWait;
360 // Check that the sequence numer is within the range that the client is
361 // expected to send before receiving a response from the server.
362 if (header.packet_packet_number == kInvalidPacketNumber ||
363 header.packet_packet_number > kMaxReasonableInitialPacketNumber) {
364 return kFateTimeWait;
367 return kFateProcess;
370 void QuicDispatcher::CleanUpSession(SessionMap::iterator it,
371 bool should_close_statelessly) {
372 QuicConnection* connection = it->second->connection();
373 QuicEncryptedPacket* connection_close_packet =
374 connection->ReleaseConnectionClosePacket();
375 write_blocked_list_.erase(connection);
376 DCHECK(!should_close_statelessly || !connection_close_packet);
377 time_wait_list_manager_->AddConnectionIdToTimeWait(
378 it->first, connection->version(), should_close_statelessly,
379 connection_close_packet);
380 session_map_.erase(it);
383 void QuicDispatcher::DeleteSessions() {
384 STLDeleteElements(&closed_session_list_);
387 void QuicDispatcher::OnCanWrite() {
388 // The socket is now writable.
389 writer_->SetWritable();
391 // Give all the blocked writers one chance to write, until we're blocked again
392 // or there's no work left.
393 while (!write_blocked_list_.empty() && !writer_->IsWriteBlocked()) {
394 QuicBlockedWriterInterface* blocked_writer =
395 write_blocked_list_.begin()->first;
396 write_blocked_list_.erase(write_blocked_list_.begin());
397 blocked_writer->OnCanWrite();
401 bool QuicDispatcher::HasPendingWrites() const {
402 return !write_blocked_list_.empty();
405 void QuicDispatcher::Shutdown() {
406 while (!session_map_.empty()) {
407 QuicServerSession* session = session_map_.begin()->second;
408 session->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY);
409 // Validate that the session removes itself from the session map on close.
410 DCHECK(session_map_.empty() || session_map_.begin()->second != session);
412 DeleteSessions();
415 void QuicDispatcher::OnConnectionClosed(QuicConnectionId connection_id,
416 QuicErrorCode error) {
417 SessionMap::iterator it = session_map_.find(connection_id);
418 if (it == session_map_.end()) {
419 LOG(DFATAL) << "ConnectionId " << connection_id
420 << " does not exist in the session map. "
421 << "Error: " << QuicUtils::ErrorToString(error);
422 LOG(DFATAL) << base::debug::StackTrace().ToString();
423 return;
426 DVLOG_IF(1, error != QUIC_NO_ERROR) << "Closing connection ("
427 << connection_id
428 << ") due to error: "
429 << QuicUtils::ErrorToString(error);
431 if (closed_session_list_.empty()) {
432 delete_sessions_alarm_->Cancel();
433 delete_sessions_alarm_->Set(helper()->GetClock()->ApproximateNow());
435 closed_session_list_.push_back(it->second);
436 const bool should_close_statelessly =
437 (error == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT);
438 CleanUpSession(it, should_close_statelessly);
441 void QuicDispatcher::OnWriteBlocked(
442 QuicBlockedWriterInterface* blocked_writer) {
443 if (!writer_->IsWriteBlocked()) {
444 LOG(DFATAL) <<
445 "QuicDispatcher::OnWriteBlocked called when the writer is not blocked.";
446 // Return without adding the connection to the blocked list, to avoid
447 // infinite loops in OnCanWrite.
448 return;
450 write_blocked_list_.insert(std::make_pair(blocked_writer, true));
453 void QuicDispatcher::OnConnectionAddedToTimeWaitList(
454 QuicConnectionId connection_id) {
455 DVLOG(1) << "Connection " << connection_id << " added to time wait list.";
458 void QuicDispatcher::OnConnectionRemovedFromTimeWaitList(
459 QuicConnectionId connection_id) {
460 DVLOG(1) << "Connection " << connection_id << " removed from time wait list.";
463 QuicServerSession* QuicDispatcher::CreateQuicSession(
464 QuicConnectionId connection_id,
465 const IPEndPoint& server_address,
466 const IPEndPoint& client_address) {
467 // The QuicServerSession takes ownership of |connection| below.
468 QuicConnection* connection = new QuicConnection(
469 connection_id, client_address, helper_.get(), connection_writer_factory_,
470 /* owns_writer= */ true, Perspective::IS_SERVER,
471 crypto_config_->HasProofSource(), supported_versions_);
473 QuicServerSession* session =
474 new QuicServerSession(config_, connection, this, crypto_config_);
475 session->Initialize();
476 if (FLAGS_quic_session_map_threshold_for_stateless_rejects != -1 &&
477 session_map_.size() >=
478 static_cast<size_t>(
479 FLAGS_quic_session_map_threshold_for_stateless_rejects)) {
480 session->set_use_stateless_rejects_if_peer_supported(true);
482 return session;
485 QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() {
486 // TODO(rjshade): The QuicTimeWaitListManager should take ownership of the
487 // per-connection packet writer.
488 time_wait_list_writer_.reset(
489 packet_writer_factory_->Create(writer_.get(), nullptr));
490 return new QuicTimeWaitListManager(time_wait_list_writer_.get(), this,
491 helper_.get(), supported_versions());
494 bool QuicDispatcher::HandlePacketForTimeWait(
495 const QuicPacketPublicHeader& header) {
496 if (header.reset_flag) {
497 // Public reset packets do not have packet numbers, so ignore the packet.
498 return false;
501 // Switch the framer to the correct version, so that the packet number can
502 // be parsed correctly.
503 framer_.set_version(time_wait_list_manager_->GetQuicVersionFromConnectionId(
504 header.connection_id));
506 // Continue parsing the packet to extract the packet number. Then
507 // send it to the time wait manager in OnUnathenticatedHeader.
508 return true;
511 void QuicDispatcher::SetLastError(QuicErrorCode error) {
512 last_error_ = error;
515 } // namespace tools
516 } // namespace net