1// Copyright 2014 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. 4 5#include "net/quic/quic_dispatcher.h" 6 7#include <errno.h> 8 9#include "base/debug/stack_trace.h" 10#include "base/logging.h" 11#include "base/stl_util.h" 12#include "net/quic/quic_blocked_writer_interface.h" 13#include "net/quic/quic_connection_helper.h" 14#include "net/quic/quic_flags.h" 15#include "net/quic/quic_per_connection_packet_writer.h" 16#include "net/quic/quic_time_wait_list_manager.h" 17#include "net/quic/quic_utils.h" 18 19namespace net { 20 21using base::StringPiece; 22using std::make_pair; 23using std::find; 24 25class DeleteSessionsAlarm : public QuicAlarm::Delegate { 26 public: 27 explicit DeleteSessionsAlarm(QuicDispatcher* dispatcher) 28 : dispatcher_(dispatcher) { 29 } 30 31 virtual QuicTime OnAlarm() OVERRIDE { 32 dispatcher_->DeleteSessions(); 33 return QuicTime::Zero(); 34 } 35 36 private: 37 QuicDispatcher* dispatcher_; 38}; 39 40class QuicDispatcher::QuicFramerVisitor : public QuicFramerVisitorInterface { 41 public: 42 explicit QuicFramerVisitor(QuicDispatcher* dispatcher) 43 : dispatcher_(dispatcher), 44 connection_id_(0) {} 45 46 // QuicFramerVisitorInterface implementation 47 virtual void OnPacket() OVERRIDE {} 48 virtual bool OnUnauthenticatedPublicHeader( 49 const QuicPacketPublicHeader& header) OVERRIDE { 50 connection_id_ = header.connection_id; 51 return dispatcher_->OnUnauthenticatedPublicHeader(header); 52 } 53 virtual bool OnUnauthenticatedHeader( 54 const QuicPacketHeader& header) OVERRIDE { 55 dispatcher_->OnUnauthenticatedHeader(header); 56 return false; 57 } 58 virtual void OnError(QuicFramer* framer) OVERRIDE { 59 DVLOG(1) << QuicUtils::ErrorToString(framer->error()); 60 } 61 62 virtual bool OnProtocolVersionMismatch( 63 QuicVersion /*received_version*/) OVERRIDE { 64 if (dispatcher_->time_wait_list_manager()->IsConnectionIdInTimeWait( 65 connection_id_)) { 66 // Keep processing after protocol mismatch - this will be dealt with by 67 // the TimeWaitListManager. 68 return true; 69 } else { 70 DLOG(DFATAL) << "Version mismatch, connection ID (" << connection_id_ 71 << ") not in time wait list."; 72 return false; 73 } 74 } 75 76 // The following methods should never get called because we always return 77 // false from OnUnauthenticatedHeader(). As a result, we never process the 78 // payload of the packet. 79 virtual void OnPublicResetPacket( 80 const QuicPublicResetPacket& /*packet*/) OVERRIDE { 81 DCHECK(false); 82 } 83 virtual void OnVersionNegotiationPacket( 84 const QuicVersionNegotiationPacket& /*packet*/) OVERRIDE { 85 DCHECK(false); 86 } 87 virtual void OnDecryptedPacket(EncryptionLevel level) OVERRIDE { 88 DCHECK(false); 89 } 90 virtual bool OnPacketHeader(const QuicPacketHeader& /*header*/) OVERRIDE { 91 DCHECK(false); 92 return false; 93 } 94 virtual void OnRevivedPacket() OVERRIDE { 95 DCHECK(false); 96 } 97 virtual void OnFecProtectedPayload(StringPiece /*payload*/) OVERRIDE { 98 DCHECK(false); 99 } 100 virtual bool OnStreamFrame(const QuicStreamFrame& /*frame*/) OVERRIDE { 101 DCHECK(false); 102 return false; 103 } 104 virtual bool OnAckFrame(const QuicAckFrame& /*frame*/) OVERRIDE { 105 DCHECK(false); 106 return false; 107 } 108 virtual bool OnCongestionFeedbackFrame( 109 const QuicCongestionFeedbackFrame& /*frame*/) OVERRIDE { 110 DCHECK(false); 111 return false; 112 } 113 virtual bool OnStopWaitingFrame( 114 const QuicStopWaitingFrame& /*frame*/) OVERRIDE { 115 DCHECK(false); 116 return false; 117 } 118 virtual bool OnPingFrame(const QuicPingFrame& /*frame*/) OVERRIDE { 119 DCHECK(false); 120 return false; 121 } 122 virtual bool OnRstStreamFrame(const QuicRstStreamFrame& /*frame*/) OVERRIDE { 123 DCHECK(false); 124 return false; 125 } 126 virtual bool OnConnectionCloseFrame( 127 const QuicConnectionCloseFrame & /*frame*/) OVERRIDE { 128 DCHECK(false); 129 return false; 130 } 131 virtual bool OnGoAwayFrame(const QuicGoAwayFrame& /*frame*/) OVERRIDE { 132 DCHECK(false); 133 return false; 134 } 135 virtual bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& /*frame*/) 136 OVERRIDE { 137 DCHECK(false); 138 return false; 139 } 140 virtual bool OnBlockedFrame(const QuicBlockedFrame& frame) OVERRIDE { 141 DCHECK(false); 142 return false; 143 } 144 virtual void OnFecData(const QuicFecData& /*fec*/) OVERRIDE { 145 DCHECK(false); 146 } 147 virtual void OnPacketComplete() OVERRIDE { 148 DCHECK(false); 149 } 150 151 private: 152 QuicDispatcher* dispatcher_; 153 154 // Latched in OnUnauthenticatedPublicHeader for use later. 155 QuicConnectionId connection_id_; 156}; 157 158QuicPacketWriter* QuicDispatcher::DefaultPacketWriterFactory::Create( 159 QuicServerPacketWriter* writer, 160 QuicConnection* connection) { 161 return new QuicPerConnectionPacketWriter(writer, connection); 162} 163 164QuicDispatcher::PacketWriterFactoryAdapter::PacketWriterFactoryAdapter( 165 QuicDispatcher* dispatcher) 166 : dispatcher_(dispatcher) {} 167 168QuicDispatcher::PacketWriterFactoryAdapter::~PacketWriterFactoryAdapter() {} 169 170QuicPacketWriter* QuicDispatcher::PacketWriterFactoryAdapter::Create( 171 QuicConnection* connection) const { 172 return dispatcher_->packet_writer_factory_->Create( 173 dispatcher_->writer_.get(), 174 connection); 175} 176 177QuicDispatcher::QuicDispatcher(const QuicConfig& config, 178 const QuicCryptoServerConfig& crypto_config, 179 const QuicVersionVector& supported_versions, 180 PacketWriterFactory* packet_writer_factory, 181 QuicConnectionHelperInterface* helper) 182 : config_(config), 183 crypto_config_(crypto_config), 184 helper_(helper), 185 delete_sessions_alarm_( 186 helper_->CreateAlarm(new DeleteSessionsAlarm(this))), 187 packet_writer_factory_(packet_writer_factory), 188 connection_writer_factory_(this), 189 supported_versions_(supported_versions), 190 current_packet_(NULL), 191 framer_(supported_versions, /*unused*/ QuicTime::Zero(), true), 192 framer_visitor_(new QuicFramerVisitor(this)) { 193 framer_.set_visitor(framer_visitor_.get()); 194} 195 196QuicDispatcher::~QuicDispatcher() { 197 STLDeleteValues(&session_map_); 198 STLDeleteElements(&closed_session_list_); 199} 200 201void QuicDispatcher::Initialize(QuicServerPacketWriter* writer) { 202 DCHECK(writer_ == NULL); 203 writer_.reset(writer); 204 time_wait_list_manager_.reset(CreateQuicTimeWaitListManager()); 205} 206 207void QuicDispatcher::ProcessPacket(const IPEndPoint& server_address, 208 const IPEndPoint& client_address, 209 const QuicEncryptedPacket& packet) { 210 current_server_address_ = server_address; 211 current_client_address_ = client_address; 212 current_packet_ = &packet; 213 // ProcessPacket will cause the packet to be dispatched in 214 // OnUnauthenticatedPublicHeader, or sent to the time wait list manager 215 // in OnAuthenticatedHeader. 216 framer_.ProcessPacket(packet); 217 // TODO(rjshade): Return a status describing if/why a packet was dropped, 218 // and log somehow. Maybe expose as a varz. 219} 220 221bool QuicDispatcher::OnUnauthenticatedPublicHeader( 222 const QuicPacketPublicHeader& header) { 223 QuicSession* session = NULL; 224 225 QuicConnectionId connection_id = header.connection_id; 226 SessionMap::iterator it = session_map_.find(connection_id); 227 if (it == session_map_.end()) { 228 if (header.reset_flag) { 229 return false; 230 } 231 if (time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)) { 232 return HandlePacketForTimeWait(header); 233 } 234 235 // Ensure the packet has a version negotiation bit set before creating a new 236 // session for it. All initial packets for a new connection are required to 237 // have the flag set. Otherwise it may be a stray packet. 238 if (header.version_flag) { 239 session = CreateQuicSession(connection_id, current_server_address_, 240 current_client_address_); 241 } 242 243 if (session == NULL) { 244 DVLOG(1) << "Failed to create session for " << connection_id; 245 // Add this connection_id fo the time-wait state, to safely reject future 246 // packets. 247 248 if (header.version_flag && 249 !framer_.IsSupportedVersion(header.versions.front())) { 250 // TODO(ianswett): Produce a no-version version negotiation packet. 251 return false; 252 } 253 254 // Use the version in the packet if possible, otherwise assume the latest. 255 QuicVersion version = header.version_flag ? header.versions.front() : 256 supported_versions_.front(); 257 time_wait_list_manager_->AddConnectionIdToTimeWait( 258 connection_id, version, NULL); 259 DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); 260 return HandlePacketForTimeWait(header); 261 } 262 DVLOG(1) << "Created new session for " << connection_id; 263 session_map_.insert(make_pair(connection_id, session)); 264 } else { 265 session = it->second; 266 } 267 268 session->connection()->ProcessUdpPacket( 269 current_server_address_, current_client_address_, *current_packet_); 270 271 // Do not parse the packet further. The session will process it completely. 272 return false; 273} 274 275void QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) { 276 DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait( 277 header.public_header.connection_id)); 278 time_wait_list_manager_->ProcessPacket(current_server_address_, 279 current_client_address_, 280 header.public_header.connection_id, 281 header.packet_sequence_number, 282 *current_packet_); 283} 284 285void QuicDispatcher::CleanUpSession(SessionMap::iterator it) { 286 QuicConnection* connection = it->second->connection(); 287 QuicEncryptedPacket* connection_close_packet = 288 connection->ReleaseConnectionClosePacket(); 289 write_blocked_list_.erase(connection); 290 time_wait_list_manager_->AddConnectionIdToTimeWait(it->first, 291 connection->version(), 292 connection_close_packet); 293 session_map_.erase(it); 294} 295 296void QuicDispatcher::DeleteSessions() { 297 STLDeleteElements(&closed_session_list_); 298} 299 300void QuicDispatcher::OnCanWrite() { 301 // We finished a write: the socket should not be blocked. 302 writer_->SetWritable(); 303 304 // Give all the blocked writers one chance to write, until we're blocked again 305 // or there's no work left. 306 while (!write_blocked_list_.empty() && !writer_->IsWriteBlocked()) { 307 QuicBlockedWriterInterface* blocked_writer = 308 write_blocked_list_.begin()->first; 309 write_blocked_list_.erase(write_blocked_list_.begin()); 310 blocked_writer->OnCanWrite(); 311 } 312} 313 314bool QuicDispatcher::HasPendingWrites() const { 315 return !write_blocked_list_.empty(); 316} 317 318void QuicDispatcher::Shutdown() { 319 while (!session_map_.empty()) { 320 QuicSession* session = session_map_.begin()->second; 321 session->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY); 322 // Validate that the session removes itself from the session map on close. 323 DCHECK(session_map_.empty() || session_map_.begin()->second != session); 324 } 325 DeleteSessions(); 326} 327 328void QuicDispatcher::OnConnectionClosed(QuicConnectionId connection_id, 329 QuicErrorCode error) { 330 SessionMap::iterator it = session_map_.find(connection_id); 331 if (it == session_map_.end()) { 332 LOG(DFATAL) << "ConnectionId " << connection_id 333 << " does not exist in the session map. " 334 << "Error: " << QuicUtils::ErrorToString(error); 335 LOG(DFATAL) << base::debug::StackTrace().ToString(); 336 return; 337 } 338 DVLOG_IF(1, error != QUIC_NO_ERROR) << "Closing connection (" 339 << connection_id 340 << ") due to error: " 341 << QuicUtils::ErrorToString(error); 342 if (closed_session_list_.empty()) { 343 delete_sessions_alarm_->Set(helper_->GetClock()->ApproximateNow()); 344 } 345 closed_session_list_.push_back(it->second); 346 CleanUpSession(it); 347} 348 349void QuicDispatcher::OnWriteBlocked( 350 QuicBlockedWriterInterface* blocked_writer) { 351 if (!writer_->IsWriteBlocked()) { 352 LOG(DFATAL) << 353 "QuicDispatcher::OnWriteBlocked called when the writer is not blocked."; 354 // Return without adding the connection to the blocked list, to avoid 355 // infinite loops in OnCanWrite. 356 return; 357 } 358 write_blocked_list_.insert(make_pair(blocked_writer, true)); 359} 360 361QuicSession* QuicDispatcher::CreateQuicSession( 362 QuicConnectionId connection_id, 363 const IPEndPoint& server_address, 364 const IPEndPoint& client_address) { 365 QuicServerSession* session = new QuicServerSession( 366 config_, 367 CreateQuicConnection(connection_id, server_address, client_address), 368 this); 369 session->InitializeSession(crypto_config_); 370 return session; 371} 372 373QuicConnection* QuicDispatcher::CreateQuicConnection( 374 QuicConnectionId connection_id, 375 const IPEndPoint& server_address, 376 const IPEndPoint& client_address) { 377 return new QuicConnection(connection_id, 378 client_address, 379 helper_, 380 connection_writer_factory_, 381 /* owns_writer= */ true, 382 /* is_server= */ true, 383 supported_versions_); 384} 385 386QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() { 387 return new QuicTimeWaitListManager( 388 writer_.get(), this, helper_, supported_versions()); 389} 390 391bool QuicDispatcher::HandlePacketForTimeWait( 392 const QuicPacketPublicHeader& header) { 393 if (header.reset_flag) { 394 // Public reset packets do not have sequence numbers, so ignore the packet. 395 return false; 396 } 397 398 // Switch the framer to the correct version, so that the sequence number can 399 // be parsed correctly. 400 framer_.set_version(time_wait_list_manager_->GetQuicVersionFromConnectionId( 401 header.connection_id)); 402 403 // Continue parsing the packet to extract the sequence number. Then 404 // send it to the time wait manager in OnUnathenticatedHeader. 405 return true; 406} 407 408} // namespace net 409