From 6e2e7ce41901242bc4bf338346250f8a10464b5e Mon Sep 17 00:00:00 2001 From: Taylor Brandstetter Date: Tue, 19 Dec 2017 10:26:23 -0800 Subject: [PATCH] Reland "Move JsepTransport from p2p/base to pc/." This is a reland of 4770fd935ac92400487bddd3b755753572e6d692 Original change's description: > Move JsepTransport from p2p/base to pc/. > > The JsepTransport class is moved to pc/ and the utility methods and > enums are moved to where they are used. > > With JsepTransport moved to pc/, JsepTransport can depend on objects in > pc/ including RtpTranport, SrtpTransport etc. > > Forked from https://webrtc-review.googlesource.com/c/src/+/31762/7 > > Bug: webrtc:8636 > Change-Id: I4e8569fe3012946e87deb280f6139f0fd98de34d > Reviewed-on: https://webrtc-review.googlesource.com/33701 > Reviewed-by: Steve Anton > Reviewed-by: Peter Thatcher > Commit-Queue: Taylor Brandstetter > Cr-Commit-Position: refs/heads/master@{#21333} Bug: webrtc:8636 Change-Id: Ibce42be898b96dd8e0266b595611d2ffc86581a8 Reviewed-on: https://webrtc-review.googlesource.com/34586 Commit-Queue: Taylor Brandstetter Reviewed-by: Peter Thatcher Cr-Commit-Position: refs/heads/master@{#21371} --- p2p/BUILD.gn | 2 - p2p/base/dtlstransportinternal.h | 14 +- p2p/base/icetransportinternal.cc | 24 ++ p2p/base/icetransportinternal.h | 103 +++++- p2p/base/jseptransport.h | 380 ++------------------- p2p/base/mockicetransport.h | 2 - p2p/base/p2ptransportchannel.cc | 11 + p2p/base/p2ptransportchannel.h | 5 + p2p/base/port.cc | 28 ++ p2p/base/port.h | 47 ++- p2p/base/port_unittest.cc | 1 - p2p/base/portinterface.h | 3 +- p2p/client/socketmonitor.h | 2 +- pc/BUILD.gn | 3 + {p2p/base => pc}/jseptransport.cc | 144 ++------ pc/jseptransport.h | 205 +++++++++++ {p2p/base => pc}/jseptransport_unittest.cc | 8 + pc/mediasession.h | 2 +- pc/transportcontroller.cc | 41 +++ pc/transportcontroller.h | 2 +- 20 files changed, 532 insertions(+), 495 deletions(-) rename {p2p/base => pc}/jseptransport.cc (79%) create mode 100644 pc/jseptransport.h rename {p2p/base => pc}/jseptransport_unittest.cc (98%) diff --git a/p2p/BUILD.gn b/p2p/BUILD.gn index cd54b7d5cc..f2173f4aed 100644 --- a/p2p/BUILD.gn +++ b/p2p/BUILD.gn @@ -33,7 +33,6 @@ rtc_static_library("rtc_p2p") { "base/dtlstransportinternal.h", "base/icetransportinternal.cc", "base/icetransportinternal.h", - "base/jseptransport.cc", "base/jseptransport.h", "base/p2pconstants.cc", "base/p2pconstants.h", @@ -156,7 +155,6 @@ if (rtc_include_tests) { sources = [ "base/asyncstuntcpsocket_unittest.cc", "base/dtlstransport_unittest.cc", - "base/jseptransport_unittest.cc", "base/p2ptransportchannel_unittest.cc", "base/packetlossestimator_unittest.cc", "base/port_unittest.cc", diff --git a/p2p/base/dtlstransportinternal.h b/p2p/base/dtlstransportinternal.h index b08868fde5..2acbda64fa 100644 --- a/p2p/base/dtlstransportinternal.h +++ b/p2p/base/dtlstransportinternal.h @@ -16,13 +16,25 @@ #include #include "p2p/base/icetransportinternal.h" -#include "p2p/base/jseptransport.h" #include "p2p/base/packettransportinternal.h" #include "rtc_base/sslstreamadapter.h" #include "rtc_base/stringencode.h" namespace cricket { +enum DtlsTransportState { + // Haven't started negotiating. + DTLS_TRANSPORT_NEW = 0, + // Have started negotiating. + DTLS_TRANSPORT_CONNECTING, + // Negotiated, and has a secure connection. + DTLS_TRANSPORT_CONNECTED, + // Transport is closed. + DTLS_TRANSPORT_CLOSED, + // Failed due to some error in the handshake process. + DTLS_TRANSPORT_FAILED, +}; + enum PacketFlags { PF_NORMAL = 0x00, // A normal packet. PF_SRTP_BYPASS = 0x01, // An encrypted SRTP packet; bypass any additional diff --git a/p2p/base/icetransportinternal.cc b/p2p/base/icetransportinternal.cc index d5fa989613..e4e56fe39f 100644 --- a/p2p/base/icetransportinternal.cc +++ b/p2p/base/icetransportinternal.cc @@ -12,6 +12,30 @@ namespace cricket { +IceConfig::IceConfig() = default; + +IceConfig::IceConfig(int receiving_timeout_ms, + int backup_connection_ping_interval, + ContinualGatheringPolicy gathering_policy, + bool prioritize_most_likely_candidate_pairs, + int stable_writable_connection_ping_interval_ms, + bool presume_writable_when_fully_relayed, + int regather_on_failed_networks_interval_ms, + int receiving_switching_delay_ms) + : receiving_timeout(receiving_timeout_ms), + backup_connection_ping_interval(backup_connection_ping_interval), + continual_gathering_policy(gathering_policy), + prioritize_most_likely_candidate_pairs( + prioritize_most_likely_candidate_pairs), + stable_writable_connection_ping_interval( + stable_writable_connection_ping_interval_ms), + presume_writable_when_fully_relayed(presume_writable_when_fully_relayed), + regather_on_failed_networks_interval( + regather_on_failed_networks_interval_ms), + receiving_switching_delay(receiving_switching_delay_ms) {} + +IceConfig::~IceConfig() = default; + IceTransportInternal::IceTransportInternal() = default; IceTransportInternal::~IceTransportInternal() = default; diff --git a/p2p/base/icetransportinternal.h b/p2p/base/icetransportinternal.h index 0a71162eea..787f66e2a4 100644 --- a/p2p/base/icetransportinternal.h +++ b/p2p/base/icetransportinternal.h @@ -12,11 +12,12 @@ #define P2P_BASE_ICETRANSPORTINTERNAL_H_ #include +#include #include "api/candidate.h" #include "p2p/base/candidatepairinterface.h" -#include "p2p/base/jseptransport.h" #include "p2p/base/packettransportinternal.h" +#include "p2p/base/port.h" #include "p2p/base/transportdescription.h" #include "rtc_base/stringencode.h" @@ -26,6 +27,106 @@ class MetricsObserverInterface; namespace cricket { +typedef std::vector Candidates; + +enum IceConnectionState { + kIceConnectionConnecting = 0, + kIceConnectionFailed, + kIceConnectionConnected, // Writable, but still checking one or more + // connections + kIceConnectionCompleted, +}; + +// TODO(deadbeef): Unify with PeerConnectionInterface::IceConnectionState +// once /talk/ and /webrtc/ are combined, and also switch to ENUM_NAME naming +// style. +enum IceGatheringState { + kIceGatheringNew = 0, + kIceGatheringGathering, + kIceGatheringComplete, +}; + +enum ContinualGatheringPolicy { + // All port allocator sessions will stop after a writable connection is found. + GATHER_ONCE = 0, + // The most recent port allocator session will keep on running. + GATHER_CONTINUALLY, + // The most recent port allocator session will keep on running, and it will + // try to recover connectivity if the channel becomes disconnected. + GATHER_CONTINUALLY_AND_RECOVER, +}; + +// ICE Nomination mode. +enum class NominationMode { + REGULAR, // Nominate once per ICE restart (Not implemented yet). + AGGRESSIVE, // Nominate every connection except that it will behave as if + // REGULAR when the remote is an ICE-LITE endpoint. + SEMI_AGGRESSIVE // Our current implementation of the nomination algorithm. + // The details are described in P2PTransportChannel. +}; + +// Information about ICE configuration. +// TODO(deadbeef): Use rtc::Optional to represent unset values, instead of +// -1. +struct IceConfig { + // The ICE connection receiving timeout value in milliseconds. + int receiving_timeout = -1; + // Time interval in milliseconds to ping a backup connection when the ICE + // channel is strongly connected. + int backup_connection_ping_interval = -1; + + ContinualGatheringPolicy continual_gathering_policy = GATHER_ONCE; + + bool gather_continually() const { + return continual_gathering_policy == GATHER_CONTINUALLY || + continual_gathering_policy == GATHER_CONTINUALLY_AND_RECOVER; + } + + // Whether we should prioritize Relay/Relay candidate when nothing + // is writable yet. + bool prioritize_most_likely_candidate_pairs = false; + + // Writable connections are pinged at a slower rate once stablized. + int stable_writable_connection_ping_interval = -1; + + // If set to true, this means the ICE transport should presume TURN-to-TURN + // candidate pairs will succeed, even before a binding response is received. + bool presume_writable_when_fully_relayed = false; + + // Interval to check on all networks and to perform ICE regathering on any + // active network having no connection on it. + rtc::Optional regather_on_failed_networks_interval; + + // Interval to perform ICE regathering on all networks + // The delay in milliseconds is sampled from the uniform distribution [a, b] + rtc::Optional regather_all_networks_interval_range; + + // The time period in which we will not switch the selected connection + // when a new connection becomes receiving but the selected connection is not + // in case that the selected connection may become receiving soon. + rtc::Optional receiving_switching_delay; + + // TODO(honghaiz): Change the default to regular nomination. + // Default nomination mode if the remote does not support renomination. + NominationMode default_nomination_mode = NominationMode::SEMI_AGGRESSIVE; + + // ICE checks (STUN pings) will not be sent at higher rate (lower interval) + // than this, no matter what other settings there are. + // Measure in milliseconds. + rtc::Optional ice_check_min_interval; + + IceConfig(); + IceConfig(int receiving_timeout_ms, + int backup_connection_ping_interval, + ContinualGatheringPolicy gathering_policy, + bool prioritize_most_likely_candidate_pairs, + int stable_writable_connection_ping_interval_ms, + bool presume_writable_when_fully_relayed, + int regather_on_failed_networks_interval_ms, + int receiving_switching_delay_ms); + ~IceConfig(); +}; + // TODO(zhihuang): Replace this with // PeerConnectionInterface::IceConnectionState. enum class IceTransportState { diff --git a/p2p/base/jseptransport.h b/p2p/base/jseptransport.h index f045556f08..3af36340e6 100644 --- a/p2p/base/jseptransport.h +++ b/p2p/base/jseptransport.h @@ -11,373 +11,35 @@ #ifndef P2P_BASE_JSEPTRANSPORT_H_ #define P2P_BASE_JSEPTRANSPORT_H_ -#include -#include -#include #include +// TODO(deadbeef): This file used to be a dumping ground of various enums, +// structs, etc., which have now moved to their own files. Delete this file +// once no one is depending on it, and they start including the more specific +// file(s) instead. + #include "api/candidate.h" -#include "api/jsep.h" -#include "api/optional.h" + +// DTLS enums/structs. +#include "p2p/base/dtlstransport.h" +#include "p2p/base/dtlstransportinternal.h" + +// ICE enums/structs. +#include "p2p/base/icetransportinternal.h" + +// Various constants. #include "p2p/base/p2pconstants.h" + +// ConnectionInfo, among many other things. +#include "p2p/base/port.h" + +// SDP structures #include "p2p/base/sessiondescription.h" #include "p2p/base/transportinfo.h" -#include "rtc_base/constructormagic.h" -#include "rtc_base/messagequeue.h" -#include "rtc_base/rtccertificate.h" -#include "rtc_base/sigslot.h" -#include "rtc_base/sslstreamadapter.h" +// Legacy typedef. namespace cricket { - -class DtlsTransportInternal; -enum class IceCandidatePairState; - typedef std::vector Candidates; - -// TODO(deadbeef): Move all of these enums, POD types and utility methods to -// another header file. - -// TODO(deadbeef): Unify with PeerConnectionInterface::IceConnectionState -// once /talk/ and /webrtc/ are combined, and also switch to ENUM_NAME naming -// style. -enum IceConnectionState { - kIceConnectionConnecting = 0, - kIceConnectionFailed, - kIceConnectionConnected, // Writable, but still checking one or more - // connections - kIceConnectionCompleted, -}; - -enum DtlsTransportState { - // Haven't started negotiating. - DTLS_TRANSPORT_NEW = 0, - // Have started negotiating. - DTLS_TRANSPORT_CONNECTING, - // Negotiated, and has a secure connection. - DTLS_TRANSPORT_CONNECTED, - // Transport is closed. - DTLS_TRANSPORT_CLOSED, - // Failed due to some error in the handshake process. - DTLS_TRANSPORT_FAILED, -}; - -// TODO(deadbeef): Unify with PeerConnectionInterface::IceConnectionState -// once /talk/ and /webrtc/ are combined, and also switch to ENUM_NAME naming -// style. -enum IceGatheringState { - kIceGatheringNew = 0, - kIceGatheringGathering, - kIceGatheringComplete, -}; - -enum ContinualGatheringPolicy { - // All port allocator sessions will stop after a writable connection is found. - GATHER_ONCE = 0, - // The most recent port allocator session will keep on running. - GATHER_CONTINUALLY, - // The most recent port allocator session will keep on running, and it will - // try to recover connectivity if the channel becomes disconnected. - GATHER_CONTINUALLY_AND_RECOVER, -}; - -// Stats that we can return about the connections for a transport channel. -// TODO(hta): Rename to ConnectionStats -struct ConnectionInfo { - ConnectionInfo(); - ConnectionInfo(const ConnectionInfo&); - ~ConnectionInfo(); - - bool best_connection; // Is this the best connection we have? - bool writable; // Has this connection received a STUN response? - bool receiving; // Has this connection received anything? - bool timeout; // Has this connection timed out? - bool new_connection; // Is this a newly created connection? - size_t rtt; // The STUN RTT for this connection. - size_t sent_total_bytes; // Total bytes sent on this connection. - size_t sent_bytes_second; // Bps over the last measurement interval. - size_t sent_discarded_packets; // Number of outgoing packets discarded due to - // socket errors. - size_t sent_total_packets; // Number of total outgoing packets attempted for - // sending. - size_t sent_ping_requests_total; // Number of STUN ping request sent. - size_t sent_ping_requests_before_first_response; // Number of STUN ping - // sent before receiving the first response. - size_t sent_ping_responses; // Number of STUN ping response sent. - - size_t recv_total_bytes; // Total bytes received on this connection. - size_t recv_bytes_second; // Bps over the last measurement interval. - size_t recv_ping_requests; // Number of STUN ping request received. - size_t recv_ping_responses; // Number of STUN ping response received. - Candidate local_candidate; // The local candidate for this connection. - Candidate remote_candidate; // The remote candidate for this connection. - void* key; // A static value that identifies this conn. - // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-state - IceCandidatePairState state; - // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-priority - uint64_t priority; - // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-nominated - bool nominated; - // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-totalroundtriptime - uint64_t total_round_trip_time_ms; - // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-currentroundtriptime - rtc::Optional current_round_trip_time_ms; -}; - -// Information about all the connections of a channel. -typedef std::vector ConnectionInfos; - -// Information about a specific channel -struct TransportChannelStats { - TransportChannelStats(); - TransportChannelStats(const TransportChannelStats&); - ~TransportChannelStats(); - - int component = 0; - ConnectionInfos connection_infos; - int srtp_crypto_suite = rtc::SRTP_INVALID_CRYPTO_SUITE; - int ssl_cipher_suite = rtc::TLS_NULL_WITH_NULL_NULL; - DtlsTransportState dtls_state = DTLS_TRANSPORT_NEW; -}; - -// Information about all the channels of a transport. -// TODO(hta): Consider if a simple vector is as good as a map. -typedef std::vector TransportChannelStatsList; - -// Information about the stats of a transport. -struct TransportStats { - TransportStats(); - ~TransportStats(); - - std::string transport_name; - TransportChannelStatsList channel_stats; -}; - -// ICE Nomination mode. -enum class NominationMode { - REGULAR, // Nominate once per ICE restart (Not implemented yet). - AGGRESSIVE, // Nominate every connection except that it will behave as if - // REGULAR when the remote is an ICE-LITE endpoint. - SEMI_AGGRESSIVE // Our current implementation of the nomination algorithm. - // The details are described in P2PTransportChannel. -}; - -// Information about ICE configuration. -// TODO(deadbeef): Use rtc::Optional to represent unset values, instead of -// -1. -struct IceConfig { - // The ICE connection receiving timeout value in milliseconds. - int receiving_timeout = -1; - // Time interval in milliseconds to ping a backup connection when the ICE - // channel is strongly connected. - int backup_connection_ping_interval = -1; - - ContinualGatheringPolicy continual_gathering_policy = GATHER_ONCE; - - bool gather_continually() const { - return continual_gathering_policy == GATHER_CONTINUALLY || - continual_gathering_policy == GATHER_CONTINUALLY_AND_RECOVER; - } - - // Whether we should prioritize Relay/Relay candidate when nothing - // is writable yet. - bool prioritize_most_likely_candidate_pairs = false; - - // Writable connections are pinged at a slower rate once stablized. - int stable_writable_connection_ping_interval = -1; - - // If set to true, this means the ICE transport should presume TURN-to-TURN - // candidate pairs will succeed, even before a binding response is received. - bool presume_writable_when_fully_relayed = false; - - // Interval to check on all networks and to perform ICE regathering on any - // active network having no connection on it. - rtc::Optional regather_on_failed_networks_interval; - - // Interval to perform ICE regathering on all networks - // The delay in milliseconds is sampled from the uniform distribution [a, b] - rtc::Optional regather_all_networks_interval_range; - - // The time period in which we will not switch the selected connection - // when a new connection becomes receiving but the selected connection is not - // in case that the selected connection may become receiving soon. - rtc::Optional receiving_switching_delay; - - // TODO(honghaiz): Change the default to regular nomination. - // Default nomination mode if the remote does not support renomination. - NominationMode default_nomination_mode = NominationMode::SEMI_AGGRESSIVE; - - // ICE checks (STUN pings) will not be sent at higher rate (lower interval) - // than this, no matter what other settings there are. - // Measure in milliseconds. - rtc::Optional ice_check_min_interval; - - IceConfig(); - IceConfig(int receiving_timeout_ms, - int backup_connection_ping_interval, - ContinualGatheringPolicy gathering_policy, - bool prioritize_most_likely_candidate_pairs, - int stable_writable_connection_ping_interval_ms, - bool presume_writable_when_fully_relayed, - int regather_on_failed_networks_interval_ms, - int receiving_switching_delay_ms); - ~IceConfig(); -}; - -bool BadTransportDescription(const std::string& desc, std::string* err_desc); - -bool IceCredentialsChanged(const std::string& old_ufrag, - const std::string& old_pwd, - const std::string& new_ufrag, - const std::string& new_pwd); - -// If a candidate is not acceptable, returns false and sets error. -bool VerifyCandidate(const Candidate& candidate, std::string* error); -bool VerifyCandidates(const Candidates& candidates, std::string* error); - -// Helper class used by TransportController that processes -// TransportDescriptions. A TransportDescription represents the -// transport-specific properties of an SDP m= section, processed according to -// JSEP. Each transport consists of DTLS and ICE transport channels for RTP -// (and possibly RTCP, if rtcp-mux isn't used). -// -// On Threading: Transport performs work solely on the network thread, and so -// its methods should only be called on the network thread. -// -// TODO(deadbeef): Move this into /pc/ and out of /p2p/base/, since it's -// PeerConnection-specific. -class JsepTransport : public sigslot::has_slots<> { - public: - // |mid| is just used for log statements in order to identify the Transport. - // Note that |certificate| is allowed to be null since a remote description - // may be set before a local certificate is generated. - JsepTransport(const std::string& mid, - const rtc::scoped_refptr& certificate); - ~JsepTransport() override; - - // Returns the MID of this transport. - const std::string& mid() const { return mid_; } - - // Add or remove channel that is affected when a local/remote transport - // description is set on this transport. Need to add all channels before - // setting a transport description. - bool AddChannel(DtlsTransportInternal* dtls, int component); - bool RemoveChannel(int component); - bool HasChannels() const; - - bool ready_for_remote_candidates() const { - return local_description_set_ && remote_description_set_; - } - - // Must be called before applying local session description. - // Needed in order to verify the local fingerprint. - void SetLocalCertificate( - const rtc::scoped_refptr& certificate); - - // Get a copy of the local certificate provided by SetLocalCertificate. - bool GetLocalCertificate( - rtc::scoped_refptr* certificate) const; - - // Set the local TransportDescription to be used by DTLS and ICE channels - // that are part of this Transport. - bool SetLocalTransportDescription(const TransportDescription& description, - webrtc::SdpType type, - std::string* error_desc); - - // Set the remote TransportDescription to be used by DTLS and ICE channels - // that are part of this Transport. - bool SetRemoteTransportDescription(const TransportDescription& description, - webrtc::SdpType type, - std::string* error_desc); - - // Set the "needs-ice-restart" flag as described in JSEP. After the flag is - // set, offers should generate new ufrags/passwords until an ICE restart - // occurs. - // - // This and the below method can be called safely from any thread as long as - // SetXTransportDescription is not in progress. - void SetNeedsIceRestartFlag(); - // Returns true if the ICE restart flag above was set, and no ICE restart has - // occurred yet for this transport (by applying a local description with - // changed ufrag/password). - bool NeedsIceRestart() const; - - // Returns role if negotiated, or empty Optional if it hasn't been negotiated - // yet. - rtc::Optional GetSslRole() const; - - // TODO(deadbeef): Make this const. See comment in transportcontroller.h. - bool GetStats(TransportStats* stats); - - // The current local transport description, possibly used - // by the transport controller. - const TransportDescription* local_description() const { - return local_description_.get(); - } - - // The current remote transport description, possibly used - // by the transport controller. - const TransportDescription* remote_description() const { - return remote_description_.get(); - } - - // TODO(deadbeef): The methods below are only public for testing. Should make - // them utility functions or objects so they can be tested independently from - // this class. - - // Returns false if the certificate's identity does not match the fingerprint, - // or either is NULL. - bool VerifyCertificateFingerprint(const rtc::RTCCertificate* certificate, - const rtc::SSLFingerprint* fingerprint, - std::string* error_desc) const; - - private: - // Negotiates the transport parameters based on the current local and remote - // transport description, such as the ICE role to use, and whether DTLS - // should be activated. - // - // Called when an answer TransportDescription is applied. - bool NegotiateTransportDescription(webrtc::SdpType local_description_type, - std::string* error_desc); - - // Negotiates the SSL role based off the offer and answer as specified by - // RFC 4145, section-4.1. Returns false if the SSL role cannot be determined - // from the local description and remote description. - bool NegotiateRole(webrtc::SdpType local_description_type, - std::string* error_desc); - - // Pushes down the transport parameters from the local description, such - // as the ICE ufrag and pwd. - bool ApplyLocalTransportDescription(DtlsTransportInternal* dtls_transport, - std::string* error_desc); - - // Pushes down the transport parameters from the remote description to the - // transport channel. - bool ApplyRemoteTransportDescription(DtlsTransportInternal* dtls_transport, - std::string* error_desc); - - // Pushes down the transport parameters obtained via negotiation. - bool ApplyNegotiatedTransportDescription( - DtlsTransportInternal* dtls_transport, - std::string* error_desc); - - const std::string mid_; - // needs-ice-restart bit as described in JSEP. - bool needs_ice_restart_ = false; - rtc::scoped_refptr certificate_; - rtc::Optional ssl_role_; - std::unique_ptr remote_fingerprint_; - std::unique_ptr local_description_; - std::unique_ptr remote_description_; - bool local_description_set_ = false; - bool remote_description_set_ = false; - - // Candidate component => DTLS channel - std::map channels_; - - RTC_DISALLOW_COPY_AND_ASSIGN(JsepTransport); -}; - -} // namespace cricket +} #endif // P2P_BASE_JSEPTRANSPORT_H_ diff --git a/p2p/base/mockicetransport.h b/p2p/base/mockicetransport.h index c77f8b1ba6..3e7aed7297 100644 --- a/p2p/base/mockicetransport.h +++ b/p2p/base/mockicetransport.h @@ -41,8 +41,6 @@ class MockIceTransport : public IceTransportInternal { MOCK_METHOD0(GetError, int()); MOCK_CONST_METHOD0(GetIceRole, cricket::IceRole()); MOCK_METHOD1(GetStats, bool(cricket::ConnectionInfos* infos)); - MOCK_CONST_METHOD0(IsDtlsActive, bool()); - MOCK_CONST_METHOD1(GetSslRole, bool(rtc::SSLRole* role)); IceTransportState GetState() const override { return IceTransportState::STATE_INIT; diff --git a/p2p/base/p2ptransportchannel.cc b/p2p/base/p2ptransportchannel.cc index e7564fad84..ddd240322e 100644 --- a/p2p/base/p2ptransportchannel.cc +++ b/p2p/base/p2ptransportchannel.cc @@ -101,6 +101,17 @@ static constexpr int DEFAULT_BACKUP_CONNECTION_PING_INTERVAL = 25 * 1000; static constexpr int a_is_better = 1; static constexpr int b_is_better = -1; +bool IceCredentialsChanged(const std::string& old_ufrag, + const std::string& old_pwd, + const std::string& new_ufrag, + const std::string& new_pwd) { + // The standard (RFC 5245 Section 9.1.1.1) says that ICE restarts MUST change + // both the ufrag and password. However, section 9.2.1.1 says changing the + // ufrag OR password indicates an ICE restart. So, to keep compatibility with + // endpoints that only change one, we'll treat this as an ICE restart. + return (old_ufrag != new_ufrag) || (old_pwd != new_pwd); +} + P2PTransportChannel::P2PTransportChannel(const std::string& transport_name, int component, PortAllocator* allocator) diff --git a/p2p/base/p2ptransportchannel.h b/p2p/base/p2ptransportchannel.h index 188f60c4f1..c2febbf1d3 100644 --- a/p2p/base/p2ptransportchannel.h +++ b/p2p/base/p2ptransportchannel.h @@ -48,6 +48,11 @@ extern const int WEAK_OR_STABILIZING_WRITABLE_CONNECTION_PING_INTERVAL; extern const int STRONG_AND_STABLE_WRITABLE_CONNECTION_PING_INTERVAL; static const int MIN_PINGS_AT_WEAK_PING_INTERVAL = 3; +bool IceCredentialsChanged(const std::string& old_ufrag, + const std::string& old_pwd, + const std::string& new_ufrag, + const std::string& new_pwd); + // Adds the port on which the candidate originated. class RemoteCandidate : public Candidate { public: diff --git a/p2p/base/port.cc b/p2p/base/port.cc index af96582fbc..21b817ae83 100644 --- a/p2p/base/port.cc +++ b/p2p/base/port.cc @@ -139,6 +139,34 @@ static std::string ComputeFoundation(const std::string& type, return rtc::ToString(rtc::ComputeCrc32(ost.str())); } +ConnectionInfo::ConnectionInfo() + : best_connection(false), + writable(false), + receiving(false), + timeout(false), + new_connection(false), + rtt(0), + sent_total_bytes(0), + sent_bytes_second(0), + sent_discarded_packets(0), + sent_total_packets(0), + sent_ping_requests_total(0), + sent_ping_requests_before_first_response(0), + sent_ping_responses(0), + recv_total_bytes(0), + recv_bytes_second(0), + recv_ping_requests(0), + recv_ping_responses(0), + key(nullptr), + state(IceCandidatePairState::WAITING), + priority(0), + nominated(false), + total_round_trip_time_ms(0) {} + +ConnectionInfo::ConnectionInfo(const ConnectionInfo&) = default; + +ConnectionInfo::~ConnectionInfo() = default; + Port::Port(rtc::Thread* thread, const std::string& type, rtc::PacketSocketFactory* factory, diff --git a/p2p/base/port.h b/p2p/base/port.h index e56afc4d7e..ca845e626b 100644 --- a/p2p/base/port.h +++ b/p2p/base/port.h @@ -20,7 +20,6 @@ #include "api/candidate.h" #include "api/optional.h" #include "p2p/base/candidatepairinterface.h" -#include "p2p/base/jseptransport.h" #include "p2p/base/packetlossestimator.h" #include "p2p/base/packetsocketfactory.h" #include "p2p/base/portinterface.h" @@ -104,6 +103,52 @@ enum class IceCandidatePairState { // frozen because we have not implemented ICE freezing logic. }; +// Stats that we can return about the connections for a transport channel. +// TODO(hta): Rename to ConnectionStats +struct ConnectionInfo { + ConnectionInfo(); + ConnectionInfo(const ConnectionInfo&); + ~ConnectionInfo(); + + bool best_connection; // Is this the best connection we have? + bool writable; // Has this connection received a STUN response? + bool receiving; // Has this connection received anything? + bool timeout; // Has this connection timed out? + bool new_connection; // Is this a newly created connection? + size_t rtt; // The STUN RTT for this connection. + size_t sent_total_bytes; // Total bytes sent on this connection. + size_t sent_bytes_second; // Bps over the last measurement interval. + size_t sent_discarded_packets; // Number of outgoing packets discarded due to + // socket errors. + size_t sent_total_packets; // Number of total outgoing packets attempted for + // sending. + size_t sent_ping_requests_total; // Number of STUN ping request sent. + size_t sent_ping_requests_before_first_response; // Number of STUN ping + // sent before receiving the first response. + size_t sent_ping_responses; // Number of STUN ping response sent. + + size_t recv_total_bytes; // Total bytes received on this connection. + size_t recv_bytes_second; // Bps over the last measurement interval. + size_t recv_ping_requests; // Number of STUN ping request received. + size_t recv_ping_responses; // Number of STUN ping response received. + Candidate local_candidate; // The local candidate for this connection. + Candidate remote_candidate; // The remote candidate for this connection. + void* key; // A static value that identifies this conn. + // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-state + IceCandidatePairState state; + // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-priority + uint64_t priority; + // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-nominated + bool nominated; + // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-totalroundtriptime + uint64_t total_round_trip_time_ms; + // https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-currentroundtriptime + rtc::Optional current_round_trip_time_ms; +}; + +// Information about all the connections of a channel. +typedef std::vector ConnectionInfos; + const char* ProtoToString(ProtocolType proto); bool StringToProto(const char* value, ProtocolType* proto); diff --git a/p2p/base/port_unittest.cc b/p2p/base/port_unittest.cc index d657947492..438e4e6008 100644 --- a/p2p/base/port_unittest.cc +++ b/p2p/base/port_unittest.cc @@ -12,7 +12,6 @@ #include #include "p2p/base/basicpacketsocketfactory.h" -#include "p2p/base/jseptransport.h" #include "p2p/base/relayport.h" #include "p2p/base/stunport.h" #include "p2p/base/tcpport.h" diff --git a/p2p/base/portinterface.h b/p2p/base/portinterface.h index 6b97fecace..e34e39abc3 100644 --- a/p2p/base/portinterface.h +++ b/p2p/base/portinterface.h @@ -14,7 +14,8 @@ #include #include -#include "p2p/base/jseptransport.h" +#include "api/candidate.h" +#include "p2p/base/transportdescription.h" #include "rtc_base/asyncpacketsocket.h" #include "rtc_base/socketaddress.h" diff --git a/p2p/client/socketmonitor.h b/p2p/client/socketmonitor.h index 6889803e04..3428b0335b 100644 --- a/p2p/client/socketmonitor.h +++ b/p2p/client/socketmonitor.h @@ -13,7 +13,7 @@ #include -#include "p2p/base/jseptransport.h" // for ConnectionInfos +#include "p2p/base/port.h" // for ConnectionInfos #include "rtc_base/criticalsection.h" #include "rtc_base/sigslot.h" #include "rtc_base/thread.h" diff --git a/pc/BUILD.gn b/pc/BUILD.gn index ba1d8a79da..aa5a5f476c 100644 --- a/pc/BUILD.gn +++ b/pc/BUILD.gn @@ -42,6 +42,8 @@ rtc_static_library("rtc_pc_base") { "dtlssrtptransport.h", "externalhmac.cc", "externalhmac.h", + "jseptransport.cc", + "jseptransport.h", "mediamonitor.cc", "mediamonitor.h", "mediasession.cc", @@ -257,6 +259,7 @@ if (rtc_include_tests) { "channelmanager_unittest.cc", "currentspeakermonitor_unittest.cc", "dtlssrtptransport_unittest.cc", + "jseptransport_unittest.cc", "mediasession_unittest.cc", "rtcpmuxfilter_unittest.cc", "rtptransport_unittest.cc", diff --git a/p2p/base/jseptransport.cc b/pc/jseptransport.cc similarity index 79% rename from p2p/base/jseptransport.cc rename to pc/jseptransport.cc index 77ea040a72..12aad7a3f0 100644 --- a/p2p/base/jseptransport.cc +++ b/pc/jseptransport.cc @@ -8,13 +8,12 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "p2p/base/jseptransport.h" +#include "pc/jseptransport.h" #include #include // for std::pair #include "api/candidate.h" -#include "p2p/base/dtlstransport.h" #include "p2p/base/p2pconstants.h" #include "p2p/base/p2ptransportchannel.h" #include "p2p/base/port.h" @@ -26,6 +25,25 @@ using webrtc::SdpType; namespace cricket { +TransportChannelStats::TransportChannelStats() = default; + +TransportChannelStats::TransportChannelStats(const TransportChannelStats&) = + default; + +TransportChannelStats::~TransportChannelStats() = default; + +TransportStats::TransportStats() = default; + +TransportStats::~TransportStats() = default; + +bool BadTransportDescription(const std::string& desc, std::string* err_desc) { + if (err_desc) { + *err_desc = desc; + } + RTC_LOG(LS_ERROR) << desc; + return false; +} + static bool VerifyIceParams(const TransportDescription& desc) { // For legacy protocols. if (desc.ice_ufrag.empty() && desc.ice_pwd.empty()) @@ -42,128 +60,6 @@ static bool VerifyIceParams(const TransportDescription& desc) { return true; } -ConnectionInfo::ConnectionInfo() - : best_connection(false), - writable(false), - receiving(false), - timeout(false), - new_connection(false), - rtt(0), - sent_total_bytes(0), - sent_bytes_second(0), - sent_discarded_packets(0), - sent_total_packets(0), - sent_ping_requests_total(0), - sent_ping_requests_before_first_response(0), - sent_ping_responses(0), - recv_total_bytes(0), - recv_bytes_second(0), - recv_ping_requests(0), - recv_ping_responses(0), - key(nullptr), - state(IceCandidatePairState::WAITING), - priority(0), - nominated(false), - total_round_trip_time_ms(0) {} - -ConnectionInfo::ConnectionInfo(const ConnectionInfo&) = default; - -ConnectionInfo::~ConnectionInfo() = default; - -TransportChannelStats::TransportChannelStats() = default; - -TransportChannelStats::TransportChannelStats(const TransportChannelStats&) = - default; - -TransportChannelStats::~TransportChannelStats() = default; - -TransportStats::TransportStats() = default; - -TransportStats::~TransportStats() = default; - -IceConfig::IceConfig() = default; - -IceConfig::IceConfig(int receiving_timeout_ms, - int backup_connection_ping_interval, - ContinualGatheringPolicy gathering_policy, - bool prioritize_most_likely_candidate_pairs, - int stable_writable_connection_ping_interval_ms, - bool presume_writable_when_fully_relayed, - int regather_on_failed_networks_interval_ms, - int receiving_switching_delay_ms) - : receiving_timeout(receiving_timeout_ms), - backup_connection_ping_interval(backup_connection_ping_interval), - continual_gathering_policy(gathering_policy), - prioritize_most_likely_candidate_pairs( - prioritize_most_likely_candidate_pairs), - stable_writable_connection_ping_interval( - stable_writable_connection_ping_interval_ms), - presume_writable_when_fully_relayed(presume_writable_when_fully_relayed), - regather_on_failed_networks_interval( - regather_on_failed_networks_interval_ms), - receiving_switching_delay(receiving_switching_delay_ms) {} - -IceConfig::~IceConfig() = default; - -bool BadTransportDescription(const std::string& desc, std::string* err_desc) { - if (err_desc) { - *err_desc = desc; - } - RTC_LOG(LS_ERROR) << desc; - return false; -} - -bool IceCredentialsChanged(const std::string& old_ufrag, - const std::string& old_pwd, - const std::string& new_ufrag, - const std::string& new_pwd) { - // The standard (RFC 5245 Section 9.1.1.1) says that ICE restarts MUST change - // both the ufrag and password. However, section 9.2.1.1 says changing the - // ufrag OR password indicates an ICE restart. So, to keep compatibility with - // endpoints that only change one, we'll treat this as an ICE restart. - return (old_ufrag != new_ufrag) || (old_pwd != new_pwd); -} - -bool VerifyCandidate(const Candidate& cand, std::string* error) { - // No address zero. - if (cand.address().IsNil() || cand.address().IsAnyIP()) { - *error = "candidate has address of zero"; - return false; - } - - // Disallow all ports below 1024, except for 80 and 443 on public addresses. - int port = cand.address().port(); - if (cand.protocol() == TCP_PROTOCOL_NAME && - (cand.tcptype() == TCPTYPE_ACTIVE_STR || port == 0)) { - // Expected for active-only candidates per - // http://tools.ietf.org/html/rfc6544#section-4.5 so no error. - // Libjingle clients emit port 0, in "active" mode. - return true; - } - if (port < 1024) { - if ((port != 80) && (port != 443)) { - *error = "candidate has port below 1024, but not 80 or 443"; - return false; - } - - if (cand.address().IsPrivateIP()) { - *error = "candidate has port of 80 or 443 with private IP address"; - return false; - } - } - - return true; -} - -bool VerifyCandidates(const Candidates& candidates, std::string* error) { - for (const Candidate& candidate : candidates) { - if (!VerifyCandidate(candidate, error)) { - return false; - } - } - return true; -} - JsepTransport::JsepTransport( const std::string& mid, const rtc::scoped_refptr& certificate) diff --git a/pc/jseptransport.h b/pc/jseptransport.h new file mode 100644 index 0000000000..068078bf07 --- /dev/null +++ b/pc/jseptransport.h @@ -0,0 +1,205 @@ +/* + * Copyright 2004 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 PC_JSEPTRANSPORT_H_ +#define PC_JSEPTRANSPORT_H_ + +#include +#include +#include +#include + +#include "api/candidate.h" +#include "api/jsep.h" +#include "api/optional.h" +#include "p2p/base/dtlstransport.h" +#include "p2p/base/p2pconstants.h" +#include "p2p/base/sessiondescription.h" +#include "p2p/base/transportinfo.h" +#include "rtc_base/constructormagic.h" +#include "rtc_base/messagequeue.h" +#include "rtc_base/rtccertificate.h" +#include "rtc_base/sigslot.h" +#include "rtc_base/sslstreamadapter.h" + +namespace cricket { + +class DtlsTransportInternal; + +struct TransportChannelStats { + TransportChannelStats(); + TransportChannelStats(const TransportChannelStats&); + ~TransportChannelStats(); + + int component = 0; + ConnectionInfos connection_infos; + int srtp_crypto_suite = rtc::SRTP_INVALID_CRYPTO_SUITE; + int ssl_cipher_suite = rtc::TLS_NULL_WITH_NULL_NULL; + DtlsTransportState dtls_state = DTLS_TRANSPORT_NEW; +}; + +// Information about all the channels of a transport. +// TODO(hta): Consider if a simple vector is as good as a map. +typedef std::vector TransportChannelStatsList; + +// Information about the stats of a transport. +struct TransportStats { + TransportStats(); + ~TransportStats(); + + std::string transport_name; + TransportChannelStatsList channel_stats; +}; + +bool BadTransportDescription(const std::string& desc, std::string* err_desc); + +// Helper class used by TransportController that processes +// TransportDescriptions. A TransportDescription represents the +// transport-specific properties of an SDP m= section, processed according to +// JSEP. Each transport consists of DTLS and ICE transport channels for RTP +// (and possibly RTCP, if rtcp-mux isn't used). +// +// On Threading: Transport performs work solely on the network thread, and so +// its methods should only be called on the network thread. +class JsepTransport : public sigslot::has_slots<> { + public: + // |mid| is just used for log statements in order to identify the Transport. + // Note that |certificate| is allowed to be null since a remote description + // may be set before a local certificate is generated. + JsepTransport(const std::string& mid, + const rtc::scoped_refptr& certificate); + ~JsepTransport() override; + + // Returns the MID of this transport. + const std::string& mid() const { return mid_; } + + // Add or remove channel that is affected when a local/remote transport + // description is set on this transport. Need to add all channels before + // setting a transport description. + bool AddChannel(DtlsTransportInternal* dtls, int component); + bool RemoveChannel(int component); + bool HasChannels() const; + + bool ready_for_remote_candidates() const { + return local_description_set_ && remote_description_set_; + } + + // Must be called before applying local session description. + // Needed in order to verify the local fingerprint. + void SetLocalCertificate( + const rtc::scoped_refptr& certificate); + + // Get a copy of the local certificate provided by SetLocalCertificate. + bool GetLocalCertificate( + rtc::scoped_refptr* certificate) const; + + // Set the local TransportDescription to be used by DTLS and ICE channels + // that are part of this Transport. + bool SetLocalTransportDescription(const TransportDescription& description, + webrtc::SdpType type, + std::string* error_desc); + + // Set the remote TransportDescription to be used by DTLS and ICE channels + // that are part of this Transport. + bool SetRemoteTransportDescription(const TransportDescription& description, + webrtc::SdpType type, + std::string* error_desc); + + // Set the "needs-ice-restart" flag as described in JSEP. After the flag is + // set, offers should generate new ufrags/passwords until an ICE restart + // occurs. + // + // This and the below method can be called safely from any thread as long as + // SetXTransportDescription is not in progress. + void SetNeedsIceRestartFlag(); + // Returns true if the ICE restart flag above was set, and no ICE restart has + // occurred yet for this transport (by applying a local description with + // changed ufrag/password). + bool NeedsIceRestart() const; + + // Returns role if negotiated, or empty Optional if it hasn't been negotiated + // yet. + rtc::Optional GetSslRole() const; + + // TODO(deadbeef): Make this const. See comment in transportcontroller.h. + bool GetStats(TransportStats* stats); + + // The current local transport description, possibly used + // by the transport controller. + const TransportDescription* local_description() const { + return local_description_.get(); + } + + // The current remote transport description, possibly used + // by the transport controller. + const TransportDescription* remote_description() const { + return remote_description_.get(); + } + + // TODO(deadbeef): The methods below are only public for testing. Should make + // them utility functions or objects so they can be tested independently from + // this class. + + // Returns false if the certificate's identity does not match the fingerprint, + // or either is NULL. + bool VerifyCertificateFingerprint(const rtc::RTCCertificate* certificate, + const rtc::SSLFingerprint* fingerprint, + std::string* error_desc) const; + + private: + // Negotiates the transport parameters based on the current local and remote + // transport description, such as the ICE role to use, and whether DTLS + // should be activated. + // + // Called when an answer TransportDescription is applied. + bool NegotiateTransportDescription(webrtc::SdpType local_description_type, + std::string* error_desc); + + // Negotiates the SSL role based off the offer and answer as specified by + // RFC 4145, section-4.1. Returns false if the SSL role cannot be determined + // from the local description and remote description. + bool NegotiateRole(webrtc::SdpType local_description_type, + std::string* error_desc); + + // Pushes down the transport parameters from the local description, such + // as the ICE ufrag and pwd. + bool ApplyLocalTransportDescription(DtlsTransportInternal* dtls_transport, + std::string* error_desc); + + // Pushes down the transport parameters from the remote description to the + // transport channel. + bool ApplyRemoteTransportDescription(DtlsTransportInternal* dtls_transport, + std::string* error_desc); + + // Pushes down the transport parameters obtained via negotiation. + bool ApplyNegotiatedTransportDescription( + DtlsTransportInternal* dtls_transport, + std::string* error_desc); + + const std::string mid_; + // needs-ice-restart bit as described in JSEP. + bool needs_ice_restart_ = false; + rtc::scoped_refptr certificate_; + rtc::Optional ssl_role_; + std::unique_ptr remote_fingerprint_; + std::unique_ptr local_description_; + std::unique_ptr remote_description_; + bool local_description_set_ = false; + bool remote_description_set_ = false; + + // Candidate component => DTLS channel + std::map channels_; + + RTC_DISALLOW_COPY_AND_ASSIGN(JsepTransport); +}; + +} // namespace cricket + +#endif // PC_JSEPTRANSPORT_H_ diff --git a/p2p/base/jseptransport_unittest.cc b/pc/jseptransport_unittest.cc similarity index 98% rename from p2p/base/jseptransport_unittest.cc rename to pc/jseptransport_unittest.cc index bcd12c5595..1111f36b0b 100644 --- a/p2p/base/jseptransport_unittest.cc +++ b/pc/jseptransport_unittest.cc @@ -7,6 +7,7 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ +#include "pc/jseptransport.h" #include @@ -59,6 +60,13 @@ class JsepTransportTest : public testing::Test, public sigslot::has_slots<> { transport_.reset(new JsepTransport("test content name", nullptr)); } + bool IceCredentialsChanged(const std::string& old_ufrag, + const std::string& old_pwd, + const std::string& new_ufrag, + const std::string& new_pwd) { + return (old_ufrag != new_ufrag) || (old_pwd != new_pwd); + } + protected: std::vector> fake_dtls_transports_; std::vector> fake_ice_transports_; diff --git a/pc/mediasession.h b/pc/mediasession.h index bfce245659..784aad8b7e 100644 --- a/pc/mediasession.h +++ b/pc/mediasession.h @@ -26,9 +26,9 @@ #include "media/base/mediaconstants.h" #include "media/base/mediaengine.h" // For DataChannelType #include "media/base/streamparams.h" -#include "p2p/base/jseptransport.h" #include "p2p/base/sessiondescription.h" #include "p2p/base/transportdescriptionfactory.h" +#include "pc/jseptransport.h" namespace cricket { diff --git a/pc/transportcontroller.cc b/pc/transportcontroller.cc index a9b030cfe9..bd9ea7505a 100644 --- a/pc/transportcontroller.cc +++ b/pc/transportcontroller.cc @@ -40,6 +40,47 @@ struct CandidatesData : public rtc::MessageData { cricket::Candidates candidates; }; +bool VerifyCandidate(const cricket::Candidate& cand, std::string* error) { + // No address zero. + if (cand.address().IsNil() || cand.address().IsAnyIP()) { + *error = "candidate has address of zero"; + return false; + } + + // Disallow all ports below 1024, except for 80 and 443 on public addresses. + int port = cand.address().port(); + if (cand.protocol() == cricket::TCP_PROTOCOL_NAME && + (cand.tcptype() == cricket::TCPTYPE_ACTIVE_STR || port == 0)) { + // Expected for active-only candidates per + // http://tools.ietf.org/html/rfc6544#section-4.5 so no error. + // Libjingle clients emit port 0, in "active" mode. + return true; + } + if (port < 1024) { + if ((port != 80) && (port != 443)) { + *error = "candidate has port below 1024, but not 80 or 443"; + return false; + } + + if (cand.address().IsPrivateIP()) { + *error = "candidate has port of 80 or 443 with private IP address"; + return false; + } + } + + return true; +} + +bool VerifyCandidates(const cricket::Candidates& candidates, + std::string* error) { + for (const cricket::Candidate& candidate : candidates) { + if (!VerifyCandidate(candidate, error)) { + return false; + } + } + return true; +} + } // namespace namespace cricket { diff --git a/pc/transportcontroller.h b/pc/transportcontroller.h index bdde17258b..67fab734b9 100644 --- a/pc/transportcontroller.h +++ b/pc/transportcontroller.h @@ -18,9 +18,9 @@ #include "api/candidate.h" #include "p2p/base/dtlstransport.h" -#include "p2p/base/jseptransport.h" #include "p2p/base/p2ptransportchannel.h" #include "pc/dtlssrtptransport.h" +#include "pc/jseptransport.h" #include "pc/rtptransport.h" #include "pc/srtptransport.h" #include "rtc_base/asyncinvoker.h"