1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #pragma once
16 
17 #include <fuchsia/bluetooth/cpp/fidl.h>
18 
19 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/server_base.h"
20 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
21 #include "pw_bluetooth_sapphire/internal/host/common/weak_self.h"
22 
23 namespace bthost {
24 
25 // ChannelServer relays packets and disconnections between the
26 // Connection FIDL protocol and a corresponding L2CAP channel.
27 class ChannelServer : public ServerBase<fuchsia::bluetooth::Channel> {
28  public:
29   // The number of inbound packets to queue in this class.
30   static constexpr size_t kDefaultReceiveQueueLimit = 20;
31 
32   // `channel` is the Channel that this ChannelServer corresponds to. This
33   // server will activate and manage the lifetime of this channel.
34   // `closed_callback` will be called when either the fuchsia.bluetooth.Channel
35   // protocol or the L2CAP channel closes. Returns nullptr on failure (failure
36   // to activate the Channel).
37   static std::unique_ptr<ChannelServer> Create(
38       fidl::InterfaceRequest<fuchsia::bluetooth::Channel> request,
39       bt::l2cap::Channel::WeakPtr channel,
40       fit::callback<void()> closed_callback);
41 
42   ~ChannelServer() override;
43 
44  private:
45   enum class State {
46     kActivating,  // Default state.
47     kActivated,
48     kDeactivating,
49     kDeactivated,
50   };
51 
52   ChannelServer(fidl::InterfaceRequest<fuchsia::bluetooth::Channel> request,
53                 bt::l2cap::Channel::WeakPtr channel,
54                 fit::callback<void()> closed_callback);
55 
56   // fuchsia::bluetooth::Channel overrides:
57   void Send(std::vector<::fuchsia::bluetooth::Packet> packets,
58             SendCallback callback) override;
59   void Receive(ReceiveCallback callback) override;
60   void WatchChannelParameters(WatchChannelParametersCallback callback) override;
61   void handle_unknown_method(uint64_t ordinal,
62                              bool method_has_response) override;
63 
64   bool Activate();
65   void Deactivate();
66 
67   void OnChannelDataReceived(bt::ByteBufferPtr rx_data);
68   void OnChannelClosed();
69   void OnProtocolClosed();
70   void DeactivateAndRequestDestruction();
71   void ServiceReceiveQueue();
72 
73   bt::l2cap::Channel::WeakPtr channel_;
74 
75   // The maximum number of inbound packets to queue when the FIDL protocol is
76   // full.
77   const size_t receive_queue_max_frames_ = kDefaultReceiveQueueLimit;
78 
79   // We use a std::deque here to minimize the number dynamic memory allocations
80   // (cf. std::list, which would require allocation on each SDU). This comes,
81   // however, at the cost of higher memory usage when the number of SDUs is
82   // small. (libc++ uses a minimum of 4KB per deque.)
83   std::deque<bt::ByteBufferPtr> receive_queue_;
84 
85   // Client callback called when either FIDL protocol closes or L2CAP channel
86   // closes.
87   fit::callback<void()> closed_cb_;
88 
89   // Callback for pending Channel::Receive() call.
90   ReceiveCallback receive_cb_ = nullptr;
91 
92   // Pending callback for a WatchChannelParameters call.
93   std::optional<WatchChannelParametersCallback>
94       pending_watch_channel_parameters_;
95 
96   State state_ = State::kActivating;
97 
98   WeakSelf<ChannelServer> weak_self_;  // Keep last.
99 };
100 
101 }  // namespace bthost
102