| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/quic_config.h" | 5 #include "net/quic/quic_config.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "net/quic/crypto/crypto_handshake_message.h" | 10 #include "net/quic/crypto/crypto_handshake_message.h" |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 QuicNegotiableTag::QuicNegotiableTag(QuicTag tag, QuicConfigPresence presence) | 122 QuicNegotiableTag::QuicNegotiableTag(QuicTag tag, QuicConfigPresence presence) |
| 123 : QuicNegotiableValue(tag, presence), | 123 : QuicNegotiableValue(tag, presence), |
| 124 negotiated_tag_(0), | 124 negotiated_tag_(0), |
| 125 default_value_(0) { | 125 default_value_(0) { |
| 126 } | 126 } |
| 127 | 127 |
| 128 QuicNegotiableTag::~QuicNegotiableTag() {} | 128 QuicNegotiableTag::~QuicNegotiableTag() {} |
| 129 | 129 |
| 130 void QuicNegotiableTag::set(const QuicTagVector& possible, | 130 void QuicNegotiableTag::set(const QuicTagVector& possible, |
| 131 QuicTag default_value) { | 131 QuicTag default_value) { |
| 132 DCHECK(std::find(possible.begin(), possible.end(), default_value) != | 132 DCHECK(ContainsQuicTag(possible, default_value)); |
| 133 possible.end()); | |
| 134 possible_values_ = possible; | 133 possible_values_ = possible; |
| 135 default_value_ = default_value; | 134 default_value_ = default_value; |
| 136 } | 135 } |
| 137 | 136 |
| 138 QuicTag QuicNegotiableTag::GetTag() const { | 137 QuicTag QuicNegotiableTag::GetTag() const { |
| 139 if (negotiated_) { | 138 if (negotiated_) { |
| 140 return negotiated_tag_; | 139 return negotiated_tag_; |
| 141 } | 140 } |
| 142 return default_value_; | 141 return default_value_; |
| 143 } | 142 } |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 const QuicTag* received_tags; | 186 const QuicTag* received_tags; |
| 188 size_t received_tags_length; | 187 size_t received_tags_length; |
| 189 QuicErrorCode error = ReadVector(peer_hello, &received_tags, | 188 QuicErrorCode error = ReadVector(peer_hello, &received_tags, |
| 190 &received_tags_length, error_details); | 189 &received_tags_length, error_details); |
| 191 if (error != QUIC_NO_ERROR) { | 190 if (error != QUIC_NO_ERROR) { |
| 192 return error; | 191 return error; |
| 193 } | 192 } |
| 194 | 193 |
| 195 if (hello_type == SERVER) { | 194 if (hello_type == SERVER) { |
| 196 if (received_tags_length != 1 || | 195 if (received_tags_length != 1 || |
| 197 std::find(possible_values_.begin(), possible_values_.end(), | 196 !ContainsQuicTag(possible_values_, *received_tags)) { |
| 198 *received_tags) == possible_values_.end()) { | |
| 199 *error_details = "Invalid " + QuicUtils::TagToString(tag_); | 197 *error_details = "Invalid " + QuicUtils::TagToString(tag_); |
| 200 return QUIC_INVALID_NEGOTIATED_VALUE; | 198 return QUIC_INVALID_NEGOTIATED_VALUE; |
| 201 } | 199 } |
| 202 negotiated_tag_ = *received_tags; | 200 negotiated_tag_ = *received_tags; |
| 203 } else { | 201 } else { |
| 204 QuicTag negotiated_tag; | 202 QuicTag negotiated_tag; |
| 205 if (!QuicUtils::FindMutualTag(possible_values_, | 203 if (!QuicUtils::FindMutualTag(possible_values_, |
| 206 received_tags, | 204 received_tags, |
| 207 received_tags_length, | 205 received_tags_length, |
| 208 QuicUtils::LOCAL_PRIORITY, | 206 QuicUtils::LOCAL_PRIORITY, |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 } | 259 } |
| 262 | 260 |
| 263 QuicErrorCode QuicFixedUint32::ProcessPeerHello( | 261 QuicErrorCode QuicFixedUint32::ProcessPeerHello( |
| 264 const CryptoHandshakeMessage& peer_hello, | 262 const CryptoHandshakeMessage& peer_hello, |
| 265 HelloType hello_type, | 263 HelloType hello_type, |
| 266 string* error_details) { | 264 string* error_details) { |
| 267 DCHECK(error_details != NULL); | 265 DCHECK(error_details != NULL); |
| 268 QuicErrorCode error = peer_hello.GetUint32(tag_, &receive_value_); | 266 QuicErrorCode error = peer_hello.GetUint32(tag_, &receive_value_); |
| 269 switch (error) { | 267 switch (error) { |
| 270 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND: | 268 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND: |
| 271 if (presence_ == PRESENCE_REQUIRED) { | 269 if (presence_ == PRESENCE_OPTIONAL) { |
| 272 *error_details = "Missing " + QuicUtils::TagToString(tag_); | 270 return QUIC_NO_ERROR; |
| 273 break; | |
| 274 } | 271 } |
| 275 error = QUIC_NO_ERROR; | 272 *error_details = "Missing " + QuicUtils::TagToString(tag_); |
| 276 break; | 273 break; |
| 277 case QUIC_NO_ERROR: | 274 case QUIC_NO_ERROR: |
| 278 has_receive_value_ = true; | 275 has_receive_value_ = true; |
| 279 break; | 276 break; |
| 280 default: | 277 default: |
| 281 *error_details = "Bad " + QuicUtils::TagToString(tag_); | 278 *error_details = "Bad " + QuicUtils::TagToString(tag_); |
| 282 break; | 279 break; |
| 283 } | 280 } |
| 284 return error; | 281 return error; |
| 285 } | 282 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 322 receive_value_ = value; | 319 receive_value_ = value; |
| 323 } | 320 } |
| 324 | 321 |
| 325 void QuicFixedTag::ToHandshakeMessage(CryptoHandshakeMessage* out) const { | 322 void QuicFixedTag::ToHandshakeMessage(CryptoHandshakeMessage* out) const { |
| 326 if (has_send_value_) { | 323 if (has_send_value_) { |
| 327 out->SetValue(tag_, send_value_); | 324 out->SetValue(tag_, send_value_); |
| 328 } | 325 } |
| 329 } | 326 } |
| 330 | 327 |
| 331 QuicErrorCode QuicFixedTag::ProcessPeerHello( | 328 QuicErrorCode QuicFixedTag::ProcessPeerHello( |
| 332 const CryptoHandshakeMessage& client_hello, | 329 const CryptoHandshakeMessage& peer_hello, |
| 333 HelloType hello_type, | 330 HelloType hello_type, |
| 334 string* error_details) { | 331 string* error_details) { |
| 335 DCHECK(error_details != NULL); | 332 DCHECK(error_details != NULL); |
| 336 QuicErrorCode error = client_hello.GetUint32(tag_, &receive_value_); | 333 QuicErrorCode error = peer_hello.GetUint32(tag_, &receive_value_); |
| 337 switch (error) { | 334 switch (error) { |
| 338 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND: | 335 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND: |
| 339 if (presence_ == PRESENCE_REQUIRED) { | 336 if (presence_ == PRESENCE_OPTIONAL) { |
| 340 *error_details = "Missing " + QuicUtils::TagToString(tag_); | 337 return QUIC_NO_ERROR; |
| 341 break; | |
| 342 } | 338 } |
| 343 error = QUIC_NO_ERROR; | 339 *error_details = "Missing " + QuicUtils::TagToString(tag_); |
| 344 break; | 340 break; |
| 345 case QUIC_NO_ERROR: | 341 case QUIC_NO_ERROR: |
| 346 has_receive_value_ = true; | 342 has_receive_value_ = true; |
| 347 break; | 343 break; |
| 348 default: | 344 default: |
| 349 *error_details = "Bad " + QuicUtils::TagToString(tag_); | 345 *error_details = "Bad " + QuicUtils::TagToString(tag_); |
| 350 break; | 346 break; |
| 351 } | 347 } |
| 352 return error; | 348 return error; |
| 353 } | 349 } |
| 354 | 350 |
| 351 QuicFixedTagVector::QuicFixedTagVector(QuicTag name, |
| 352 QuicConfigPresence presence) |
| 353 : QuicConfigValue(name, presence), |
| 354 has_send_values_(false), |
| 355 has_receive_values_(false) { |
| 356 } |
| 357 |
| 358 QuicFixedTagVector::~QuicFixedTagVector() {} |
| 359 |
| 360 bool QuicFixedTagVector::HasSendValues() const { |
| 361 return has_send_values_; |
| 362 } |
| 363 |
| 364 QuicTagVector QuicFixedTagVector::GetSendValues() const { |
| 365 LOG_IF(DFATAL, !has_send_values_) << "No send values to get for tag:" << tag_; |
| 366 return send_values_; |
| 367 } |
| 368 |
| 369 void QuicFixedTagVector::SetSendValues(const QuicTagVector& values) { |
| 370 has_send_values_ = true; |
| 371 send_values_ = values; |
| 372 } |
| 373 |
| 374 bool QuicFixedTagVector::HasReceivedValues() const { |
| 375 return has_receive_values_; |
| 376 } |
| 377 |
| 378 QuicTagVector QuicFixedTagVector::GetReceivedValues() const { |
| 379 LOG_IF(DFATAL, !has_receive_values_) |
| 380 << "No receive value to get for tag:" << tag_; |
| 381 return receive_values_; |
| 382 } |
| 383 |
| 384 void QuicFixedTagVector::SetReceivedValues(const QuicTagVector& values) { |
| 385 has_receive_values_ = true; |
| 386 receive_values_ = values; |
| 387 } |
| 388 |
| 389 void QuicFixedTagVector::ToHandshakeMessage(CryptoHandshakeMessage* out) const { |
| 390 if (has_send_values_) { |
| 391 out->SetVector(tag_, send_values_); |
| 392 } |
| 393 } |
| 394 |
| 395 QuicErrorCode QuicFixedTagVector::ProcessPeerHello( |
| 396 const CryptoHandshakeMessage& peer_hello, |
| 397 HelloType hello_type, |
| 398 string* error_details) { |
| 399 DCHECK(error_details != NULL); |
| 400 const QuicTag* received_tags; |
| 401 size_t received_tags_length; |
| 402 QuicErrorCode error = |
| 403 peer_hello.GetTaglist(tag_, &received_tags, &received_tags_length); |
| 404 switch (error) { |
| 405 case QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND: |
| 406 if (presence_ == PRESENCE_OPTIONAL) { |
| 407 return QUIC_NO_ERROR; |
| 408 } |
| 409 *error_details = "Missing " + QuicUtils::TagToString(tag_); |
| 410 break; |
| 411 case QUIC_NO_ERROR: |
| 412 has_receive_values_ = true; |
| 413 for (size_t i = 0; i < received_tags_length; ++i) { |
| 414 receive_values_.push_back(received_tags[i]); |
| 415 } |
| 416 break; |
| 417 default: |
| 418 *error_details = "Bad " + QuicUtils::TagToString(tag_); |
| 419 break; |
| 420 } |
| 421 return error; |
| 422 } |
| 423 |
| 355 QuicConfig::QuicConfig() | 424 QuicConfig::QuicConfig() |
| 356 : congestion_control_(kCGST, PRESENCE_REQUIRED), | 425 : congestion_feedback_(kCGST, PRESENCE_REQUIRED), |
| 426 congestion_options_(kCOPT, PRESENCE_OPTIONAL), |
| 357 loss_detection_(kLOSS, PRESENCE_OPTIONAL), | 427 loss_detection_(kLOSS, PRESENCE_OPTIONAL), |
| 358 idle_connection_state_lifetime_seconds_(kICSL, PRESENCE_REQUIRED), | 428 idle_connection_state_lifetime_seconds_(kICSL, PRESENCE_REQUIRED), |
| 359 keepalive_timeout_seconds_(kKATO, PRESENCE_OPTIONAL), | 429 keepalive_timeout_seconds_(kKATO, PRESENCE_OPTIONAL), |
| 360 max_streams_per_connection_(kMSPC, PRESENCE_REQUIRED), | 430 max_streams_per_connection_(kMSPC, PRESENCE_REQUIRED), |
| 361 max_time_before_crypto_handshake_(QuicTime::Delta::Zero()), | 431 max_time_before_crypto_handshake_(QuicTime::Delta::Zero()), |
| 362 initial_congestion_window_(kSWND, PRESENCE_OPTIONAL), | 432 initial_congestion_window_(kSWND, PRESENCE_OPTIONAL), |
| 363 initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL), | 433 initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL), |
| 364 // TODO(rjshade): Make this PRESENCE_REQUIRED when retiring | 434 // TODO(rjshade): Make this PRESENCE_REQUIRED when retiring |
| 365 // QUIC_VERSION_17. | 435 // QUIC_VERSION_17. |
| 366 initial_flow_control_window_bytes_(kIFCW, PRESENCE_OPTIONAL) { | 436 initial_flow_control_window_bytes_(kIFCW, PRESENCE_OPTIONAL) { |
| 367 } | 437 } |
| 368 | 438 |
| 369 QuicConfig::~QuicConfig() {} | 439 QuicConfig::~QuicConfig() {} |
| 370 | 440 |
| 371 void QuicConfig::set_congestion_control( | 441 void QuicConfig::set_congestion_feedback( |
| 372 const QuicTagVector& congestion_control, | 442 const QuicTagVector& congestion_feedback, |
| 373 QuicTag default_congestion_control) { | 443 QuicTag default_congestion_feedback) { |
| 374 congestion_control_.set(congestion_control, default_congestion_control); | 444 congestion_feedback_.set(congestion_feedback, default_congestion_feedback); |
| 375 } | 445 } |
| 376 | 446 |
| 377 QuicTag QuicConfig::congestion_control() const { | 447 QuicTag QuicConfig::congestion_feedback() const { |
| 378 return congestion_control_.GetTag(); | 448 return congestion_feedback_.GetTag(); |
| 449 } |
| 450 |
| 451 void QuicConfig::SetCongestionOptionsToSend( |
| 452 const QuicTagVector& congestion_options) { |
| 453 congestion_options_.SetSendValues(congestion_options); |
| 454 } |
| 455 |
| 456 bool QuicConfig::HasReceivedCongestionOptions() const { |
| 457 return congestion_options_.HasReceivedValues(); |
| 458 } |
| 459 |
| 460 QuicTagVector QuicConfig::ReceivedCongestionOptions() const { |
| 461 return congestion_options_.GetReceivedValues(); |
| 379 } | 462 } |
| 380 | 463 |
| 381 void QuicConfig::SetLossDetectionToSend(QuicTag loss_detection) { | 464 void QuicConfig::SetLossDetectionToSend(QuicTag loss_detection) { |
| 382 loss_detection_.SetSendValue(loss_detection); | 465 loss_detection_.SetSendValue(loss_detection); |
| 383 } | 466 } |
| 384 | 467 |
| 385 bool QuicConfig::HasReceivedLossDetection() const { | 468 bool QuicConfig::HasReceivedLossDetection() const { |
| 386 return loss_detection_.HasReceivedValue(); | 469 return loss_detection_.HasReceivedValue(); |
| 387 } | 470 } |
| 388 | 471 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 459 } | 542 } |
| 460 | 543 |
| 461 uint32 QuicConfig::ReceivedInitialFlowControlWindowBytes() const { | 544 uint32 QuicConfig::ReceivedInitialFlowControlWindowBytes() const { |
| 462 return initial_flow_control_window_bytes_.GetReceivedValue(); | 545 return initial_flow_control_window_bytes_.GetReceivedValue(); |
| 463 } | 546 } |
| 464 | 547 |
| 465 bool QuicConfig::negotiated() { | 548 bool QuicConfig::negotiated() { |
| 466 // TODO(ianswett): Add the negotiated parameters once and iterate over all | 549 // TODO(ianswett): Add the negotiated parameters once and iterate over all |
| 467 // of them in negotiated, ToHandshakeMessage, ProcessClientHello, and | 550 // of them in negotiated, ToHandshakeMessage, ProcessClientHello, and |
| 468 // ProcessServerHello. | 551 // ProcessServerHello. |
| 469 return congestion_control_.negotiated() && | 552 return congestion_feedback_.negotiated() && |
| 470 idle_connection_state_lifetime_seconds_.negotiated() && | 553 idle_connection_state_lifetime_seconds_.negotiated() && |
| 471 keepalive_timeout_seconds_.negotiated() && | 554 keepalive_timeout_seconds_.negotiated() && |
| 472 max_streams_per_connection_.negotiated(); | 555 max_streams_per_connection_.negotiated(); |
| 473 } | 556 } |
| 474 | 557 |
| 475 void QuicConfig::SetDefaults() { | 558 void QuicConfig::SetDefaults() { |
| 476 QuicTagVector congestion_control; | 559 QuicTagVector congestion_feedback; |
| 477 if (FLAGS_enable_quic_pacing) { | 560 if (FLAGS_enable_quic_pacing) { |
| 478 congestion_control.push_back(kPACE); | 561 congestion_feedback.push_back(kPACE); |
| 479 } | 562 } |
| 480 congestion_control.push_back(kQBIC); | 563 congestion_feedback.push_back(kQBIC); |
| 481 congestion_control_.set(congestion_control, kQBIC); | 564 congestion_feedback_.set(congestion_feedback, kQBIC); |
| 482 idle_connection_state_lifetime_seconds_.set(kDefaultTimeoutSecs, | 565 idle_connection_state_lifetime_seconds_.set(kDefaultTimeoutSecs, |
| 483 kDefaultInitialTimeoutSecs); | 566 kDefaultInitialTimeoutSecs); |
| 484 // kKATO is optional. Return 0 if not negotiated. | 567 // kKATO is optional. Return 0 if not negotiated. |
| 485 keepalive_timeout_seconds_.set(0, 0); | 568 keepalive_timeout_seconds_.set(0, 0); |
| 486 max_streams_per_connection_.set(kDefaultMaxStreamsPerConnection, | 569 max_streams_per_connection_.set(kDefaultMaxStreamsPerConnection, |
| 487 kDefaultMaxStreamsPerConnection); | 570 kDefaultMaxStreamsPerConnection); |
| 488 max_time_before_crypto_handshake_ = QuicTime::Delta::FromSeconds( | 571 max_time_before_crypto_handshake_ = QuicTime::Delta::FromSeconds( |
| 489 kDefaultMaxTimeForCryptoHandshakeSecs); | 572 kDefaultMaxTimeForCryptoHandshakeSecs); |
| 490 } | 573 } |
| 491 | 574 |
| 492 void QuicConfig::EnablePacing(bool enable_pacing) { | 575 void QuicConfig::EnablePacing(bool enable_pacing) { |
| 493 QuicTagVector congestion_control; | 576 QuicTagVector congestion_feedback; |
| 494 if (enable_pacing) { | 577 if (enable_pacing) { |
| 495 congestion_control.push_back(kPACE); | 578 congestion_feedback.push_back(kPACE); |
| 496 } | 579 } |
| 497 congestion_control.push_back(kQBIC); | 580 congestion_feedback.push_back(kQBIC); |
| 498 congestion_control_.set(congestion_control, kQBIC); | 581 congestion_feedback_.set(congestion_feedback, kQBIC); |
| 499 } | 582 } |
| 500 | 583 |
| 501 void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const { | 584 void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const { |
| 502 congestion_control_.ToHandshakeMessage(out); | 585 congestion_feedback_.ToHandshakeMessage(out); |
| 503 idle_connection_state_lifetime_seconds_.ToHandshakeMessage(out); | 586 idle_connection_state_lifetime_seconds_.ToHandshakeMessage(out); |
| 504 keepalive_timeout_seconds_.ToHandshakeMessage(out); | 587 keepalive_timeout_seconds_.ToHandshakeMessage(out); |
| 505 max_streams_per_connection_.ToHandshakeMessage(out); | 588 max_streams_per_connection_.ToHandshakeMessage(out); |
| 506 initial_congestion_window_.ToHandshakeMessage(out); | 589 initial_congestion_window_.ToHandshakeMessage(out); |
| 507 initial_round_trip_time_us_.ToHandshakeMessage(out); | 590 initial_round_trip_time_us_.ToHandshakeMessage(out); |
| 508 loss_detection_.ToHandshakeMessage(out); | 591 loss_detection_.ToHandshakeMessage(out); |
| 509 initial_flow_control_window_bytes_.ToHandshakeMessage(out); | 592 initial_flow_control_window_bytes_.ToHandshakeMessage(out); |
| 593 congestion_options_.ToHandshakeMessage(out); |
| 510 } | 594 } |
| 511 | 595 |
| 512 QuicErrorCode QuicConfig::ProcessPeerHello( | 596 QuicErrorCode QuicConfig::ProcessPeerHello( |
| 513 const CryptoHandshakeMessage& peer_hello, | 597 const CryptoHandshakeMessage& peer_hello, |
| 514 HelloType hello_type, | 598 HelloType hello_type, |
| 515 string* error_details) { | 599 string* error_details) { |
| 516 DCHECK(error_details != NULL); | 600 DCHECK(error_details != NULL); |
| 517 | 601 |
| 518 QuicErrorCode error = QUIC_NO_ERROR; | 602 QuicErrorCode error = QUIC_NO_ERROR; |
| 519 if (error == QUIC_NO_ERROR) { | 603 if (error == QUIC_NO_ERROR) { |
| 520 error = congestion_control_.ProcessPeerHello( | 604 error = congestion_feedback_.ProcessPeerHello( |
| 521 peer_hello, hello_type, error_details); | 605 peer_hello, hello_type, error_details); |
| 522 } | 606 } |
| 523 if (error == QUIC_NO_ERROR) { | 607 if (error == QUIC_NO_ERROR) { |
| 524 error = idle_connection_state_lifetime_seconds_.ProcessPeerHello( | 608 error = idle_connection_state_lifetime_seconds_.ProcessPeerHello( |
| 525 peer_hello, hello_type, error_details); | 609 peer_hello, hello_type, error_details); |
| 526 } | 610 } |
| 527 if (error == QUIC_NO_ERROR) { | 611 if (error == QUIC_NO_ERROR) { |
| 528 error = keepalive_timeout_seconds_.ProcessPeerHello( | 612 error = keepalive_timeout_seconds_.ProcessPeerHello( |
| 529 peer_hello, hello_type, error_details); | 613 peer_hello, hello_type, error_details); |
| 530 } | 614 } |
| (...skipping 10 matching lines...) Expand all Loading... |
| 541 peer_hello, hello_type, error_details); | 625 peer_hello, hello_type, error_details); |
| 542 } | 626 } |
| 543 if (error == QUIC_NO_ERROR) { | 627 if (error == QUIC_NO_ERROR) { |
| 544 error = initial_flow_control_window_bytes_.ProcessPeerHello( | 628 error = initial_flow_control_window_bytes_.ProcessPeerHello( |
| 545 peer_hello, hello_type, error_details); | 629 peer_hello, hello_type, error_details); |
| 546 } | 630 } |
| 547 if (error == QUIC_NO_ERROR) { | 631 if (error == QUIC_NO_ERROR) { |
| 548 error = loss_detection_.ProcessPeerHello( | 632 error = loss_detection_.ProcessPeerHello( |
| 549 peer_hello, hello_type, error_details); | 633 peer_hello, hello_type, error_details); |
| 550 } | 634 } |
| 635 if (error == QUIC_NO_ERROR) { |
| 636 error = congestion_options_.ProcessPeerHello( |
| 637 peer_hello, hello_type, error_details); |
| 638 } |
| 551 return error; | 639 return error; |
| 552 } | 640 } |
| 553 | 641 |
| 554 } // namespace net | 642 } // namespace net |
| OLD | NEW |