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

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: Cleaning up. 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 packet_(nullptr),
Ryan Hamilton 2016/09/10 16:29:47 nit: no need for this as the default constructor w
Jana 2016/09/10 23:08:31 Done.
241 use_error_code_from_rewrite_(false),
242 weak_factory_(this) { 241 weak_factory_(this) {
243 sockets_.push_back(std::move(socket)); 242 sockets_.push_back(std::move(socket));
244 packet_readers_.push_back(base::WrapUnique(new QuicChromiumPacketReader( 243 packet_readers_.push_back(base::WrapUnique(new QuicChromiumPacketReader(
245 sockets_.back().get(), clock, this, yield_after_packets, 244 sockets_.back().get(), clock, this, yield_after_packets,
246 yield_after_duration, net_log_))); 245 yield_after_duration, net_log_)));
247 crypto_stream_.reset( 246 crypto_stream_.reset(
248 crypto_client_stream_factory->CreateQuicCryptoClientStream( 247 crypto_client_stream_factory->CreateQuicCryptoClientStream(
249 server_id, this, base::WrapUnique(new ProofVerifyContextChromium( 248 server_id, this, base::WrapUnique(new ProofVerifyContextChromium(
250 cert_verify_flags, net_log_)), 249 cert_verify_flags, net_log_)),
251 crypto_config)); 250 crypto_config));
(...skipping 693 matching lines...) Expand 10 before | Expand all | Expand 10 after
945 void QuicChromiumClientSession::OnSuccessfulVersionNegotiation( 944 void QuicChromiumClientSession::OnSuccessfulVersionNegotiation(
946 const QuicVersion& version) { 945 const QuicVersion& version) {
947 logger_->OnSuccessfulVersionNegotiation(version); 946 logger_->OnSuccessfulVersionNegotiation(version);
948 QuicSpdySession::OnSuccessfulVersionNegotiation(version); 947 QuicSpdySession::OnSuccessfulVersionNegotiation(version);
949 } 948 }
950 949
951 int QuicChromiumClientSession::HandleWriteError( 950 int QuicChromiumClientSession::HandleWriteError(
952 int error_code, 951 int error_code,
953 scoped_refptr<StringIOBuffer> packet) { 952 scoped_refptr<StringIOBuffer> packet) {
954 DCHECK(packet != nullptr); 953 DCHECK(packet != nullptr);
955 use_error_code_from_rewrite_ = false; 954 DCHECK_NE(ERR_IO_PENDING, error_code);
956 if (stream_factory_) { 955 DCHECK_GT(0, error_code);
957 stream_factory_->MaybeMigrateSingleSession(this, WRITE_ERROR, packet); 956
957 // Post a task to migrate the session onto a new network.
958 task_runner_->PostTask(
959 FROM_HERE,
960 base::Bind(&QuicChromiumClientSession::MigrateSessionOnWriteError,
961 weak_factory_.GetWeakPtr()));
962
963 // Store packet in the session since the actual migration and packet rewrite
964 // can happen via this posted task or via an async network notification.
965 packet_ = packet;
966
967 // Cause the packet writer to return ERR_IO_PENDING and block so
968 // that there are no write errors due to subsequent writes while the
969 // session tries migrating to a new writer/socket.
Ryan Hamilton 2016/09/10 16:29:46 Since the actual write happen after yet another Po
Jana 2016/09/10 23:08:30 Much more accurate -- done.
970 return ERR_IO_PENDING;
971 }
972
973 void QuicChromiumClientSession::MigrateSessionOnWriteError() {
974 if (packet_ == nullptr)
975 // If packet_ no longer exists, it must have been written on a
976 // different migration attempt. Do not attempt another migration.
Ryan Hamilton 2016/09/10 16:29:46 nit: As written, the body of this if is 3 lines lo
Jana 2016/09/10 23:08:30 I assumed that comments didn't count. It's about r
977 return;
978
979 if (stream_factory_ != nullptr &&
980 stream_factory_->MaybeMigrateSingleSession(this, WRITE_ERROR) ==
981 MigrationResult::SUCCESS)
982 return;
983
984 // Close the connection if migration failed. Do not cause a
985 // connection close packet to be sent since socket may be borked.
986 connection()->CloseConnection(QUIC_PACKET_WRITE_ERROR,
987 "Write and subsequent migration failed",
988 ConnectionCloseBehavior::SILENT_CLOSE);
989 }
990
991 void QuicChromiumClientSession::WriteToNewSocket(
992 scoped_refptr<StringIOBuffer> packet) {
993 if (packet == nullptr) {
994 connection()->SendPing();
995 return;
958 } 996 }
Ryan Hamilton 2016/09/10 16:29:46 Under what circumstances is this code path hit? Ca
Jana 2016/09/10 23:08:31 You're partially right that you can hit this code
Jana 2016/09/11 05:30:46 Ok, I've simplified and removed the possibility of
959 return use_error_code_from_rewrite_ ? error_code_from_rewrite_ : error_code; 997 WriteResult result =
Ryan Hamilton 2016/09/10 16:29:46 Let's add a comment here to explain that the conne
Jana 2016/09/10 23:08:30 Done.
998 static_cast<QuicChromiumPacketWriter*>(connection()->writer())
999 ->WritePacketToSocket(packet);
1000
1001 // If write completes synchronously, notify the connection. The writer
1002 // notifies the connection on async completions.
1003 if (result.error_code < 0 && result.error_code != ERR_IO_PENDING) {
1004 connection()->OnWriteError(result.error_code);
Ryan Hamilton 2016/09/10 16:29:47 In theory, we should never get a WriteError becaus
Jana 2016/09/10 23:08:31 Correct. I see this in the tests on multiple write
1005 return;
1006 }
1007 if (result.error_code != ERR_IO_PENDING)
1008 connection()->OnCanWrite();
Ryan Hamilton 2016/09/10 16:29:47 nit: how about if (result.error_code == ERR_IO_PE
Jana 2016/09/10 23:08:31 Done. I have a mild preference for it to stay here
960 } 1009 }
961 1010
962 void QuicChromiumClientSession::OnWriteError(int error_code) { 1011 void QuicChromiumClientSession::OnWriteError(int error_code) {
963 DCHECK_NE(ERR_IO_PENDING, error_code); 1012 DCHECK_NE(ERR_IO_PENDING, error_code);
964 DCHECK_GT(0, error_code); 1013 DCHECK_GT(0, error_code);
965 connection()->OnWriteError(error_code); 1014 connection()->OnWriteError(error_code);
966 } 1015 }
967 1016
968 void QuicChromiumClientSession::OnWriteUnblocked() { 1017 void QuicChromiumClientSession::OnWriteUnblocked() {
969 connection()->OnCanWrite(); 1018 connection()->OnCanWrite();
970 } 1019 }
971 1020
972 void QuicChromiumClientSession::OnPathDegrading() { 1021 void QuicChromiumClientSession::OnPathDegrading() {
973 if (stream_factory_) { 1022 if (stream_factory_) {
974 stream_factory_->MaybeMigrateSingleSession(this, EARLY_MIGRATION, nullptr); 1023 stream_factory_->MaybeMigrateSingleSession(this, EARLY_MIGRATION);
Ryan Hamilton 2016/09/10 16:29:47 Is it possible that this is called while a write i
Jana 2016/09/10 23:08:31 This should be handled in the same way as NCN-migr
975 } 1024 }
976 } 1025 }
977 1026
978 bool QuicChromiumClientSession::HasOpenDynamicStreams() const { 1027 bool QuicChromiumClientSession::HasOpenDynamicStreams() const {
979 return QuicSession::HasOpenDynamicStreams() || 1028 return QuicSession::HasOpenDynamicStreams() ||
980 GetNumDrainingOutgoingStreams() > 0; 1029 GetNumDrainingOutgoingStreams() > 0;
981 } 1030 }
982 1031
983 void QuicChromiumClientSession::OnProofValid( 1032 void QuicChromiumClientSession::OnProofValid(
984 const QuicCryptoClientConfig::CachedState& cached) { 1033 const QuicCryptoClientConfig::CachedState& cached) {
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
1171 going_away_ = true; 1220 going_away_ = true;
1172 DCHECK_EQ(0u, GetNumActiveStreams()); 1221 DCHECK_EQ(0u, GetNumActiveStreams());
1173 // Will delete |this|. 1222 // Will delete |this|.
1174 if (stream_factory_) 1223 if (stream_factory_)
1175 stream_factory_->OnSessionClosed(this); 1224 stream_factory_->OnSessionClosed(this);
1176 } 1225 }
1177 1226
1178 bool QuicChromiumClientSession::MigrateToSocket( 1227 bool QuicChromiumClientSession::MigrateToSocket(
1179 std::unique_ptr<DatagramClientSocket> socket, 1228 std::unique_ptr<DatagramClientSocket> socket,
1180 std::unique_ptr<QuicChromiumPacketReader> reader, 1229 std::unique_ptr<QuicChromiumPacketReader> reader,
1181 std::unique_ptr<QuicChromiumPacketWriter> writer, 1230 std::unique_ptr<QuicChromiumPacketWriter> writer) {
1182 scoped_refptr<StringIOBuffer> packet) {
1183 DCHECK_EQ(sockets_.size(), packet_readers_.size()); 1231 DCHECK_EQ(sockets_.size(), packet_readers_.size());
1184 if (sockets_.size() >= kMaxReadersPerQuicSession) { 1232 if (sockets_.size() >= kMaxReadersPerQuicSession) {
1233 packet_ = nullptr;
1185 return false; 1234 return false;
1186 } 1235 }
1236
1187 // TODO(jri): Make SetQuicPacketWriter take a scoped_ptr. 1237 // TODO(jri): Make SetQuicPacketWriter take a scoped_ptr.
1188 packet_readers_.push_back(std::move(reader)); 1238 packet_readers_.push_back(std::move(reader));
1189 sockets_.push_back(std::move(socket)); 1239 sockets_.push_back(std::move(socket));
1190 StartReading(); 1240 StartReading();
1191 QuicChromiumPacketWriter* raw_writer = writer.get();
1192 connection()->SetQuicPacketWriter(writer.release(), /*owns_writer=*/true); 1241 connection()->SetQuicPacketWriter(writer.release(), /*owns_writer=*/true);
1193 if (packet == nullptr) { 1242
1194 connection()->SendPing(); 1243 // Post task to write the pending packet or a PING packet to the new socket.
1195 return true; 1244 task_runner_->PostTask(
1196 } 1245 FROM_HERE, base::Bind(&QuicChromiumClientSession::WriteToNewSocket,
1197 // Packet rewrite after migration on socket write error. 1246 weak_factory_.GetWeakPtr(), packet_));
Ryan Hamilton 2016/09/10 16:29:46 Since we're not writing immediately, I think we ne
Jana 2016/09/10 23:08:31 Good point. I'll add a ShouldWriteBlock to the del
1198 error_code_from_rewrite_ = raw_writer->WritePacketToSocket(packet.get()); 1247
1199 use_error_code_from_rewrite_ = true; 1248 // Reset packet_ since (i) the posted write can result in a write
1249 // error, causing packet_ to be used again, and (ii) avoids a later
1250 // migration attempt if any pending migration task is executed.
1251 packet_ = nullptr;
Ryan Hamilton 2016/09/10 16:29:47 Is (i) actually correct? If I understand correctly
Jana 2016/09/10 23:08:31 Right, I think the comment wasn't clear -- but I'v
1200 return true; 1252 return true;
1201 } 1253 }
1202 1254
1203 void QuicChromiumClientSession::PopulateNetErrorDetails( 1255 void QuicChromiumClientSession::PopulateNetErrorDetails(
1204 NetErrorDetails* details) { 1256 NetErrorDetails* details) {
1205 details->quic_port_migration_detected = port_migration_detected_; 1257 details->quic_port_migration_detected = port_migration_detected_;
1206 } 1258 }
1207 1259
1208 const DatagramClientSocket* QuicChromiumClientSession::GetDefaultSocket() 1260 const DatagramClientSocket* QuicChromiumClientSession::GetDefaultSocket()
1209 const { 1261 const {
(...skipping 27 matching lines...) Expand all
1237 } 1289 }
1238 1290
1239 void QuicChromiumClientSession::DeletePromised( 1291 void QuicChromiumClientSession::DeletePromised(
1240 QuicClientPromisedInfo* promised) { 1292 QuicClientPromisedInfo* promised) {
1241 if (IsOpenStream(promised->id())) 1293 if (IsOpenStream(promised->id()))
1242 streams_pushed_and_claimed_count_++; 1294 streams_pushed_and_claimed_count_++;
1243 QuicClientSessionBase::DeletePromised(promised); 1295 QuicClientSessionBase::DeletePromised(promised);
1244 } 1296 }
1245 1297
1246 } // namespace net 1298 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698