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