| /* | 
 |  *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 | #ifndef NET_DCSCTP_SOCKET_TRANSMISSION_CONTROL_BLOCK_H_ | 
 | #define NET_DCSCTP_SOCKET_TRANSMISSION_CONTROL_BLOCK_H_ | 
 |  | 
 | #include <cstdint> | 
 | #include <functional> | 
 | #include <memory> | 
 | #include <string> | 
 | #include <utility> | 
 | #include <vector> | 
 |  | 
 | #include "absl/functional/bind_front.h" | 
 | #include "absl/strings/string_view.h" | 
 | #include "api/task_queue/task_queue_base.h" | 
 | #include "net/dcsctp/common/sequence_numbers.h" | 
 | #include "net/dcsctp/packet/chunk/cookie_echo_chunk.h" | 
 | #include "net/dcsctp/packet/sctp_packet.h" | 
 | #include "net/dcsctp/public/dcsctp_options.h" | 
 | #include "net/dcsctp/public/dcsctp_socket.h" | 
 | #include "net/dcsctp/rx/data_tracker.h" | 
 | #include "net/dcsctp/rx/reassembly_queue.h" | 
 | #include "net/dcsctp/socket/capabilities.h" | 
 | #include "net/dcsctp/socket/context.h" | 
 | #include "net/dcsctp/socket/heartbeat_handler.h" | 
 | #include "net/dcsctp/socket/packet_sender.h" | 
 | #include "net/dcsctp/socket/stream_reset_handler.h" | 
 | #include "net/dcsctp/timer/timer.h" | 
 | #include "net/dcsctp/tx/retransmission_error_counter.h" | 
 | #include "net/dcsctp/tx/retransmission_queue.h" | 
 | #include "net/dcsctp/tx/retransmission_timeout.h" | 
 | #include "net/dcsctp/tx/send_queue.h" | 
 |  | 
 | namespace dcsctp { | 
 |  | 
 | // The TransmissionControlBlock (TCB) represents an open connection to a peer, | 
 | // and holds all the resources for that. If the connection is e.g. shutdown, | 
 | // closed or restarted, this object will be deleted and/or replaced. | 
 | class TransmissionControlBlock : public Context { | 
 |  public: | 
 |   TransmissionControlBlock(TimerManager& timer_manager, | 
 |                            absl::string_view log_prefix, | 
 |                            const DcSctpOptions& options, | 
 |                            const Capabilities& capabilities, | 
 |                            DcSctpSocketCallbacks& callbacks, | 
 |                            SendQueue& send_queue, | 
 |                            VerificationTag my_verification_tag, | 
 |                            TSN my_initial_tsn, | 
 |                            VerificationTag peer_verification_tag, | 
 |                            TSN peer_initial_tsn, | 
 |                            size_t a_rwnd, | 
 |                            TieTag tie_tag, | 
 |                            PacketSender& packet_sender, | 
 |                            std::function<bool()> is_connection_established); | 
 |  | 
 |   // Implementation of `Context`. | 
 |   bool is_connection_established() const override { | 
 |     return is_connection_established_(); | 
 |   } | 
 |   TSN my_initial_tsn() const override { return my_initial_tsn_; } | 
 |   TSN peer_initial_tsn() const override { return peer_initial_tsn_; } | 
 |   DcSctpSocketCallbacks& callbacks() const override { return callbacks_; } | 
 |   void ObserveRTT(webrtc::TimeDelta rtt) override; | 
 |   webrtc::TimeDelta current_rto() const override { return rto_.rto(); } | 
 |   bool IncrementTxErrorCounter(absl::string_view reason) override { | 
 |     return tx_error_counter_.Increment(reason); | 
 |   } | 
 |   void ClearTxErrorCounter() override { tx_error_counter_.Clear(); } | 
 |   SctpPacket::Builder PacketBuilder() const override { | 
 |     return SctpPacket::Builder(peer_verification_tag_, options_); | 
 |   } | 
 |   bool HasTooManyTxErrors() const override { | 
 |     return tx_error_counter_.IsExhausted(); | 
 |   } | 
 |   void Send(SctpPacket::Builder& builder) override { | 
 |     packet_sender_.Send(builder, | 
 |                         /*write_checksum=*/!capabilities_.zero_checksum); | 
 |   } | 
 |  | 
 |   // Other accessors | 
 |   DataTracker& data_tracker() { return data_tracker_; } | 
 |   ReassemblyQueue& reassembly_queue() { return reassembly_queue_; } | 
 |   RetransmissionQueue& retransmission_queue() { return retransmission_queue_; } | 
 |   StreamResetHandler& stream_reset_handler() { return stream_reset_handler_; } | 
 |   HeartbeatHandler& heartbeat_handler() { return heartbeat_handler_; } | 
 |   size_t cwnd() const { return retransmission_queue_.cwnd(); } | 
 |   webrtc::TimeDelta current_srtt() const { return rto_.srtt(); } | 
 |  | 
 |   // Returns this socket's verification tag, set in all packet headers. | 
 |   VerificationTag my_verification_tag() const { return my_verification_tag_; } | 
 |   // Returns the peer's verification tag, which should be in received packets. | 
 |   VerificationTag peer_verification_tag() const { | 
 |     return peer_verification_tag_; | 
 |   } | 
 |   // All negotiated supported capabilities. | 
 |   const Capabilities& capabilities() const { return capabilities_; } | 
 |   // A 64-bit tie-tag, used to e.g. detect reconnections. | 
 |   TieTag tie_tag() const { return tie_tag_; } | 
 |  | 
 |   // Sends a SACK, if there is a need to. | 
 |   void MaybeSendSack(); | 
 |  | 
 |   // Sends a FORWARD-TSN, if it is needed and allowed (rate-limited). | 
 |   void MaybeSendForwardTsn(SctpPacket::Builder& builder, webrtc::Timestamp now); | 
 |  | 
 |   // Will be set while the socket is in kCookieEcho state. In this state, there | 
 |   // can only be a single packet outstanding, and it must contain the COOKIE | 
 |   // ECHO chunk as the first chunk in that packet, until the COOKIE ACK has been | 
 |   // received, which will make the socket call `ClearCookieEchoChunk`. | 
 |   void SetCookieEchoChunk(CookieEchoChunk chunk) { | 
 |     cookie_echo_chunk_ = std::move(chunk); | 
 |   } | 
 |  | 
 |   // Called when the COOKIE ACK chunk has been received, to allow further | 
 |   // packets to be sent. | 
 |   void ClearCookieEchoChunk() { cookie_echo_chunk_ = absl::nullopt; } | 
 |  | 
 |   bool has_cookie_echo_chunk() const { return cookie_echo_chunk_.has_value(); } | 
 |  | 
 |   void MaybeSendFastRetransmit(); | 
 |  | 
 |   // Fills `builder` (which may already be filled with control chunks) with | 
 |   // other control and data chunks, and sends packets as much as can be | 
 |   // allowed by the congestion control algorithm. | 
 |   void SendBufferedPackets(SctpPacket::Builder& builder, webrtc::Timestamp now); | 
 |  | 
 |   // As above, but without passing in a builder. If `cookie_echo_chunk_` is | 
 |   // present, then only one packet will be sent, with this chunk as the first | 
 |   // chunk. | 
 |   void SendBufferedPackets(webrtc::Timestamp now) { | 
 |     SctpPacket::Builder builder(peer_verification_tag_, options_); | 
 |     SendBufferedPackets(builder, now); | 
 |   } | 
 |  | 
 |   // Returns a textual representation of this object, for logging. | 
 |   std::string ToString() const; | 
 |  | 
 |   HandoverReadinessStatus GetHandoverReadiness() const; | 
 |  | 
 |   void AddHandoverState(DcSctpSocketHandoverState& state); | 
 |   void RestoreFromState(const DcSctpSocketHandoverState& handover_state); | 
 |  | 
 |  private: | 
 |   // Will be called when the retransmission timer (t3-rtx) expires. | 
 |   webrtc::TimeDelta OnRtxTimerExpiry(); | 
 |   // Will be called when the delayed ack timer expires. | 
 |   webrtc::TimeDelta OnDelayedAckTimerExpiry(); | 
 |  | 
 |   const absl::string_view log_prefix_; | 
 |   const DcSctpOptions options_; | 
 |   TimerManager& timer_manager_; | 
 |   // Negotiated capabilities that both peers support. | 
 |   const Capabilities capabilities_; | 
 |   DcSctpSocketCallbacks& callbacks_; | 
 |   // The data retransmission timer, called t3-rtx in SCTP. | 
 |   const std::unique_ptr<Timer> t3_rtx_; | 
 |   // Delayed ack timer, which triggers when acks should be sent (when delayed). | 
 |   const std::unique_ptr<Timer> delayed_ack_timer_; | 
 |   const VerificationTag my_verification_tag_; | 
 |   const TSN my_initial_tsn_; | 
 |   const VerificationTag peer_verification_tag_; | 
 |   const TSN peer_initial_tsn_; | 
 |   // Nonce, used to detect reconnections. | 
 |   const TieTag tie_tag_; | 
 |   const std::function<bool()> is_connection_established_; | 
 |   PacketSender& packet_sender_; | 
 |   // Rate limiting of FORWARD-TSN. Next can be sent at or after this timestamp. | 
 |   webrtc::Timestamp limit_forward_tsn_until_ = webrtc::Timestamp::Zero(); | 
 |  | 
 |   RetransmissionTimeout rto_; | 
 |   RetransmissionErrorCounter tx_error_counter_; | 
 |   DataTracker data_tracker_; | 
 |   ReassemblyQueue reassembly_queue_; | 
 |   RetransmissionQueue retransmission_queue_; | 
 |   StreamResetHandler stream_reset_handler_; | 
 |   HeartbeatHandler heartbeat_handler_; | 
 |  | 
 |   // Only valid when the socket state == State::kCookieEchoed. In this state, | 
 |   // the socket must wait for COOKIE ACK to continue sending any packets (not | 
 |   // including a COOKIE ECHO). So if `cookie_echo_chunk_` is present, the | 
 |   // SendBufferedChunks will always only just send one packet, with this chunk | 
 |   // as the first chunk in the packet. | 
 |   absl::optional<CookieEchoChunk> cookie_echo_chunk_ = absl::nullopt; | 
 | }; | 
 | }  // namespace dcsctp | 
 |  | 
 | #endif  // NET_DCSCTP_SOCKET_TRANSMISSION_CONTROL_BLOCK_H_ |