| OLD | NEW |
| 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/tools/quic/quic_simple_client.h" | 5 #include "net/tools/quic/quic_simple_client.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/run_loop.h" | 8 #include "base/run_loop.h" |
| 9 #include "base/thread_task_runner_handle.h" | 9 #include "base/thread_task_runner_handle.h" |
| 10 #include "net/base/net_errors.h" | 10 #include "net/base/net_errors.h" |
| 11 #include "net/http/http_request_info.h" | 11 #include "net/http/http_request_info.h" |
| 12 #include "net/http/http_response_info.h" | 12 #include "net/http/http_response_info.h" |
| 13 #include "net/quic/crypto/quic_random.h" | 13 #include "net/quic/crypto/quic_random.h" |
| 14 #include "net/quic/quic_connection.h" | 14 #include "net/quic/quic_connection.h" |
| 15 #include "net/quic/quic_connection_helper.h" | 15 #include "net/quic/quic_connection_helper.h" |
| 16 #include "net/quic/quic_crypto_client_stream.h" | |
| 17 #include "net/quic/quic_default_packet_writer.h" | 16 #include "net/quic/quic_default_packet_writer.h" |
| 18 #include "net/quic/quic_flags.h" | 17 #include "net/quic/quic_flags.h" |
| 19 #include "net/quic/quic_protocol.h" | 18 #include "net/quic/quic_protocol.h" |
| 20 #include "net/quic/quic_server_id.h" | 19 #include "net/quic/quic_server_id.h" |
| 21 #include "net/quic/spdy_utils.h" | 20 #include "net/quic/spdy_utils.h" |
| 22 #include "net/spdy/spdy_http_utils.h" | 21 #include "net/spdy/spdy_http_utils.h" |
| 23 #include "net/udp/udp_client_socket.h" | 22 #include "net/udp/udp_client_socket.h" |
| 24 | 23 |
| 25 using std::string; | 24 using std::string; |
| 26 using std::vector; | 25 using std::vector; |
| 27 | 26 |
| 28 namespace net { | 27 namespace net { |
| 29 namespace tools { | 28 namespace tools { |
| 30 | 29 |
| 31 void QuicSimpleClient::ClientQuicDataToResend::Resend() { | 30 void QuicSimpleClient::ClientQuicDataToResend::Resend() { |
| 32 client_->SendRequest(*headers_, body_, fin_); | 31 client_->SendRequest(*headers_, body_, fin_); |
| 33 delete headers_; | 32 delete headers_; |
| 34 headers_ = nullptr; | 33 headers_ = nullptr; |
| 35 } | 34 } |
| 36 | 35 |
| 37 QuicSimpleClient::QuicSimpleClient(IPEndPoint server_address, | 36 QuicSimpleClient::QuicSimpleClient(IPEndPoint server_address, |
| 38 const QuicServerId& server_id, | 37 const QuicServerId& server_id, |
| 39 const QuicVersionVector& supported_versions) | 38 const QuicVersionVector& supported_versions) |
| 40 : server_address_(server_address), | 39 : QuicClientBase(server_id, supported_versions, QuicConfig()), |
| 41 server_id_(server_id), | 40 server_address_(server_address), |
| 42 local_port_(0), | 41 local_port_(0), |
| 43 helper_(CreateQuicConnectionHelper()), | 42 helper_(CreateQuicConnectionHelper()), |
| 44 initialized_(false), | 43 initialized_(false), |
| 45 supported_versions_(supported_versions), | |
| 46 packet_reader_started_(false), | 44 packet_reader_started_(false), |
| 47 weak_factory_(this) {} | 45 weak_factory_(this) {} |
| 48 | 46 |
| 49 QuicSimpleClient::QuicSimpleClient(IPEndPoint server_address, | 47 QuicSimpleClient::QuicSimpleClient(IPEndPoint server_address, |
| 50 const QuicServerId& server_id, | 48 const QuicServerId& server_id, |
| 51 const QuicVersionVector& supported_versions, | 49 const QuicVersionVector& supported_versions, |
| 52 const QuicConfig& config) | 50 const QuicConfig& config) |
| 53 : server_address_(server_address), | 51 : QuicClientBase(server_id, supported_versions, config), |
| 54 server_id_(server_id), | 52 server_address_(server_address), |
| 55 config_(config), | |
| 56 local_port_(0), | 53 local_port_(0), |
| 57 helper_(CreateQuicConnectionHelper()), | 54 helper_(CreateQuicConnectionHelper()), |
| 58 initialized_(false), | 55 initialized_(false), |
| 59 supported_versions_(supported_versions), | |
| 60 initial_max_packet_length_(0), | |
| 61 num_stateless_rejects_received_(0), | |
| 62 num_sent_client_hellos_(0), | |
| 63 connection_error_(QUIC_NO_ERROR), | |
| 64 connected_or_attempting_connect_(false), | |
| 65 packet_reader_started_(false), | 56 packet_reader_started_(false), |
| 66 weak_factory_(this) {} | 57 weak_factory_(this) {} |
| 67 | 58 |
| 68 QuicSimpleClient::~QuicSimpleClient() { | 59 QuicSimpleClient::~QuicSimpleClient() { |
| 69 if (connected()) { | 60 if (connected()) { |
| 70 session()->connection()->SendConnectionClosePacket( | 61 session()->connection()->SendConnectionClosePacket( |
| 71 QUIC_PEER_GOING_AWAY, ""); | 62 QUIC_PEER_GOING_AWAY, ""); |
| 72 } | 63 } |
| 73 STLDeleteElements(&data_to_resend_on_connect_); | 64 STLDeleteElements(&data_to_resend_on_connect_); |
| 74 STLDeleteElements(&data_sent_before_handshake_); | 65 STLDeleteElements(&data_sent_before_handshake_); |
| 75 } | 66 } |
| 76 | 67 |
| 77 bool QuicSimpleClient::Initialize() { | 68 bool QuicSimpleClient::Initialize() { |
| 78 DCHECK(!initialized_); | 69 DCHECK(!initialized_); |
| 79 | 70 |
| 80 num_sent_client_hellos_ = 0; | 71 QuicClientBase::Initialize(); |
| 81 num_stateless_rejects_received_ = 0; | |
| 82 connection_error_ = QUIC_NO_ERROR; | |
| 83 connected_or_attempting_connect_ = false; | |
| 84 | 72 |
| 85 if (!CreateUDPSocket()) { | 73 if (!CreateUDPSocket()) { |
| 86 return false; | 74 return false; |
| 87 } | 75 } |
| 88 | 76 |
| 89 initialized_ = true; | 77 initialized_ = true; |
| 90 return true; | 78 return true; |
| 91 } | 79 } |
| 92 | 80 |
| 93 QuicSimpleClient::DummyPacketWriterFactory::DummyPacketWriterFactory( | |
| 94 QuicPacketWriter* writer) | |
| 95 : writer_(writer) {} | |
| 96 | |
| 97 QuicSimpleClient::DummyPacketWriterFactory::~DummyPacketWriterFactory() {} | |
| 98 | |
| 99 QuicPacketWriter* QuicSimpleClient::DummyPacketWriterFactory::Create( | |
| 100 QuicConnection* /*connection*/) const { | |
| 101 return writer_; | |
| 102 } | |
| 103 | |
| 104 QuicSimpleClient::QuicDataToResend::QuicDataToResend(HttpRequestInfo* headers, | 81 QuicSimpleClient::QuicDataToResend::QuicDataToResend(HttpRequestInfo* headers, |
| 105 StringPiece body, | 82 StringPiece body, |
| 106 bool fin) | 83 bool fin) |
| 107 : headers_(headers), body_(body), fin_(fin) {} | 84 : headers_(headers), body_(body), fin_(fin) {} |
| 108 | 85 |
| 109 QuicSimpleClient::QuicDataToResend::~QuicDataToResend() { | 86 QuicSimpleClient::QuicDataToResend::~QuicDataToResend() { |
| 110 if (headers_) { | 87 if (headers_) { |
| 111 delete headers_; | 88 delete headers_; |
| 112 } | 89 } |
| 113 } | 90 } |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 } | 163 } |
| 187 if (FLAGS_enable_quic_stateless_reject_support && connected() && | 164 if (FLAGS_enable_quic_stateless_reject_support && connected() && |
| 188 !data_to_resend_on_connect_.empty()) { | 165 !data_to_resend_on_connect_.empty()) { |
| 189 // A connection has been established and there was previously queued data | 166 // A connection has been established and there was previously queued data |
| 190 // to resend. Resend it and empty the queue. | 167 // to resend. Resend it and empty the queue. |
| 191 for (QuicDataToResend* data : data_to_resend_on_connect_) { | 168 for (QuicDataToResend* data : data_to_resend_on_connect_) { |
| 192 data->Resend(); | 169 data->Resend(); |
| 193 } | 170 } |
| 194 STLDeleteElements(&data_to_resend_on_connect_); | 171 STLDeleteElements(&data_to_resend_on_connect_); |
| 195 } | 172 } |
| 196 if (session_.get() != nullptr && | 173 if (session() != nullptr && |
| 197 session_->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { | 174 session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { |
| 198 // We've successfully created a session but we're not connected, and there | 175 // We've successfully created a session but we're not connected, and there |
| 199 // is no stateless reject to recover from. Give up trying. | 176 // is no stateless reject to recover from. Give up trying. |
| 200 break; | 177 break; |
| 201 } | 178 } |
| 202 } | 179 } |
| 203 if (!connected() && | 180 if (!connected() && |
| 204 GetNumSentClientHellos() > QuicCryptoClientStream::kMaxClientHellos && | 181 GetNumSentClientHellos() > QuicCryptoClientStream::kMaxClientHellos && |
| 205 session_ != nullptr && | 182 session() != nullptr && |
| 206 session_->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { | 183 session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { |
| 207 // The overall connection failed due too many stateless rejects. | 184 // The overall connection failed due too many stateless rejects. |
| 208 connection_error_ = QUIC_CRYPTO_TOO_MANY_REJECTS; | 185 set_connection_error(QUIC_CRYPTO_TOO_MANY_REJECTS); |
| 209 } | 186 } |
| 210 return session_->connection()->connected(); | 187 return session()->connection()->connected(); |
| 211 } | |
| 212 | |
| 213 QuicClientSession* QuicSimpleClient::CreateQuicClientSession( | |
| 214 const QuicConfig& config, | |
| 215 QuicConnection* connection, | |
| 216 const QuicServerId& server_id, | |
| 217 QuicCryptoClientConfig* crypto_config) { | |
| 218 return new QuicClientSession(config, connection, server_id_, &crypto_config_); | |
| 219 } | 188 } |
| 220 | 189 |
| 221 void QuicSimpleClient::StartConnect() { | 190 void QuicSimpleClient::StartConnect() { |
| 222 DCHECK(initialized_); | 191 DCHECK(initialized_); |
| 223 DCHECK(!connected()); | 192 DCHECK(!connected()); |
| 224 | 193 |
| 225 writer_.reset(CreateQuicPacketWriter()); | 194 set_writer(CreateQuicPacketWriter()); |
| 226 | 195 |
| 227 DummyPacketWriterFactory factory(writer_.get()); | 196 DummyPacketWriterFactory factory(writer()); |
| 228 | 197 |
| 229 if (connected_or_attempting_connect_) { | 198 if (connected_or_attempting_connect()) { |
| 230 // Before we destroy the last session and create a new one, gather its stats | 199 // Before we destroy the last session and create a new one, gather its stats |
| 231 // and update the stats for the overall connection. | 200 // and update the stats for the overall connection. |
| 232 num_sent_client_hellos_ += session_->GetNumSentClientHellos(); | 201 UpdateStats(); |
| 233 if (session_->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { | 202 if (session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { |
| 234 // If the last error was due to a stateless reject, queue up the data to | 203 // If the last error was due to a stateless reject, queue up the data to |
| 235 // be resent on the next successful connection. | 204 // be resent on the next successful connection. |
| 236 // TODO(jokulik): I'm a little bit concerned about ordering here. Maybe | 205 // TODO(jokulik): I'm a little bit concerned about ordering here. Maybe |
| 237 // we should just maintain one queue? | 206 // we should just maintain one queue? |
| 238 ++num_stateless_rejects_received_; | |
| 239 DCHECK(data_to_resend_on_connect_.empty()); | 207 DCHECK(data_to_resend_on_connect_.empty()); |
| 240 data_to_resend_on_connect_.swap(data_sent_before_handshake_); | 208 data_to_resend_on_connect_.swap(data_sent_before_handshake_); |
| 241 } | 209 } |
| 242 } | 210 } |
| 243 | 211 |
| 244 session_.reset(CreateQuicClientSession( | 212 CreateQuicClientSession(new QuicConnection( |
| 245 config_, | 213 GetNextConnectionId(), server_address_, helper_.get(), factory, |
| 246 new QuicConnection(GetNextConnectionId(), server_address_, helper_.get(), | 214 /* owns_writer= */ false, Perspective::IS_CLIENT, server_id().is_https(), |
| 247 factory, | 215 supported_versions())); |
| 248 /* owns_writer= */ false, Perspective::IS_CLIENT, | |
| 249 server_id_.is_https(), supported_versions_), | |
| 250 server_id_, &crypto_config_)); | |
| 251 if (initial_max_packet_length_ != 0) { | |
| 252 session_->connection()->set_max_packet_length(initial_max_packet_length_); | |
| 253 } | |
| 254 session_->Initialize(); | |
| 255 session_->CryptoConnect(); | |
| 256 connected_or_attempting_connect_ = true; | |
| 257 } | |
| 258 | 216 |
| 259 bool QuicSimpleClient::EncryptionBeingEstablished() { | 217 session()->Initialize(); |
| 260 return !session_->IsEncryptionEstablished() && | 218 session()->CryptoConnect(); |
| 261 session_->connection()->connected(); | 219 set_connected_or_attempting_connect(true); |
| 262 } | 220 } |
| 263 | 221 |
| 264 void QuicSimpleClient::Disconnect() { | 222 void QuicSimpleClient::Disconnect() { |
| 265 DCHECK(initialized_); | 223 DCHECK(initialized_); |
| 266 | 224 |
| 267 if (connected()) { | 225 if (connected()) { |
| 268 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY); | 226 session()->connection()->SendConnectionClose(QUIC_PEER_GOING_AWAY); |
| 269 } | 227 } |
| 270 STLDeleteElements(&data_to_resend_on_connect_); | 228 STLDeleteElements(&data_to_resend_on_connect_); |
| 271 STLDeleteElements(&data_sent_before_handshake_); | 229 STLDeleteElements(&data_sent_before_handshake_); |
| 272 | 230 |
| 273 writer_.reset(); | 231 reset_writer(); |
| 274 packet_reader_.reset(); | 232 packet_reader_.reset(); |
| 275 | 233 |
| 276 initialized_ = false; | 234 initialized_ = false; |
| 277 } | 235 } |
| 278 | 236 |
| 279 void QuicSimpleClient::SendRequest(const HttpRequestInfo& headers, | 237 void QuicSimpleClient::SendRequest(const HttpRequestInfo& headers, |
| 280 base::StringPiece body, | 238 StringPiece body, |
| 281 bool fin) { | 239 bool fin) { |
| 282 QuicSpdyClientStream* stream = CreateReliableClientStream(); | 240 QuicSpdyClientStream* stream = CreateReliableClientStream(); |
| 283 if (stream == nullptr) { | 241 if (stream == nullptr) { |
| 284 LOG(DFATAL) << "stream creation failed!"; | 242 LOG(DFATAL) << "stream creation failed!"; |
| 285 return; | 243 return; |
| 286 } | 244 } |
| 287 SpdyHeaderBlock header_block; | 245 SpdyHeaderBlock header_block; |
| 288 SpdyMajorVersion spdy_version = | 246 SpdyMajorVersion spdy_version = |
| 289 SpdyUtils::GetSpdyVersionForQuicVersion(stream->version()); | 247 SpdyUtils::GetSpdyVersionForQuicVersion(stream->version()); |
| 290 CreateSpdyHeadersFromHttpRequest(headers, headers.extra_headers, spdy_version, | 248 CreateSpdyHeadersFromHttpRequest(headers, headers.extra_headers, spdy_version, |
| 291 true, &header_block); | 249 true, &header_block); |
| 292 stream->set_visitor(this); | 250 stream->set_visitor(this); |
| 293 stream->SendRequest(header_block, body, fin); | 251 stream->SendRequest(header_block, body, fin); |
| 294 if (FLAGS_enable_quic_stateless_reject_support) { | 252 if (FLAGS_enable_quic_stateless_reject_support) { |
| 295 // Record this in case we need to resend. | 253 // Record this in case we need to resend. |
| 296 auto new_headers = new HttpRequestInfo; | 254 auto new_headers = new HttpRequestInfo; |
| 297 *new_headers = headers; | 255 *new_headers = headers; |
| 298 auto data_to_resend = | 256 auto data_to_resend = |
| 299 new ClientQuicDataToResend(new_headers, body, fin, this); | 257 new ClientQuicDataToResend(new_headers, body, fin, this); |
| 300 MaybeAddQuicDataToResend(data_to_resend); | 258 MaybeAddQuicDataToResend(data_to_resend); |
| 301 } | 259 } |
| 302 } | 260 } |
| 303 | 261 |
| 304 void QuicSimpleClient::MaybeAddQuicDataToResend( | 262 void QuicSimpleClient::MaybeAddQuicDataToResend( |
| 305 QuicDataToResend* data_to_resend) { | 263 QuicDataToResend* data_to_resend) { |
| 306 DCHECK(FLAGS_enable_quic_stateless_reject_support); | 264 DCHECK(FLAGS_enable_quic_stateless_reject_support); |
| 307 if (session_->IsCryptoHandshakeConfirmed()) { | 265 if (session()->IsCryptoHandshakeConfirmed()) { |
| 308 // The handshake is confirmed. No need to continue saving requests to | 266 // The handshake is confirmed. No need to continue saving requests to |
| 309 // resend. | 267 // resend. |
| 310 STLDeleteElements(&data_sent_before_handshake_); | 268 STLDeleteElements(&data_sent_before_handshake_); |
| 311 delete data_to_resend; | 269 delete data_to_resend; |
| 312 return; | 270 return; |
| 313 } | 271 } |
| 314 | 272 |
| 315 // The handshake is not confirmed. Push the data onto the queue of data to | 273 // The handshake is not confirmed. Push the data onto the queue of data to |
| 316 // resend if statelessly rejected. | 274 // resend if statelessly rejected. |
| 317 data_sent_before_handshake_.push_back(data_to_resend); | 275 data_sent_before_handshake_.push_back(data_to_resend); |
| 318 } | 276 } |
| 319 | 277 |
| 320 void QuicSimpleClient::SendRequestAndWaitForResponse( | 278 void QuicSimpleClient::SendRequestAndWaitForResponse( |
| 321 const HttpRequestInfo& request, | 279 const HttpRequestInfo& request, |
| 322 base::StringPiece body, | 280 StringPiece body, |
| 323 bool fin) { | 281 bool fin) { |
| 324 SendRequest(request, body, fin); | 282 SendRequest(request, body, fin); |
| 325 while (WaitForEvents()) {} | 283 while (WaitForEvents()) {} |
| 326 } | 284 } |
| 327 | 285 |
| 328 void QuicSimpleClient::SendRequestsAndWaitForResponse( | 286 void QuicSimpleClient::SendRequestsAndWaitForResponse( |
| 329 const base::CommandLine::StringVector& url_list) { | 287 const base::CommandLine::StringVector& url_list) { |
| 330 for (size_t i = 0; i < url_list.size(); ++i) { | 288 for (size_t i = 0; i < url_list.size(); ++i) { |
| 331 HttpRequestInfo request; | 289 HttpRequestInfo request; |
| 332 request.method = "GET"; | 290 request.method = "GET"; |
| 333 request.url = GURL(url_list[i]); | 291 request.url = GURL(url_list[i]); |
| 334 SendRequest(request, "", true); | 292 SendRequest(request, "", true); |
| 335 } | 293 } |
| 336 | 294 |
| 337 while (WaitForEvents()) {} | 295 while (WaitForEvents()) {} |
| 338 } | 296 } |
| 339 | 297 |
| 340 QuicSpdyClientStream* QuicSimpleClient::CreateReliableClientStream() { | |
| 341 if (!connected()) { | |
| 342 return nullptr; | |
| 343 } | |
| 344 | |
| 345 return session_->CreateOutgoingDynamicStream(); | |
| 346 } | |
| 347 | |
| 348 void QuicSimpleClient::WaitForStreamToClose(QuicStreamId id) { | |
| 349 DCHECK(connected()); | |
| 350 | |
| 351 while (connected() && !session_->IsClosedStream(id)) { | |
| 352 WaitForEvents(); | |
| 353 } | |
| 354 } | |
| 355 | |
| 356 void QuicSimpleClient::WaitForCryptoHandshakeConfirmed() { | |
| 357 DCHECK(connected()); | |
| 358 | |
| 359 while (connected() && !session_->IsCryptoHandshakeConfirmed()) { | |
| 360 WaitForEvents(); | |
| 361 } | |
| 362 } | |
| 363 | |
| 364 bool QuicSimpleClient::WaitForEvents() { | 298 bool QuicSimpleClient::WaitForEvents() { |
| 365 DCHECK(connected()); | 299 DCHECK(connected()); |
| 366 | 300 |
| 367 base::RunLoop().RunUntilIdle(); | 301 base::RunLoop().RunUntilIdle(); |
| 368 | 302 |
| 369 DCHECK(session_ != nullptr); | 303 DCHECK(session() != nullptr); |
| 370 if (!connected() && | 304 if (!connected() && |
| 371 session_->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { | 305 session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { |
| 372 DCHECK(FLAGS_enable_quic_stateless_reject_support); | 306 DCHECK(FLAGS_enable_quic_stateless_reject_support); |
| 373 DVLOG(1) << "Detected stateless reject while waiting for events. " | 307 DVLOG(1) << "Detected stateless reject while waiting for events. " |
| 374 << "Attempting to reconnect."; | 308 << "Attempting to reconnect."; |
| 375 Connect(); | 309 Connect(); |
| 376 } | 310 } |
| 377 | 311 |
| 378 return session_->num_active_requests() != 0; | 312 return session()->num_active_requests() != 0; |
| 379 } | 313 } |
| 380 | 314 |
| 381 bool QuicSimpleClient::MigrateSocket(const IPAddressNumber& new_host) { | 315 bool QuicSimpleClient::MigrateSocket(const IPAddressNumber& new_host) { |
| 382 if (!connected()) { | 316 if (!connected()) { |
| 383 return false; | 317 return false; |
| 384 } | 318 } |
| 385 | 319 |
| 386 bind_to_address_ = new_host; | 320 bind_to_address_ = new_host; |
| 387 if (!CreateUDPSocket()) { | 321 if (!CreateUDPSocket()) { |
| 388 return false; | 322 return false; |
| 389 } | 323 } |
| 390 | 324 |
| 391 session_->connection()->SetSelfAddress(client_address_); | 325 session()->connection()->SetSelfAddress(client_address_); |
| 392 | 326 |
| 393 QuicPacketWriter* writer = CreateQuicPacketWriter(); | 327 QuicPacketWriter* writer = CreateQuicPacketWriter(); |
| 394 DummyPacketWriterFactory factory(writer); | 328 DummyPacketWriterFactory factory(writer); |
| 395 if (writer_.get() != writer) { | 329 set_writer(writer); |
| 396 writer_.reset(writer); | 330 session()->connection()->SetQuicPacketWriter(writer, false); |
| 397 } | |
| 398 session_->connection()->SetQuicPacketWriter(writer, false); | |
| 399 | 331 |
| 400 return true; | 332 return true; |
| 401 } | 333 } |
| 402 | 334 |
| 403 void QuicSimpleClient::OnClose(QuicDataStream* stream) { | 335 void QuicSimpleClient::OnClose(QuicDataStream* stream) { |
| 404 DCHECK(stream != nullptr); | 336 DCHECK(stream != nullptr); |
| 405 QuicSpdyClientStream* client_stream = | 337 QuicSpdyClientStream* client_stream = |
| 406 static_cast<QuicSpdyClientStream*>(stream); | 338 static_cast<QuicSpdyClientStream*>(stream); |
| 407 HttpResponseInfo response; | 339 HttpResponseInfo response; |
| 408 SpdyMajorVersion spdy_version = | 340 SpdyMajorVersion spdy_version = |
| 409 SpdyUtils::GetSpdyVersionForQuicVersion(client_stream->version()); | 341 SpdyUtils::GetSpdyVersionForQuicVersion(client_stream->version()); |
| 410 SpdyHeadersToHttpResponse(client_stream->headers(), spdy_version, &response); | 342 SpdyHeadersToHttpResponse(client_stream->headers(), spdy_version, &response); |
| 411 if (response_listener_.get() != nullptr) { | 343 if (response_listener_.get() != nullptr) { |
| 412 response_listener_->OnCompleteResponse( | 344 response_listener_->OnCompleteResponse( |
| 413 stream->id(), *response.headers, client_stream->data()); | 345 stream->id(), *response.headers, client_stream->data()); |
| 414 } | 346 } |
| 415 | 347 |
| 416 // Store response headers and body. | 348 // Store response headers and body. |
| 417 if (store_response_) { | 349 if (store_response_) { |
| 418 latest_response_code_ = client_stream->response_code(); | 350 latest_response_code_ = client_stream->response_code(); |
| 419 response.headers->GetNormalizedHeaders(&latest_response_headers_); | 351 response.headers->GetNormalizedHeaders(&latest_response_headers_); |
| 420 latest_response_body_ = client_stream->data(); | 352 latest_response_body_ = client_stream->data(); |
| 421 } | 353 } |
| 422 } | 354 } |
| 423 | 355 |
| 424 bool QuicSimpleClient::connected() const { | |
| 425 return session_.get() && session_->connection() && | |
| 426 session_->connection()->connected(); | |
| 427 } | |
| 428 | |
| 429 bool QuicSimpleClient::goaway_received() const { | |
| 430 return session_ != nullptr && session_->goaway_received(); | |
| 431 } | |
| 432 | |
| 433 size_t QuicSimpleClient::latest_response_code() const { | 356 size_t QuicSimpleClient::latest_response_code() const { |
| 434 LOG_IF(DFATAL, !store_response_) << "Response not stored!"; | 357 LOG_IF(DFATAL, !store_response_) << "Response not stored!"; |
| 435 return latest_response_code_; | 358 return latest_response_code_; |
| 436 } | 359 } |
| 437 | 360 |
| 438 const string& QuicSimpleClient::latest_response_headers() const { | 361 const string& QuicSimpleClient::latest_response_headers() const { |
| 439 LOG_IF(DFATAL, !store_response_) << "Response not stored!"; | 362 LOG_IF(DFATAL, !store_response_) << "Response not stored!"; |
| 440 return latest_response_headers_; | 363 return latest_response_headers_; |
| 441 } | 364 } |
| 442 | 365 |
| 443 const string& QuicSimpleClient::latest_response_body() const { | 366 const string& QuicSimpleClient::latest_response_body() const { |
| 444 LOG_IF(DFATAL, !store_response_) << "Response not stored!"; | 367 LOG_IF(DFATAL, !store_response_) << "Response not stored!"; |
| 445 return latest_response_body_; | 368 return latest_response_body_; |
| 446 } | 369 } |
| 447 | 370 |
| 448 int QuicSimpleClient::GetNumSentClientHellos() { | |
| 449 // If we are not actively attempting to connect, the session object | |
| 450 // corresponds to the previous connection and should not be used. | |
| 451 const int current_session_hellos = !connected_or_attempting_connect_ | |
| 452 ? 0 | |
| 453 : session_->GetNumSentClientHellos(); | |
| 454 return num_sent_client_hellos_ + current_session_hellos; | |
| 455 } | |
| 456 | |
| 457 QuicErrorCode QuicSimpleClient::connection_error() const { | |
| 458 // Return the high-level error if there was one. Otherwise, return the | |
| 459 // connection error from the last session. | |
| 460 if (connection_error_ != QUIC_NO_ERROR) { | |
| 461 return connection_error_; | |
| 462 } | |
| 463 if (session_.get() == nullptr) { | |
| 464 return QUIC_NO_ERROR; | |
| 465 } | |
| 466 return session_->error(); | |
| 467 } | |
| 468 | |
| 469 QuicConnectionId QuicSimpleClient::GetNextConnectionId() { | |
| 470 QuicConnectionId server_designated_id = GetNextServerDesignatedConnectionId(); | |
| 471 return server_designated_id ? server_designated_id | |
| 472 : GenerateNewConnectionId(); | |
| 473 } | |
| 474 | |
| 475 QuicConnectionId QuicSimpleClient::GetNextServerDesignatedConnectionId() { | |
| 476 QuicCryptoClientConfig::CachedState* cached = | |
| 477 crypto_config_.LookupOrCreate(server_id_); | |
| 478 // If the cached state indicates that we should use a server-designated | |
| 479 // connection ID, then return that connection ID. | |
| 480 CHECK(cached != nullptr) << "QuicClientCryptoConfig::LookupOrCreate returned " | |
| 481 << "unexpected nullptr."; | |
| 482 return cached->has_server_designated_connection_id() | |
| 483 ? cached->GetNextServerDesignatedConnectionId() | |
| 484 : 0; | |
| 485 } | |
| 486 | |
| 487 QuicConnectionId QuicSimpleClient::GenerateNewConnectionId() { | 371 QuicConnectionId QuicSimpleClient::GenerateNewConnectionId() { |
| 488 return helper_->GetRandomGenerator()->RandUint64(); | 372 return helper_->GetRandomGenerator()->RandUint64(); |
| 489 } | 373 } |
| 490 | 374 |
| 491 QuicConnectionHelper* QuicSimpleClient::CreateQuicConnectionHelper() { | 375 QuicConnectionHelper* QuicSimpleClient::CreateQuicConnectionHelper() { |
| 492 return new QuicConnectionHelper(base::ThreadTaskRunnerHandle::Get().get(), | 376 return new QuicConnectionHelper(base::ThreadTaskRunnerHandle::Get().get(), |
| 493 &clock_, QuicRandom::GetInstance()); | 377 &clock_, QuicRandom::GetInstance()); |
| 494 } | 378 } |
| 495 | 379 |
| 496 QuicPacketWriter* QuicSimpleClient::CreateQuicPacketWriter() { | 380 QuicPacketWriter* QuicSimpleClient::CreateQuicPacketWriter() { |
| 497 return new QuicDefaultPacketWriter(socket_.get()); | 381 return new QuicDefaultPacketWriter(socket_.get()); |
| 498 } | 382 } |
| 499 | 383 |
| 500 void QuicSimpleClient::OnReadError(int result) { | 384 void QuicSimpleClient::OnReadError(int result) { |
| 501 LOG(ERROR) << "QuicSimpleClient read failed: " << ErrorToShortString(result); | 385 LOG(ERROR) << "QuicSimpleClient read failed: " << ErrorToShortString(result); |
| 502 Disconnect(); | 386 Disconnect(); |
| 503 } | 387 } |
| 504 | 388 |
| 505 bool QuicSimpleClient::OnPacket(const QuicEncryptedPacket& packet, | 389 bool QuicSimpleClient::OnPacket(const QuicEncryptedPacket& packet, |
| 506 IPEndPoint local_address, | 390 IPEndPoint local_address, |
| 507 IPEndPoint peer_address) { | 391 IPEndPoint peer_address) { |
| 508 session_->connection()->ProcessUdpPacket(local_address, peer_address, packet); | 392 session()->connection()->ProcessUdpPacket(local_address, peer_address, |
| 509 if (!session_->connection()->connected()) { | 393 packet); |
| 394 if (!session()->connection()->connected()) { |
| 510 return false; | 395 return false; |
| 511 } | 396 } |
| 512 | 397 |
| 513 return true; | 398 return true; |
| 514 } | 399 } |
| 515 | 400 |
| 516 } // namespace tools | 401 } // namespace tools |
| 517 } // namespace net | 402 } // namespace net |
| OLD | NEW |