| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #pragma once |
| |
| #include <assert.h> |
| #include <tuple> |
| #include <vector> |
| #include "slice.h" |
| #include "status.h" |
| |
| namespace overnet { |
| |
| class AckFrame { |
| public: |
| class Writer { |
| public: |
| explicit Writer(const AckFrame* ack_frame); |
| |
| size_t wire_length() const { return wire_length_; } |
| uint8_t* Write(uint8_t* out) const; |
| |
| private: |
| const AckFrame* const ack_frame_; |
| const uint8_t ack_to_seq_length_; |
| const uint8_t ack_delay_us_length_; |
| const uint8_t window_grant_bytes_length_; |
| std::vector<uint8_t> nack_length_; |
| size_t wire_length_; |
| }; |
| |
| AckFrame(uint64_t ack_to_seq, uint64_t ack_delay_us, |
| uint64_t window_grant_bytes) |
| : ack_to_seq_(ack_to_seq), |
| ack_delay_us_(ack_delay_us), |
| window_grant_bytes_(window_grant_bytes) { |
| assert(ack_to_seq_ > 0); |
| } |
| |
| AckFrame(uint64_t ack_to_seq, uint64_t ack_delay_us, |
| uint64_t window_grant_bytes, |
| std::initializer_list<uint64_t> nack_seqs) |
| : ack_to_seq_(ack_to_seq), |
| ack_delay_us_(ack_delay_us), |
| window_grant_bytes_(window_grant_bytes), |
| nack_seqs_(nack_seqs) {} |
| |
| explicit AckFrame(uint64_t ack_to_seq) : AckFrame(ack_to_seq, 0, 0) {} |
| |
| AckFrame(const AckFrame&) = delete; |
| AckFrame& operator=(const AckFrame&) = delete; |
| |
| AckFrame(AckFrame&& other) |
| : ack_to_seq_(other.ack_to_seq_), |
| ack_delay_us_(other.ack_delay_us_), |
| window_grant_bytes_(other.window_grant_bytes_), |
| nack_seqs_(std::move(other.nack_seqs_)) {} |
| |
| AckFrame& operator=(AckFrame&& other) { |
| ack_to_seq_ = other.ack_to_seq_; |
| ack_delay_us_ = other.ack_delay_us_; |
| window_grant_bytes_ = other.window_grant_bytes_; |
| nack_seqs_ = std::move(other.nack_seqs_); |
| return *this; |
| } |
| |
| void AddNack(uint64_t seq) { |
| assert(ack_to_seq_ > 0); |
| assert(seq > (nack_seqs_.empty() ? ack_to_seq_ - 1 : nack_seqs_.back())); |
| nack_seqs_.push_back(seq); |
| } |
| |
| static StatusOr<AckFrame> Parse(Slice slice); |
| |
| friend bool operator==(const AckFrame& a, const AckFrame& b) { |
| return std::tie(a.ack_to_seq_, a.ack_delay_us_, a.window_grant_bytes_, |
| a.nack_seqs_) == std::tie(b.ack_to_seq_, b.ack_delay_us_, |
| b.window_grant_bytes_, |
| b.nack_seqs_); |
| } |
| |
| uint64_t ack_to_seq() const { return ack_to_seq_; } |
| uint64_t ack_delay_us() const { return ack_delay_us_; } |
| uint64_t window_grant_bytes() const { return window_grant_bytes_; } |
| const std::vector<uint64_t>& nack_seqs() const { return nack_seqs_; } |
| |
| private: |
| // All messages with sequence number prior to ack_to_seq_ are implicitly |
| // acknowledged. |
| uint64_t ack_to_seq_; |
| // How long between receiving ack_to_seq_-1 and generating this data |
| // structure. |
| uint64_t ack_delay_us_; |
| // Size of window grant: acks also grant flow control window |
| // such a grant is for ack_to_seq_ onwards. |
| uint64_t window_grant_bytes_; |
| // All messages contained in nack_seqs_ need to be resent. |
| // NOTE: it's assumed that nack_seqs_ is in-order and all value are greater |
| // than or equal to ack_to_seq_. |
| std::vector<uint64_t> nack_seqs_; |
| }; |
| |
| std::ostream& operator<<(std::ostream& out, const AckFrame& ack_frame); |
| |
| } // namespace overnet |