text: /*
   *  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/buffer.h"
  #include "rtc_base/constructor_magic.h"
  #include "rtc_base/copy_on_write_buffer.h"
  #include "rtc_base/task_utils/pending_task_safety_flag.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.
    webrtc::ScopedTaskSafety task_safety_;
    // 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_
  