You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ma...@apache.org on 2018/08/24 07:02:21 UTC

[trafficserver] 02/02: Send BLOCKED frame

This is an automated email from the ASF dual-hosted git repository.

masaori pushed a commit to branch quic-latest
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit 7a195464eca6c51c491dfb14d6343e06f863ac46
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Thu Aug 23 16:05:16 2018 +0900

    Send BLOCKED frame
    
    QUICRemoteFlowController::update() create BLOCKED(_STREAM) frame. It will be sent when STREAMs have anything to send.
---
 iocore/net/QUICNetVConnection.cc                | 22 +++++++++----
 iocore/net/quic/QUICFlowController.cc           |  6 ++--
 iocore/net/quic/QUICStream.cc                   | 17 ++++++++--
 iocore/net/quic/test/test_QUICFlowController.cc | 43 ++++++++++++++++++++++---
 4 files changed, 73 insertions(+), 15 deletions(-)

diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc
index 03fde79..a019f9b 100644
--- a/iocore/net/QUICNetVConnection.cc
+++ b/iocore/net/QUICNetVConnection.cc
@@ -1214,7 +1214,8 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa
   bool ack_only = true;
   if (this->_connection_error || this->_packet_retransmitter.will_generate_frame(level) ||
       this->_handshake_handler->will_generate_frame(level) || this->_stream_manager->will_generate_frame(level) ||
-      this->_path_validator->will_generate_frame(level)) {
+      this->_path_validator->will_generate_frame(level) || this->_local_flow_controller->will_generate_frame(level) ||
+      (this->_stream_manager->will_generate_frame(level) && this->_remote_flow_controller->will_generate_frame(level))) {
     ack_only = false;
   }
 
@@ -1241,7 +1242,7 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa
   }
 
   // PATH_CHALLENGE, PATH_RESPOSNE
-  frame = this->_path_validator->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size);
+  frame = this->_path_validator->generate_frame(level, UINT16_MAX, max_frame_size);
   if (frame) {
     ++frame_count;
     this->_store_frame(buf, len, max_frame_size, std::move(frame));
@@ -1249,22 +1250,31 @@ QUICNetVConnection::_packetize_frames(QUICEncryptionLevel level, uint64_t max_pa
 
   // NEW_CONNECTION_ID
   if (this->_alt_con_manager) {
-    frame = this->_alt_con_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size);
+    frame = this->_alt_con_manager->generate_frame(level, UINT16_MAX, max_frame_size);
     while (frame) {
       ++frame_count;
       this->_store_frame(buf, len, max_frame_size, std::move(frame));
 
-      frame = this->_alt_con_manager->generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size);
+      frame = this->_alt_con_manager->generate_frame(level, UINT16_MAX, max_frame_size);
     }
   }
 
   // Lost frames
-  frame = this->_packet_retransmitter.generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size);
+  frame = this->_packet_retransmitter.generate_frame(level, UINT16_MAX, max_frame_size);
   while (frame) {
     ++frame_count;
     this->_store_frame(buf, len, max_frame_size, std::move(frame));
 
-    frame = this->_packet_retransmitter.generate_frame(level, this->_remote_flow_controller->credit(), max_frame_size);
+    frame = this->_packet_retransmitter.generate_frame(level, UINT16_MAX, max_frame_size);
+  }
+
+  // BLOCKED
+  if (this->_remote_flow_controller->credit() == 0 && this->_stream_manager->will_generate_frame(level)) {
+    frame = this->_remote_flow_controller->generate_frame(level, UINT16_MAX, max_frame_size);
+    if (frame) {
+      ++frame_count;
+      this->_store_frame(buf, len, max_frame_size, std::move(frame));
+    }
   }
 
   // STREAM, MAX_STREAM_DATA, STREAM_BLOCKED
diff --git a/iocore/net/quic/QUICFlowController.cc b/iocore/net/quic/QUICFlowController.cc
index 57357f1..70ff181 100644
--- a/iocore/net/quic/QUICFlowController.cc
+++ b/iocore/net/quic/QUICFlowController.cc
@@ -100,6 +100,7 @@ QUICFlowController::set_limit(QUICOffset limit)
   this->_limit = limit;
 }
 
+// For RemoteFlowController, caller of this function should also check QUICStreamManager::will_generate_frame()
 bool
 QUICFlowController::will_generate_frame(QUICEncryptionLevel level)
 {
@@ -142,8 +143,9 @@ QUICRemoteFlowController::update(QUICOffset offset)
 {
   int ret = QUICFlowController::update(offset);
 
-  // Send BLOCKED(_STREAM) frame
-  if (!this->_blocked && offset > this->_limit) {
+  // Create BLOCKED(_STREAM) frame
+  // The frame will be sent if stream has something to send.
+  if (!this->_blocked && offset >= this->_limit) {
     this->_frame   = this->_create_frame();
     this->_blocked = true;
   }
diff --git a/iocore/net/quic/QUICStream.cc b/iocore/net/quic/QUICStream.cc
index ff38147..d2a5a3f 100644
--- a/iocore/net/quic/QUICStream.cc
+++ b/iocore/net/quic/QUICStream.cc
@@ -403,6 +403,10 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit
     return frame;
   }
 
+  if (connection_credit == 0) {
+    return frame;
+  }
+
   if (maximum_frame_size <= MAX_STREAM_FRAME_OVERHEAD) {
     return frame;
   }
@@ -413,13 +417,20 @@ QUICStream::generate_frame(QUICEncryptionLevel level, uint64_t connection_credit
     return frame;
   }
 
+  // STREAM_BLOCKED
+  uint64_t stream_credit = this->_remote_flow_controller.credit();
+  // The `bytes_avail` should be also checked before calling QUICRemoteFlowController::generate_frame(), but we don't need it.
+  // Because it's already checked in above.
+  if (stream_credit == 0) {
+    frame = this->_remote_flow_controller.generate_frame(level, connection_credit, maximum_frame_size);
+  }
+
   int64_t data_len = reader->block_read_avail();
   int64_t len      = 0;
   bool fin         = false;
 
-  len = std::min(data_len, static_cast<int64_t>(
-                             std::min(static_cast<uint64_t>(maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD),
-                                      std::min(this->_remote_flow_controller.credit(), static_cast<uint64_t>(connection_credit)))));
+  len = std::min(data_len, static_cast<int64_t>(std::min(static_cast<uint64_t>(maximum_frame_size - MAX_STREAM_FRAME_OVERHEAD),
+                                                         std::min(stream_credit, static_cast<uint64_t>(connection_credit)))));
 
   if (this->_write_vio.nbytes == static_cast<int64_t>(this->_send_offset + len)) {
     fin = true;
diff --git a/iocore/net/quic/test/test_QUICFlowController.cc b/iocore/net/quic/test/test_QUICFlowController.cc
index 0d8749c..951a0e5 100644
--- a/iocore/net/quic/test/test_QUICFlowController.cc
+++ b/iocore/net/quic/test/test_QUICFlowController.cc
@@ -132,20 +132,20 @@ TEST_CASE("QUICFlowController_Remote_Connection", "[quic]")
   CHECK(fc.current_limit() == 1024);
   CHECK(ret == 0);
 
-  ret = fc.update(1024);
-  CHECK(fc.current_offset() == 1024);
+  ret = fc.update(1000);
+  CHECK(fc.current_offset() == 1000);
   CHECK(fc.current_limit() == 1024);
   CHECK(ret == 0);
 
   // Delay
   ret = fc.update(512);
-  CHECK(fc.current_offset() == 1024);
+  CHECK(fc.current_offset() == 1000);
   CHECK(fc.current_limit() == 1024);
   CHECK(ret == 0);
 
   // Exceed limit
   ret = fc.update(1280);
-  CHECK(fc.current_offset() == 1024);
+  CHECK(fc.current_offset() == 1000);
   CHECK(fc.current_limit() == 1024);
   CHECK(ret != 0);
   QUICFrameUPtr frame = fc.generate_frame(QUICEncryptionLevel::ONE_RTT, 0, 1024);
@@ -154,6 +154,38 @@ TEST_CASE("QUICFlowController_Remote_Connection", "[quic]")
 
   // MAX_STREAM_DATA
   fc.forward_limit(2048);
+  CHECK(fc.current_offset() == 1000);
+  CHECK(fc.current_limit() == 2048);
+
+  ret = fc.update(1280);
+  CHECK(fc.current_offset() == 1280);
+  CHECK(fc.current_limit() == 2048);
+  CHECK(ret == 0);
+}
+
+TEST_CASE("QUICFlowController_Remote_Connection_ZERO_Credit", "[quic]")
+{
+  int ret = 0;
+  QUICRemoteConnectionFlowController fc(1024);
+
+  // Check initial state
+  CHECK(fc.current_offset() == 0);
+  CHECK(fc.current_limit() == 1024);
+
+  // Zero credit
+  ret = fc.update(1024);
+  CHECK(fc.current_offset() == 1024);
+  CHECK(fc.current_limit() == 1024);
+  CHECK(ret == 0);
+
+  CHECK(fc.will_generate_frame(QUICEncryptionLevel::ONE_RTT));
+  // if there're anything to send
+  QUICFrameUPtr frame = fc.generate_frame(QUICEncryptionLevel::ONE_RTT, 0, 1024);
+  CHECK(frame);
+  CHECK(frame->type() == QUICFrameType::BLOCKED);
+
+  // MAX_STREAM_DATA
+  fc.forward_limit(2048);
   CHECK(fc.current_offset() == 1024);
   CHECK(fc.current_limit() == 2048);
 
@@ -251,6 +283,9 @@ TEST_CASE("QUICFlowController_Remote_Stream", "[quic]")
   CHECK(fc.current_limit() == 1024);
   CHECK(ret == 0);
 
+  CHECK(fc.credit() == 0);
+  CHECK(fc.will_generate_frame(QUICEncryptionLevel::ONE_RTT));
+
   // Delay
   ret = fc.update(512);
   CHECK(fc.current_offset() == 1024);