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