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 <set>
17 #include <unordered_map>
18 #include <unordered_set>
19 #include <vector>
20 
21 #include "pw_bluetooth_sapphire/internal/host/sdp/sdp.h"
22 
23 namespace bt::sdp {
24 
25 // A ServiceRecord represents a service record in a SDP database.
26 // The service has a number of attributes identified by defined IDs and each
27 // attribute has a value.
28 class ServiceRecord {
29  public:
30   // Create a new service record.
31   // Generates a UUID and sets the Service ID attribute.
32   ServiceRecord();
33 
34   // Disallow assign.
35   ServiceRecord& operator=(const ServiceRecord&) = delete;
36   // Allow copy and move.
37   ServiceRecord(const ServiceRecord&);
38   ServiceRecord(ServiceRecord&&) = default;
39 
40   // Directly sets an attribute to a specific DataElement
41   void SetAttribute(AttributeId id, DataElement value);
42 
43   // Get the value of an attribute. The attribute must be set.
44   // Use HasAttribute() to detect if an attribute is set.
45   const DataElement& GetAttribute(AttributeId id) const;
46 
47   // Returns true if there is an attribute with |id| in this record.
48   bool HasAttribute(AttributeId id) const;
49 
50   // Removes the attribute identified by |id|. Idempotent.
51   void RemoveAttribute(AttributeId id);
52 
53   // Protocol-only services only reserve a protocol endpoint, and don't
54   // advertise a service in the SDP database.
55   bool IsProtocolOnly() const;
56 
57   // Returns true if the ServiceRecord contains the required fields
58   // needed for SDP registration.
59   bool IsRegisterable() const;
60 
61   // Returns the handle of this service.
handle()62   ServiceHandle handle() const { return handle_; }
63 
64   void SetHandle(ServiceHandle handle);
65 
66   // Returns the set of attributes in this record that are in
67   // the range |start| - |end| inclusive.
68   // If |start| > |end| or no attributes are present, returns a
69   // an empty set.
70   std::set<AttributeId> GetAttributesInRange(AttributeId start,
71                                              AttributeId end) const;
72 
73   // Returns true if any value of the attributes in this service contain all
74   // of the |uuids| given.  The uuids need not be in any specific attribute
75   // value.
76   bool FindUUID(const std::unordered_set<UUID>& uuids) const;
77 
78   // Convenience function to set the service class id list attribute.
79   void SetServiceClassUUIDs(const std::vector<UUID>& classes);
80 
81   using ProtocolListId = uint8_t;
82 
83   constexpr static ProtocolListId kPrimaryProtocolList = 0x00;
84 
85   // Adds a protocol to a protocol descriptor list.
86   // Convenience function for adding protocol descriptor list attributes.
87   // |id| identifies the list to be added to.
88   // |uuid| must be a protocol UUID.
89   // |params| is either:
90   //   - a DataElement sequence of parameters
91   //   - a null DataElement, for which nothing will be appended
92   //   - a single DataElement parameter
93   // kPrimaryProtocolList is presented as the primary protocol.
94   // Other protocol will be added to the additional protocol lists,
95   void AddProtocolDescriptor(const ProtocolListId id,
96                              const UUID& uuid,
97                              DataElement params);
98 
99   // Adds a profile to the bluetooth profile descriptor list attribute.
100   // |uuid| is the UUID of the profile. |major| and |minor| are the major and
101   // minor versions of the profile supported.
102   void AddProfile(const UUID& uuid, uint8_t major, uint8_t minor);
103 
104   // Adds a set of language attributes.
105   // |language| is required (and must be two characters long)
106   // At least one other attribute must be non-empty.
107   // Empty attributes will be omitted.
108   // All strings are UTF-8 encoded.
109   // Returns true if attributes were added, false otherwise.
110   bool AddInfo(const std::string& language_code,
111                const std::string& name,
112                const std::string& description,
113                const std::string& provider);
114 
115   // A set of language attributes representing human-readable information.
116   // All strings are UTF-8 encoded.
117   struct Information {
118     // |language_code| is expected to be two characters long.
119     std::string language_code;
120     std::optional<std::string> name;
121     std::optional<std::string> description;
122     std::optional<std::string> provider;
123   };
124   // Returns the set of language attributes stored in this record.
125   // The returned list may be empty if kLanguageBaseAttributeIdList doesn't
126   // exist in the record.
127   std::vector<Information> GetInfo() const;
128 
129   // Set the security level required to connect to this service.
130   // See v5.0, Vol 3, Part C, Section 5.2.2.8
set_security_level(SecurityLevel security_level)131   void set_security_level(SecurityLevel security_level) {
132     security_level_ = security_level;
133   }
security_level()134   SecurityLevel security_level() const { return security_level_; }
135 
136   // Debug representation of a service record used for Inspect.
137   // Only includes kBluetoothProfileDescriptorList and kServiceClassIdList to
138   // minimize log spam.
139   std::string ToString() const;
140 
141  private:
142   ServiceHandle handle_;
143 
144   std::map<AttributeId, DataElement> attributes_;
145 
146   // Additional protocol lists, by id.
147   // Each one of these elements is a sequence of the form that would qualify as
148   // a protocol list (a sequence of sequences of protocols and params)
149   std::unordered_map<ProtocolListId, DataElement> addl_protocols_;
150 
151   SecurityLevel security_level_;
152 };
153 
154 }  // namespace bt::sdp
155