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

Side by Side Diff: net/quic/chromium/quic_chromium_client_session.cc

Issue 2319343004: Makes migration on write error asynchronous to avoid reentrancy issues (Closed)
Patch Set: added tests for async write before notification and fixed call to OnCanWrite Created 4 years, 3 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/quic/chromium/quic_chromium_client_session.h" 5 #include "net/quic/chromium/quic_chromium_client_session.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/callback_helpers.h" 9 #include "base/callback_helpers.h"
10 #include "base/location.h" 10 #include "base/location.h"
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 logger_(new QuicConnectionLogger(this, 230 logger_(new QuicConnectionLogger(this,
231 connection_description, 231 connection_description,
232 std::move(socket_performance_watcher), 232 std::move(socket_performance_watcher),
233 net_log_)), 233 net_log_)),
234 going_away_(false), 234 going_away_(false),
235 port_migration_detected_(false), 235 port_migration_detected_(false),
236 disabled_reason_(QUIC_DISABLED_NOT), 236 disabled_reason_(QUIC_DISABLED_NOT),
237 token_binding_signatures_(kTokenBindingSignatureMapSize), 237 token_binding_signatures_(kTokenBindingSignatureMapSize),
238 streams_pushed_count_(0), 238 streams_pushed_count_(0),
239 streams_pushed_and_claimed_count_(0), 239 streams_pushed_and_claimed_count_(0),
240 error_code_from_rewrite_(OK), 240 migration_pending_(false),
241 use_error_code_from_rewrite_(false), 241 write_pending_(false),
242 weak_factory_(this) { 242 weak_factory_(this) {
243 sockets_.push_back(std::move(socket)); 243 sockets_.push_back(std::move(socket));
244 packet_readers_.push_back(base::WrapUnique(new QuicChromiumPacketReader( 244 packet_readers_.push_back(base::WrapUnique(new QuicChromiumPacketReader(
245 sockets_.back().get(), clock, this, yield_after_packets, 245 sockets_.back().get(), clock, this, yield_after_packets,
246 yield_after_duration, net_log_))); 246 yield_after_duration, net_log_)));
247 crypto_stream_.reset( 247 crypto_stream_.reset(
248 crypto_client_stream_factory->CreateQuicCryptoClientStream( 248 crypto_client_stream_factory->CreateQuicCryptoClientStream(
249 server_id, this, base::WrapUnique(new ProofVerifyContextChromium( 249 server_id, this, base::WrapUnique(new ProofVerifyContextChromium(
250 cert_verify_flags, net_log_)), 250 cert_verify_flags, net_log_)),
251 crypto_config)); 251 crypto_config));
(...skipping 693 matching lines...) Expand 10 before | Expand all | Expand 10 after
945 void QuicChromiumClientSession::OnSuccessfulVersionNegotiation( 945 void QuicChromiumClientSession::OnSuccessfulVersionNegotiation(
946 const QuicVersion& version) { 946 const QuicVersion& version) {
947 logger_->OnSuccessfulVersionNegotiation(version); 947 logger_->OnSuccessfulVersionNegotiation(version);
948 QuicSpdySession::OnSuccessfulVersionNegotiation(version); 948 QuicSpdySession::OnSuccessfulVersionNegotiation(version);
949 } 949 }
950 950
951 int QuicChromiumClientSession::HandleWriteError( 951 int QuicChromiumClientSession::HandleWriteError(
952 int error_code, 952 int error_code,
953 scoped_refptr<StringIOBuffer> packet) { 953 scoped_refptr<StringIOBuffer> packet) {
954 DCHECK(packet != nullptr); 954 DCHECK(packet != nullptr);
955 use_error_code_from_rewrite_ = false; 955 DCHECK_NE(ERR_IO_PENDING, error_code);
956 if (stream_factory_) { 956 DCHECK_GT(0, error_code);
957 stream_factory_->MaybeMigrateSingleSession(this, WRITE_ERROR, packet); 957 DCHECK(!migration_pending_);
958 DCHECK(packet_ == nullptr);
959
960 // Post a task to migrate the session onto a new network.
961 task_runner_->PostTask(
962 FROM_HERE,
963 base::Bind(&QuicChromiumClientSession::MigrateSessionOnWriteError,
964 weak_factory_.GetWeakPtr()));
965
966 // Store packet in the session since the actual migration and packet rewrite
967 // can happen via this posted task or via an async network notification.
968 packet_ = packet;
969 migration_pending_ = true;
Ryan Hamilton 2016/09/12 00:52:18 This is the only place migration_pending_ is set t
Jana 2016/09/12 21:08:02 This is used (later in the pause CL) by the NCN co
970 static_cast<QuicChromiumPacketWriter*>(connection()->writer())
971 ->set_write_blocked(true);
Ryan Hamilton 2016/09/12 00:52:18 This is not needed is it? By returning ERR_IO_PEND
Jana 2016/09/12 21:08:02 Oh of course -- I am not sure why I added this her
972
973 // Cause the packet writer to return ERR_IO_PENDING and block so
974 // that the actual migration happens from the message loop instead
975 // of under the call stack of QuicConnection::WritePacket.
976 return ERR_IO_PENDING;
977 }
978
979 void QuicChromiumClientSession::MigrateSessionOnWriteError() {
980 // If migration_pending_ is false, an earlier task completed migration.
981 if (!migration_pending_)
982 return;
983
984 if (stream_factory_ != nullptr &&
985 stream_factory_->MaybeMigrateSingleSession(this, WRITE_ERROR) ==
986 MigrationResult::SUCCESS)
987 return;
Ryan Hamilton 2016/09/12 00:52:18 nit: {}s needed.
Jana 2016/09/12 21:08:02 Done.
988
989 // Close the connection if migration failed. Do not cause a
990 // connection close packet to be sent since socket may be borked.
991 connection()->CloseConnection(QUIC_PACKET_WRITE_ERROR,
992 "Write and subsequent migration failed",
993 ConnectionCloseBehavior::SILENT_CLOSE);
994 }
995
996 void QuicChromiumClientSession::WriteToNewSocket() {
997 // If write_pending_ is false, an earlier task wrote to the new socket.
998 if (!write_pending_)
999 return;
Ryan Hamilton 2016/09/12 01:32:57 You can take this or leave it... If we removed thi
Jana 2016/09/12 21:08:02 I did have the code doing that earlier, but enforc
1000 // Prevent any pending migration or write tasks from executing.
1001 write_pending_ = false;
1002 migration_pending_ = false;
1003
1004 static_cast<QuicChromiumPacketWriter*>(connection()->writer())
1005 ->set_write_blocked(false);
1006 DCHECK(!connection()->writer()->IsWriteBlocked());
1007
1008 if (packet_ == nullptr) {
1009 connection()->SendPing();
1010 // The connection may have been blocked before the migration
1011 // started. Unblock the connection if sending the PING packet did
1012 // not leave the writer blocked.
Ryan Hamilton 2016/09/12 00:52:18 I think the best thing to do is to call OnCanWrite
Jana 2016/09/12 21:08:02 Hm. Yeah, this does make reasoning simpler. Done.
1013 if (!connection()->writer()->IsWriteBlocked())
1014 connection()->OnCanWrite();
1015 return;
958 } 1016 }
959 return use_error_code_from_rewrite_ ? error_code_from_rewrite_ : error_code; 1017
1018 // Set packet_ to null first. We cannot set packet_ to null after
1019 // the following write since the write may result in packet_ being
1020 // reused via a write error.
Ryan Hamilton 2016/09/12 00:52:18 Avoid first person in comments: // Set packet t
Jana 2016/09/12 21:08:02 Done.
1021 scoped_refptr<StringIOBuffer> packet = packet_;
1022 packet_ = nullptr;
1023
1024 // The connection is waiting for the original write to complete
1025 // asynchronously. The new writer will notify the connection if the
1026 // write below completes asynchronously, but a synchronous competion
1027 // must be propagated back to the connection here.
1028 WriteResult result =
1029 static_cast<QuicChromiumPacketWriter*>(connection()->writer())
1030 ->WritePacketToSocket(packet);
1031
1032 if (result.error_code == ERR_IO_PENDING)
1033 return;
1034 // All write errors should be mapped into ERR_IO_PENDING by
1035 // HandleWriteError.
1036 DCHECK(result.error_code >= 0);
Ryan Hamilton 2016/09/12 00:52:18 nit: DCHECK_LT(0, result.error_code);
Jana 2016/09/12 21:08:02 Done.
1037 connection()->OnCanWrite();
960 } 1038 }
961 1039
962 void QuicChromiumClientSession::OnWriteError(int error_code) { 1040 void QuicChromiumClientSession::OnWriteError(int error_code) {
963 DCHECK_NE(ERR_IO_PENDING, error_code); 1041 DCHECK_NE(ERR_IO_PENDING, error_code);
964 DCHECK_GT(0, error_code); 1042 DCHECK_GT(0, error_code);
965 connection()->OnWriteError(error_code); 1043 connection()->OnWriteError(error_code);
966 } 1044 }
967 1045
968 void QuicChromiumClientSession::OnWriteUnblocked() { 1046 void QuicChromiumClientSession::OnWriteUnblocked() {
969 connection()->OnCanWrite(); 1047 connection()->OnCanWrite();
970 } 1048 }
971 1049
972 void QuicChromiumClientSession::OnPathDegrading() { 1050 void QuicChromiumClientSession::OnPathDegrading() {
973 if (stream_factory_) { 1051 if (stream_factory_) {
974 stream_factory_->MaybeMigrateSingleSession(this, EARLY_MIGRATION, nullptr); 1052 stream_factory_->MaybeMigrateSingleSession(this, EARLY_MIGRATION);
975 } 1053 }
976 } 1054 }
977 1055
978 bool QuicChromiumClientSession::HasOpenDynamicStreams() const { 1056 bool QuicChromiumClientSession::HasOpenDynamicStreams() const {
979 return QuicSession::HasOpenDynamicStreams() || 1057 return QuicSession::HasOpenDynamicStreams() ||
980 GetNumDrainingOutgoingStreams() > 0; 1058 GetNumDrainingOutgoingStreams() > 0;
981 } 1059 }
982 1060
983 void QuicChromiumClientSession::OnProofValid( 1061 void QuicChromiumClientSession::OnProofValid(
984 const QuicCryptoClientConfig::CachedState& cached) { 1062 const QuicCryptoClientConfig::CachedState& cached) {
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
1171 going_away_ = true; 1249 going_away_ = true;
1172 DCHECK_EQ(0u, GetNumActiveStreams()); 1250 DCHECK_EQ(0u, GetNumActiveStreams());
1173 // Will delete |this|. 1251 // Will delete |this|.
1174 if (stream_factory_) 1252 if (stream_factory_)
1175 stream_factory_->OnSessionClosed(this); 1253 stream_factory_->OnSessionClosed(this);
1176 } 1254 }
1177 1255
1178 bool QuicChromiumClientSession::MigrateToSocket( 1256 bool QuicChromiumClientSession::MigrateToSocket(
1179 std::unique_ptr<DatagramClientSocket> socket, 1257 std::unique_ptr<DatagramClientSocket> socket,
1180 std::unique_ptr<QuicChromiumPacketReader> reader, 1258 std::unique_ptr<QuicChromiumPacketReader> reader,
1181 std::unique_ptr<QuicChromiumPacketWriter> writer, 1259 std::unique_ptr<QuicChromiumPacketWriter> writer) {
1182 scoped_refptr<StringIOBuffer> packet) {
1183 DCHECK_EQ(sockets_.size(), packet_readers_.size()); 1260 DCHECK_EQ(sockets_.size(), packet_readers_.size());
1184 if (sockets_.size() >= kMaxReadersPerQuicSession) { 1261 if (sockets_.size() >= kMaxReadersPerQuicSession)
1185 return false; 1262 return false;
1186 } 1263
1187 // TODO(jri): Make SetQuicPacketWriter take a scoped_ptr. 1264 // TODO(jri): Make SetQuicPacketWriter take a scoped_ptr.
1188 packet_readers_.push_back(std::move(reader)); 1265 packet_readers_.push_back(std::move(reader));
1189 sockets_.push_back(std::move(socket)); 1266 sockets_.push_back(std::move(socket));
1190 StartReading(); 1267 StartReading();
1191 QuicChromiumPacketWriter* raw_writer = writer.get();
1192 connection()->SetQuicPacketWriter(writer.release(), /*owns_writer=*/true); 1268 connection()->SetQuicPacketWriter(writer.release(), /*owns_writer=*/true);
1193 if (packet == nullptr) { 1269
1194 connection()->SendPing(); 1270 // Post task to write the pending packet or a PING packet to the new
1195 return true; 1271 // socket. Also block the writer to prevent is being used until
Ryan Hamilton 2016/09/12 00:52:18 Can you add some language here which explains that
Jana 2016/09/12 21:08:02 Done.
1196 } 1272 // WriteToNewSocket completes.
Ryan Hamilton 2016/09/12 00:52:18 nit: move this sentence down to the call to block
Jana 2016/09/12 21:08:02 Done.
1197 // Packet rewrite after migration on socket write error. 1273 task_runner_->PostTask(
1198 error_code_from_rewrite_ = raw_writer->WritePacketToSocket(packet.get()); 1274 FROM_HERE, base::Bind(&QuicChromiumClientSession::WriteToNewSocket,
1199 use_error_code_from_rewrite_ = true; 1275 weak_factory_.GetWeakPtr()));
1276
1277 // Block the writer until the task posted is executed.
1278 static_cast<QuicChromiumPacketWriter*>(connection()->writer())
1279 ->set_write_blocked(true);
1280
1281 // Migration completed and write task posted.
1282 migration_pending_ = false;
1283 write_pending_ = true;
1200 return true; 1284 return true;
1201 } 1285 }
1202 1286
1203 void QuicChromiumClientSession::PopulateNetErrorDetails( 1287 void QuicChromiumClientSession::PopulateNetErrorDetails(
1204 NetErrorDetails* details) { 1288 NetErrorDetails* details) {
1205 details->quic_port_migration_detected = port_migration_detected_; 1289 details->quic_port_migration_detected = port_migration_detected_;
1206 } 1290 }
1207 1291
1208 const DatagramClientSocket* QuicChromiumClientSession::GetDefaultSocket() 1292 const DatagramClientSocket* QuicChromiumClientSession::GetDefaultSocket()
1209 const { 1293 const {
(...skipping 27 matching lines...) Expand all
1237 } 1321 }
1238 1322
1239 void QuicChromiumClientSession::DeletePromised( 1323 void QuicChromiumClientSession::DeletePromised(
1240 QuicClientPromisedInfo* promised) { 1324 QuicClientPromisedInfo* promised) {
1241 if (IsOpenStream(promised->id())) 1325 if (IsOpenStream(promised->id()))
1242 streams_pushed_and_claimed_count_++; 1326 streams_pushed_and_claimed_count_++;
1243 QuicClientSessionBase::DeletePromised(promised); 1327 QuicClientSessionBase::DeletePromised(promised);
1244 } 1328 }
1245 1329
1246 } // namespace net 1330 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698