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