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