text: /*
   *  Copyright 2019 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 P2P_BASE_CONNECTION_H_
  #define P2P_BASE_CONNECTION_H_
  
  #include <memory>
  #include <string>
  #include <vector>
  
  #include "absl/strings/string_view.h"
  #include "absl/types/optional.h"
  #include "api/candidate.h"
  #include "api/transport/stun.h"
  #include "logging/rtc_event_log/ice_logger.h"
  #include "p2p/base/candidate_pair_interface.h"
  #include "p2p/base/connection_info.h"
  #include "p2p/base/p2p_transport_channel_ice_field_trials.h"
  #include "p2p/base/stun_request.h"
  #include "p2p/base/transport_description.h"
  #include "rtc_base/async_packet_socket.h"
  #include "rtc_base/message_handler.h"
  #include "rtc_base/network.h"
  #include "rtc_base/numerics/event_based_exponential_moving_average.h"
  #include "rtc_base/rate_tracker.h"
  #include "rtc_base/weak_ptr.h"
  
  namespace cricket {
  
  // Version number for GOOG_PING, this is added to have the option of
  // adding other flavors in the future.
  constexpr int kGoogPingVersion = 1;
  
  // Connection and Port has circular dependencies.
  // So we use forward declaration rather than include.
  class Port;
  
  // Forward declaration so that a ConnectionRequest can contain a Connection.
  class Connection;
  
  struct CandidatePair final : public CandidatePairInterface {
    ~CandidatePair() override = default;
  
    const Candidate& local_candidate() const override { return local; }
    const Candidate& remote_candidate() const override { return remote; }
  
    Candidate local;
    Candidate remote;
  };
  
  // A ConnectionRequest is a simple STUN ping used to determine writability.
  class ConnectionRequest : public StunRequest {
   public:
    ConnectionRequest(StunRequestManager& manager, Connection* connection);
    void Prepare(StunMessage* message) override;
    void OnResponse(StunMessage* response) override;
    void OnErrorResponse(StunMessage* response) override;
    void OnTimeout() override;
    void OnSent() override;
    int resend_delay() override;
  
   private:
    Connection* const connection_;
  };
  
  // Represents a communication link between a port on the local client and a
  // port on the remote client.
  class Connection : public CandidatePairInterface {
   public:
    struct SentPing {
      SentPing(const std::string id, int64_t sent_time, uint32_t nomination)
          : id(id), sent_time(sent_time), nomination(nomination) {}
  
      std::string id;
      int64_t sent_time;
      uint32_t nomination;
    };
  
    ~Connection() override;
  
    // A unique ID assigned when the connection is created.
    uint32_t id() const { return id_; }
  
    webrtc::TaskQueueBase* network_thread() const;
  
    // Implementation of virtual methods in CandidatePairInterface.
    // Returns the description of the local port
    const Candidate& local_candidate() const override;
    // Returns the description of the remote port to which we communicate.
    const Candidate& remote_candidate() const override;
  
    // Return local network for this connection.
    virtual const rtc::Network* network() const;
    // Return generation for this connection.
    virtual int generation() const;
  
    // Returns the pair priority.
    virtual uint64_t priority() const;
  
    enum WriteState {
      STATE_WRITABLE = 0,          // we have received ping responses recently
      STATE_WRITE_UNRELIABLE = 1,  // we have had a few ping failures
      STATE_WRITE_INIT = 2,        // we have yet to receive a ping response
      STATE_WRITE_TIMEOUT = 3,     // we have had a large number of ping failures
    };
  
    WriteState write_state() const;
    bool writable() const;
    bool receiving() const;
  
    const Port* port() const {
      RTC_DCHECK_RUN_ON(network_thread_);
      return port_.get();
    }
  
    // Determines whether the connection has finished connecting.  This can only
    // be false for TCP connections.
    bool connected() const;
    bool weak() const;
    bool active() const;
  
    // A connection is dead if it can be safely deleted.
    bool dead(int64_t now) const;
  
    // Estimate of the round-trip time over this connection.
    int rtt() const;
  
    int unwritable_timeout() const;
    void set_unwritable_timeout(const absl::optional<int>& value_ms);
    int unwritable_min_checks() const;
    void set_unwritable_min_checks(const absl::optional<int>& value);
    int inactive_timeout() const;
    void set_inactive_timeout(const absl::optional<int>& value);
  
    // Gets the `ConnectionInfo` stats, where `best_connection` has not been
    // populated (default value false).
    ConnectionInfo stats();
  
    sigslot::signal1<Connection*> SignalStateChange;
  
    // Sent when the connection has decided that it is no longer of value.  It
    // will delete itself immediately after this call.
    sigslot::signal1<Connection*> SignalDestroyed;
  
    // The connection can send and receive packets asynchronously.  This matches
    // the interface of AsyncPacketSocket, which may use UDP or TCP under the
    // covers.
    virtual int Send(const void* data,
                     size_t size,
                     const rtc::PacketOptions& options) = 0;
  
    // Error if Send() returns < 0
    virtual int GetError() = 0;
  
    sigslot::signal4<Connection*, const char*, size_t, int64_t> SignalReadPacket;
  
    sigslot::signal1<Connection*> SignalReadyToSend;
  
    // Called when a packet is received on this connection.
    void OnReadPacket(const char* data, size_t size, int64_t packet_time_us);
  
    // Called when the socket is currently able to send.
    void OnReadyToSend();
  
    // Called when a connection is determined to be no longer useful to us.  We
    // still keep it around in case the other side wants to use it.  But we can
    // safely stop pinging on it and we can allow it to time out if the other
    // side stops using it as well.
    bool pruned() const;
    void Prune();
  
    bool use_candidate_attr() const;
    void set_use_candidate_attr(bool enable);
  
    void set_nomination(uint32_t value);
  
    uint32_t remote_nomination() const;
    // One or several pairs may be nominated based on if Regular or Aggressive
    // Nomination is used. https://tools.ietf.org/html/rfc5245#section-8
    // `nominated` is defined both for the controlling or controlled agent based
    // on if a nomination has been pinged or acknowledged. The controlled agent
    // gets its `remote_nomination_` set when pinged by the controlling agent with
    // a nomination value. The controlling agent gets its `acked_nomination_` set
    // when receiving a response to a nominating ping.
    bool nominated() const;
  
    int receiving_timeout() const;
    void set_receiving_timeout(absl::optional<int> receiving_timeout_ms);
  
    // Makes the connection go away.
    void Destroy();
  
    // Makes the connection go away, in a failed state.
    void FailAndDestroy();
  
    // Prunes the connection and sets its state to STATE_FAILED,
    // It will not be used or send pings although it can still receive packets.
    void FailAndPrune();
  
    // Checks that the state of this connection is up-to-date.  The argument is
    // the current time, which is compared against various timeouts.
    void UpdateState(int64_t now);
  
    void UpdateLocalIceParameters(int component,
                                  absl::string_view username_fragment,
                                  absl::string_view password);
  
    // Called when this connection should try checking writability again.
    int64_t last_ping_sent() const;
    void Ping(int64_t now);
    void ReceivedPingResponse(
        int rtt,
        const std::string& request_id,
        const absl::optional<uint32_t>& nomination = absl::nullopt);
  
    int64_t last_ping_response_received() const;
    const absl::optional<std::string>& last_ping_id_received() const;
  
    // Used to check if any STUN ping response has been received.
    int rtt_samples() const;
  
    // Called whenever a valid ping is received on this connection.  This is
    // public because the connection intercepts the first ping for us.
    int64_t last_ping_received() const;
  
    void ReceivedPing(
        const absl::optional<std::string>& request_id = absl::nullopt);
    // Handles the binding request; sends a response if this is a valid request.
    void HandleStunBindingOrGoogPingRequest(IceMessage* msg);
    // Handles the piggyback acknowledgement of the lastest connectivity check
    // that the remote peer has received, if it is indicated in the incoming
    // connectivity check from the peer.
    void HandlePiggybackCheckAcknowledgementIfAny(StunMessage* msg);
    // Timestamp when data was last sent (or attempted to be sent).
    int64_t last_send_data() const;
    int64_t last_data_received() const;
  
    // Debugging description of this connection
    std::string ToDebugId() const;
    std::string ToString() const;
    std::string ToSensitiveString() const;
    // Structured description of this candidate pair.
    const webrtc::IceCandidatePairDescription& ToLogDescription();
    void set_ice_event_log(webrtc::IceEventLog* ice_event_log);
  
    // Prints pings_since_last_response_ into a string.
    void PrintPingsSinceLastResponse(std::string* pings, size_t max);
  
    // `set_selected` is only used for logging in ToString above.  The flag is
    // set true by P2PTransportChannel for its selected candidate pair.
    // TODO(tommi): Remove `selected()` once not referenced downstream.
    bool selected() const;
    void set_selected(bool selected);
  
    // This signal will be fired if this connection is nominated by the
    // controlling side.
    sigslot::signal1<Connection*> SignalNominated;
  
    // Invoked when Connection receives STUN error response with 487 code.
    void HandleRoleConflictFromPeer();
  
    IceCandidatePairState state() const;
  
    int num_pings_sent() const;
  
    uint32_t ComputeNetworkCost() const;
  
    // Update the ICE password and/or generation of the remote candidate if the
    // ufrag in `params` matches the candidate's ufrag, and the
    // candidate's password and/or ufrag has not been set.
    void MaybeSetRemoteIceParametersAndGeneration(const IceParameters& params,
                                                  int generation);
  
    // If `remote_candidate_` is peer reflexive and is equivalent to
    // `new_candidate` except the type, update `remote_candidate_` to
    // `new_candidate`.
    void MaybeUpdatePeerReflexiveCandidate(const Candidate& new_candidate);
  
    // Returns the last received time of any data, stun request, or stun
    // response in milliseconds
    int64_t last_received() const;
    // Returns the last time when the connection changed its receiving state.
    int64_t receiving_unchanged_since() const;
  
    bool stable(int64_t now) const;
  
    // Check if we sent `val` pings without receving a response.
    bool TooManyOutstandingPings(const absl::optional<int>& val) const;
  
    // Called by Port when the network cost changes.
    void SetLocalCandidateNetworkCost(uint16_t cost);
  
    void SetIceFieldTrials(const IceFieldTrials* field_trials);
    const rtc::EventBasedExponentialMovingAverage& GetRttEstimate() const {
      return rtt_estimate_;
    }
  
    // Reset the connection to a state of a newly connected.
    // - STATE_WRITE_INIT
    // - receving = false
    // - throw away all pending request
    // - reset RttEstimate
    //
    // Keep the following unchanged:
    // - connected
    // - remote_candidate
    // - statistics
    //
    // Does not trigger SignalStateChange
    void ForgetLearnedState();
  
    void SendStunBindingResponse(const StunMessage* message);
    void SendGoogPingResponse(const StunMessage* message);
    void SendResponseMessage(const StunMessage& response);
  
    // An accessor for unit tests.
    Port* PortForTest() { return port_.get(); }
    const Port* PortForTest() const { return port_.get(); }
  
    // Public for unit tests.
    uint32_t acked_nomination() const;
    void set_remote_nomination(uint32_t remote_nomination);
  
   protected:
    // Constructs a new connection to the given remote port.
    Connection(rtc::WeakPtr<Port> port, size_t index, const Candidate& candidate);
  
    // Called back when StunRequestManager has a stun packet to send
    void OnSendStunPacket(const void* data, size_t size, StunRequest* req);
  
    // Callbacks from ConnectionRequest
    virtual void OnConnectionRequestResponse(ConnectionRequest* req,
                                             StunMessage* response);
    void OnConnectionRequestErrorResponse(ConnectionRequest* req,
                                          StunMessage* response)
        RTC_RUN_ON(network_thread_);
    void OnConnectionRequestTimeout(ConnectionRequest* req)
        RTC_RUN_ON(network_thread_);
    void OnConnectionRequestSent(ConnectionRequest* req)
        RTC_RUN_ON(network_thread_);
  
    bool rtt_converged() const;
  
    // If the response is not received within 2 * RTT, the response is assumed to
    // be missing.
    bool missing_responses(int64_t now) const;
  
    // Changes the state and signals if necessary.
    void set_write_state(WriteState value);
    void UpdateReceiving(int64_t now);
    void set_state(IceCandidatePairState state);
    void set_connected(bool value);
  
    // The local port where this connection sends and receives packets.
    Port* port() { return port_.get(); }
  
    // NOTE: A pointer to the network thread is held by `port_` so in theory we
    // shouldn't need to hold on to this pointer here, but rather defer to
    // port_->thread(). However, some tests delete the classes in the wrong order
    // so `port_` may be deleted before an instance of this class is deleted.
    // TODO(tommi): This ^^^ should be fixed.
    webrtc::TaskQueueBase* const network_thread_;
    const uint32_t id_;
    rtc::WeakPtr<Port> port_;
    Candidate local_candidate_ RTC_GUARDED_BY(network_thread_);
    Candidate remote_candidate_;
  
    ConnectionInfo stats_;
    rtc::RateTracker recv_rate_tracker_;
    rtc::RateTracker send_rate_tracker_;
    int64_t last_send_data_ = 0;
  
   private:
    // Update the local candidate based on the mapped address attribute.
    // If the local candidate changed, fires SignalStateChange.
    void MaybeUpdateLocalCandidate(ConnectionRequest* request,
                                   StunMessage* response)
        RTC_RUN_ON(network_thread_);
  
    void LogCandidatePairConfig(webrtc::IceCandidatePairConfigType type)
        RTC_RUN_ON(network_thread_);
    void LogCandidatePairEvent(webrtc::IceCandidatePairEventType type,
                               uint32_t transaction_id)
        RTC_RUN_ON(network_thread_);
  
    // Check if this IceMessage is identical
    // to last message ack:ed STUN_BINDING_REQUEST.
    bool ShouldSendGoogPing(const StunMessage* message)
        RTC_RUN_ON(network_thread_);
  
    WriteState write_state_ RTC_GUARDED_BY(network_thread_);
    bool receiving_ RTC_GUARDED_BY(network_thread_);
    bool connected_ RTC_GUARDED_BY(network_thread_);
    bool pruned_ RTC_GUARDED_BY(network_thread_);
    bool selected_ RTC_GUARDED_BY(network_thread_) = false;
    // By default `use_candidate_attr_` flag will be true,
    // as we will be using aggressive nomination.
    // But when peer is ice-lite, this flag "must" be initialized to false and
    // turn on when connection becomes "best connection".
    bool use_candidate_attr_ RTC_GUARDED_BY(network_thread_);
    // Used by the controlling side to indicate that this connection will be
    // selected for transmission if the peer supports ICE-renomination when this
    // value is positive. A larger-value indicates that a connection is nominated
    // later and should be selected by the controlled side with higher precedence.
    // A zero-value indicates not nominating this connection.
    uint32_t nomination_ RTC_GUARDED_BY(network_thread_) = 0;
    // The last nomination that has been acknowledged.
    uint32_t acked_nomination_ RTC_GUARDED_BY(network_thread_) = 0;
    // Used by the controlled side to remember the nomination value received from
    // the controlling side. When the peer does not support ICE re-nomination, its
    // value will be 1 if the connection has been nominated.
    uint32_t remote_nomination_ RTC_GUARDED_BY(network_thread_) = 0;
  
    StunRequestManager requests_ RTC_GUARDED_BY(network_thread_);
    int rtt_ RTC_GUARDED_BY(network_thread_);
    int rtt_samples_ RTC_GUARDED_BY(network_thread_) = 0;
    // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-totalroundtriptime
    uint64_t total_round_trip_time_ms_ RTC_GUARDED_BY(network_thread_) = 0;
    // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-currentroundtriptime
    absl::optional<uint32_t> current_round_trip_time_ms_
        RTC_GUARDED_BY(network_thread_);
    int64_t last_ping_sent_ RTC_GUARDED_BY(
        network_thread_);  // last time we sent a ping to the other side
    int64_t last_ping_received_
        RTC_GUARDED_BY(network_thread_);  // last time we received a ping from the
                                          // other side
    int64_t last_data_received_ RTC_GUARDED_BY(network_thread_);
    int64_t last_ping_response_received_ RTC_GUARDED_BY(network_thread_);
    int64_t receiving_unchanged_since_ RTC_GUARDED_BY(network_thread_) = 0;
    std::vector<SentPing> pings_since_last_response_
        RTC_GUARDED_BY(network_thread_);
    // Transaction ID of the last connectivity check received. Null if having not
    // received a ping yet.
    absl::optional<std::string> last_ping_id_received_
        RTC_GUARDED_BY(network_thread_);
  
    absl::optional<int> unwritable_timeout_ RTC_GUARDED_BY(network_thread_);
    absl::optional<int> unwritable_min_checks_ RTC_GUARDED_BY(network_thread_);
    absl::optional<int> inactive_timeout_ RTC_GUARDED_BY(network_thread_);
  
    IceCandidatePairState state_ RTC_GUARDED_BY(network_thread_);
    // Time duration to switch from receiving to not receiving.
    absl::optional<int> receiving_timeout_ RTC_GUARDED_BY(network_thread_);
    int64_t time_created_ms_ RTC_GUARDED_BY(network_thread_);
    int num_pings_sent_ RTC_GUARDED_BY(network_thread_) = 0;
  
    absl::optional<webrtc::IceCandidatePairDescription> log_description_
        RTC_GUARDED_BY(network_thread_);
    webrtc::IceEventLog* ice_event_log_ RTC_GUARDED_BY(network_thread_) = nullptr;
  
    // GOOG_PING_REQUEST is sent in place of STUN_BINDING_REQUEST
    // if configured via field trial, the remote peer supports it (signaled
    // in STUN_BINDING) and if the last STUN BINDING is identical to the one
    // that is about to be sent.
    absl::optional<bool> remote_support_goog_ping_
        RTC_GUARDED_BY(network_thread_);
    std::unique_ptr<StunMessage> cached_stun_binding_
        RTC_GUARDED_BY(network_thread_);
  
    const IceFieldTrials* field_trials_;
    rtc::EventBasedExponentialMovingAverage rtt_estimate_
        RTC_GUARDED_BY(network_thread_);
  
    friend class ConnectionRequest;
  };
  
  // ProxyConnection defers all the interesting work to the port.
  class ProxyConnection : public Connection {
   public:
    ProxyConnection(rtc::WeakPtr<Port> port,
                    size_t index,
                    const Candidate& remote_candidate);
  
    int Send(const void* data,
             size_t size,
             const rtc::PacketOptions& options) override;
    int GetError() override;
  
   private:
    int error_ = 0;
  };
  
  }  // namespace cricket
  
  #endif  // P2P_BASE_CONNECTION_H_
  