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