1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://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,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "gatt_cache.h"
17 #include "bt_def.h"
18 #include "gatt_defines.h"
19
20 namespace bluetooth {
21 using Descriptors = std::pair<std::map<uint16_t, GattCache::Descriptor> *, uint16_t>;
22
AddService(const Service & service)23 void GattCache::AddService(const Service &service)
24 {
25 auto it = services_.emplace(service.handle_, service);
26 if (!it.second) {
27 it.first->second.endHandle_ = service.endHandle_;
28 it.first->second.uuid_ = service.uuid_;
29 }
30 }
31
Clear()32 void GattCache::Clear()
33 {
34 services_.clear();
35 }
36
AddIncludeService(uint16_t serviceHandle,const IncludeService & includeService)37 int GattCache::AddIncludeService(uint16_t serviceHandle, const IncludeService &includeService)
38 {
39 auto it = services_.find(serviceHandle);
40 if (it != services_.end()) {
41 it->second.includeServices_.push_back(includeService);
42
43 return GattStatus::GATT_SUCCESS;
44 }
45
46 return GattStatus::INVALID_PARAMETER;
47 }
48
AddCharacteristic(uint16_t serviceHandle,const Characteristic & characteristic)49 int GattCache::AddCharacteristic(uint16_t serviceHandle, const Characteristic &characteristic)
50 {
51 auto it = services_.find(serviceHandle);
52 if (it != services_.end()) {
53 auto result = it->second.characteristics_.emplace(characteristic.handle_, characteristic);
54 if (result.second) {
55 valueHandleMap_.emplace(characteristic.valueHandle_, std::make_pair(serviceHandle, characteristic.handle_));
56 } else {
57 result.first->second.properties_ = characteristic.properties_;
58 result.first->second.uuid_ = characteristic.uuid_;
59 }
60 return GattStatus::GATT_SUCCESS;
61 }
62 return GattStatus::INVALID_PARAMETER;
63 }
64
AddDescriptor(uint16_t cccHandle,const Descriptor & descriptor)65 int GattCache::AddDescriptor(uint16_t cccHandle, const Descriptor &descriptor)
66 {
67 for (auto &sIt : services_) {
68 auto cIt = sIt.second.characteristics_.find(cccHandle);
69 if (cIt != sIt.second.characteristics_.end()) {
70 cIt->second.descriptors_.emplace(descriptor.handle_, descriptor);
71 valueHandleMap_.emplace(descriptor.handle_, std::make_pair(sIt.second.handle_, cIt->second.handle_));
72 return GattStatus::GATT_SUCCESS;
73 }
74 }
75
76 return GattStatus::INVALID_PARAMETER;
77 }
78
GetCharacteristic(int16_t valueHandle)79 const GattCache::Characteristic *GattCache::GetCharacteristic(int16_t valueHandle)
80 {
81 auto it = valueHandleMap_.find(valueHandle);
82 if (it != valueHandleMap_.end()) {
83 auto svc = services_.find(it->second.first);
84 if (svc != services_.end()) {
85 auto ccc = svc->second.characteristics_.find(it->second.second);
86 if (ccc != svc->second.characteristics_.end()) {
87 return &ccc->second;
88 }
89 }
90 }
91 return nullptr;
92 }
93
GetDescriptor(int16_t valueHandle)94 const GattCache::Descriptor *GattCache::GetDescriptor(int16_t valueHandle)
95 {
96 auto it = valueHandleMap_.find(valueHandle);
97 if (it == valueHandleMap_.end()) {
98 return nullptr;
99 }
100 auto svc = services_.find(it->second.first);
101 if (svc == services_.end()) {
102 return nullptr;
103 }
104 auto ccc = svc->second.characteristics_.find(it->second.second);
105 if (ccc == svc->second.characteristics_.end()) {
106 return nullptr;
107 }
108 auto descriptor = ccc->second.descriptors_.find(valueHandle);
109 if (descriptor != ccc->second.descriptors_.end()) {
110 return nullptr;
111 }
112 return &descriptor->second;
113 }
114
GetCharacteristicEndHandle(uint16_t serviceHandle,uint16_t cccHandle) const115 uint16_t GattCache::GetCharacteristicEndHandle(uint16_t serviceHandle, uint16_t cccHandle) const
116 {
117 auto svc = services_.find(serviceHandle);
118 if (svc == services_.end()) {
119 return INVALID_ATTRIBUTE_HANDLE;
120 }
121
122 auto ccc = svc->second.characteristics_.find(cccHandle);
123 if (ccc == svc->second.characteristics_.end()) {
124 return INVALID_ATTRIBUTE_HANDLE;
125 }
126
127 if (++ccc != svc->second.characteristics_.end()) {
128 return ccc->second.handle_ - MIN_ATTRIBUTE_HANDLE;
129 }
130
131 return svc->second.endHandle_;
132 }
133
GetServices()134 std::map<uint16_t, GattCache::Service> &GattCache::GetServices()
135 {
136 return services_;
137 }
138
GetIncludeServices(uint16_t serviceHandle)139 std::vector<GattCache::IncludeService> *GattCache::GetIncludeServices(uint16_t serviceHandle)
140 {
141 auto service = services_.find(serviceHandle);
142 if (service != services_.end()) {
143 return &service->second.includeServices_;
144 }
145 return nullptr;
146 }
147
GetCharacteristics(uint16_t serviceHandle)148 std::map<uint16_t, GattCache::Characteristic> *GattCache::GetCharacteristics(uint16_t serviceHandle)
149 {
150 auto service = services_.find(serviceHandle);
151 if (service != services_.end()) {
152 return &service->second.characteristics_;
153 }
154 return nullptr;
155 }
156
GetDescriptors(uint16_t cccHandle)157 Descriptors GattCache::GetDescriptors(uint16_t cccHandle)
158 {
159 for (auto &service : services_) {
160 auto it = service.second.characteristics_.find(cccHandle);
161 if (it != service.second.characteristics_.end()) {
162 return std::make_pair(&it->second.descriptors_, service.second.handle_);
163 }
164 }
165 return std::make_pair(nullptr, 0);
166 }
167
168 const std::string GattCache::GATT_STORAGE_PRIFIX = "gatt_storage_cache_";
169
StoredToFile(const GattDevice & address) const170 int GattCache::StoredToFile(const GattDevice& address) const
171 {
172 std::vector<StorageBlob> storage;
173
174 for (auto &svc : services_) {
175 StorageBlob svcBlob = {};
176 svcBlob.handle_ = svc.second.handle_;
177 svcBlob.type_ = (svc.second.isPrimary_ ? Uuid::ConvertFrom16Bits(UUID_PRIMARY_SERVICE)
178 : Uuid::ConvertFrom16Bits(UUID_SECONDARY_SERVICE));
179 svcBlob.value_.service_.uuid_ = svc.second.uuid_;
180 svcBlob.value_.service_.endHandle_ = svc.second.endHandle_;
181 storage.push_back(svcBlob);
182
183 for (auto &isvc : svc.second.includeServices_) {
184 StorageBlob isvcBlob = {};
185 isvcBlob.handle_ = isvc.handle_;
186 isvcBlob.type_ = Uuid::ConvertFrom16Bits(UUID_INCLUDE_SERVICE);
187 isvcBlob.value_.includeService_.handle_ = isvc.startHandle_;
188 isvcBlob.value_.includeService_.endHandle_ = isvc.endHandle_;
189 isvcBlob.value_.includeService_.uuid_ = isvc.uuid_;
190 storage.push_back(isvcBlob);
191 }
192
193 for (auto &ccc : svc.second.characteristics_) {
194 StorageBlob cccBlob = {};
195 cccBlob.handle_ = ccc.second.handle_;
196 cccBlob.type_ = Uuid::ConvertFrom16Bits(UUID_CHARACTERISTIC);
197 cccBlob.value_.characteristic_.properties_ = ccc.second.properties_;
198 cccBlob.value_.characteristic_.valueHandle_ = ccc.second.valueHandle_;
199 cccBlob.value_.characteristic_.uuid_ = ccc.second.uuid_;
200 storage.push_back(cccBlob);
201
202 for (auto &desc : ccc.second.descriptors_) {
203 StorageBlob descBlob = {};
204 descBlob.handle_ = desc.second.handle_;
205 descBlob.type_ = desc.second.uuid_;
206 storage.push_back(descBlob);
207 }
208 }
209 }
210
211 return WriteStorageBlobToFile(address, storage);
212 }
213
LoadFromFile(const GattDevice & address)214 int GattCache::LoadFromFile(const GattDevice& address)
215 {
216 std::vector<StorageBlob> storage = ReadStorageBlobFromFile(address);
217
218 uint16_t currentSvcHandle = 0;
219 uint16_t currentCccHandle = 0;
220 for (auto &item : storage) {
221 if (item.type_ == Uuid::ConvertFrom16Bits(UUID_PRIMARY_SERVICE) ||
222 item.type_ == Uuid::ConvertFrom16Bits(UUID_SECONDARY_SERVICE)) {
223 AddService(
224 GattCache::Service((item.type_ == Uuid::ConvertFrom16Bits(UUID_PRIMARY_SERVICE)) ? true : false,
225 item.handle_,
226 item.value_.service_.endHandle_,
227 item.value_.service_.uuid_));
228 currentSvcHandle = item.handle_;
229 } else if (item.type_ == Uuid::ConvertFrom16Bits(UUID_INCLUDE_SERVICE)) {
230 AddIncludeService(currentSvcHandle,
231 GattCache::IncludeService(item.handle_,
232 item.value_.includeService_.handle_,
233 item.value_.includeService_.endHandle_,
234 item.value_.includeService_.uuid_));
235 } else if (item.type_ == Uuid::ConvertFrom16Bits(UUID_CHARACTERISTIC)) {
236 AddCharacteristic(currentSvcHandle,
237 GattCache::Characteristic(item.handle_,
238 item.value_.characteristic_.properties_,
239 item.value_.characteristic_.valueHandle_,
240 item.value_.characteristic_.uuid_));
241 currentCccHandle = item.handle_;
242 } else {
243 AddDescriptor(currentCccHandle, GattCache::Descriptor(item.handle_, item.type_));
244 }
245 }
246
247 return GattStatus::GATT_SUCCESS;
248 }
249
GenerateGattCacheFileName(const GattDevice & address)250 std::string GattCache::GenerateGattCacheFileName(const GattDevice &address)
251 {
252 return (GATT_STORAGE_PRIFIX + address.addr_.GetAddress() + "_" +
253 ((address.transport_ == GATT_TRANSPORT_TYPE_CLASSIC) ? "CLASSIC" : "LE"));
254 }
255
WriteStorageBlobToFile(const GattDevice & address,std::vector<StorageBlob> & blob) const256 int GattCache::WriteStorageBlobToFile(const GattDevice& address, std::vector<StorageBlob> &blob) const
257 {
258 FILE* fd = fopen(GenerateGattCacheFileName(address).c_str(), "wb");
259 if (fd == nullptr) {
260 return GattStatus::REQUEST_NOT_SUPPORT;
261 }
262
263 uint16_t blobSize = blob.size();
264 if (fwrite(&blobSize, sizeof(uint16_t), 1, fd) != 1) {
265 fclose(fd);
266 return GattStatus::INTERNAL_ERROR;
267 }
268
269 if (fwrite(blob.data(), sizeof(StorageBlob), blobSize, fd) != blobSize) {
270 fclose(fd);
271 return GattStatus::INTERNAL_ERROR;
272 }
273
274 fclose(fd);
275
276 return GattStatus::GATT_SUCCESS;
277 }
278
ReadStorageBlobFromFile(const GattDevice & address) const279 std::vector<GattCache::StorageBlob> GattCache::ReadStorageBlobFromFile(const GattDevice &address) const
280 {
281 FILE* fd = fopen(GenerateGattCacheFileName(address).c_str(), "rb");
282 if (fd == nullptr) {
283 return std::vector<StorageBlob>();
284 }
285
286 uint16_t blobSize = 0;
287 if (fread(&blobSize, sizeof(uint16_t), 1, fd) != 1) {
288 fclose(fd);
289 return std::vector<StorageBlob>();
290 }
291
292 std::vector<StorageBlob> blob(blobSize, {0, {}, {}});
293 if (fread(blob.data(), sizeof(StorageBlob), blobSize, fd) != blobSize) {
294 fclose(fd);
295 return std::vector<StorageBlob>();
296 }
297
298 fclose(fd);
299 return blob;
300 }
301 } // namespace bluetooth