code/quic-toy-server/net/quic/core/quic_framer.cc
// Append IETF Format Ack Frame. The IETF Ack Frame format is, basically,
//   Largest Ack'ed
//   ACK Delay
//   ACK Block Count (after the first)
//   Blocks
//    which is a series of alternating ACK and GAP blocks, each
//    containing the number of packets in the respective ACK- or
//    GAP-block, minus 1. So, for example, if the Blocks were
//    0/0/0/0/0 then it means 1-packet-acked, 1 packet in a gap,
//    1-packet-acked, 1-packet-gap, 1-packet-acked & the first
//    packet has seq# LargestAcked, the last one has seq# LargestAcked-4.
Append IETF Format Ack Frame. The IETF Ack Frame format is, basically,
Largest Ack'ed
ACK Delay
ACK Block Count (after the first)
Blocks
which is a series of alternating ACK and GAP blocks, each
containing the number of packets in the respective ACK- or
GAP-block, minus 1.
Append IETF Format Ack Frame . The IETF Ack Frame format is basically Largest Ack ' ed ACK Delay ACK Block Count ( after the first ) Blocks which is a series of alternating ACK and GAP blocks each containing the number of packets in the respective ACK - or GAP - block minus 1 .
bool QuicFramer::AppendIetfAckFrameAndTypeByte(const QuicAckFrame& frame,
                                               QuicDataWriter* writer) {
  if (!writer->WriteUInt8(IETF_ACK)) {
    set_detailed_error("No room for frame-type");
    return false;
  }
  QuicPacketNumber largest_acked = LargestAcked(frame);
  if (!writer->WriteVarInt62(largest_acked)) {
    set_detailed_error("No room for largest-acked in ack frame");
    return false;
  }
  uint64_t ack_delay_time_us;
  if (frame.ack_delay_time.IsInfinite()) {
    QUIC_BUG << "Ack frame time delay is infinite";
    return false;
  }
  DCHECK_LE(0u, frame.ack_delay_time.ToMicroseconds());
  ack_delay_time_us = frame.ack_delay_time.ToMicroseconds();
  ack_delay_time_us = ack_delay_time_us >> kIetfAckTimestampShift;
  if (!writer->WriteVarInt62(ack_delay_time_us)) {
    set_detailed_error("No room for ack-delay in ack frame");
    return false;
  }
  uint64_t ack_block_count = frame.packets.NumIntervals();
  if (ack_block_count == 0) {
    QUIC_BUG << "Trying to build an ack frame with no ack blocks";
    return false;
  }
  if (!writer->WriteVarInt62(ack_block_count - 1)) {
    set_detailed_error("No room for ack block count in ack frame");
    return false;
  }
  auto itr = frame.packets.rbegin();  
  uint64_t block_length = itr->max() - itr->min();
  if (block_length == 0) {
    QUIC_BUG << "Have a 0-length range in QuicAckFrame::packets";
    return false;
  }
  if (!writer->WriteVarInt62(block_length - 1)) {
    set_detailed_error("No room for first ack block in ack frame");
    return false;
  }
  size_t previous_ack_end = itr->min();
  ack_block_count--;
  while (ack_block_count) {
    itr++;
    size_t gap = previous_ack_end - itr->max() - 1;
    if (!writer->WriteVarInt62(gap)) {
      set_detailed_error("No room for gap block in ack frame");
      return false;
    }
    block_length = itr->max() - itr->min();
    if (block_length == 0) {
      QUIC_BUG << "Have a 0-length range in QuicAckFrame::packets";
      return false;
    }
    if (!writer->WriteVarInt62(block_length - 1)) {
      set_detailed_error("No room for nth ack block in ack frame");
      return false;
    }
    previous_ack_end = itr->min();
    ack_block_count--;
  }
  return true;
}
bool QuicFramer :: AppendIetfAckFrameAndTypeByte ( const QuicAckFrame & frame , QuicDataWriter * writer ) { if ( ! writer -> WriteUInt8 ( IETF_ACK ) ) { set_detailed_error ( " " ) ; return false ; } QuicPacketNumber largest_acked = LargestAcked ( frame ) ; if ( ! writer -> WriteVarInt62 ( largest_acked ) ) { set_detailed_error ( " " ) ; return false ; } uint64_t ack_delay_time_us ; if ( frame . ack_delay_time . IsInfinite ( ) ) { QUIC_BUG << " " ; return false ; } DCHECK_LE ( 0u , frame . ack_delay_time . ToMicroseconds ( ) ) ; ack_delay_time_us = frame . ack_delay_time . ToMicroseconds ( ) ; ack_delay_time_us = ack_delay_time_us >> kIetfAckTimestampShift ; if ( ! writer -> WriteVarInt62 ( ack_delay_time_us ) ) { set_detailed_error ( " " ) ; return false ; } uint64_t ack_block_count = frame . packets . NumIntervals ( ) ; if ( ack_block_count == 0 ) { QUIC_BUG << " " ; return false ; } if ( ! writer -> WriteVarInt62 ( ack_block_count - 1 ) ) { set_detailed_error ( " " ) ; return false ; } auto itr = frame . packets . rbegin ( ) ; uint64_t block_length = itr -> max ( ) - itr -> min ( ) ; if ( block_length == 0 ) { QUIC_BUG << " " ; return false ; } if ( ! writer -> WriteVarInt62 ( block_length - 1 ) ) { set_detailed_error ( " " ) ; return false ; } size_t previous_ack_end = itr -> min ( ) ; ack_block_count -- ; while ( ack_block_count ) { itr ++ ; size_t gap = previous_ack_end - itr -> max ( ) - 1 ; if ( ! writer -> WriteVarInt62 ( gap ) ) { set_detailed_error ( " " ) ; return false ; } block_length = itr -> max ( ) - itr -> min ( ) ; if ( block_length == 0 ) { QUIC_BUG << " " ; return false ; } if ( ! writer -> WriteVarInt62 ( block_length - 1 ) ) { set_detailed_error ( " " ) ; return false ; } previous_ack_end = itr -> min ( ) ; ack_block_count -- ; } return true ; }
Append IETF Format Ack Frame.
Append IETF Format Ack Frame .
// TODO(fkastenholz) when we get real IETF QUIC, need to get // the currect shift from the transport parameters. // Do the block-count // Calculate the block count we will put into the frame. // ID says the value is "The number of Additional ACK Block (and // Gap) fields after the First ACK Block." We interpret this as //  - n(==0) means just the First ACK Block //  - n(>0)  means a First Ack block followed by N pairs //           of Gap/Ack. So if N is 1, there is a First, //           a Gap, and a final Ack. // first range // Do the first block. // The ranges in frame.packets are [low...high), so //  a) we should never see 0 and //  b) we need to subtract 1 when writing the value out. // TODO(fkastenholz) this loop adds all blocks to the frame, // failing if the frame buffer is not large enough. In the future, // we should put in as many as we can, adjusting the count to // indicate just what we put in. Or at least have an option to do this. // Do the gap separating the two ack-blocks // Math note: value of the gap is nr of packets separating the two // acks. If we have two sets of ack'd packets, 1,2,3 and 7,8,...x //  A) The gap size is 3 (the gap is packets 4,5,6), which is //     encoded in the frame as 2. //  B) The two frame.packets ranges are [1,4) and [7,x) so the //     gap calculation is (7-4)-1 ==> (3)-1 ==> 2. // next range // Mind the gap // Add the ack-block (itr already points to it)