From 1ae4d12b9d6ae7fee2c49eaa9a83f588fa6259db Mon Sep 17 00:00:00 2001
From: Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
Date: Sun, 18 Nov 2018 12:05:49 +0900
Subject: [PATCH] Better max stream datalen computation

---
 lib/ngtcp2_pkt.c        | 22 ++++++++++----
 tests/main.c            |  2 ++
 tests/ngtcp2_pkt_test.c | 64 +++++++++++++++++++++++++++++++++++++++++
 tests/ngtcp2_pkt_test.h |  1 +
 4 files changed, 84 insertions(+), 5 deletions(-)

diff --git a/lib/ngtcp2_pkt.c b/lib/ngtcp2_pkt.c
index 0e8d7747..ad69c01a 100644
--- a/lib/ngtcp2_pkt.c
+++ b/lib/ngtcp2_pkt.c
@@ -1997,15 +1997,27 @@ size_t ngtcp2_pkt_stream_max_datalen(uint64_t stream_id, uint64_t offset,
   size_t n = 1 /* type */ + ngtcp2_put_varint_len(stream_id) +
              (offset ? ngtcp2_put_varint_len(offset) : 0);
 
-  if (left < n) {
+  if (left <= n) {
     return (size_t)-1;
   }
 
-  n += ngtcp2_put_varint_len(ngtcp2_min(len, left - n));
+  left -= n;
 
-  if (left < n) {
-    return (size_t)-1;
+  if (left > 8 + 1073741823 && len > 1073741823) {
+    len = ngtcp2_min(len, 4611686018427387903lu);
+    return ngtcp2_min(len, left - 8);
+  }
+
+  if (left > 4 + 16383 && len > 16383) {
+    len = ngtcp2_min(len, 1073741823);
+    return ngtcp2_min(len, left - 4);
+  }
+
+  if (left > 2 + 63 && len > 63) {
+    len = ngtcp2_min(len, 16383);
+    return ngtcp2_min(len, left - 2);
   }
 
-  return ngtcp2_min(len, left - n);
+  len = ngtcp2_min(len, 63);
+  return ngtcp2_min(len, left - 1);
 }
diff --git a/tests/main.c b/tests/main.c
index 29398e26..4fdfb007 100644
--- a/tests/main.c
+++ b/tests/main.c
@@ -124,6 +124,8 @@ int main() {
       !CU_add_test(pSuite, "pkt_write_retry", test_ngtcp2_pkt_write_retry) ||
       !CU_add_test(pSuite, "pkt_write_version_negotiation",
                    test_ngtcp2_pkt_write_version_negotiation) ||
+      !CU_add_test(pSuite, "pkt_stream_max_datalen",
+                   test_ngtcp2_pkt_stream_max_datalen) ||
       !CU_add_test(pSuite, "get_varint", test_ngtcp2_get_varint) ||
       !CU_add_test(pSuite, "get_varint_len", test_ngtcp2_get_varint_len) ||
       !CU_add_test(pSuite, "put_varint_len", test_ngtcp2_put_varint_len) ||
diff --git a/tests/ngtcp2_pkt_test.c b/tests/ngtcp2_pkt_test.c
index 51b3000b..00818c28 100644
--- a/tests/ngtcp2_pkt_test.c
+++ b/tests/ngtcp2_pkt_test.c
@@ -1158,3 +1158,67 @@ void test_ngtcp2_pkt_write_version_negotiation(void) {
     CU_ASSERT(sv[i] == ngtcp2_get_uint32(p));
   }
 }
+
+void test_ngtcp2_pkt_stream_max_datalen(void) {
+  size_t len;
+
+  len = ngtcp2_pkt_stream_max_datalen(63, 0, 0, 2);
+
+  CU_ASSERT((size_t)-1 == len);
+
+  len = ngtcp2_pkt_stream_max_datalen(63, 0, 0, 3);
+
+  CU_ASSERT(0 == len);
+
+  len = ngtcp2_pkt_stream_max_datalen(63, 0, 1, 3);
+
+  CU_ASSERT(0 == len);
+
+  len = ngtcp2_pkt_stream_max_datalen(63, 0, 1, 4);
+
+  CU_ASSERT(1 == len);
+
+  len = ngtcp2_pkt_stream_max_datalen(63, 1, 1, 4);
+
+  CU_ASSERT(0 == len);
+
+  len = ngtcp2_pkt_stream_max_datalen(63, 0, 63, 66);
+
+  CU_ASSERT(63 == len);
+
+  len = ngtcp2_pkt_stream_max_datalen(63, 0, 63, 65);
+
+  CU_ASSERT(62 == len);
+
+  len = ngtcp2_pkt_stream_max_datalen(63, 0, 1396, 1400);
+
+  CU_ASSERT(1396 == len);
+
+  len = ngtcp2_pkt_stream_max_datalen(63, 0, 1396, 1399);
+
+  CU_ASSERT(1395 == len);
+
+  len = ngtcp2_pkt_stream_max_datalen(63, 0, 1396, 9);
+
+  CU_ASSERT(6 == len);
+
+  len = ngtcp2_pkt_stream_max_datalen(63, 0, 16385, 16391);
+
+  CU_ASSERT(16385 == len);
+
+  len = ngtcp2_pkt_stream_max_datalen(63, 0, 16385, 16390);
+
+  CU_ASSERT(16384 == len);
+
+  len = ngtcp2_pkt_stream_max_datalen(63, 0, 1073741824, 1073741834);
+
+  CU_ASSERT(1073741824 == len);
+
+  len = ngtcp2_pkt_stream_max_datalen(63, 0, 1073741824, 1073741833);
+
+  CU_ASSERT(1073741823 == len);
+
+  len = ngtcp2_pkt_stream_max_datalen(63, 0, 16383, 16387);
+
+  CU_ASSERT(16383 == len);
+}
diff --git a/tests/ngtcp2_pkt_test.h b/tests/ngtcp2_pkt_test.h
index 23223fc0..34b9b372 100644
--- a/tests/ngtcp2_pkt_test.h
+++ b/tests/ngtcp2_pkt_test.h
@@ -58,5 +58,6 @@ void test_ngtcp2_pkt_validate_ack(void);
 void test_ngtcp2_pkt_write_stateless_reset(void);
 void test_ngtcp2_pkt_write_retry(void);
 void test_ngtcp2_pkt_write_version_negotiation(void);
+void test_ngtcp2_pkt_stream_max_datalen(void);
 
 #endif /* NGTCP2_PKT_TEST_H */
-- 
GitLab