Chromium Code Reviews| 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_client.h" | 5 #include "net/tools/quic/quic_client.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <netinet/in.h> | 8 #include <netinet/in.h> |
| 9 #include <string.h> | 9 #include <string.h> |
| 10 #include <sys/epoll.h> | 10 #include <sys/epoll.h> |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 37 | 37 |
| 38 using base::StringPiece; | 38 using base::StringPiece; |
| 39 using base::StringToInt; | 39 using base::StringToInt; |
| 40 using std::string; | 40 using std::string; |
| 41 using std::vector; | 41 using std::vector; |
| 42 | 42 |
| 43 namespace net { | 43 namespace net { |
| 44 | 44 |
| 45 const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET; | 45 const int kEpollFlags = EPOLLIN | EPOLLOUT | EPOLLET; |
| 46 | 46 |
| 47 void QuicClient::ClientQuicDataToResend::Resend() { | |
| 48 client_->SendRequest(*headers_, body_, fin_); | |
| 49 headers_ = nullptr; | |
| 50 } | |
| 51 | |
| 52 QuicClient::QuicClient(IPEndPoint server_address, | 47 QuicClient::QuicClient(IPEndPoint server_address, |
| 53 const QuicServerId& server_id, | 48 const QuicServerId& server_id, |
| 54 const QuicVersionVector& supported_versions, | 49 const QuicVersionVector& supported_versions, |
| 55 EpollServer* epoll_server, | 50 EpollServer* epoll_server, |
| 56 std::unique_ptr<ProofVerifier> proof_verifier) | 51 std::unique_ptr<ProofVerifier> proof_verifier) |
| 57 : QuicClient(server_address, | 52 : QuicClient(server_address, |
| 58 server_id, | 53 server_id, |
| 59 supported_versions, | 54 supported_versions, |
| 60 QuicConfig(), | 55 QuicConfig(), |
| 61 epoll_server, | 56 epoll_server, |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 167 | 162 |
| 168 bool QuicClient::Connect() { | 163 bool QuicClient::Connect() { |
| 169 // Attempt multiple connects until the maximum number of client hellos have | 164 // Attempt multiple connects until the maximum number of client hellos have |
| 170 // been sent. | 165 // been sent. |
| 171 while (!connected() && | 166 while (!connected() && |
| 172 GetNumSentClientHellos() <= QuicCryptoClientStream::kMaxClientHellos) { | 167 GetNumSentClientHellos() <= QuicCryptoClientStream::kMaxClientHellos) { |
| 173 StartConnect(); | 168 StartConnect(); |
| 174 while (EncryptionBeingEstablished()) { | 169 while (EncryptionBeingEstablished()) { |
| 175 WaitForEvents(); | 170 WaitForEvents(); |
| 176 } | 171 } |
| 177 if (FLAGS_enable_quic_stateless_reject_support && connected() && | 172 if (FLAGS_enable_quic_stateless_reject_support && connected()) { |
| 178 !data_to_resend_on_connect_.empty()) { | 173 // Resend any previously queued data. |
|
Zhongyi Shi
2016/09/27 04:40:25
nit: comments here seem to be out of sync with int
Ryan Hamilton
2016/09/27 14:28:00
Silly long story, but will be fixed in the next cl
| |
| 179 // A connection has been established and there was previously queued data | 174 ResendSavedData(); |
| 180 // to resend. Resend it and empty the queue. | |
| 181 std::vector<std::unique_ptr<QuicDataToResend>> old_data; | |
| 182 old_data.swap(data_to_resend_on_connect_); | |
| 183 for (const auto& data : old_data) { | |
| 184 data->Resend(); | |
| 185 } | |
| 186 } | 175 } |
| 187 if (session() != nullptr && | 176 if (session() != nullptr && |
| 188 session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { | 177 session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { |
| 189 // We've successfully created a session but we're not connected, and there | 178 // We've successfully created a session but we're not connected, and there |
| 190 // is no stateless reject to recover from. Give up trying. | 179 // is no stateless reject to recover from. Give up trying. |
| 191 break; | 180 break; |
| 192 } | 181 } |
| 193 } | 182 } |
| 194 if (!connected() && | 183 if (!connected() && |
| 195 GetNumSentClientHellos() > QuicCryptoClientStream::kMaxClientHellos && | 184 GetNumSentClientHellos() > QuicCryptoClientStream::kMaxClientHellos && |
| 196 session() != nullptr && | 185 session() != nullptr && |
| 197 session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { | 186 session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { |
| 198 // The overall connection failed due too many stateless rejects. | 187 // The overall connection failed due too many stateless rejects. |
| 199 set_connection_error(QUIC_CRYPTO_TOO_MANY_REJECTS); | 188 set_connection_error(QUIC_CRYPTO_TOO_MANY_REJECTS); |
| 200 } | 189 } |
| 201 return session()->connection()->connected(); | 190 return session()->connection()->connected(); |
| 202 } | 191 } |
| 203 | 192 |
| 204 void QuicClient::StartConnect() { | 193 void QuicClient::StartConnect() { |
| 205 DCHECK(initialized_); | 194 DCHECK(initialized_); |
| 206 DCHECK(!connected()); | 195 DCHECK(!connected()); |
| 207 | 196 |
| 208 QuicPacketWriter* writer = CreateQuicPacketWriter(); | 197 QuicPacketWriter* writer = CreateQuicPacketWriter(); |
| 209 | 198 |
| 210 if (connected_or_attempting_connect()) { | 199 if (connected_or_attempting_connect()) { |
| 211 // If the last error was not a stateless reject, then the queued up data | 200 // If the last error was not a stateless reject, then the queued up data |
| 212 // does not need to be resent. | 201 // does not need to be resent. |
| 213 if (session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { | 202 if (session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) { |
| 214 data_to_resend_on_connect_.clear(); | 203 ClearDataToResend(); |
| 215 } | 204 } |
| 216 // Before we destroy the last session and create a new one, gather its stats | 205 // Before we destroy the last session and create a new one, gather its stats |
| 217 // and update the stats for the overall connection. | 206 // and update the stats for the overall connection. |
| 218 UpdateStats(); | 207 UpdateStats(); |
| 219 } | 208 } |
| 220 | 209 |
| 221 CreateQuicClientSession(new QuicConnection( | 210 CreateQuicClientSession(new QuicConnection( |
| 222 GetNextConnectionId(), server_address_, helper(), alarm_factory(), writer, | 211 GetNextConnectionId(), server_address_, helper(), alarm_factory(), writer, |
| 223 /* owns_writer= */ false, Perspective::IS_CLIENT, supported_versions())); | 212 /* owns_writer= */ false, Perspective::IS_CLIENT, supported_versions())); |
| 224 | 213 |
| 225 // Reset |writer()| after |session()| so that the old writer outlives the old | 214 // Reset |writer()| after |session()| so that the old writer outlives the old |
| 226 // session. | 215 // session. |
| 227 set_writer(writer); | 216 set_writer(writer); |
| 228 session()->Initialize(); | 217 session()->Initialize(); |
| 229 session()->CryptoConnect(); | 218 session()->CryptoConnect(); |
| 230 set_connected_or_attempting_connect(true); | 219 set_connected_or_attempting_connect(true); |
| 231 } | 220 } |
| 232 | 221 |
| 233 void QuicClient::Disconnect() { | 222 void QuicClient::Disconnect() { |
| 234 DCHECK(initialized_); | 223 DCHECK(initialized_); |
| 235 | 224 |
| 236 if (connected()) { | 225 if (connected()) { |
| 237 session()->connection()->CloseConnection( | 226 session()->connection()->CloseConnection( |
| 238 QUIC_PEER_GOING_AWAY, "Client disconnecting", | 227 QUIC_PEER_GOING_AWAY, "Client disconnecting", |
| 239 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); | 228 ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); |
| 240 } | 229 } |
| 241 | 230 |
| 242 data_to_resend_on_connect_.clear(); | 231 ClearDataToResend(); |
| 243 | 232 |
| 244 CleanUpAllUDPSockets(); | 233 CleanUpAllUDPSockets(); |
| 245 | 234 |
| 246 initialized_ = false; | 235 initialized_ = false; |
| 247 } | 236 } |
| 248 | 237 |
| 249 void QuicClient::CleanUpUDPSocket(int fd) { | 238 void QuicClient::CleanUpUDPSocket(int fd) { |
| 250 CleanUpUDPSocketImpl(fd); | 239 CleanUpUDPSocketImpl(fd); |
| 251 fd_address_map_.erase(fd); | 240 fd_address_map_.erase(fd); |
| 252 } | 241 } |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 269 void QuicClient::SendRequest(const SpdyHeaderBlock& headers, | 258 void QuicClient::SendRequest(const SpdyHeaderBlock& headers, |
| 270 StringPiece body, | 259 StringPiece body, |
| 271 bool fin) { | 260 bool fin) { |
| 272 QuicClientPushPromiseIndex::TryHandle* handle; | 261 QuicClientPushPromiseIndex::TryHandle* handle; |
| 273 QuicAsyncStatus rv = push_promise_index()->Try(headers, this, &handle); | 262 QuicAsyncStatus rv = push_promise_index()->Try(headers, this, &handle); |
| 274 if (rv == QUIC_SUCCESS) | 263 if (rv == QUIC_SUCCESS) |
| 275 return; | 264 return; |
| 276 | 265 |
| 277 if (rv == QUIC_PENDING) { | 266 if (rv == QUIC_PENDING) { |
| 278 // May need to retry request if asynchronous rendezvous fails. | 267 // May need to retry request if asynchronous rendezvous fails. |
| 279 std::unique_ptr<SpdyHeaderBlock> new_headers( | 268 AddPromiseDataToResend(headers, body, fin); |
| 280 new SpdyHeaderBlock(headers.Clone())); | |
| 281 push_promise_data_to_resend_.reset( | |
| 282 new ClientQuicDataToResend(std::move(new_headers), body, fin, this)); | |
| 283 return; | 269 return; |
| 284 } | 270 } |
| 285 | 271 |
| 286 QuicSpdyClientStream* stream = CreateReliableClientStream(); | 272 QuicSpdyClientStream* stream = CreateReliableClientStream(); |
| 287 if (stream == nullptr) { | 273 if (stream == nullptr) { |
| 288 QUIC_BUG << "stream creation failed!"; | 274 QUIC_BUG << "stream creation failed!"; |
| 289 return; | 275 return; |
| 290 } | 276 } |
| 291 stream->SendRequest(headers.Clone(), body, fin); | 277 stream->SendRequest(headers.Clone(), body, fin); |
| 292 if (FLAGS_enable_quic_stateless_reject_support) { | 278 // Record this in case we need to resend. |
| 293 // Record this in case we need to resend. | 279 MaybeAddDataToResend(headers, body, fin); |
| 294 std::unique_ptr<SpdyHeaderBlock> new_headers( | |
| 295 new SpdyHeaderBlock(headers.Clone())); | |
| 296 auto data_to_resend = | |
| 297 new ClientQuicDataToResend(std::move(new_headers), body, fin, this); | |
| 298 MaybeAddQuicDataToResend(std::unique_ptr<QuicDataToResend>(data_to_resend)); | |
| 299 } | |
| 300 } | |
| 301 | |
| 302 void QuicClient::MaybeAddQuicDataToResend( | |
| 303 std::unique_ptr<QuicDataToResend> data_to_resend) { | |
| 304 DCHECK(FLAGS_enable_quic_stateless_reject_support); | |
| 305 if (session()->IsCryptoHandshakeConfirmed()) { | |
| 306 // The handshake is confirmed. No need to continue saving requests to | |
| 307 // resend. | |
| 308 data_to_resend_on_connect_.clear(); | |
| 309 return; | |
| 310 } | |
| 311 | |
| 312 // The handshake is not confirmed. Push the data onto the queue of data to | |
| 313 // resend if statelessly rejected. | |
| 314 data_to_resend_on_connect_.push_back(std::move(data_to_resend)); | |
| 315 } | 280 } |
| 316 | 281 |
| 317 void QuicClient::SendRequestAndWaitForResponse(const SpdyHeaderBlock& headers, | 282 void QuicClient::SendRequestAndWaitForResponse(const SpdyHeaderBlock& headers, |
| 318 StringPiece body, | 283 StringPiece body, |
| 319 bool fin) { | 284 bool fin) { |
| 320 SendRequest(headers, body, fin); | 285 SendRequest(headers, body, fin); |
| 321 while (WaitForEvents()) { | 286 while (WaitForEvents()) { |
| 322 } | 287 } |
| 323 } | 288 } |
| 324 | 289 |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 424 LOG(ERROR) << "Invalid response headers: no status code"; | 389 LOG(ERROR) << "Invalid response headers: no status code"; |
| 425 } | 390 } |
| 426 latest_response_headers_ = response_headers.DebugString(); | 391 latest_response_headers_ = response_headers.DebugString(); |
| 427 latest_response_header_block_ = response_headers.Clone(); | 392 latest_response_header_block_ = response_headers.Clone(); |
| 428 latest_response_body_ = client_stream->data(); | 393 latest_response_body_ = client_stream->data(); |
| 429 latest_response_trailers_ = | 394 latest_response_trailers_ = |
| 430 client_stream->received_trailers().DebugString(); | 395 client_stream->received_trailers().DebugString(); |
| 431 } | 396 } |
| 432 } | 397 } |
| 433 | 398 |
| 434 bool QuicClient::CheckVary(const SpdyHeaderBlock& client_request, | |
| 435 const SpdyHeaderBlock& promise_request, | |
| 436 const SpdyHeaderBlock& promise_response) { | |
| 437 return true; | |
| 438 } | |
| 439 | |
| 440 void QuicClient::OnRendezvousResult(QuicSpdyStream* stream) { | |
| 441 std::unique_ptr<ClientQuicDataToResend> data_to_resend = | |
| 442 std::move(push_promise_data_to_resend_); | |
| 443 if (stream) { | |
| 444 stream->set_visitor(this); | |
| 445 stream->OnDataAvailable(); | |
| 446 } else if (data_to_resend.get()) { | |
| 447 data_to_resend->Resend(); | |
| 448 } | |
| 449 } | |
| 450 | |
| 451 size_t QuicClient::latest_response_code() const { | 399 size_t QuicClient::latest_response_code() const { |
| 452 QUIC_BUG_IF(!store_response_) << "Response not stored!"; | 400 QUIC_BUG_IF(!store_response_) << "Response not stored!"; |
| 453 return latest_response_code_; | 401 return latest_response_code_; |
| 454 } | 402 } |
| 455 | 403 |
| 456 const string& QuicClient::latest_response_headers() const { | 404 const string& QuicClient::latest_response_headers() const { |
| 457 QUIC_BUG_IF(!store_response_) << "Response not stored!"; | 405 QUIC_BUG_IF(!store_response_) << "Response not stored!"; |
| 458 return latest_response_headers_; | 406 return latest_response_headers_; |
| 459 } | 407 } |
| 460 | 408 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 493 return fd_address_map_.back().first; | 441 return fd_address_map_.back().first; |
| 494 } | 442 } |
| 495 | 443 |
| 496 void QuicClient::ProcessPacket(const IPEndPoint& self_address, | 444 void QuicClient::ProcessPacket(const IPEndPoint& self_address, |
| 497 const IPEndPoint& peer_address, | 445 const IPEndPoint& peer_address, |
| 498 const QuicReceivedPacket& packet) { | 446 const QuicReceivedPacket& packet) { |
| 499 session()->connection()->ProcessUdpPacket(self_address, peer_address, packet); | 447 session()->connection()->ProcessUdpPacket(self_address, peer_address, packet); |
| 500 } | 448 } |
| 501 | 449 |
| 502 } // namespace net | 450 } // namespace net |
| OLD | NEW |