/* * Copyright 2020 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_SCTP_DATA_CHANNEL_H_ #define PC_SCTP_DATA_CHANNEL_H_ #include #include #include #include #include "absl/types/optional.h" #include "api/data_channel_interface.h" #include "api/priority.h" #include "api/rtc_error.h" #include "api/scoped_refptr.h" #include "api/sequence_checker.h" #include "api/task_queue/pending_task_safety_flag.h" #include "api/transport/data_channel_transport_interface.h" #include "pc/data_channel_utils.h" #include "pc/sctp_utils.h" #include "rtc_base/containers/flat_set.h" #include "rtc_base/copy_on_write_buffer.h" #include "rtc_base/ssl_stream_adapter.h" // For SSLRole #include "rtc_base/system/no_unique_address.h" #include "rtc_base/thread.h" #include "rtc_base/thread_annotations.h" #include "rtc_base/weak_ptr.h" namespace webrtc { class SctpDataChannel; // Interface that acts as a bridge from the data channel to the transport. // All methods in this interface need to be invoked on the network thread. class SctpDataChannelControllerInterface { public: // Sends the data to the transport. virtual RTCError SendData(StreamId sid, const SendDataParams& params, const rtc::CopyOnWriteBuffer& payload) = 0; // Adds the data channel SID to the transport for SCTP. virtual void AddSctpDataStream(StreamId sid) = 0; // Begins the closing procedure by sending an outgoing stream reset. Still // need to wait for callbacks to tell when this completes. virtual void RemoveSctpDataStream(StreamId sid) = 0; // Notifies the controller of state changes. virtual void OnChannelStateChanged(SctpDataChannel* data_channel, DataChannelInterface::DataState state) = 0; protected: virtual ~SctpDataChannelControllerInterface() {} }; struct InternalDataChannelInit : public DataChannelInit { enum OpenHandshakeRole { kOpener, kAcker, kNone }; // The default role is kOpener because the default `negotiated` is false. InternalDataChannelInit() : open_handshake_role(kOpener) {} explicit InternalDataChannelInit(const DataChannelInit& base); // Does basic validation to determine if a data channel instance can be // constructed using the configuration. bool IsValid() const; OpenHandshakeRole open_handshake_role; // Optional fallback or backup flag from PC that's used for non-prenegotiated // stream ids in situations where we cannot determine the SSL role from the // transport for purposes of generating a stream ID. // See: https://www.rfc-editor.org/rfc/rfc8832.html#name-protocol-overview absl::optional fallback_ssl_role; }; // Helper class to allocate unique IDs for SCTP DataChannels. class SctpSidAllocator { public: SctpSidAllocator() = default; // Gets the first unused odd/even id based on the DTLS role. If `role` is // SSL_CLIENT, the allocated id starts from 0 and takes even numbers; // otherwise, the id starts from 1 and takes odd numbers. // If a `StreamId` cannot be allocated, `StreamId::HasValue()` will be false. StreamId AllocateSid(rtc::SSLRole role); // Attempts to reserve a specific sid. Returns false if it's unavailable. bool ReserveSid(StreamId sid); // Indicates that `sid` isn't in use any more, and is thus available again. void ReleaseSid(StreamId sid); private: flat_set used_sids_ RTC_GUARDED_BY(&sequence_checker_); RTC_NO_UNIQUE_ADDRESS SequenceChecker sequence_checker_{ SequenceChecker::kDetached}; }; // SctpDataChannel is an implementation of the DataChannelInterface based on // SctpTransport. It provides an implementation of unreliable or // reliable data channels. // DataChannel states: // kConnecting: The channel has been created the transport might not yet be // ready. // kOpen: The open handshake has been performed (if relevant) and the data // channel is able to send messages. // kClosing: DataChannelInterface::Close has been called, or the remote side // initiated the closing procedure, but the closing procedure has not // yet finished. // kClosed: The closing handshake is finished (possibly initiated from this, // side, possibly from the peer). // // How the closing procedure works for SCTP: // 1. Alice calls Close(), state changes to kClosing. // 2. Alice finishes sending any queued data. // 3. Alice calls RemoveSctpDataStream, sends outgoing stream reset. // 4. Bob receives incoming stream reset; OnClosingProcedureStartedRemotely // called. // 5. Bob sends outgoing stream reset. // 6. Alice receives incoming reset, Bob receives acknowledgement. Both receive // OnClosingProcedureComplete callback and transition to kClosed. class SctpDataChannel : public DataChannelInterface { public: static rtc::scoped_refptr Create( rtc::WeakPtr controller, const std::string& label, bool connected_to_transport, const InternalDataChannelInit& config, rtc::Thread* signaling_thread, rtc::Thread* network_thread); // Instantiates an API proxy for a SctpDataChannel instance that will be // handed out to external callers. // The `signaling_safety` flag is used for the ObserverAdapter callback proxy // which delivers callbacks on the signaling thread but must not deliver such // callbacks after the peerconnection has been closed. The data controller // will update the flag when closed, which will cancel any pending event // notifications. static rtc::scoped_refptr CreateProxy( rtc::scoped_refptr channel, rtc::scoped_refptr signaling_safety); void RegisterObserver(DataChannelObserver* observer) override; void UnregisterObserver() override; std::string label() const override; bool reliable() const override; bool ordered() const override; // Backwards compatible accessors uint16_t maxRetransmitTime() const override; uint16_t maxRetransmits() const override; absl::optional maxPacketLifeTime() const override; absl::optional maxRetransmitsOpt() const override; std::string protocol() const override; bool negotiated() const override; int id() const override; Priority priority() const override; uint64_t buffered_amount() const override; void Close() override; DataState state() const override; RTCError error() const override; uint32_t messages_sent() const override; uint64_t bytes_sent() const override; uint32_t messages_received() const override; uint64_t bytes_received() const override; bool Send(const DataBuffer& buffer) override; void SendAsync(DataBuffer buffer, absl::AnyInvocable on_complete) override; // Close immediately, ignoring any queued data or closing procedure. // This is called when the underlying SctpTransport is being destroyed. // It is also called by the PeerConnection if SCTP ID assignment fails. void CloseAbruptlyWithError(RTCError error); // Specializations of CloseAbruptlyWithError void CloseAbruptlyWithDataChannelFailure(const std::string& message); // Called when the SctpTransport's ready to use. That can happen when we've // finished negotiation, or if the channel was created after negotiation has // already finished. void OnTransportReady(); void OnDataReceived(DataMessageType type, const rtc::CopyOnWriteBuffer& payload); // Sets the SCTP sid and adds to transport layer if not set yet. Should only // be called once. void SetSctpSid_n(StreamId sid); // The remote side started the closing procedure by resetting its outgoing // stream (our incoming stream). Sets state to kClosing. void OnClosingProcedureStartedRemotely(); // The closing procedure is complete; both incoming and outgoing stream // resets are done and the channel can transition to kClosed. Called // asynchronously after RemoveSctpDataStream. void OnClosingProcedureComplete(); // Called when the transport channel is created. void OnTransportChannelCreated(); // Called when the transport channel is unusable. // This method makes sure the DataChannel is disconnected and changes state // to kClosed. void OnTransportChannelClosed(RTCError error); DataChannelStats GetStats() const; // Returns a unique identifier that's guaranteed to always be available, // doesn't change throughout SctpDataChannel's lifetime and is used for // stats purposes (see also `GetStats()`). int internal_id() const { return internal_id_; } StreamId sid_n() const { RTC_DCHECK_RUN_ON(network_thread_); return id_n_; } // Reset the allocator for internal ID values for testing, so that // the internal IDs generated are predictable. Test only. static void ResetInternalIdAllocatorForTesting(int new_value); protected: SctpDataChannel(const InternalDataChannelInit& config, rtc::WeakPtr controller, const std::string& label, bool connected_to_transport, rtc::Thread* signaling_thread, rtc::Thread* network_thread); ~SctpDataChannel() override; private: class ObserverAdapter; // The OPEN(_ACK) signaling state. enum HandshakeState { kHandshakeInit, kHandshakeShouldSendOpen, kHandshakeShouldSendAck, kHandshakeWaitingForAck, kHandshakeReady }; RTCError SendImpl(DataBuffer buffer) RTC_RUN_ON(network_thread_); void UpdateState() RTC_RUN_ON(network_thread_); void SetState(DataState state) RTC_RUN_ON(network_thread_); void DeliverQueuedReceivedData() RTC_RUN_ON(network_thread_); void SendQueuedDataMessages() RTC_RUN_ON(network_thread_); RTCError SendDataMessage(const DataBuffer& buffer, bool queue_if_blocked) RTC_RUN_ON(network_thread_); bool QueueSendDataMessage(const DataBuffer& buffer) RTC_RUN_ON(network_thread_); void SendQueuedControlMessages() RTC_RUN_ON(network_thread_); bool SendControlMessage(const rtc::CopyOnWriteBuffer& buffer) RTC_RUN_ON(network_thread_); bool connected_to_transport() const RTC_RUN_ON(network_thread_) { return network_safety_->alive(); } rtc::Thread* const signaling_thread_; rtc::Thread* const network_thread_; StreamId id_n_ RTC_GUARDED_BY(network_thread_); const int internal_id_; const std::string label_; const std::string protocol_; const absl::optional max_retransmit_time_; const absl::optional max_retransmits_; const absl::optional priority_; const bool negotiated_; const bool ordered_; DataChannelObserver* observer_ RTC_GUARDED_BY(network_thread_) = nullptr; std::unique_ptr observer_adapter_; DataState state_ RTC_GUARDED_BY(network_thread_) = kConnecting; RTCError error_ RTC_GUARDED_BY(network_thread_); uint32_t messages_sent_ RTC_GUARDED_BY(network_thread_) = 0; uint64_t bytes_sent_ RTC_GUARDED_BY(network_thread_) = 0; uint32_t messages_received_ RTC_GUARDED_BY(network_thread_) = 0; uint64_t bytes_received_ RTC_GUARDED_BY(network_thread_) = 0; rtc::WeakPtr controller_ RTC_GUARDED_BY(network_thread_); HandshakeState handshake_state_ RTC_GUARDED_BY(network_thread_) = kHandshakeInit; // Did we already start the graceful SCTP closing procedure? bool started_closing_procedure_ RTC_GUARDED_BY(network_thread_) = false; // Control messages that always have to get sent out before any queued // data. PacketQueue queued_control_data_ RTC_GUARDED_BY(network_thread_); PacketQueue queued_received_data_ RTC_GUARDED_BY(network_thread_); PacketQueue queued_send_data_ RTC_GUARDED_BY(network_thread_); rtc::scoped_refptr network_safety_ = PendingTaskSafetyFlag::CreateDetachedInactive(); }; } // namespace webrtc #endif // PC_SCTP_DATA_CHANNEL_H_