Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(347)

Side by Side Diff: net/quic/quic_dispatcher.cc

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

Powered by Google App Engine
This is Rietveld 408576698