| /* | 
 |  *  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/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" | 
 |  | 
 | 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: | 
 |   explicit ConnectionRequest(Connection* connection); | 
 |   void Prepare(StunMessage* request) 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 sigslot::has_slots<> { | 
 |  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; | 
 |  | 
 |   // 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); | 
 |  | 
 |   // 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); | 
 |  | 
 |   bool reported() const; | 
 |   void set_reported(bool reported); | 
 |  | 
 |   // `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; | 
 |  | 
 |   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* request); | 
 |   void SendGoogPingResponse(const StunMessage* request); | 
 |   void SendResponseMessage(const StunMessage& response); | 
 |  | 
 |   // An accessor for unit tests. | 
 |   Port* PortForTest() { return port_; } | 
 |   const Port* PortForTest() const { return port_; } | 
 |  | 
 |   // 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(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_; } | 
 |   const Port* port() const { return port_; } | 
 |  | 
 |   // 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_; | 
 |   Port* const port_; | 
 |   size_t local_candidate_index_ 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; | 
 |   // Set to true when deletion has been scheduled and must not be done again. | 
 |   // See `Destroy()` for more details. | 
 |   bool pending_delete_ RTC_GUARDED_BY(network_thread_) = false; | 
 |  | 
 |  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_); | 
 |  | 
 |   bool reported_ 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 Port; | 
 |   friend class ConnectionRequest; | 
 |   friend class P2PTransportChannel; | 
 | }; | 
 |  | 
 | // ProxyConnection defers all the interesting work to the port. | 
 | class ProxyConnection : public Connection { | 
 |  public: | 
 |   ProxyConnection(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_ |