text: // Copyright 2020 The Fuchsia Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_TESTING_FAKE_DYNAMIC_CHANNEL_H_
  #define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_TESTING_FAKE_DYNAMIC_CHANNEL_H_
  
  #include <lib/fit/function.h>
  
  #include <memory>
  
  #include "src/connectivity/bluetooth/core/bt-host/common/byte_buffer.h"
  #include "src/connectivity/bluetooth/core/bt-host/hci/hci.h"
  #include "src/connectivity/bluetooth/core/bt-host/l2cap/l2cap_defs.h"
  #include "src/lib/fxl/memory/ref_ptr.h"
  #include "src/lib/fxl/memory/weak_ptr.h"
  
  namespace bt {
  namespace testing {
  
  // Manages individual FakeDynamicChannel instances as created by
  // FakeSignalingServer. There are two potential states that an indiviudal
  // channel can be in - open and closed.
  // If the channel is open, then device has received a ConnectionRequest
  // associated with this channel, sent out a corresponding ConfigurationRequest,
  // and received a ConfigurationRequest in response. The channel is ready to
  // handle packets.
  // Closed: The channel is not ready to handle packets. It may still be
  // registered with the FakeL2cap instance managing it.
  // Note that when the device has received a ConnectionRequest and sent out a
  // ConfigurationRequest but is still awaiting a ConfigurationRequest from
  // bt-host, it will still be connected (as there will be a local channel ID
  // assigned to it) but it is not Open state.
  class FakeDynamicChannel {
   public:
    // Callback associated with handling packet |sdu| sent across the channel.
    // Set by the service associated with the channel's PSM.
    using PacketHandlerCallback = fit::function<void(const ByteBuffer& sdu)>;
  
    // Callback associated with sending packet |sdu| through this dynamic
    // channel. Set by the service associated with the channel's PSM.
    using SendPacketCallback = fit::function<void(const ByteBuffer& sdu)>;
  
    // Callback associated with closing and tearing down this dynamic channel.
    // Set by the service associated with the channel's PSM.
    using ChannelDeletedCallback = fit::function<void()>;
  
    // Create a FakeDynamicChannel with Connection Handle |conn|, Protocol
    // Service Multiplexer (PSM) |psm| locally registered Channel ID |local_cid|,
    // and remote Channel ID |remote_cid|. Set to closed upon creation.
    FakeDynamicChannel(hci::ConnectionHandle conn, l2cap::PSM psm, l2cap::ChannelId local_cid,
                       l2cap::ChannelId remote_cid);
  
    // Call the ChannelDeletedCallback instance associated with the server upon
    // destroying the channel instance.
    ~FakeDynamicChannel() {
      if (channel_deleted_callback_) {
        channel_deleted_callback_();
      }
    }
  
    void set_opened() { opened_ = true; }
    void set_closed() { opened_ = false; }
    void set_configuration_request_received() { configuration_request_received_ = true; }
    void set_configuration_response_received() { configuration_response_received_ = true; }
    void set_packet_handler_callback(PacketHandlerCallback packet_handler_callback) {
      packet_handler_callback_ = std::move(packet_handler_callback);
    }
    void set_send_packet_callback(SendPacketCallback send_packet_callback) {
      send_packet_callback_ = std::move(send_packet_callback);
    }
    void set_channel_deleted_callback(ChannelDeletedCallback channel_deleted_callback) {
      channel_deleted_callback_ = std::move(channel_deleted_callback);
    }
  
    hci::ConnectionHandle handle() const { return handle_; }
    bool opened() const { return opened_; }
    bool configuration_request_received() const { return configuration_request_received_; }
    bool configuration_response_received() const { return configuration_response_received_; }
    l2cap::PSM psm() const { return psm_; }
    l2cap::ChannelId local_cid() const { return local_cid_; }
    l2cap::ChannelId remote_cid() const { return remote_cid_; }
    PacketHandlerCallback& packet_handler_callback() { return packet_handler_callback_; }
    SendPacketCallback& send_packet_callback() { return send_packet_callback_; }
    ChannelDeletedCallback& channel_deleted_callback() { return channel_deleted_callback_; }
  
    // Return a WeakPtr instance of this FakeDynamicChannel
    fxl::WeakPtr<FakeDynamicChannel> AsWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); }
  
   private:
    // ConnectionHandle associated with what
    hci::ConnectionHandle handle_;
  
    // If the device is connected  and so is ready to communicate over the channel.
    bool opened_;
  
    // If the initial ConfigurationRequest needed to open the channel has been
    // received. There must be a ConfigurationRequest and ConfigurationResponse
    // received in order to open up the channel.
    bool configuration_request_received_;
  
    // If the initial ConfigurationResponse needed to open the channel has been
    // received. There must be a ConfigurationRequest and ConfigurationResponse
    // received in order to open up the channel.
    bool configuration_response_received_;
  
    // The Protocol Service Multiplexer (PSM) associated with the channel.
    const l2cap::PSM psm_;
  
    // Identifies the local device's endpoint of this channel. Will be unique on
    // this device as long as this channel remains open.
    const l2cap::ChannelId local_cid_;
  
    // Identifies the endpoint of this channel on the peer device. Set upon
    // connection completion.
    const l2cap::ChannelId remote_cid_;
  
    // Callback associated with handling data packets sent to this channel.
    PacketHandlerCallback packet_handler_callback_;
  
    // Callback associated with sending data packets using this channel.
    SendPacketCallback send_packet_callback_;
  
    // Callback associated with closing the dynamic channel.
    ChannelDeletedCallback channel_deleted_callback_;
  
    // Any management of FakeDynamicChannel instances outside of FakeL2cap
    // should be done through the use of WeakPtrs.
    fxl::WeakPtrFactory<FakeDynamicChannel> weak_ptr_factory_;
  
    DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(FakeDynamicChannel);
  };
  
  }  // namespace testing
  }  // namespace bt
  
  #endif  // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_TESTING_FAKE_DYNAMIC_CHANNEL_H_
  