dcsctp: Use strong type for MaxRetransmits
It's put in the public folder since the intention is to expose it in
SendOptions.
Additionally, use TimeMs::InfiniteFuture() to represent sending a
message with no limited lifetime (i.e. to send it reliably).
One benefit for these two is avoiding using absl::optional more than
necessary, as it results in larger struct sizes for the outstanding
data chunks.
Bug: webrtc:12943
Change-Id: I87a340f0e0905342878fe9d2a74869bfcd6b0076
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/235984
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#35323}
diff --git a/net/dcsctp/public/types.h b/net/dcsctp/public/types.h
index 1f13255..8faec08 100644
--- a/net/dcsctp/public/types.h
+++ b/net/dcsctp/public/types.h
@@ -105,6 +105,18 @@
return DurationMs(*lhs - *rhs);
}
+// The maximum number of times the socket should attempt to retransmit a
+// message which fails the first time in unreliable mode.
+class MaxRetransmits : public webrtc::StrongAlias<class TimeMsTag, uint16_t> {
+ public:
+ constexpr explicit MaxRetransmits(const UnderlyingType& v)
+ : webrtc::StrongAlias<class TimeMsTag, uint16_t>(v) {}
+
+ // There should be no limit - the message should be sent reliably.
+ static constexpr MaxRetransmits NoLimit() {
+ return MaxRetransmits(std::numeric_limits<uint16_t>::max());
+ }
+};
} // namespace dcsctp
#endif // NET_DCSCTP_PUBLIC_TYPES_H_
diff --git a/net/dcsctp/tx/outstanding_data.cc b/net/dcsctp/tx/outstanding_data.cc
index 1f3a24f..dc998de 100644
--- a/net/dcsctp/tx/outstanding_data.cc
+++ b/net/dcsctp/tx/outstanding_data.cc
@@ -15,13 +15,15 @@
#include <vector>
#include "net/dcsctp/common/math.h"
+#include "net/dcsctp/common/sequence_numbers.h"
+#include "net/dcsctp/public/types.h"
#include "rtc_base/logging.h"
namespace dcsctp {
// The number of times a packet must be NACKed before it's retransmitted.
// See https://tools.ietf.org/html/rfc4960#section-7.2.4
-constexpr size_t kNumberOfNacksForRetransmission = 3;
+constexpr uint8_t kNumberOfNacksForRetransmission = 3;
// Returns how large a chunk will be, serialized, carrying the data
size_t OutstandingData::GetSerializedChunkSize(const Data& data) const {
@@ -40,8 +42,7 @@
if ((retransmit_now || nack_count_ >= kNumberOfNacksForRetransmission) &&
!is_abandoned_) {
// Nacked enough times - it's considered lost.
- if (!max_retransmissions_.has_value() ||
- num_retransmissions_ < max_retransmissions_) {
+ if (num_retransmissions_ < *max_retransmissions_) {
should_be_retransmitted_ = true;
return NackAction::kRetransmit;
}
@@ -65,7 +66,7 @@
}
bool OutstandingData::Item::has_expired(TimeMs now) const {
- return expires_at_.has_value() && *expires_at_ <= now;
+ return expires_at_ <= now;
}
bool OutstandingData::IsConsistent() const {
@@ -251,8 +252,9 @@
Data::IsEnd(true), item.data().is_unordered);
Item& added_item =
outstanding_data_
- .emplace(tsn, Item(std::move(message_end), absl::nullopt, TimeMs(0),
- absl::nullopt))
+ .emplace(tsn,
+ Item(std::move(message_end), MaxRetransmits::NoLimit(),
+ TimeMs(0), TimeMs::InfiniteFuture()))
.first->second;
// The added chunk shouldn't be included in `outstanding_bytes`, so set it
// as acked.
@@ -345,9 +347,9 @@
absl::optional<UnwrappedTSN> OutstandingData::Insert(
const Data& data,
- absl::optional<size_t> max_retransmissions,
+ MaxRetransmits max_retransmissions,
TimeMs time_sent,
- absl::optional<TimeMs> expires_at) {
+ TimeMs expires_at) {
UnwrappedTSN tsn = next_tsn_;
next_tsn_.Increment();
diff --git a/net/dcsctp/tx/outstanding_data.h b/net/dcsctp/tx/outstanding_data.h
index b9394f8..dc9aab7 100644
--- a/net/dcsctp/tx/outstanding_data.h
+++ b/net/dcsctp/tx/outstanding_data.h
@@ -109,11 +109,10 @@
// Schedules `data` to be sent, with the provided partial reliability
// parameters. Returns the TSN if the item was actually added and scheduled to
// be sent, and absl::nullopt if it shouldn't be sent.
- absl::optional<UnwrappedTSN> Insert(
- const Data& data,
- absl::optional<size_t> max_retransmissions,
- TimeMs time_sent,
- absl::optional<TimeMs> expires_at);
+ absl::optional<UnwrappedTSN> Insert(const Data& data,
+ MaxRetransmits max_retransmissions,
+ TimeMs time_sent,
+ TimeMs expires_at);
// Nacks all outstanding data.
void NackAll();
@@ -149,9 +148,9 @@
};
explicit Item(Data data,
- absl::optional<size_t> max_retransmissions,
+ MaxRetransmits max_retransmissions,
TimeMs time_sent,
- absl::optional<TimeMs> expires_at)
+ TimeMs expires_at)
: max_retransmissions_(max_retransmissions),
time_sent_(time_sent),
expires_at_(expires_at),
@@ -207,18 +206,18 @@
// The number of times the DATA chunk has been nacked (by having received a
// SACK which doesn't include it). Will be cleared on retransmissions.
- size_t nack_count_ = 0;
+ uint8_t nack_count_ = 0;
// The number of times the DATA chunk has been retransmitted.
- size_t num_retransmissions_ = 0;
+ uint16_t num_retransmissions_ = 0;
// If the message was sent with a maximum number of retransmissions, this is
// set to that number. The value zero (0) means that it will never be
// retransmitted.
- const absl::optional<size_t> max_retransmissions_;
+ const MaxRetransmits max_retransmissions_;
// When the packet was sent, and placed in this queue.
const TimeMs time_sent_;
- // If the message was sent with an expiration time, this is set. At this
- // exact millisecond, the item is considered expired.
- const absl::optional<TimeMs> expires_at_;
+ // At this exact millisecond, the item is considered expired. If the message
+ // is not to be expired, this is set to the infinite future.
+ const TimeMs expires_at_;
// The actual data to send/retransmit.
Data data_;
};
diff --git a/net/dcsctp/tx/outstanding_data_test.cc b/net/dcsctp/tx/outstanding_data_test.cc
index c911784..c161cbb 100644
--- a/net/dcsctp/tx/outstanding_data_test.cc
+++ b/net/dcsctp/tx/outstanding_data_test.cc
@@ -65,7 +65,8 @@
TEST_F(OutstandingDataTest, InsertChunk) {
ASSERT_HAS_VALUE_AND_ASSIGN(
UnwrappedTSN tsn,
- buf_.Insert(gen_.Ordered({1}, "BE"), absl::nullopt, kNow, absl::nullopt));
+ buf_.Insert(gen_.Ordered({1}, "BE"), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture()));
EXPECT_EQ(tsn.Wrap(), TSN(10));
@@ -81,7 +82,8 @@
}
TEST_F(OutstandingDataTest, AcksSingleChunk) {
- buf_.Insert(gen_.Ordered({1}, "BE"), absl::nullopt, kNow, absl::nullopt);
+ buf_.Insert(gen_.Ordered({1}, "BE"), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
OutstandingData::AckInfo ack =
buf_.HandleSack(unwrapper_.Unwrap(TSN(10)), {}, false);
@@ -100,7 +102,8 @@
}
TEST_F(OutstandingDataTest, AcksPreviousChunkDoesntUpdate) {
- buf_.Insert(gen_.Ordered({1}, "BE"), absl::nullopt, kNow, absl::nullopt);
+ buf_.Insert(gen_.Ordered({1}, "BE"), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
buf_.HandleSack(unwrapper_.Unwrap(TSN(9)), {}, false);
EXPECT_EQ(buf_.outstanding_bytes(), DataChunk::kHeaderSize + RoundUpTo4(1));
@@ -115,8 +118,10 @@
}
TEST_F(OutstandingDataTest, AcksAndNacksWithGapAckBlocks) {
- buf_.Insert(gen_.Ordered({1}, "B"), absl::nullopt, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, "E"), absl::nullopt, kNow, absl::nullopt);
+ buf_.Insert(gen_.Ordered({1}, "B"), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, "E"), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
std::vector<SackChunk::GapAckBlock> gab = {SackChunk::GapAckBlock(2, 2)};
OutstandingData::AckInfo ack =
@@ -138,8 +143,10 @@
}
TEST_F(OutstandingDataTest, NacksThreeTimesWithSameTsnDoesntRetransmit) {
- buf_.Insert(gen_.Ordered({1}, "B"), absl::nullopt, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, "E"), absl::nullopt, kNow, absl::nullopt);
+ buf_.Insert(gen_.Ordered({1}, "B"), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, "E"), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
std::vector<SackChunk::GapAckBlock> gab1 = {SackChunk::GapAckBlock(2, 2)};
EXPECT_FALSE(
@@ -161,10 +168,14 @@
}
TEST_F(OutstandingDataTest, NacksThreeTimesResultsInRetransmission) {
- buf_.Insert(gen_.Ordered({1}, "B"), absl::nullopt, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, ""), absl::nullopt, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, ""), absl::nullopt, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, "E"), absl::nullopt, kNow, absl::nullopt);
+ buf_.Insert(gen_.Ordered({1}, "B"), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, ""), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, ""), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, "E"), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
std::vector<SackChunk::GapAckBlock> gab1 = {SackChunk::GapAckBlock(2, 2)};
EXPECT_FALSE(
@@ -197,11 +208,15 @@
}
TEST_F(OutstandingDataTest, NacksThreeTimesResultsInAbandoning) {
- static constexpr uint16_t kMaxRetransmissions = 0;
- buf_.Insert(gen_.Ordered({1}, "B"), kMaxRetransmissions, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, ""), kMaxRetransmissions, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, ""), kMaxRetransmissions, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, "E"), kMaxRetransmissions, kNow, absl::nullopt);
+ static constexpr MaxRetransmits kMaxRetransmissions(0);
+ buf_.Insert(gen_.Ordered({1}, "B"), kMaxRetransmissions, kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, ""), kMaxRetransmissions, kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, ""), kMaxRetransmissions, kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, "E"), kMaxRetransmissions, kNow,
+ TimeMs::InfiniteFuture());
std::vector<SackChunk::GapAckBlock> gab1 = {SackChunk::GapAckBlock(2, 2)};
EXPECT_FALSE(
@@ -233,11 +248,15 @@
}
TEST_F(OutstandingDataTest, NacksThreeTimesResultsInAbandoningWithPlaceholder) {
- static constexpr uint16_t kMaxRetransmissions = 0;
- buf_.Insert(gen_.Ordered({1}, "B"), kMaxRetransmissions, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, ""), kMaxRetransmissions, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, ""), kMaxRetransmissions, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, ""), kMaxRetransmissions, kNow, absl::nullopt);
+ static constexpr MaxRetransmits kMaxRetransmissions(0);
+ buf_.Insert(gen_.Ordered({1}, "B"), kMaxRetransmissions, kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, ""), kMaxRetransmissions, kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, ""), kMaxRetransmissions, kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, ""), kMaxRetransmissions, kNow,
+ TimeMs::InfiniteFuture());
std::vector<SackChunk::GapAckBlock> gab1 = {SackChunk::GapAckBlock(2, 2)};
EXPECT_FALSE(
@@ -271,16 +290,16 @@
TEST_F(OutstandingDataTest, ExpiresChunkBeforeItIsInserted) {
static constexpr TimeMs kExpiresAt = kNow + DurationMs(1);
- EXPECT_TRUE(
- buf_.Insert(gen_.Ordered({1}, "B"), absl::nullopt, kNow, kExpiresAt)
- .has_value());
- EXPECT_TRUE(buf_.Insert(gen_.Ordered({1}, ""), absl::nullopt,
+ EXPECT_TRUE(buf_.Insert(gen_.Ordered({1}, "B"), MaxRetransmits::NoLimit(),
+ kNow, kExpiresAt)
+ .has_value());
+ EXPECT_TRUE(buf_.Insert(gen_.Ordered({1}, ""), MaxRetransmits::NoLimit(),
kNow + DurationMs(0), kExpiresAt)
.has_value());
EXPECT_CALL(on_discard_, Call(IsUnordered(false), StreamID(1), MID(42)))
.WillOnce(Return(false));
- EXPECT_FALSE(buf_.Insert(gen_.Ordered({1}, "E"), absl::nullopt,
+ EXPECT_FALSE(buf_.Insert(gen_.Ordered({1}, "E"), MaxRetransmits::NoLimit(),
kNow + DurationMs(1), kExpiresAt)
.has_value());
@@ -296,10 +315,13 @@
}
TEST_F(OutstandingDataTest, CanGenerateForwardTsn) {
- static constexpr uint16_t kMaxRetransmissions = 0;
- buf_.Insert(gen_.Ordered({1}, "B"), kMaxRetransmissions, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, ""), kMaxRetransmissions, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, "E"), kMaxRetransmissions, kNow, absl::nullopt);
+ static constexpr MaxRetransmits kMaxRetransmissions(0);
+ buf_.Insert(gen_.Ordered({1}, "B"), kMaxRetransmissions, kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, ""), kMaxRetransmissions, kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, "E"), kMaxRetransmissions, kNow,
+ TimeMs::InfiniteFuture());
EXPECT_CALL(on_discard_, Call(IsUnordered(false), StreamID(1), MID(42)))
.WillOnce(Return(false));
@@ -318,14 +340,22 @@
}
TEST_F(OutstandingDataTest, AckWithGapBlocksFromRFC4960Section334) {
- buf_.Insert(gen_.Ordered({1}, "B"), absl::nullopt, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, ""), absl::nullopt, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, ""), absl::nullopt, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, ""), absl::nullopt, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, ""), absl::nullopt, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, ""), absl::nullopt, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, ""), absl::nullopt, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, "E"), absl::nullopt, kNow, absl::nullopt);
+ buf_.Insert(gen_.Ordered({1}, "B"), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, ""), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, ""), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, ""), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, ""), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, ""), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, ""), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, "E"), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
EXPECT_THAT(buf_.GetChunkStatesForTesting(),
testing::ElementsAre(Pair(TSN(9), State::kAcked), //
@@ -352,11 +382,12 @@
}
TEST_F(OutstandingDataTest, MeasureRTT) {
- buf_.Insert(gen_.Ordered({1}, "BE"), absl::nullopt, kNow, absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, "BE"), absl::nullopt, kNow + DurationMs(1),
- absl::nullopt);
- buf_.Insert(gen_.Ordered({1}, "BE"), absl::nullopt, kNow + DurationMs(2),
- absl::nullopt);
+ buf_.Insert(gen_.Ordered({1}, "BE"), MaxRetransmits::NoLimit(), kNow,
+ TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, "BE"), MaxRetransmits::NoLimit(),
+ kNow + DurationMs(1), TimeMs::InfiniteFuture());
+ buf_.Insert(gen_.Ordered({1}, "BE"), MaxRetransmits::NoLimit(),
+ kNow + DurationMs(2), TimeMs::InfiniteFuture());
static constexpr DurationMs kDuration(123);
ASSERT_HAS_VALUE_AND_ASSIGN(
diff --git a/net/dcsctp/tx/retransmission_queue.cc b/net/dcsctp/tx/retransmission_queue.cc
index 85399f2..d980710 100644
--- a/net/dcsctp/tx/retransmission_queue.cc
+++ b/net/dcsctp/tx/retransmission_queue.cc
@@ -440,8 +440,11 @@
absl::optional<UnwrappedTSN> tsn = outstanding_data_.Insert(
chunk_opt->data,
- partial_reliability_ ? chunk_opt->max_retransmissions : absl::nullopt,
- now, partial_reliability_ ? chunk_opt->expires_at : absl::nullopt);
+ partial_reliability_ ? chunk_opt->max_retransmissions
+ : MaxRetransmits::NoLimit(),
+ now,
+ partial_reliability_ ? chunk_opt->expires_at
+ : TimeMs::InfiniteFuture());
if (tsn.has_value()) {
to_be_sent.emplace_back(tsn->Wrap(), std::move(chunk_opt->data));
diff --git a/net/dcsctp/tx/retransmission_queue_test.cc b/net/dcsctp/tx/retransmission_queue_test.cc
index b2c2997..0165555 100644
--- a/net/dcsctp/tx/retransmission_queue_test.cc
+++ b/net/dcsctp/tx/retransmission_queue_test.cc
@@ -354,7 +354,7 @@
EXPECT_CALL(producer_, Produce)
.WillOnce([this](TimeMs, size_t) {
SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "BE"));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; });
@@ -384,7 +384,7 @@
EXPECT_CALL(producer_, Produce)
.WillOnce([this](TimeMs, size_t) {
SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "BE"));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; });
@@ -426,7 +426,7 @@
EXPECT_CALL(producer_, Produce)
.WillOnce([this](TimeMs, size_t) {
SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "BE"));
- dts.max_retransmissions = 3;
+ dts.max_retransmissions = MaxRetransmits(3);
return dts;
})
.WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; });
@@ -517,17 +517,17 @@
EXPECT_CALL(producer_, Produce)
.WillOnce([this](TimeMs, size_t) {
SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "B"));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillOnce([this](TimeMs, size_t) {
SendQueue::DataToSend dts(gen_.Ordered({5, 6, 7, 8}, ""));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillOnce([this](TimeMs, size_t) {
SendQueue::DataToSend dts(gen_.Ordered({9, 10, 11, 12}, ""));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; });
@@ -572,17 +572,17 @@
EXPECT_CALL(producer_, Produce)
.WillOnce([this](TimeMs, size_t) {
SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "B"));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillOnce([this](TimeMs, size_t) {
SendQueue::DataToSend dts(gen_.Ordered({5, 6, 7, 8}, ""));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillOnce([this](TimeMs, size_t) {
SendQueue::DataToSend dts(gen_.Ordered({9, 10, 11, 12}, "E"));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; });
@@ -627,28 +627,28 @@
DataGeneratorOptions opts;
opts.stream_id = StreamID(1);
SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "B", opts));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillOnce([this](TimeMs, size_t) {
DataGeneratorOptions opts;
opts.stream_id = StreamID(2);
SendQueue::DataToSend dts(gen_.Unordered({1, 2, 3, 4}, "B", opts));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillOnce([this](TimeMs, size_t) {
DataGeneratorOptions opts;
opts.stream_id = StreamID(3);
SendQueue::DataToSend dts(gen_.Ordered({9, 10, 11, 12}, "B", opts));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillOnce([this](TimeMs, size_t) {
DataGeneratorOptions opts;
opts.stream_id = StreamID(4);
SendQueue::DataToSend dts(gen_.Ordered({13, 14, 15, 16}, "B", opts));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; });
@@ -742,7 +742,7 @@
EXPECT_CALL(producer_, Produce)
.WillOnce([this](TimeMs, size_t) {
SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "B"));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; });
@@ -907,17 +907,17 @@
EXPECT_CALL(producer_, Produce)
.WillOnce([this](TimeMs, size_t) {
SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "B"));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillOnce([this](TimeMs, size_t) {
SendQueue::DataToSend dts(gen_.Ordered({5, 6, 7, 8}, ""));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillOnce([this](TimeMs, size_t) {
SendQueue::DataToSend dts(gen_.Ordered({9, 10, 11, 12}, ""));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillRepeatedly([](TimeMs, size_t) { return absl::nullopt; });
@@ -1006,7 +1006,7 @@
EXPECT_CALL(producer_, Produce)
.WillOnce([this](TimeMs, size_t) {
SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "BE"));
- dts.max_retransmissions = 0;
+ dts.max_retransmissions = MaxRetransmits(0);
return dts;
})
.WillOnce(CreateChunk())
@@ -1077,7 +1077,7 @@
EXPECT_CALL(producer_, Produce)
.WillOnce([this](TimeMs, size_t) {
SendQueue::DataToSend dts(gen_.Ordered({1, 2, 3, 4}, "BE"));
- dts.max_retransmissions = 2;
+ dts.max_retransmissions = MaxRetransmits(2);
return dts;
})
.WillOnce(CreateChunk())
diff --git a/net/dcsctp/tx/rr_send_queue.cc b/net/dcsctp/tx/rr_send_queue.cc
index eaaf34a..21744cc 100644
--- a/net/dcsctp/tx/rr_send_queue.cc
+++ b/net/dcsctp/tx/rr_send_queue.cc
@@ -11,6 +11,7 @@
#include <cstdint>
#include <deque>
+#include <limits>
#include <map>
#include <utility>
#include <vector>
@@ -49,7 +50,7 @@
}
// Message has expired. Remove it and inspect the next one.
- if (item.expires_at.has_value() && *item.expires_at <= now) {
+ if (item.expires_at <= now) {
buffered_amount_.Decrease(item.remaining_size);
total_buffered_amount_.Decrease(item.remaining_size);
items_.pop_front();
@@ -125,7 +126,7 @@
}
void RRSendQueue::OutgoingStream::Add(DcSctpMessage message,
- absl::optional<TimeMs> expires_at,
+ TimeMs expires_at,
const SendOptions& send_options) {
buffered_amount_.Increase(message.payload().size());
total_buffered_amount_.Increase(message.payload().size());
@@ -186,7 +187,14 @@
item->message_id.value(), fsn, ppid,
std::move(payload), is_beginning, is_end,
item->send_options.unordered));
- chunk.max_retransmissions = item->send_options.max_retransmissions;
+ if (item->send_options.max_retransmissions.has_value() &&
+ *item->send_options.max_retransmissions >=
+ std::numeric_limits<MaxRetransmits::UnderlyingType>::min() &&
+ *item->send_options.max_retransmissions <=
+ std::numeric_limits<MaxRetransmits::UnderlyingType>::max()) {
+ chunk.max_retransmissions =
+ MaxRetransmits(*item->send_options.max_retransmissions);
+ }
chunk.expires_at = item->expires_at;
if (is_end) {
@@ -278,7 +286,7 @@
RTC_DCHECK(!message.payload().empty());
// Any limited lifetime should start counting from now - when the message
// has been added to the queue.
- absl::optional<TimeMs> expires_at = absl::nullopt;
+ TimeMs expires_at = TimeMs::InfiniteFuture();
if (send_options.lifetime.has_value()) {
// `expires_at` is the time when it expires. Which is slightly larger than
// the message's lifetime, as the message is alive during its entire
diff --git a/net/dcsctp/tx/rr_send_queue.h b/net/dcsctp/tx/rr_send_queue.h
index 94b80d6..3007cd0 100644
--- a/net/dcsctp/tx/rr_send_queue.h
+++ b/net/dcsctp/tx/rr_send_queue.h
@@ -124,7 +124,7 @@
// Enqueues a message to this stream.
void Add(DcSctpMessage message,
- absl::optional<TimeMs> expires_at,
+ TimeMs expires_at,
const SendOptions& send_options);
// Possibly produces a data chunk to send.
@@ -161,7 +161,7 @@
// An enqueued message and metadata.
struct Item {
explicit Item(DcSctpMessage msg,
- absl::optional<TimeMs> expires_at,
+ TimeMs expires_at,
const SendOptions& send_options)
: message(std::move(msg)),
expires_at(expires_at),
@@ -169,7 +169,7 @@
remaining_offset(0),
remaining_size(message.payload().size()) {}
DcSctpMessage message;
- absl::optional<TimeMs> expires_at;
+ TimeMs expires_at;
SendOptions send_options;
// The remaining payload (offset and size) to be sent, when it has been
// fragmented.
diff --git a/net/dcsctp/tx/send_queue.h b/net/dcsctp/tx/send_queue.h
index 877dbdd..a821d20 100644
--- a/net/dcsctp/tx/send_queue.h
+++ b/net/dcsctp/tx/send_queue.h
@@ -32,8 +32,8 @@
Data data;
// Partial reliability - RFC3758
- absl::optional<int> max_retransmissions;
- absl::optional<TimeMs> expires_at;
+ MaxRetransmits max_retransmissions = MaxRetransmits::NoLimit();
+ TimeMs expires_at = TimeMs::InfiniteFuture();
};
virtual ~SendQueue() = default;