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/bredr/cpp/fidl.h>
18 
19 #include "lib/fidl/cpp/binding.h"
20 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/channel_server.h"
21 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/server_base.h"
22 #include "pw_bluetooth_sapphire/fuchsia/host/socket/socket_factory.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
24 #include "pw_bluetooth_sapphire/internal/host/gap/bredr_connection_manager.h"
25 #include "pw_bluetooth_sapphire/internal/host/sdp/server.h"
26 #include "pw_intrusive_ptr/intrusive_ptr.h"
27 
28 namespace bthost {
29 
30 // Implements the bredr::Profile FIDL interface.
31 class ProfileServer : public ServerBase<fuchsia::bluetooth::bredr::Profile> {
32  public:
33   ProfileServer(
34       bt::gap::Adapter::WeakPtr adapter,
35       fidl::InterfaceRequest<fuchsia::bluetooth::bredr::Profile> request);
36   ~ProfileServer() override;
37 
38   // If true, use Channel.socket. If false, use Channel.connection.
39   // TODO(fxbug.dev/330590954): Remove once migration to Connection is complete.
set_use_sockets(bool enable)40   void set_use_sockets(bool enable) { use_sockets_ = enable; }
41 
42  private:
43   class AudioDirectionExt;
44 
45   class L2capParametersExt final
46       : public ServerBase<fuchsia::bluetooth::bredr::L2capParametersExt> {
47    public:
L2capParametersExt(fidl::InterfaceRequest<fuchsia::bluetooth::bredr::L2capParametersExt> request,bt::l2cap::Channel::WeakPtr channel)48     L2capParametersExt(
49         fidl::InterfaceRequest<fuchsia::bluetooth::bredr::L2capParametersExt>
50             request,
51         bt::l2cap::Channel::WeakPtr channel)
52         : ServerBase(this, std::move(request)),
53           unique_id_(channel->unique_id()),
54           channel_(std::move(channel)) {}
55 
unique_id()56     bt::l2cap::Channel::UniqueId unique_id() const { return unique_id_; }
57 
58     void RequestParameters(fuchsia::bluetooth::ChannelParameters requested,
59                            RequestParametersCallback callback) override;
60 
61     void handle_unknown_method(uint64_t ordinal,
62                                bool method_has_response) override;
63 
64    private:
65     bt::l2cap::Channel::UniqueId unique_id_;
66     bt::l2cap::Channel::WeakPtr channel_;
67   };
68 
69   class AudioOffloadExt final
70       : public ServerBase<fuchsia::bluetooth::bredr::AudioOffloadExt> {
71    public:
AudioOffloadExt(ProfileServer & profile_server,fidl::InterfaceRequest<fuchsia::bluetooth::bredr::AudioOffloadExt> request,bt::l2cap::Channel::WeakPtr channel,bt::gap::Adapter::WeakPtr adapter)72     AudioOffloadExt(
73         ProfileServer& profile_server,
74         fidl::InterfaceRequest<fuchsia::bluetooth::bredr::AudioOffloadExt>
75             request,
76         bt::l2cap::Channel::WeakPtr channel,
77         bt::gap::Adapter::WeakPtr adapter)
78         : ServerBase(this, std::move(request)),
79           profile_server_(profile_server),
80           unique_id_(channel->unique_id()),
81           channel_(std::move(channel)),
82           adapter_(std::move(adapter)) {}
83     void GetSupportedFeatures(GetSupportedFeaturesCallback callback) override;
84     void StartAudioOffload(
85         fuchsia::bluetooth::bredr::AudioOffloadConfiguration
86             audio_offload_configuration,
87         fidl::InterfaceRequest<
88             fuchsia::bluetooth::bredr::AudioOffloadController> controller)
89         override;
90 
unique_id()91     bt::l2cap::Channel::UniqueId unique_id() const { return unique_id_; }
92 
93     void handle_unknown_method(uint64_t ordinal,
94                                bool method_has_response) override;
95 
96    private:
97     std::unique_ptr<bt::l2cap::A2dpOffloadManager::Configuration>
98     AudioOffloadConfigFromFidl(
99         fuchsia::bluetooth::bredr::AudioOffloadConfiguration&
100             audio_offload_configuration);
101 
102     ProfileServer& profile_server_;
103     bt::l2cap::Channel::UniqueId unique_id_;
104     bt::l2cap::Channel::WeakPtr channel_;
105     bt::gap::Adapter::WeakPtr adapter_;
106   };
107 
108   class AudioOffloadController
109       : public ServerBase<fuchsia::bluetooth::bredr::AudioOffloadController> {
110    public:
AudioOffloadController(fidl::InterfaceRequest<fuchsia::bluetooth::bredr::AudioOffloadController> request,bt::l2cap::Channel::WeakPtr channel)111     explicit AudioOffloadController(
112         fidl::InterfaceRequest<
113             fuchsia::bluetooth::bredr::AudioOffloadController> request,
114         bt::l2cap::Channel::WeakPtr channel)
115         : ServerBase(this, std::move(request)),
116           unique_id_(channel->unique_id()),
117           channel_(std::move(channel)) {}
118 
119     void handle_unknown_method(uint64_t ordinal,
120                                bool method_has_response) override;
121 
unique_id()122     bt::l2cap::Channel::UniqueId unique_id() const { return unique_id_; }
123 
124     void Stop(StopCallback callback) override;
125 
SendOnStartedEvent()126     void SendOnStartedEvent() { binding()->events().OnStarted(); }
127 
Close(zx_status_t epitaph)128     void Close(zx_status_t epitaph) { binding()->Close(epitaph); }
129 
GetWeakPtr()130     WeakPtr<AudioOffloadController> GetWeakPtr() {
131       return weak_self_.GetWeakPtr();
132     }
133 
134    private:
135     bt::l2cap::Channel::UniqueId unique_id_;
136     bt::l2cap::Channel::WeakPtr channel_;
137     WeakSelf<AudioOffloadController> weak_self_{this};
138   };
139 
140   class ScoConnectionServer final
141       : public ServerBase<fuchsia::bluetooth::bredr::ScoConnection> {
142    public:
143     explicit ScoConnectionServer(
144         fidl::InterfaceRequest<fuchsia::bluetooth::bredr::ScoConnection>
145             request,
146         ProfileServer* profile_server);
147     ~ScoConnectionServer() override;
148     // Call bt::gap::ScoConnection::Activate with the appropriate callbacks. On
149     // error, destroys this server.
150     void Activate();
151 
OnConnectedParams(::fuchsia::bluetooth::bredr::ScoConnectionParameters params)152     void OnConnectedParams(
153         ::fuchsia::bluetooth::bredr::ScoConnectionParameters params) {
154       OnConnectionComplete(
155           ::fuchsia::bluetooth::bredr::
156               ScoConnectionOnConnectionCompleteRequest::WithConnectedParams(
157                   std::move(params)));
158     }
159 
160     // Sends the OnConnectionComplete event with `error` and shuts down the
161     // server.
162     void OnError(::fuchsia::bluetooth::bredr::ScoErrorCode error);
163 
164     const std::vector<fuchsia::bluetooth::bredr::ScoConnectionParameters>&
parameters()165     parameters() const {
166       return parameters_;
167     }
168 
set_parameters(std::vector<fuchsia::bluetooth::bredr::ScoConnectionParameters> params)169     void set_parameters(
170         std::vector<fuchsia::bluetooth::bredr::ScoConnectionParameters>
171             params) {
172       parameters_ = std::move(params);
173     }
174 
set_request_handle(bt::gap::Adapter::BrEdr::ScoRequestHandle handle)175     void set_request_handle(bt::gap::Adapter::BrEdr::ScoRequestHandle handle) {
176       request_handle_ = std::move(handle);
177     }
178 
set_connection(bt::sco::ScoConnection::WeakPtr connection)179     void set_connection(bt::sco::ScoConnection::WeakPtr connection) {
180       connection_ = std::move(connection);
181     }
182 
GetWeakPtr()183     WeakPtr<ScoConnectionServer> GetWeakPtr() {
184       return weak_self_.GetWeakPtr();
185     }
186 
187    private:
188     // ScoConnection overrides:
189     void Read(ReadCallback callback) override;
190     void Write(::fuchsia::bluetooth::bredr::ScoConnectionWriteRequest request,
191                WriteCallback callback) override;
192     void handle_unknown_method(uint64_t ordinal,
193                                bool method_has_response) override;
194 
195     void TryRead();
196 
197     // Closes the server with `epitaph` and destroys the server.
198     void Close(zx_status_t epitaph);
199 
OnConnectionComplete(::fuchsia::bluetooth::bredr::ScoConnectionOnConnectionCompleteRequest request)200     void OnConnectionComplete(
201         ::fuchsia::bluetooth::bredr::ScoConnectionOnConnectionCompleteRequest
202             request) {
203       binding()->events().OnConnectionComplete(std::move(request));
204     }
205 
206     std::optional<bt::gap::Adapter::BrEdr::ScoRequestHandle> request_handle_;
207     std::vector<fuchsia::bluetooth::bredr::ScoConnectionParameters> parameters_;
208 
209     bt::sco::ScoConnection::WeakPtr connection_;
210     // Non-null when a read request is waiting for an inbound packet.
211     fit::callback<void(::fuchsia::bluetooth::bredr::ScoConnection_Read_Result)>
212         read_cb_;
213 
214     ProfileServer* profile_server_;
215 
216     // Keep this as the last member to make sure that all weak pointers are
217     // invalidated before other members get destroyed.
218     WeakSelf<ScoConnectionServer> weak_self_;
219   };
220 
221   // fuchsia::bluetooth::bredr::Profile overrides:
222   void Advertise(fuchsia::bluetooth::bredr::ProfileAdvertiseRequest request,
223                  AdvertiseCallback callback) override;
224   void Search(
225       ::fuchsia::bluetooth::bredr::ProfileSearchRequest request) override;
226   void Connect(fuchsia::bluetooth::PeerId peer_id,
227                fuchsia::bluetooth::bredr::ConnectParameters connection,
228                ConnectCallback callback) override;
229   void ConnectSco(
230       ::fuchsia::bluetooth::bredr::ProfileConnectScoRequest request) override;
231   void handle_unknown_method(uint64_t ordinal,
232                              bool method_has_response) override;
233 
234   // Callback when clients close or revoke their connection targets
235   void OnConnectionReceiverClosed(uint64_t ad_id);
236 
237   // Callback when clients close their search results
238   void OnSearchResultError(uint64_t search_id, zx_status_t status);
239 
240   // Callback for incoming connections
241   void OnChannelConnected(uint64_t ad_id,
242                           bt::l2cap::Channel::WeakPtr channel,
243                           const bt::sdp::DataElement& protocol_list);
244 
245   // Callback for services found on connected device
246   void OnServiceFound(
247       uint64_t search_id,
248       bt::PeerId peer_id,
249       const std::map<bt::sdp::AttributeId, bt::sdp::DataElement>& attributes);
250 
251   // Callback for SCO connections requests.
252   static void OnScoConnectionResult(
253       WeakPtr<ScoConnectionServer>& server,
254       bt::sco::ScoConnectionManager::AcceptConnectionResult result);
255 
256   // Callback when clients close their audio direction extension.
257   void OnAudioDirectionExtError(AudioDirectionExt* ext_server,
258                                 zx_status_t status);
259 
260   // Create an AudioDirectionExt server for the given channel and set up
261   // callbacks. Returns the client end of the channel.
262   fidl::InterfaceHandle<fuchsia::bluetooth::bredr::AudioDirectionExt>
263   BindAudioDirectionExtServer(bt::l2cap::Channel::WeakPtr channel);
264 
265   // Callback when clients close their l2cap parameters extension.
266   void OnL2capParametersExtError(L2capParametersExt* ext_server,
267                                  zx_status_t status);
268 
269   // Create an L2capParametersExt server for the given channel and set up
270   // callbacks. Returns the client end of the channel.
271   fidl::InterfaceHandle<fuchsia::bluetooth::bredr::L2capParametersExt>
272   BindL2capParametersExtServer(bt::l2cap::Channel::WeakPtr channel);
273 
274   // Callback when clients close their audio offload extension.
275   void OnAudioOffloadExtError(AudioOffloadExt* ext_server, zx_status_t status);
276 
277   // Create an AudioOffloadExt server for the given channel and set up
278   // callbacks. Returns the client end of the channel.
279   fidl::InterfaceHandle<fuchsia::bluetooth::bredr::AudioOffloadExt>
280   BindAudioOffloadExtServer(bt::l2cap::Channel::WeakPtr channel);
281 
282   // Create an Connection server for the given channel and set up callbacks.
283   // Returns the client end of the channel, or null on failure.
284   std::optional<fidl::InterfaceHandle<fuchsia::bluetooth::Channel>>
285   BindChannelServer(bt::l2cap::Channel::WeakPtr channel,
286                     fit::callback<void()> closed_callback);
287 
288   // Create a FIDL Channel from an l2cap::Channel. A Connection relay is created
289   // from |channel| and returned in the FIDL Channel.
290   std::optional<fuchsia::bluetooth::bredr::Channel> ChannelToFidl(
291       bt::l2cap::Channel::WeakPtr channel);
292 
adapter()293   const bt::gap::Adapter::WeakPtr& adapter() const { return adapter_; }
294 
295   // Advertised Services
296   struct AdvertisedService {
AdvertisedServiceAdvertisedService297     AdvertisedService(
298         fidl::InterfacePtr<fuchsia::bluetooth::bredr::ConnectionReceiver>
299             receiver,
300         bt::sdp::Server::RegistrationHandle registration_handle)
301         : receiver(std::move(receiver)),
302           registration_handle(registration_handle) {}
303     fidl::InterfacePtr<fuchsia::bluetooth::bredr::ConnectionReceiver> receiver;
304     bt::sdp::Server::RegistrationHandle registration_handle;
305   };
306 
307   uint64_t advertised_total_;
308   std::map<uint64_t, AdvertisedService> current_advertised_;
309 
310   // Searches registered
311   struct RegisteredSearch {
RegisteredSearchRegisteredSearch312     RegisteredSearch(
313         fidl::InterfacePtr<fuchsia::bluetooth::bredr::SearchResults> results,
314         bt::gap::BrEdrConnectionManager::SearchId search_id)
315         : results(std::move(results)), search_id(search_id) {}
316     fidl::InterfacePtr<fuchsia::bluetooth::bredr::SearchResults> results;
317     bt::gap::BrEdrConnectionManager::SearchId search_id;
318   };
319 
320   uint64_t searches_total_;
321   std::map<uint64_t, RegisteredSearch> searches_;
322 
323   class AudioDirectionExt final
324       : public ServerBase<fuchsia::bluetooth::bredr::AudioDirectionExt> {
325    public:
326     // Calls to SetPriority() are forwarded to |priority_cb|.
AudioDirectionExt(fidl::InterfaceRequest<fuchsia::bluetooth::bredr::AudioDirectionExt> request,bt::l2cap::Channel::WeakPtr channel)327     AudioDirectionExt(fidl::InterfaceRequest<
328                           fuchsia::bluetooth::bredr::AudioDirectionExt> request,
329                       bt::l2cap::Channel::WeakPtr channel)
330         : ServerBase(this, std::move(request)),
331           unique_id_(channel->unique_id()),
332           channel_(std::move(channel)) {}
333 
unique_id()334     bt::l2cap::Channel::UniqueId unique_id() const { return unique_id_; }
335 
336     // fuchsia::bluetooth::bredr::AudioDirectionExt overrides:
337     void SetPriority(fuchsia::bluetooth::bredr::A2dpDirectionPriority priority,
338                      SetPriorityCallback callback) override;
339 
340     void handle_unknown_method(uint64_t ordinal,
341                                bool method_has_response) override;
342 
343    private:
344     bt::l2cap::Channel::UniqueId unique_id_;
345     bt::l2cap::Channel::WeakPtr channel_;
346   };
347   std::unordered_map<bt::l2cap::Channel::UniqueId,
348                      std::unique_ptr<L2capParametersExt>>
349       l2cap_parameters_ext_servers_;
350 
351   std::unordered_map<bt::l2cap::Channel::UniqueId,
352                      std::unique_ptr<AudioDirectionExt>>
353       audio_direction_ext_servers_;
354 
355   std::unordered_map<bt::l2cap::Channel::UniqueId,
356                      std::unique_ptr<AudioOffloadExt>>
357       audio_offload_ext_servers_;
358 
359   std::unique_ptr<AudioOffloadController> audio_offload_controller_server_;
360 
361   bt::gap::Adapter::WeakPtr adapter_;
362 
363   // If true, use Channel.socket. If false, use Channel.connection.
364   bool use_sockets_ = true;
365 
366   // Creates sockets that bridge L2CAP channels to profile processes.
367   bt::socket::SocketFactory<bt::l2cap::Channel> l2cap_socket_factory_;
368 
369   std::unordered_map<bt::l2cap::Channel::UniqueId,
370                      std::unique_ptr<ChannelServer>>
371       channel_servers_;
372 
373   std::unordered_map<ScoConnectionServer*, std::unique_ptr<ScoConnectionServer>>
374       sco_connection_servers_;
375 
376   // Keep this as the last member to make sure that all weak pointers are
377   // invalidated before other members get destroyed.
378   WeakSelf<ProfileServer> weak_self_;
379 
380   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ProfileServer);
381 };
382 
383 }  // namespace bthost
384