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