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"
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"
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;
32 // An alarm that informs the QuicDispatcher to delete old sessions.
33 class DeleteSessionsAlarm
: public QuicAlarm::Delegate
{
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();
47 QuicDispatcher
* dispatcher_
;
49 DISALLOW_COPY_AND_ASSIGN(DeleteSessionsAlarm
);
54 class QuicDispatcher::QuicFramerVisitor
: public QuicFramerVisitorInterface
{
56 explicit QuicFramerVisitor(QuicDispatcher
* dispatcher
)
57 : dispatcher_(dispatcher
),
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
);
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.
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
89 void OnPublicResetPacket(const QuicPublicResetPacket
& /*packet*/) override
{
92 void OnVersionNegotiationPacket(
93 const QuicVersionNegotiationPacket
& /*packet*/) override
{
96 void OnDecryptedPacket(EncryptionLevel level
) override
{ DCHECK(false); }
97 bool OnPacketHeader(const QuicPacketHeader
& /*header*/) override
{
101 void OnRevivedPacket() override
{ DCHECK(false); }
102 void OnFecProtectedPayload(StringPiece
/*payload*/) override
{
105 bool OnStreamFrame(const QuicStreamFrame
& /*frame*/) override
{
109 bool OnAckFrame(const QuicAckFrame
& /*frame*/) override
{
113 bool OnStopWaitingFrame(const QuicStopWaitingFrame
& /*frame*/) override
{
117 bool OnPingFrame(const QuicPingFrame
& /*frame*/) override
{
121 bool OnRstStreamFrame(const QuicRstStreamFrame
& /*frame*/) override
{
125 bool OnConnectionCloseFrame(
126 const QuicConnectionCloseFrame
& /*frame*/) override
{
130 bool OnGoAwayFrame(const QuicGoAwayFrame
& /*frame*/) override
{
134 bool OnWindowUpdateFrame(const QuicWindowUpdateFrame
& /*frame*/) override
{
138 bool OnBlockedFrame(const QuicBlockedFrame
& frame
) override
{
142 void OnFecData(const QuicFecData
& /*fec*/) override
{ DCHECK(false); }
143 void OnPacketComplete() override
{ DCHECK(false); }
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(),
171 QuicDispatcher::QuicDispatcher(const QuicConfig
& config
,
172 const QuicCryptoServerConfig
* crypto_config
,
173 const QuicVersionVector
& supported_versions
,
174 PacketWriterFactory
* packet_writer_factory
,
175 QuicConnectionHelperInterface
* helper
)
177 crypto_config_(crypto_config
),
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
223 if (current_client_address_
.port() == 0) {
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
231 if (header
.connection_id_length
!= PACKET_8BYTE_CONNECTION_ID
) {
235 // Packets with connection IDs for active connections are processed
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_
);
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
) {
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
;
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
275 // Set the framer's version and continue processing.
276 framer_
.set_version(version
);
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
,
293 // Packet's connection ID is unknown.
294 // Apply the validity checks.
295 QuicPacketFate fate
= ValidityChecks(header
);
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);
319 // Add this connection_id to the time-wait state, to safely reject
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
,
334 // Do nothing with the packet.
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
;
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
);
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();
426 DVLOG_IF(1, error
!= QUIC_NO_ERROR
) << "Closing connection ("
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()) {
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.
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() >=
479 FLAGS_quic_session_map_threshold_for_stateless_rejects
)) {
480 session
->set_use_stateless_rejects_if_peer_supported(true);
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.
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.
511 void QuicDispatcher::SetLastError(QuicErrorCode error
) {