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. |
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 |