Chromium Code Reviews| Index: net/quic/quic_chromium_client_session.cc |
| diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc |
| index 4aabc7a22ab3000f63dfea73c28a76a67787913c..626103fc5746a2c9aa82ddb6dac5b0d501684b6a 100644 |
| --- a/net/quic/quic_chromium_client_session.cc |
| +++ b/net/quic/quic_chromium_client_session.cc |
| @@ -40,6 +40,11 @@ const int k0RttHandshakeTimeoutMs = 300; |
| // IPv6 packets have an additional 20 bytes of overhead than IPv4 packets. |
| const size_t kAdditionalOverheadForIPv6 = 20; |
| +// Maximum number of Readers that are created for any session due to |
| +// connection migration. A new Reader is created every time this endpoint's |
| +// IP address changes. |
| +const size_t kMaxReadersPerQuicSession = 5; |
| + |
| // Histograms for tracking down the crashes from http://crbug.com/354669 |
| // Note: these values must be kept in sync with the corresponding values in: |
| // tools/metrics/histograms/histograms.xml |
| @@ -178,18 +183,11 @@ QuicChromiumClientSession::QuicChromiumClientSession( |
| server_id_(server_id), |
| require_confirmation_(false), |
| stream_factory_(stream_factory), |
| - socket_(socket.Pass()), |
| transport_security_state_(transport_security_state), |
| server_info_(server_info.Pass()), |
| num_total_streams_(0), |
| task_runner_(task_runner), |
| net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_QUIC_SESSION)), |
| - packet_reader_(socket_.get(), |
| - clock, |
| - this, |
| - yield_after_packets, |
| - yield_after_duration, |
| - net_log_), |
| dns_resolution_end_time_(dns_resolution_end_time), |
| logger_(new QuicConnectionLogger(this, |
| connection_description, |
| @@ -198,6 +196,10 @@ QuicChromiumClientSession::QuicChromiumClientSession( |
| going_away_(false), |
| disabled_reason_(QUIC_DISABLED_NOT), |
| weak_factory_(this) { |
| + sockets_.push_back(socket.Pass()); |
| + packet_readers_.push_back(make_scoped_ptr(new QuicPacketReader( |
| + sockets_.back().get(), clock, this, yield_after_packets, |
| + yield_after_duration, net_log_))); |
| crypto_stream_.reset( |
| crypto_client_stream_factory |
| ? crypto_client_stream_factory->CreateQuicCryptoClientStream( |
| @@ -770,7 +772,10 @@ void QuicChromiumClientSession::OnConnectionClosed(QuicErrorCode error, |
| if (!callback_.is_null()) { |
| base::ResetAndReturn(&callback_).Run(ERR_QUIC_PROTOCOL_ERROR); |
| } |
| - socket_->Close(); |
| + |
| + for (auto& socket : sockets_) { |
|
Ryan Hamilton
2015/12/18 22:00:18
nit: I'd use the full type here. (no need for {}s)
|
| + socket->Close(); |
| + } |
| QuicSession::OnConnectionClosed(error, from_peer); |
| DCHECK(dynamic_streams().empty()); |
| CloseAllStreams(ERR_UNEXPECTED); |
| @@ -816,7 +821,9 @@ void QuicChromiumClientSession::OnProofVerifyDetailsAvailable( |
| } |
| void QuicChromiumClientSession::StartReading() { |
| - packet_reader_.StartReading(); |
| + for (auto& packet_reader : packet_readers_) { |
| + packet_reader->StartReading(); |
| + } |
|
Ryan Hamilton
2015/12/18 22:00:18
nit: no need for {}s
|
| } |
| void QuicChromiumClientSession::CloseSessionOnError(int error, |
| @@ -912,7 +919,15 @@ QuicChromiumClientSession::GetWeakPtr() { |
| return weak_factory_.GetWeakPtr(); |
| } |
| -void QuicChromiumClientSession::OnReadError(int result) { |
| +void QuicChromiumClientSession::OnReadError( |
| + int result, |
| + const DatagramClientSocket* socket) { |
| + DCHECK(socket != nullptr); |
| + if (socket != GetDefaultSocket()) { |
| + // Ignore read errors from old sockets that are no longer active. |
| + // TODO(jri): Maybe clean up old sockets on error. |
|
Ryan Hamilton
2015/12/18 22:00:18
Do we stop reading on the socket in this case?
|
| + return; |
| + } |
| DVLOG(1) << "Closing session on read error: " << result; |
| UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ReadError", -result); |
| NotifyFactoryOfSessionGoingAway(); |
| @@ -981,4 +996,28 @@ void QuicChromiumClientSession::OnConnectTimeout() { |
| // DCHECK_EQ(0u, GetNumOpenOutgoingStreams()); |
| } |
| +bool QuicChromiumClientSession::MigrateToSocket( |
|
Ryan Hamilton
2015/12/18 22:00:19
I think we should probably have tests for this new
|
| + scoped_ptr<DatagramClientSocket> socket, |
| + scoped_ptr<QuicPacketReader> reader, |
| + scoped_ptr<QuicPacketWriter> writer) { |
| + DCHECK_EQ(sockets_.size(), packet_readers_.size()); |
| + if (sockets_.size() >= kMaxReadersPerQuicSession) { |
| + return false; |
| + } |
| + // TODO(jri): Make SetQuicPacketWriter take a scoped_ptr. |
|
Ryan Hamilton
2015/12/18 22:00:19
I don't think that's possible because the connecti
|
| + connection()->SetQuicPacketWriter(writer.release(), /*owns_writer=*/true); |
|
Ryan Hamilton
2015/12/18 22:00:19
So all new data will go out over this new writer,
|
| + packet_readers_.push_back(reader.Pass()); |
| + sockets_.push_back(socket.Pass()); |
| + StartReading(); |
| + connection()->SendPing(); |
| + return true; |
| +} |
| + |
| +const DatagramClientSocket* QuicChromiumClientSession::GetDefaultSocket() |
| + const { |
| + DCHECK(sockets_.back().get() != nullptr); |
| + // The most recently added socket is the currently active one. |
| + return sockets_.back().get(); |
| +} |
| + |
| } // namespace net |