123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- /*
- * Copyright (c) 2012 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 MEDIA_SCTP_SCTP_TRANSPORT_H_
- #define MEDIA_SCTP_SCTP_TRANSPORT_H_
- #include <errno.h>
- #include <cstdint>
- #include <map>
- #include <memory>
- #include <set>
- #include <string>
- #include <vector>
- #include "absl/types/optional.h"
- #include "api/transport/sctp_transport_factory_interface.h"
- #include "rtc_base/async_invoker.h"
- #include "rtc_base/buffer.h"
- #include "rtc_base/constructor_magic.h"
- #include "rtc_base/copy_on_write_buffer.h"
- #include "rtc_base/third_party/sigslot/sigslot.h"
- #include "rtc_base/thread.h"
- // For SendDataParams/ReceiveDataParams.
- #include "media/base/media_channel.h"
- #include "media/sctp/sctp_transport_internal.h"
- // Defined by "usrsctplib/usrsctp.h"
- struct sockaddr_conn;
- struct sctp_assoc_change;
- struct sctp_rcvinfo;
- struct sctp_stream_reset_event;
- struct sctp_sendv_spa;
- // Defined by <sys/socket.h>
- struct socket;
- namespace cricket {
- // Holds data to be passed on to a transport.
- struct SctpInboundPacket;
- // From transport calls, data flows like this:
- // [network thread (although it can in princple be another thread)]
- // 1. SctpTransport::SendData(data)
- // 2. usrsctp_sendv(data)
- // [network thread returns; sctp thread then calls the following]
- // 3. OnSctpOutboundPacket(wrapped_data)
- // [sctp thread returns having async invoked on the network thread]
- // 4. SctpTransport::OnPacketFromSctpToNetwork(wrapped_data)
- // 5. DtlsTransport::SendPacket(wrapped_data)
- // 6. ... across network ... a packet is sent back ...
- // 7. SctpTransport::OnPacketReceived(wrapped_data)
- // 8. usrsctp_conninput(wrapped_data)
- // [network thread returns; sctp thread then calls the following]
- // 9. OnSctpInboundData(data)
- // 10. SctpTransport::OnDataFromSctpToTransport(data)
- // [sctp thread returns having async invoked on the network thread]
- // 11. SctpTransport::OnDataFromSctpToTransport(data)
- // 12. SctpTransport::SignalDataReceived(data)
- // [from the same thread, methods registered/connected to
- // SctpTransport are called with the recieved data]
- class SctpTransport : public SctpTransportInternal,
- public sigslot::has_slots<> {
- public:
- // |network_thread| is where packets will be processed and callbacks from
- // this transport will be posted, and is the only thread on which public
- // methods can be called.
- // |transport| is not required (can be null).
- SctpTransport(rtc::Thread* network_thread,
- rtc::PacketTransportInternal* transport);
- ~SctpTransport() override;
- // SctpTransportInternal overrides (see sctptransportinternal.h for comments).
- void SetDtlsTransport(rtc::PacketTransportInternal* transport) override;
- bool Start(int local_port, int remote_port, int max_message_size) override;
- bool OpenStream(int sid) override;
- bool ResetStream(int sid) override;
- bool SendData(const SendDataParams& params,
- const rtc::CopyOnWriteBuffer& payload,
- SendDataResult* result = nullptr) override;
- bool ReadyToSendData() override;
- int max_message_size() const override { return max_message_size_; }
- absl::optional<int> max_outbound_streams() const override {
- return max_outbound_streams_;
- }
- absl::optional<int> max_inbound_streams() const override {
- return max_inbound_streams_;
- }
- void set_debug_name_for_testing(const char* debug_name) override {
- debug_name_ = debug_name;
- }
- int InjectDataOrNotificationFromSctpForTesting(void* data,
- size_t length,
- struct sctp_rcvinfo rcv,
- int flags);
- // Exposed to allow Post call from c-callbacks.
- // TODO(deadbeef): Remove this or at least make it return a const pointer.
- rtc::Thread* network_thread() const { return network_thread_; }
- private:
- // A message to be sent by the sctp library. This class is used to track the
- // progress of writing a single message to the sctp library in the presence of
- // partial writes. In this case, the Advance() function is provided in order
- // to advance over what has already been accepted by the sctp library and
- // avoid copying the remaining partial message buffer.
- class OutgoingMessage {
- public:
- OutgoingMessage(const rtc::CopyOnWriteBuffer& buffer,
- const SendDataParams& send_params)
- : buffer_(buffer), send_params_(send_params) {}
- // Advances the buffer by the incremented amount. Must not advance further
- // than the current data size.
- void Advance(size_t increment) {
- RTC_DCHECK_LE(increment + offset_, buffer_.size());
- offset_ += increment;
- }
- size_t size() const { return buffer_.size() - offset_; }
- const void* data() const { return buffer_.data() + offset_; }
- SendDataParams send_params() const { return send_params_; }
- private:
- const rtc::CopyOnWriteBuffer buffer_;
- const SendDataParams send_params_;
- size_t offset_ = 0;
- };
- void ConnectTransportSignals();
- void DisconnectTransportSignals();
- // Creates the socket and connects.
- bool Connect();
- // Returns false when opening the socket failed.
- bool OpenSctpSocket();
- // Helpet method to set socket options.
- bool ConfigureSctpSocket();
- // Sets |sock_ |to nullptr.
- void CloseSctpSocket();
- // Sends a SCTP_RESET_STREAM for all streams in closing_ssids_.
- bool SendQueuedStreamResets();
- // Sets the "ready to send" flag and fires signal if needed.
- void SetReadyToSendData();
- // Sends the outgoing buffered message that was only partially accepted by the
- // sctp lib because it did not have enough space. Returns true if the entire
- // buffered message was accepted by the sctp lib.
- bool SendBufferedMessage();
- // Tries to send the |payload| on the usrsctp lib. The message will be
- // advanced by the amount that was sent.
- SendDataResult SendMessageInternal(OutgoingMessage* message);
- // Callbacks from DTLS transport.
- void OnWritableState(rtc::PacketTransportInternal* transport);
- virtual void OnPacketRead(rtc::PacketTransportInternal* transport,
- const char* data,
- size_t len,
- const int64_t& packet_time_us,
- int flags);
- void OnClosed(rtc::PacketTransportInternal* transport);
- // Methods related to usrsctp callbacks.
- void OnSendThresholdCallback();
- sockaddr_conn GetSctpSockAddr(int port);
- // Called using |invoker_| to send packet on the network.
- void OnPacketFromSctpToNetwork(const rtc::CopyOnWriteBuffer& buffer);
- // Called on the SCTP thread.
- // Flags are standard socket API flags (RFC 6458).
- int OnDataOrNotificationFromSctp(void* data,
- size_t length,
- struct sctp_rcvinfo rcv,
- int flags);
- // Called using |invoker_| to decide what to do with the data.
- void OnDataFromSctpToTransport(const ReceiveDataParams& params,
- const rtc::CopyOnWriteBuffer& buffer);
- // Called using |invoker_| to decide what to do with the notification.
- void OnNotificationFromSctp(const rtc::CopyOnWriteBuffer& buffer);
- void OnNotificationAssocChange(const sctp_assoc_change& change);
- void OnStreamResetEvent(const struct sctp_stream_reset_event* evt);
- // Responsible for marshalling incoming data to the transports listeners, and
- // outgoing data to the network interface.
- rtc::Thread* network_thread_;
- // Helps pass inbound/outbound packets asynchronously to the network thread.
- rtc::AsyncInvoker invoker_;
- // Underlying DTLS transport.
- rtc::PacketTransportInternal* transport_ = nullptr;
- // Track the data received from usrsctp between callbacks until the EOR bit
- // arrives.
- rtc::CopyOnWriteBuffer partial_incoming_message_;
- ReceiveDataParams partial_params_;
- int partial_flags_;
- // A message that was attempted to be sent, but was only partially accepted by
- // usrsctp lib with usrsctp_sendv() because it cannot buffer the full message.
- // This occurs because we explicitly set the EOR bit when sending, so
- // usrsctp_sendv() is not atomic.
- absl::optional<OutgoingMessage> partial_outgoing_message_;
- bool was_ever_writable_ = false;
- int local_port_ = kSctpDefaultPort;
- int remote_port_ = kSctpDefaultPort;
- int max_message_size_ = kSctpSendBufferSize;
- struct socket* sock_ = nullptr; // The socket created by usrsctp_socket(...).
- // Has Start been called? Don't create SCTP socket until it has.
- bool started_ = false;
- // Are we ready to queue data (SCTP socket created, and not blocked due to
- // congestion control)? Different than |transport_|'s "ready to send".
- bool ready_to_send_data_ = false;
- // Used to keep track of the status of each stream (or rather, each pair of
- // incoming/outgoing streams with matching IDs). It's specifically used to
- // keep track of the status of resets, but more information could be put here
- // later.
- //
- // See datachannel.h for a summary of the closing procedure.
- struct StreamStatus {
- // Closure initiated by application via ResetStream? Note that
- // this may be true while outgoing_reset_initiated is false if the outgoing
- // reset needed to be queued.
- bool closure_initiated = false;
- // Whether we've initiated the outgoing stream reset via
- // SCTP_RESET_STREAMS.
- bool outgoing_reset_initiated = false;
- // Whether usrsctp has indicated that the incoming/outgoing streams have
- // been reset. It's expected that the peer will reset its outgoing stream
- // (our incoming stream) after receiving the reset for our outgoing stream,
- // though older versions of chromium won't do this. See crbug.com/559394
- // for context.
- bool outgoing_reset_complete = false;
- bool incoming_reset_complete = false;
- // Some helper methods to improve code readability.
- bool is_open() const {
- return !closure_initiated && !incoming_reset_complete &&
- !outgoing_reset_complete;
- }
- // We need to send an outgoing reset if the application has closed the data
- // channel, or if we received a reset of the incoming stream from the
- // remote endpoint, indicating the data channel was closed remotely.
- bool need_outgoing_reset() const {
- return (incoming_reset_complete || closure_initiated) &&
- !outgoing_reset_initiated;
- }
- bool reset_complete() const {
- return outgoing_reset_complete && incoming_reset_complete;
- }
- };
- // Entries should only be removed from this map if |reset_complete| is
- // true.
- std::map<uint32_t, StreamStatus> stream_status_by_sid_;
- // A static human-readable name for debugging messages.
- const char* debug_name_ = "SctpTransport";
- // Hides usrsctp interactions from this header file.
- class UsrSctpWrapper;
- // Number of channels negotiated. Not set before negotiation completes.
- absl::optional<int> max_outbound_streams_;
- absl::optional<int> max_inbound_streams_;
- // Used for associating this transport with the underlying sctp socket in
- // various callbacks.
- uintptr_t id_ = 0;
- RTC_DISALLOW_COPY_AND_ASSIGN(SctpTransport);
- };
- class SctpTransportFactory : public webrtc::SctpTransportFactoryInterface {
- public:
- explicit SctpTransportFactory(rtc::Thread* network_thread)
- : network_thread_(network_thread) {}
- std::unique_ptr<SctpTransportInternal> CreateSctpTransport(
- rtc::PacketTransportInternal* transport) override {
- return std::unique_ptr<SctpTransportInternal>(
- new SctpTransport(network_thread_, transport));
- }
- private:
- rtc::Thread* network_thread_;
- };
- } // namespace cricket
- #endif // MEDIA_SCTP_SCTP_TRANSPORT_H_
|