1 // Copyright 2023 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 #include <lib/fit/function.h>
17 
18 #include <optional>
19 #include <unordered_map>
20 
21 #include "pw_bluetooth_sapphire/internal/host/common/weak_self.h"
22 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel_manager.h"
23 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
24 #include "pw_bluetooth_sapphire/internal/host/l2cap/scoped_channel.h"
25 #include "pw_bluetooth_sapphire/internal/host/sdp/pdu.h"
26 #include "pw_bluetooth_sapphire/internal/host/sdp/sdp.h"
27 #include "pw_bluetooth_sapphire/internal/host/sdp/service_record.h"
28 
29 namespace bt::sdp {
30 
31 // The SDP server object owns the Service Database and all Service Records.
32 // Only one server is expected to exist per host.
33 // This object is not thread-safe.
34 // TODO(jamuraa): make calls thread-safe or ensure single-threadedness
35 class Server final {
36  public:
37   static constexpr const char* kInspectNodeName = "sdp_server";
38   // A placeholder value for a dynamic PSM.
39   // Note: This is not a valid PSM value itself. It is used to request a
40   // randomly generated dynamic PSM.
41   static constexpr uint16_t kDynamicPsm = 0xffff;
42 
43   // A new SDP server, which starts with just a ServiceDiscoveryService record.
44   // Registers itself with |l2cap| when created.
45   explicit Server(l2cap::ChannelManager* l2cap);
46   ~Server();
47 
48   // Attach SDP server inspect node as a child node of |parent|.
49   void AttachInspect(inspect::Node& parent,
50                      std::string name = kInspectNodeName);
51 
52   // Initialize a new SDP profile connection with |peer_id| on |channel|.
53   // Returns false if the channel cannot be activated.
54   bool AddConnection(l2cap::Channel::WeakPtr channel);
55 
56   // An identifier for a set of services that have been registered at the same
57   // time.
58   using RegistrationHandle = uint32_t;
59 
60   const RegistrationHandle kNotRegistered = 0x00000000;
61 
62   // Given incomplete ServiceRecords, register services that will be made
63   // available over SDP. Takes ownership of |records|. Channels created for this
64   // service will be configured using the preferred parameters in |chan_params|.
65   //
66   // A non-zero RegistrationHandle will be returned if the service was
67   // successfully registered.
68   //
69   // If any record in |records| fails registration checks, none of the services
70   // will be registered.
71   //
72   // |conn_cb| will be called for any connections made to any of the services in
73   // |records| with a connected channel and the descriptor list for the endpoint
74   // which was connected.
75   using ConnectCallback =
76       fit::function<void(l2cap::Channel::WeakPtr, const DataElement&)>;
77   RegistrationHandle RegisterService(std::vector<ServiceRecord> records,
78                                      l2cap::ChannelParameters chan_params,
79                                      ConnectCallback conn_cb);
80 
81   // Unregister services previously registered with RegisterService. Idempotent.
82   // Returns |true| if any records were removed.
83   bool UnregisterService(RegistrationHandle handle);
84 
85   // Returns a list of records for the provided |handle|.
86   // The returned list may be empty if |handle| is not registered.
87   std::vector<ServiceRecord> GetRegisteredServices(
88       RegistrationHandle handle) const;
89 
90   // Define the ServiceDiscoveryService record for the SDP server object.
91   // This method is public for testing purposes.
92   static ServiceRecord MakeServiceDiscoveryService();
93 
94   // Construct a response based on input packet |sdu| and max size
95   // |max_tx_sdu_size|. Note that this function can both be called by means of
96   // connecting an l2cap::Channel and directly querying its database. As long
97   // as the database does not change between requests, both of these approaches
98   // are compatible.
99   // This function will drop the packet if the PDU is too short, and it will
100   // handle most errors by returning a valid packet with an ErrorResponse.
101   std::optional<ByteBufferPtr> HandleRequest(ByteBufferPtr sdu,
102                                              uint16_t max_tx_sdu_size);
103 
104   // Returns the set of allocated L2CAP PSMs in the SDP server.
105   // TESTONLY hook and should not be used otherwise.
106   std::set<l2cap::Psm> AllocatedPsmsForTest() const;
107 
108  private:
109   // Returns the next unused Service Handle, or 0 if none are available.
110   ServiceHandle GetNextHandle();
111 
112   // Performs a Service Search, returning any service record that contains
113   // all UUID from the |search_pattern|
114   ServiceSearchResponse SearchServices(
115       const std::unordered_set<UUID>& pattern) const;
116 
117   // Gets Service Attributes in the |attribute_ranges| from the service record
118   // with |handle|.
119   ServiceAttributeResponse GetServiceAttributes(
120       ServiceHandle handle, const std::list<AttributeRange>& ranges) const;
121 
122   // Retrieves Service Attributes in the |attribute_ranges|, using the pattern
123   // to search for the services that contain all UUIDs from the |search_pattern|
124   ServiceSearchAttributeResponse SearchAllServiceAttributes(
125       const std::unordered_set<UUID>& search_pattern,
126       const std::list<AttributeRange>& attribute_ranges) const;
127 
128   // An array of PSM to ServiceHandle assignments that are used to represent
129   // the services that need to be registered in Server::QueueService.
130   using ProtocolQueue = std::vector<std::pair<l2cap::Psm, ServiceHandle>>;
131 
132   /// Returns true if the |psm| is allocated in the SDP server.
IsAllocated(l2cap::Psm psm)133   bool IsAllocated(l2cap::Psm psm) const { return psm_to_service_.count(psm); }
134 
135   // Attempts to add the |psm| to the queue of protocols to be registered.
136   // Returns true if the PSM was successfully added to the queue, false
137   // otherwise.
138   bool AddPsmToProtocol(ProtocolQueue* protocols_to_register,
139                         l2cap::Psm psm,
140                         ServiceHandle handle) const;
141 
142   // Returns the next available dynamic PSM. A PSM is considered available if it
143   // has not been allocated already nor reserved in |queued_psms|. Returns
144   // |kInvalidPsm| if no PSM is available.
145   l2cap::Psm GetDynamicPsm(const ProtocolQueue* queued_psms) const;
146 
147   // Given a complete ServiceRecord, extracts the PSM, ProtocolDescriptorList,
148   // and any AdditionalProtocolDescriptorList information. Allocates any dynamic
149   // PSMs that were requested in the aforementioned protocol lists.
150   // Inserts the extracted info into |psm_to_register|.
151   //
152   // Returns |true| if the protocols are successfully validated and queued,
153   // |false| otherwise.
154   bool QueueService(ServiceRecord* record,
155                     ProtocolQueue* protocols_to_register);
156 
157   // l2cap::Channel callbacks
158   void OnChannelClosed(l2cap::Channel::UniqueId channel_id);
159 
160   // Updates the property values associated with the |sdp_server_node_|.
161   void UpdateInspectProperties();
162 
163   // Send |bytes| over the channel associated with the connection handle
164   // |conn|. Logs an error if channel not found.
165   void Send(l2cap::Channel::UniqueId channel_id, ByteBufferPtr bytes);
166 
167   // Used to register callbacks for the channels of services registered.
168   l2cap::ChannelManager* l2cap_;
169 
170   struct InspectProperties {
171     // Inspect hierarchy node representing the sdp server.
172     inspect::Node sdp_server_node;
173 
174     // Each ServiceRecord has it's record and nodes associated wth the
175     // registered PSMs.
176     struct InspectServiceRecordProperties {
177       InspectServiceRecordProperties(std::string record,
178                                      std::unordered_set<l2cap::Psm> psms);
179       void AttachInspect(inspect::Node& parent, std::string name);
180       inspect::Node node;
181       // The record description.
182       const std::string record;
183       inspect::StringProperty record_property;
184       // The node for the registered PSMs.
185       inspect::Node psms_node;
186       // The currently registered PSMs.
187       const std::unordered_set<l2cap::Psm> psms;
188       std::vector<std::pair<inspect::Node, inspect::StringProperty>> psm_nodes;
189     };
190 
191     // The currently registered ServiceRecords.
192     std::vector<InspectServiceRecordProperties> svc_record_properties;
193   };
194   InspectProperties inspect_properties_;
195 
196   // Map of channels that are opened to the server.  Keyed by the channels
197   // unique id.
198   std::unordered_map<l2cap::Channel::UniqueId, l2cap::ScopedChannel> channels_;
199   // The map of ServiceHandles that are associated with ServiceRecords.
200   // This is a 1:1 mapping.
201   std::unordered_map<ServiceHandle, ServiceRecord> records_;
202 
203   // Which PSMs are registered to services. Multiple ServiceHandles can be
204   // registered to a single PSM.
205   std::unordered_map<l2cap::Psm, std::unordered_set<ServiceHandle>>
206       psm_to_service_;
207   // The set of PSMs that are registered to a service.
208   std::unordered_map<ServiceHandle, std::unordered_set<l2cap::Psm>>
209       service_to_psms_;
210 
211   // The next available ServiceHandle.
212   ServiceHandle next_handle_;
213 
214   // The set of ServiceHandles that are registered together, identified by a
215   // RegistrationHandle.
216   std::unordered_map<RegistrationHandle, std::set<ServiceHandle>>
217       reg_to_service_;
218 
219   // The service database state tracker.
220   uint32_t db_state_ [[maybe_unused]];
221 
222   WeakSelf<Server> weak_ptr_factory_;
223 
224   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Server);
225 };
226 
227 }  // namespace bt::sdp
228