1 /*
2  * Copyright (c) 2022 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 <thread>
17 #include <queue>
18 #include "scan_mdns_service.h"
19 #include "scan_system_data.h"
20 #include "securec.h"
21 #include "mdns_common.h"
22 
23 #define TXT_MAX 256
24 
25 namespace OHOS::Scan {
26 using namespace OHOS::NetManagerStandard;
27 namespace {
28 std::map<std::string, ScanDeviceInfoTCP> g_ipToScannerInfo;
29 std::mutex g_ipToScannerInfoLock;
30 std::queue<ScanDeviceInfoSync> g_infoQueue;
31 std::mutex g_infoQueueLock;
GetServiceAttribute(MDnsServiceInfo & info,const std::string & key)32 static std::string GetServiceAttribute(MDnsServiceInfo &info, const std::string& key)
33 {
34     TxtRecord attrMap = info.GetAttrMap();
35     auto attrArrSize = attrMap.size();
36     if (attrArrSize < 1) {
37         SCAN_HILOGE("can not get attr");
38         return "";
39     }
40     auto it = attrMap.find(key);
41     if (it == attrMap.end() || it->second.empty()) {
42         SCAN_HILOGE("can not find key, key = [%{public}s]", key.c_str());
43         return "";
44     }
45     return std::string(it->second.begin(), it->second.end());
46 }
47 }
48 std::map<std::string, sptr<ScanMDnsDiscoveryObserver>> ScanMdnsService::discoveryCallBackPtrs_;
49 bool ScanMdnsService::isListening_ = false;
50 std::mutex ScanMdnsService::discoveryCallBackPtrsLock_;
51 
InsertIpToScannerInfo(const std::string & ip,ScanDeviceInfoTCP & scanDeviceInfoTCP)52 void ScanMdnsService::InsertIpToScannerInfo(const std::string& ip, ScanDeviceInfoTCP& scanDeviceInfoTCP)
53 {
54     g_ipToScannerInfo.insert(std::make_pair(ip, scanDeviceInfoTCP));
55 }
56 
OnStartDiscoverService()57 bool ScanMdnsService::OnStartDiscoverService()
58 {
59     if (isListening_) {
60         SCAN_HILOGD("scanner's mdns discovery is already started.");
61         return true;
62     }
63     const std::vector<std::string> scannerServiceTypes = { "_scanner._tcp" };
64     constexpr int32_t MDNS_PORT = 5353;
65     {
66         std::lock_guard<std::mutex> autoLock(g_ipToScannerInfoLock);
67         g_ipToScannerInfo.clear();
68     }
69     for (const auto& type : scannerServiceTypes) {
70         MDnsServiceInfo mdnsInfo;
71         mdnsInfo.type = type;
72         mdnsInfo.port = MDNS_PORT;
73         sptr<ScanMDnsDiscoveryObserver> callbackPtr = new (std::nothrow) ScanMDnsDiscoveryObserver(mdnsInfo);
74         if (callbackPtr == nullptr) {
75             SCAN_HILOGE("scanMDnsDiscoveryCallBack_ is a nullptr.");
76             OnStopDiscoverService();
77             return false;
78         }
79         int32_t ret = DelayedSingleton<MDnsClient>::GetInstance()->StartDiscoverService(
80             mdnsInfo.type, callbackPtr);
81         if (ret != NETMANAGER_EXT_SUCCESS) {
82             SCAN_HILOGE("mdns service [%{public}s] startDiscover failed, ret = [%{public}d].",
83                 mdnsInfo.type.c_str(), ret);
84             OnStopDiscoverService();
85             return false;
86         }
87         {
88             std::lock_guard<std::mutex> autoLock(discoveryCallBackPtrsLock_);
89             auto it = discoveryCallBackPtrs_.find(type);
90             if (it == discoveryCallBackPtrs_.end()) {
91                 discoveryCallBackPtrs_.insert(std::make_pair(type, callbackPtr));
92             } else {
93                 it->second = callbackPtr;
94             }
95             isListening_ = true;
96             std::thread updateScannerId(UpdateScannerIdThread);
97             updateScannerId.detach();
98         }
99     }
100     return true;
101 }
102 
UpdateScannerIdThread()103 void ScanMdnsService::UpdateScannerIdThread()
104 {
105     auto saPtr = ScanServiceAbility::GetInstance();
106     if (saPtr == nullptr) {
107         SCAN_HILOGE("saPtr is a nullptr");
108         return;
109     }
110     while (isListening_) {
111         {
112             std::lock_guard<std::mutex> autoLock(g_infoQueueLock);
113             while (!g_infoQueue.empty()) {
114                 saPtr->UpdateScannerId(g_infoQueue.front());
115                 g_infoQueue.pop();
116             }
117         }
118         constexpr int32_t sleepTime = 100000; // 100ms
119         usleep(sleepTime);
120     }
121 }
122 
OnStopDiscoverService()123 bool ScanMdnsService::OnStopDiscoverService()
124 {
125     for (auto& [serviceName, discoveryCallBackPtr] : discoveryCallBackPtrs_) {
126         if (discoveryCallBackPtr == nullptr) {
127             continue;
128         }
129         int32_t ret = DelayedSingleton<MDnsClient>::GetInstance()->StopDiscoverService(discoveryCallBackPtr);
130         if (ret != NETMANAGER_EXT_SUCCESS) {
131             SCAN_HILOGE("mdns service [%{public}s] startDiscover failed, ret = [%{public}d].",
132                 serviceName.c_str(), ret);
133             return false;
134         }
135         discoveryCallBackPtr = nullptr;
136     }
137     {
138         std::lock_guard<std::mutex> autoLock(discoveryCallBackPtrsLock_);
139         discoveryCallBackPtrs_.clear();
140         isListening_ = false;
141     }
142     return true;
143 }
144 
FindNetScannerInfoByIp(const std::string & ip,ScanDeviceInfoTCP & netScannerInfo)145 bool ScanMdnsService::FindNetScannerInfoByIp(const std::string& ip, ScanDeviceInfoTCP& netScannerInfo)
146 {
147     std::lock_guard<std::mutex> autoLock(g_ipToScannerInfoLock);
148     auto it = g_ipToScannerInfo.find(ip);
149     if (it == g_ipToScannerInfo.end()) {
150         SCAN_HILOGW("cannot find scanner info in map.");
151         return false;
152     }
153     netScannerInfo = it->second;
154     return true;
155 }
156 
HandleServiceFound(const MDnsServiceInfo & info,int32_t retCode)157 void ScanMDnsDiscoveryObserver::HandleServiceFound(const MDnsServiceInfo &info, int32_t retCode)
158 {
159     SCAN_HILOGD("Found mdns service info, name = [%{private}s]", info.name.c_str());
160     sptr<ScanMDnsResolveObserver> scanMDnsResolveCallBack_ = new (std::nothrow) ScanMDnsResolveObserver(info);
161     if (scanMDnsResolveCallBack_ == nullptr) {
162         SCAN_HILOGE("scanMDnsResolveCallBack_ is a nullptr.");
163         return;
164     }
165     int32_t ret = DelayedSingleton<MDnsClient>::GetInstance()->ResolveService(info, scanMDnsResolveCallBack_);
166     if (ret != NETMANAGER_EXT_SUCCESS) {
167         SCAN_HILOGE("mdns ResolveService failed, ret = [%{public}d].", ret);
168     }
169 }
170 
HandleResolveResult(const MDnsServiceInfo & info,int32_t retCode)171 void ScanMDnsResolveObserver::HandleResolveResult(const MDnsServiceInfo &info, int32_t retCode)
172 {
173     MDnsServiceInfo tempInfo = info;
174     SCAN_HILOGD("MDnsInfo name = [%{private}s], type = [%{private}s]", info.name.c_str(), info.type.c_str());
175     std::unique_ptr<ScanDeviceInfoTCP> scannerInfo = std::make_unique<ScanDeviceInfoTCP>();
176     scannerInfo->addr = tempInfo.addr;
177     scannerInfo->deviceName = tempInfo.name;
178     scannerInfo->port = std::to_string(tempInfo.port);
179     const std::string uuidKey = "UUID";
180     std::string uuidValue = GetServiceAttribute(tempInfo, uuidKey);
181     scannerInfo->uuid = uuidValue;
182     {
183         std::lock_guard<std::mutex> autoLock(g_ipToScannerInfoLock);
184         auto it = g_ipToScannerInfo.find(scannerInfo->addr);
185         if (it == g_ipToScannerInfo.end()) {
186             g_ipToScannerInfo.insert(std::make_pair(scannerInfo->addr, *scannerInfo));
187         } else {
188             it->second = *scannerInfo;
189         }
190     }
191     ScanSystemData &scanData = ScanSystemData::GetInstance();
192     auto pair = scanData.UpdateNetScannerByUuid(uuidValue, scannerInfo->addr);
193     if (pair.second == "") {
194         SCAN_HILOGE("UpdateNetScannerByUuid fail.");
195         return;
196     }
197     if (!scanData.SaveScannerMap()) {
198         SCAN_HILOGW("SaveScannerMap fail");
199     }
200     ScanDeviceInfoSync syncInfo;
201     syncInfo.deviceId = pair.second;
202     syncInfo.oldDeviceId = pair.first;
203     syncInfo.discoverMode = "TCP";
204     syncInfo.uniqueId = scannerInfo->addr;
205     syncInfo.syncMode = "update";
206     {
207         std::lock_guard<std::mutex> autoLock(g_infoQueueLock);
208         g_infoQueue.push(syncInfo);
209     }
210     {
211         std::lock_guard<std::mutex> autoLock(g_ipToScannerInfoLock);
212         auto it = g_ipToScannerInfo.find(scannerInfo->addr);
213         if (it == g_ipToScannerInfo.end()) {
214             g_ipToScannerInfo.insert(std::make_pair(scannerInfo->addr, *scannerInfo));
215         } else {
216             it->second = *scannerInfo;
217         }
218     }
219 }
220 
HandleServiceLost(const MDnsServiceInfo & info,int32_t retCode)221 void ScanMDnsDiscoveryObserver::HandleServiceLost(const MDnsServiceInfo &info, int32_t retCode)
222 {
223     SCAN_HILOGD("Loss mdns service info, name = [%{private}s]", info.name.c_str());
224     sptr<ScanMDnsLossResolveObserver> callBack = new (std::nothrow) ScanMDnsLossResolveObserver(info);
225     if (callBack == nullptr) {
226         SCAN_HILOGE("callBack is a nullptr");
227         return;
228     }
229     int32_t ret = DelayedSingleton<MDnsClient>::GetInstance()->ResolveService(info, callBack);
230     if (ret != NETMANAGER_EXT_SUCCESS) {
231         SCAN_HILOGE("mdns ResolveService failed, ret = %{public}d", ret);
232     }
233 }
234 
HandleResolveResult(const MDnsServiceInfo & info,int32_t retCode)235 void ScanMDnsLossResolveObserver::HandleResolveResult(const MDnsServiceInfo &info, int32_t retCode)
236 {
237     MDnsServiceInfo tempInfo = info;
238     SCAN_HILOGD("mdnsloss name = [%{private}s], type = [%{private}s]", info.name.c_str(), info.type.c_str());
239     {
240         std::lock_guard<std::mutex> autoLock(g_ipToScannerInfoLock);
241         std::string ip = info.addr;
242         auto it = g_ipToScannerInfo.find(ip);
243         if (it != g_ipToScannerInfo.end()) {
244             g_ipToScannerInfo.erase(it);
245         }
246     }
247 }
248 
HandleStopDiscover(const MDnsServiceInfo & serviceInfo,int32_t retCode)249 void ScanMDnsDiscoveryObserver::HandleStopDiscover(const MDnsServiceInfo &serviceInfo, int32_t retCode)
250 {
251     SCAN_HILOGD("Stop mdns service info, name = [%{private}s]", serviceInfo.name.c_str());
252 }
253 
254 }  // namespace OHOS::Scan
255