/* * Copyright 2017 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_JSEP_TRANSPORT_CONTROLLER_H_ #define PC_JSEP_TRANSPORT_CONTROLLER_H_ #include #include #include #include #include #include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" #include "api/async_dns_resolver.h" #include "api/candidate.h" #include "api/crypto/crypto_options.h" #include "api/environment/environment.h" #include "api/ice_transport_interface.h" #include "api/jsep.h" #include "api/local_network_access_permission.h" #include "api/peer_connection_interface.h" #include "api/rtc_error.h" #include "api/rtp_transport_factory.h" #include "api/scoped_refptr.h" #include "api/sequence_checker.h" #include "api/task_queue/task_queue_base.h" #include "api/transport/data_channel_transport_interface.h" #include "api/transport/ecn_marking.h" #include "api/transport/sctp_transport_factory_interface.h" #include "api/units/timestamp.h" #include "modules/rtp_rtcp/source/rtp_packet_received.h" #include "p2p/base/ice_transport_internal.h" #include "p2p/base/packet_transport_internal.h" #include "p2p/base/port.h" #include "p2p/base/port_allocator.h" #include "p2p/base/transport_description.h" #include "p2p/base/transport_info.h" #include "p2p/dtls/dtls_transport_factory.h" #include "p2p/dtls/dtls_transport_internal.h" #include "pc/dtls_srtp_transport.h" #include "pc/dtls_transport.h" #include "pc/jsep_transport.h" #include "pc/jsep_transport_collection.h" #include "pc/rtp_transport.h" #include "pc/rtp_transport_internal.h" #include "pc/sctp_transport.h" #include "pc/session_description.h" #include "pc/transport_stats.h" #include "rtc_base/copy_on_write_buffer.h" #include "rtc_base/rtc_certificate.h" #include "rtc_base/ssl_certificate.h" #include "rtc_base/ssl_stream_adapter.h" #include "rtc_base/thread.h" #include "rtc_base/thread_annotations.h" namespace webrtc { class JsepTransportController final { public: // Used when the RtpTransport/DtlsTransport of the m= section is changed // because the section is rejected or BUNDLE is enabled. class Observer { public: virtual ~Observer() {} // Returns true if media associated with `mid` was successfully set up to be // demultiplexed on `rtp_transport`. Could return false if two bundled m= // sections use the same SSRC, for example. // // If a data channel transport must be negotiated, `data_channel_transport` // and `negotiation_state` indicate negotiation status. If // `data_channel_transport` is null, the data channel transport should not // be used. Otherwise, the value is a pointer to the transport to be used // for data channels on `mid`, if any. // // The observer should not send data on `data_channel_transport` until // `negotiation_state` is provisional or final. It should not delete // `data_channel_transport` or any fallback transport until // `negotiation_state` is final. virtual bool OnTransportChanged( absl::string_view mid, RtpTransportInternal* rtp_transport, scoped_refptr dtls_transport, DataChannelTransportInterface* data_channel_transport) = 0; }; struct Config { // If `redetermine_role_on_ice_restart` is true, ICE role is redetermined // upon setting a local transport description that indicates an ICE // restart. bool redetermine_role_on_ice_restart = true; SSLProtocolVersion ssl_max_version = SSL_PROTOCOL_DTLS_12; // `crypto_options` is used to determine if created DTLS transports // negotiate GCM crypto suites or not. CryptoOptions crypto_options; PeerConnectionInterface::BundlePolicy bundle_policy = PeerConnectionInterface::kBundlePolicyBalanced; PeerConnectionInterface::RtcpMuxPolicy rtcp_mux_policy = PeerConnectionInterface::kRtcpMuxPolicyRequire; bool disable_encryption = false; bool enable_external_auth = false; // Used to inject the ICE/DTLS/SRTP transports created externally. IceTransportFactory* ice_transport_factory = nullptr; DtlsTransportFactory* dtls_transport_factory = nullptr; RtpTransportFactory* rtp_transport_factory = nullptr; Observer* transport_observer = nullptr; // Must be provided and valid for the lifetime of the // JsepTransportController instance. absl::AnyInvocable rtcp_handler; absl::AnyInvocable un_demuxable_packet_handler; // Factory for SCTP transports. SctpTransportFactoryInterface* sctp_factory = nullptr; absl::AnyInvocable on_dtls_handshake_error = [](SSLHandshakeError s) {}; absl::AnyInvocable&) const> signal_ice_candidates_gathered = [](absl::string_view, const std::vector&) {}; absl::AnyInvocable signal_ice_connection_state = [](IceConnectionState) {}; absl::AnyInvocable signal_connection_state = [](PeerConnectionInterface::PeerConnectionState) {}; absl::AnyInvocable signal_standardized_ice_connection_state = [](PeerConnectionInterface::IceConnectionState) {}; absl::AnyInvocable signal_ice_gathering_state = [](webrtc::IceGatheringState) {}; absl::AnyInvocable signal_ice_candidate_error = [](const webrtc::IceCandidateErrorEvent&) {}; absl::AnyInvocable&) const> signal_ice_candidates_removed = [](IceTransportInternal*, const std::vector&) {}; absl::AnyInvocable signal_ice_candidate_pair_changed = [](const webrtc::CandidatePairChangeEvent&) {}; }; // The ICE related events are fired on the `network_thread`. // All the transport related methods are called on the `network_thread` // and destruction of the JsepTransportController must occur on the // `network_thread`. JsepTransportController( const Environment& env, TaskQueueBase* signaling_thread, Thread* network_thread, PortAllocator* port_allocator, AsyncDnsResolverFactoryInterface* async_dns_resolver_factory, LocalNetworkAccessPermissionFactoryInterface* lna_permission_factory, Config config); ~JsepTransportController(); JsepTransportController(const JsepTransportController&) = delete; JsepTransportController& operator=(const JsepTransportController&) = delete; // The main method to be called; applies a description at the transport // level, creating/destroying transport objects as needed and updating their // properties. This includes RTP, DTLS, and ICE (but not SCTP). At least not // yet? May make sense to in the future. // // `local_desc` must always be valid. If a remote description has previously // been set via a call to `SetRemoteDescription()` then `remote_desc` should // point to that description object in order to keep the current local and // remote session descriptions in sync. // // Must be called on the signaling thread. RTCError SetLocalDescription(SdpType type, const SessionDescription* local_desc, const SessionDescription* remote_desc); // Call to apply a remote description (See `SetLocalDescription()` for local). // // `remote_desc` must always be valid. If a local description has previously // been set via a call to `SetLocalDescription()` then `local_desc` should // point to that description object in order to keep the current local and // remote session descriptions in sync. // // Must be called on the signaling thread. RTCError SetRemoteDescription(SdpType type, const SessionDescription* local_desc, const SessionDescription* remote_desc); // Get transports to be used for the provided `mid`. If bundling is enabled, // calling GetRtpTransport for multiple MIDs may yield the same object. RtpTransportInternal* GetRtpTransport(absl::string_view mid) const; DtlsTransportInternal* GetDtlsTransport(absl::string_view mid); // Gets the externally sharable version of the DtlsTransport. scoped_refptr LookupDtlsTransportByMid_n( absl::string_view mid); scoped_refptr LookupDtlsTransportByMid(absl::string_view mid); scoped_refptr GetSctpTransport(absl::string_view mid) const; DataChannelTransportInterface* GetDataChannelTransport( absl::string_view mid) const; /********************* * ICE-related methods ********************/ // This method is public to allow PeerConnection to update it from // SetConfiguration. void SetIceConfig(const IceConfig& config); // 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. 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). If the transport has been deleted as a result of // bundling, returns false. // // Must be called on the signaling thread. bool NeedsIceRestart(absl::string_view mid) const; // Start gathering candidates for any new transports, or transports doing an // ICE restart. // // Must be called on the signaling thread. void MaybeStartGathering(); RTCError AddRemoteCandidates(absl::string_view mid, const std::vector& candidates); // Must be called on the signaling thread. bool RemoveRemoteCandidate(const IceCandidate* candidate); /********************** * DTLS-related methods *********************/ // Specifies the identity to use in this session. // Can only be called once. // // Must be called on the signaling thread. bool SetLocalCertificate(const scoped_refptr& certificate); scoped_refptr GetLocalCertificate( absl::string_view mid) const; // Caller owns returned certificate chain. This method mainly exists for // stats reporting. std::unique_ptr GetRemoteSSLCertChain( absl::string_view mid) const; // Get negotiated role, if one has been negotiated. // // Must be called on the signaling thread. std::optional GetDtlsRole(absl::string_view mid) const; bool GetStats(absl::string_view transport_name, TransportStats* stats) const; // Must be called on the signaling thread. RTCError RollbackTransports(); private: // Always called via a blocking call from the signaling thread. RTCError SetLocalDescription_n(SdpType type, const SessionDescription* local_desc, const SessionDescription* remote_desc) RTC_RUN_ON(network_thread_); // Always called via a blocking call from the signaling thread. RTCError SetRemoteDescription_n(SdpType type, const SessionDescription* local_desc, const SessionDescription* remote_desc) RTC_RUN_ON(network_thread_); // Always called via a blocking call from the signaling thread. bool NeedsIceRestart_n(absl::string_view mid) const RTC_RUN_ON(network_thread_); // Always called via a blocking call from the signaling thread. bool RemoveRemoteCandidate_n(const IceCandidate* candidate) RTC_RUN_ON(network_thread_); // Always called via a blocking call from the signaling thread. RTCError RollbackTransports_n() RTC_RUN_ON(network_thread_); // Always called via a blocking call from the signaling thread. void MaybeStartGathering_n() RTC_RUN_ON(network_thread_); // Always called via a blocking call from the signaling thread. bool SetLocalCertificate_n(const scoped_refptr& certificate) RTC_RUN_ON(network_thread_); // Called from SetLocalDescription and SetRemoteDescription. // When `local` is true, local_desc must be valid. Similarly when // `local` is false, remote_desc must be valid. The description counterpart // to the one that's being applied, may be nullptr but when it's supplied // the counterpart description's content groups will be kept up to date for // `type == SdpType::kAnswer`. RTCError ApplyDescription_n(bool local, SdpType type, const SessionDescription* local_desc, const SessionDescription* remote_desc) RTC_RUN_ON(network_thread_); RTCError ValidateAndMaybeUpdateBundleGroups( bool local, SdpType type, const SessionDescription* local_desc, const SessionDescription* remote_desc) RTC_RUN_ON(network_thread_); RTCError ValidateContent(const ContentInfo& content_info); void HandleRejectedContent(const ContentInfo& content_info) RTC_RUN_ON(network_thread_); bool HandleBundledContent(const ContentInfo& content_info, const ContentGroup& bundle_group) RTC_RUN_ON(network_thread_); JsepTransportDescription CreateJsepTransportDescription( const ContentInfo& content_info, const TransportInfo& transport_info, const std::vector& encrypted_extension_ids, int rtp_abs_sendtime_extn_id); std::map> MergeEncryptedHeaderExtensionIdsForBundles( const SessionDescription* description); std::vector GetEncryptedHeaderExtensionIds( const ContentInfo& content_info); int GetRtpAbsSendTimeHeaderExtensionId(const ContentInfo& content_info); // This method takes the BUNDLE group into account. If the JsepTransport is // destroyed because of BUNDLE, it would return the transport which other // transports are bundled on (In current implementation, it is the first // content in the BUNDLE group). const JsepTransport* GetJsepTransportForMid(absl::string_view mid) const RTC_RUN_ON(network_thread_); JsepTransport* GetJsepTransportForMid(absl::string_view mid) RTC_RUN_ON(network_thread_); // Get the JsepTransport without considering the BUNDLE group. Return nullptr // if the JsepTransport is destroyed. const JsepTransport* GetJsepTransportByName( absl::string_view transport_name) const RTC_RUN_ON(network_thread_); JsepTransport* GetJsepTransportByName(absl::string_view transport_name) RTC_RUN_ON(network_thread_); // Creates jsep transport. Noop if transport is already created. // Transport is created either during SetLocalDescription (`local` == true) or // during SetRemoteDescription (`local` == false). Passing `local` helps to // differentiate initiator (caller) from answerer (callee). RTCError MaybeCreateJsepTransport(bool local, const ContentInfo& content_info, const SessionDescription& description) RTC_RUN_ON(network_thread_); void DestroyAllJsepTransports_n() RTC_RUN_ON(network_thread_); void SetIceRole_n(IceRole ice_role) RTC_RUN_ON(network_thread_); IceRole DetermineIceRole(JsepTransport* jsep_transport, const TransportInfo& transport_info, SdpType type, bool local); std::unique_ptr CreateDtlsTransport( const ContentInfo& content_info, bool rtcp); scoped_refptr CreateIceTransport( absl::string_view transport_name, bool rtcp); std::unique_ptr CreateUnencryptedRtpTransport( absl::string_view transport_name, std::unique_ptr rtp_packet_transport, std::unique_ptr rtcp_packet_transport); // Creates a DTLS SRTP transport. std::unique_ptr CreateDtlsSrtpTransport( absl::string_view transport_name, std::unique_ptr rtp_dtls_transport, std::unique_ptr rtcp_dtls_transport); std::unique_ptr CreateRtpTransport( absl::string_view transport_name, std::unique_ptr rtp_dtls_transport, std::unique_ptr rtcp_dtls_transport); // Collect all the DtlsTransports, including RTP and RTCP, from the // JsepTransports, including those not mapped to a MID because they are being // kept alive in case of rollback. std::vector GetDtlsTransports(); // Same as the above, but doesn't include rollback transports. // JsepTransportController can iterate all the DtlsTransports and update the // aggregate states. std::vector GetActiveDtlsTransports(); // Handlers for signals from Transport. void OnTransportWritableState_n(PacketTransportInternal* transport) RTC_RUN_ON(network_thread_); void OnTransportReceivingState_n(PacketTransportInternal* transport) RTC_RUN_ON(network_thread_); void OnTransportGatheringState_n(IceTransportInternal* transport) RTC_RUN_ON(network_thread_); void OnTransportCandidateGathered_n(IceTransportInternal* transport, const Candidate& candidate) RTC_RUN_ON(network_thread_); void OnTransportCandidateError_n(IceTransportInternal* transport, const IceCandidateErrorEvent& event) RTC_RUN_ON(network_thread_); void OnTransportCandidatesRemoved_n(IceTransportInternal* transport, const Candidates& candidates) RTC_RUN_ON(network_thread_); void OnTransportRoleConflict_n(IceTransportInternal* transport) RTC_RUN_ON(network_thread_); void OnTransportStateChanged_n(IceTransportInternal* transport) RTC_RUN_ON(network_thread_); void OnTransportCandidatePairChanged_n(const CandidatePairChangeEvent& event) RTC_RUN_ON(network_thread_); void UpdateAggregateStates_n() RTC_RUN_ON(network_thread_); void OnRtcpPacketReceived_n(CopyOnWriteBuffer packet, std::optional arrival_time, EcnMarking ecn) RTC_RUN_ON(network_thread_); void OnUnDemuxableRtpPacketReceived_n(const RtpPacketReceived& packet) RTC_RUN_ON(network_thread_); void OnDtlsHandshakeError(SSLHandshakeError error); bool OnTransportChanged(absl::string_view mid, JsepTransport* transport); const Environment env_; TaskQueueBase* const signaling_thread_; Thread* const network_thread_; PortAllocator* const port_allocator_ = nullptr; AsyncDnsResolverFactoryInterface* const async_dns_resolver_factory_ = nullptr; LocalNetworkAccessPermissionFactoryInterface* const lna_permission_factory_ = nullptr; JsepTransportCollection transports_ RTC_GUARDED_BY(network_thread_); // Aggregate states for Transports. // standardized_ice_connection_state_ is intended to replace // ice_connection_state, see bugs.webrtc.org/9308 IceConnectionState ice_connection_state_ = kIceConnectionConnecting; PeerConnectionInterface::IceConnectionState standardized_ice_connection_state_ = PeerConnectionInterface::kIceConnectionNew; PeerConnectionInterface::PeerConnectionState combined_connection_state_ = PeerConnectionInterface::PeerConnectionState::kNew; IceGatheringState ice_gathering_state_ = kIceGatheringNew; const Config config_; IceConfig ice_config_; IceRole ice_role_ = ICEROLE_CONTROLLING; scoped_refptr certificate_; BundleManager bundles_; }; } // namespace webrtc #endif // PC_JSEP_TRANSPORT_CONTROLLER_H_