Skip to content

Commit

Permalink
Support sending ACK_RECEIVE_TIMESTAMP frames.
Browse files Browse the repository at this point in the history
Per TBD IETF receive timestamp proposal:
https://github.com/wcsmith/draft-quic-receive-ts
  • Loading branch information
wcsmith committed Oct 25, 2021
1 parent 8960078 commit 06fffc1
Show file tree
Hide file tree
Showing 3 changed files with 680 additions and 4 deletions.
164 changes: 160 additions & 4 deletions quic/core/quic_framer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5069,9 +5069,11 @@ size_t QuicFramer::GetIetfAckFrameSize(const QuicAckFrame& frame) {
previous_smallest = iter->min();
}

// ECN counts.
if (frame.ecn_counters_populated &&
if (process_timestamps_) {
ack_frame_size += GetIetfAckFrameTimestampSize(frame);
} else if (frame.ecn_counters_populated &&
(frame.ect_0_count || frame.ect_1_count || frame.ecn_ce_count)) {
// ECN counts.
ack_frame_size += QuicDataWriter::GetVarInt62Len(frame.ect_0_count);
ack_frame_size += QuicDataWriter::GetVarInt62Len(frame.ect_1_count);
ack_frame_size += QuicDataWriter::GetVarInt62Len(frame.ecn_ce_count);
Expand All @@ -5080,6 +5082,74 @@ size_t QuicFramer::GetIetfAckFrameSize(const QuicAckFrame& frame) {
return ack_frame_size;
}

size_t QuicFramer::GetIetfAckFrameTimestampSize(const QuicAckFrame& frame) {
size_t size = 0;

QuicIntervalSet<QuicPacketNumber> timestamp_ranges;
auto it = frame.received_packet_times.begin();
if (frame.received_packet_times.size() > max_receive_timestamps_per_ack_) {
// Limit the number of reported timestamps to the most recent specified max.
std::advance(it, frame.received_packet_times.size() -
max_receive_timestamps_per_ack_);
}
for (; it != frame.received_packet_times.end(); it++) {
timestamp_ranges.Add(it->first, it->first + 1);
}

size += QuicDataWriter::GetVarInt62Len(timestamp_ranges.Size());

QuicPacketNumber prev_packet_number = LargestAcked(frame);
QuicTime prev_time = creation_time_;

auto ts_it = frame.received_packet_times.rbegin();
for (auto range_it = timestamp_ranges.rbegin();
range_it != timestamp_ranges.rend(); range_it++) {
if (prev_packet_number < (range_it->max() - 1)) {
QUIC_BUG(quic_bug_xxx_1) << "Packet gap must be decreasing";
return 0;
}
uint64_t gap = prev_packet_number - (range_it->max() - 1);
size += QuicDataWriter::GetVarInt62Len(gap);
size += QuicDataWriter::GetVarInt62Len(range_it->Length());
for (size_t i = 0; i < range_it->Length(); i++) {
if (ts_it->first != range_it->max() - i - 1) {
QUIC_BUG(quic_bug_xxx_2)
<< "Receive timestamp packet numbers must be in decreasing order";
return 0;
}
if (range_it == timestamp_ranges.rbegin() && i == 0) {
// The first delta is from framer creation to the current receive
// timestamp (forward in time), whereas in the common case subsequent
// deltas move backwards in time.
if (ts_it->second < creation_time_) {
QUIC_BUG(quic_bug_xxx_3) << "Receive timestamp must be after basis";
return 0;
}
uint64_t time_delta = (ts_it->second - creation_time_).ToMicroseconds();
time_delta = ((time_delta - 1) >> receive_timestamps_exponent_) + 1;
size += QuicDataWriter::GetVarInt62Len(time_delta);
time_delta = time_delta << receive_timestamps_exponent_;
prev_time =
creation_time_ + QuicTime::Delta::FromMicroseconds(time_delta);
} else {
if (prev_time < ts_it->second) {
QUIC_BUG(quic_bug_xxx_4) << "Receive timestamps must be decreasing";
return 0;
}
uint64_t time_delta = (prev_time - ts_it->second).ToMicroseconds();
time_delta = time_delta >> receive_timestamps_exponent_;
size += QuicDataWriter::GetVarInt62Len(time_delta);
time_delta = time_delta << receive_timestamps_exponent_;
prev_time = prev_time - QuicTime::Delta::FromMicroseconds(time_delta);
}
ts_it++;
}
prev_packet_number = range_it->min() - 2;
}

return size;
}

size_t QuicFramer::GetAckFrameSize(
const QuicAckFrame& ack,
QuicPacketNumberLength /*packet_number_length*/) {
Expand Down Expand Up @@ -5789,6 +5859,83 @@ bool QuicFramer::AppendTimestampsToAckFrame(const QuicAckFrame& frame,
return true;
}

bool QuicFramer::AppendIetfTimestampsToAckFrame(const QuicAckFrame& frame,
QuicDataWriter* writer) {
QuicIntervalSet<QuicPacketNumber> timestamp_ranges;
auto it = frame.received_packet_times.begin();
if (frame.received_packet_times.size() > max_receive_timestamps_per_ack_) {
// Limit the number of reported timestamps to the most recent.
std::advance(it, frame.received_packet_times.size() -
max_receive_timestamps_per_ack_);
}
for (; it != frame.received_packet_times.end(); it++) {
timestamp_ranges.Add(it->first, it->first + 1);
}

if (!writer->WriteVarInt62(timestamp_ranges.Size())) {
return false;
}

QuicPacketNumber prev_packet_number = LargestAcked(frame);
QuicTime prev_time = creation_time_;

auto ts_it = frame.received_packet_times.rbegin();
for (auto range_it = timestamp_ranges.rbegin();
range_it != timestamp_ranges.rend(); range_it++) {
if (prev_packet_number < (range_it->max() - 1)) {
set_detailed_error("Packet gap must be decreasing");
return false;
}
uint64_t gap = prev_packet_number - (range_it->max() - 1);
if (!writer->WriteVarInt62(gap)) {
return false;
}
if (!writer->WriteVarInt62(range_it->Length())) {
return false;
}
for (size_t i = 0; i < range_it->Length(); i++) {
if (ts_it->first != range_it->max() - i - 1) {
set_detailed_error("Receive timestamp packet numbers must be in decreasing order");
return false;
}
if (range_it == timestamp_ranges.rbegin() && i == 0) {
if (ts_it->second < creation_time_) {
set_detailed_error("Receive timestamp must be after basis");
return false;
}
// The first delta is from framer creation to the current receive
// timestamp (forward in time), whereas in the common case subsequent
// deltas move backwards in time.
uint64_t time_delta = (ts_it->second - creation_time_).ToMicroseconds();
// Round up the first exponent-encoded time delta so that the next
// receive timestamp is guaranteed to be decreasing.
time_delta = ((time_delta - 1) >> receive_timestamps_exponent_) + 1;
if (!writer->WriteVarInt62(time_delta)) {
return false;
}
time_delta = time_delta << receive_timestamps_exponent_;
prev_time =
creation_time_ + QuicTime::Delta::FromMicroseconds(time_delta);
} else {
if (prev_time < ts_it->second) {
set_detailed_error("Receive timestamps must be decreasing");
return false;
}
uint64_t time_delta = (prev_time - ts_it->second).ToMicroseconds();
time_delta = time_delta >> receive_timestamps_exponent_;
if (!writer->WriteVarInt62(time_delta)) {
return false;
}
time_delta = time_delta << receive_timestamps_exponent_;
prev_time = prev_time - QuicTime::Delta::FromMicroseconds(time_delta);
}
ts_it++;
}
prev_packet_number = range_it->min() - 2;
}
return true;
}

bool QuicFramer::AppendStopWaitingFrame(const QuicPacketHeader& header,
const QuicStopWaitingFrame& frame,
QuicDataWriter* writer) {
Expand Down Expand Up @@ -5826,8 +5973,11 @@ bool QuicFramer::AppendIetfAckFrameAndTypeByte(const QuicAckFrame& frame,
QuicDataWriter* writer) {
uint8_t type = IETF_ACK;
uint64_t ecn_size = 0;
if (frame.ecn_counters_populated &&
(frame.ect_0_count || frame.ect_1_count || frame.ecn_ce_count)) {
if (max_receive_timestamps_per_ack_ > 0 &&
frame.received_packet_times.size() > 0) {
type = IETF_ACK_RECEIVE_TIMESTAMPS;
} else if (frame.ecn_counters_populated &&
(frame.ect_0_count || frame.ect_1_count || frame.ecn_ce_count)) {
// Change frame type to ACK_ECN if any ECN count is available.
type = IETF_ACK_ECN;
ecn_size = (QuicDataWriter::GetVarInt62Len(frame.ect_0_count) +
Expand Down Expand Up @@ -5932,6 +6082,12 @@ bool QuicFramer::AppendIetfAckFrameAndTypeByte(const QuicAckFrame& frame,
}
}

if (type == IETF_ACK_RECEIVE_TIMESTAMPS) {
if (!AppendIetfTimestampsToAckFrame(frame, writer)) {
return false;
}
}

return true;
}

Expand Down
10 changes: 10 additions & 0 deletions quic/core/quic_framer.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,11 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
process_timestamps_ = process_timestamps;
}

// Sets the max number of receive timestamps to send per ACK frame.
void set_max_receive_timestamps_per_ack(uint32_t max_timestamps) {
max_receive_timestamps_per_ack_ = max_timestamps;
}

// Sets the exponent to use when writing/reading ACK receive timestamps.
void set_receive_timestamps_exponent(uint32_t exponent) {
receive_timestamps_exponent_ = exponent;
Expand Down Expand Up @@ -900,6 +905,7 @@ class QUIC_EXPORT_PRIVATE QuicFramer {

// Computes the wire size in bytes of time stamps in |ack|.
size_t GetAckFrameTimeStampSize(const QuicAckFrame& ack);
size_t GetIetfAckFrameTimestampSize(const QuicAckFrame& ack);

// Computes the wire size in bytes of the |ack| frame.
size_t GetAckFrameSize(const QuicAckFrame& ack,
Expand Down Expand Up @@ -963,6 +969,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
// of the frame.
bool AppendIetfAckFrameAndTypeByte(const QuicAckFrame& frame,
QuicDataWriter* writer);
bool AppendIetfTimestampsToAckFrame(const QuicAckFrame& frame,
QuicDataWriter* writer);

bool AppendStopWaitingFrame(const QuicPacketHeader& header,
const QuicStopWaitingFrame& frame,
Expand Down Expand Up @@ -1128,6 +1136,8 @@ class QUIC_EXPORT_PRIVATE QuicFramer {
// If true, send and process timestamps in the ACK frame.
// TODO(ianswett): Remove the mutable once set_process_timestamps isn't const.
mutable bool process_timestamps_;
// The max number of receive timestamps to send per ACK frame.
uint32_t max_receive_timestamps_per_ack_;
// The exponent to use when writing/reading ACK receive timestamps.
uint32_t receive_timestamps_exponent_;
// The creation time of the connection, used to calculate timestamps.
Expand Down
Loading

0 comments on commit 06fffc1

Please sign in to comment.