1 /*
2  * Copyright (c) 2023 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 "softbus_adapter.h"
17 
18 #include <cinttypes>
19 #include <cstddef>
20 #include <mutex>
21 
22 #include "dfs_error.h"
23 #include "utils_log.h"
24 
25 
26 namespace OHOS::FileManagement::CloudSync {
27 using namespace std;
28 constexpr int MIN_BW = 1024 * 1024 * 40;
29 constexpr int MAX_WAIT_TIMEOUT = 10000;
30 constexpr int MIN_LATENCY = 1000;
31 const string SERVICE_NAME = "OHOS.Filemanagement.Dfs.ICloudSyncService";
32 
GetInstance()33 SoftbusAdapter &SoftbusAdapter::GetInstance()
34 {
35     static SoftbusAdapter instance;
36     return instance;
37 }
38 
CreateSessionServer(const char *packageName, const char *sessionName)39 int32_t SoftbusAdapter::CreateSessionServer(const char *packageName, const char *sessionName)
40 {
41     SocketInfo info = {
42         .name = const_cast<char*>(sessionName),
43         .pkgName = const_cast<char*>(packageName),
44     };
45     int socket = ::Socket(info);
46     if (socket <= 0) {
47         LOGE("Failed to CreateSessionServer ret:%{public}d, sessionName:%{public}s", socket, sessionName);
48         return ERR_BAD_VALUE;
49     }
50     std::string saveKey = std::string(sessionName) + std::string(packageName);
51     {
52         lock_guard<mutex> lock(sessionMutex_);
53         auto sessionAndPackage = sessionAndPackageMap_.find(socket);
54         if (sessionAndPackage == sessionAndPackageMap_.end()) {
55             sessionAndPackageMap_.insert({socket, saveKey});
56         }
57     }
58     QosTV serverQos[] = {
59         { .qos = QOS_TYPE_MIN_BW,            .value = MIN_BW},
60         { .qos = QOS_TYPE_MAX_WAIT_TIMEOUT,      .value = MAX_WAIT_TIMEOUT },
61         { .qos = QOS_TYPE_MIN_LATENCY,       .value = MIN_LATENCY},
62     };
63 
64     ISocketListener listener = {
65         .OnBind = SoftbusAdapter::OnBind,
66         .OnShutdown = SoftbusAdapter::OnShutdown,
67         .OnBytes = SoftbusAdapter::OnBytes,
68         .OnMessage = nullptr,
69         .OnStream = nullptr,
70         .OnFile = SoftbusAdapter::OnFile,
71     };
72 
73     int32_t ret = ::Listen(socket, serverQos, QOS_COUNT, &listener);
74     if (ret != 0) {
75         LOGE("Failed to CreateSessionServer sessionName:%{public}s", sessionName);
76         return ret;
77     }
78     LOGD("Succeed to CreateSessionServer, sessionName:%{public}s", sessionName);
79     return E_OK;
80 }
81 
RemoveSessionServer(const char *packageName, const char *sessionName)82 int32_t SoftbusAdapter::RemoveSessionServer(const char *packageName, const char *sessionName)
83 {
84     std::string val = std::string(sessionName) + std::string(packageName);
85     int32_t socket = SoftbusAdapter::GetInstance().GetSocketNameFromMap(val);
86     string existSessionName = SoftbusAdapter::GetInstance().GetSessionNameFromMap(socket);
87     if (strcmp(existSessionName.c_str(), sessionName) != 0) {
88         LOGE("Failed to RemoveSessionServer sessionName:%{public}s", sessionName);
89         return ERR_BAD_VALUE;
90     }
91     SoftbusAdapter::GetInstance().RemoveSesion(socket);
92     ::Shutdown(socket);
93     LOGD("Succeed to RemoveSessionServer, sessionName:%{public}s", sessionName);
94     return E_OK;
95 }
96 
OnBind(int socket, PeerSocketInfo info)97 void SoftbusAdapter::OnBind(int socket, PeerSocketInfo info)
98 {
99     string sessionName = info.name;
100     string networkId = info.networkId;
101     if (sessionName.empty()) {
102         LOGE("get session name failed");
103         return;
104     }
105 
106     auto listener = SoftbusAdapter::GetInstance().GetListener(sessionName);
107     if (!listener) {
108         LOGD("UnRegisterListener for session %{public}d", socket);
109         return;
110     }
111 
112     listener->OnSessionOpened(socket, 0);
113     SoftbusAdapter::GetInstance().AcceptSesion(socket, sessionName, networkId);
114 }
115 
OnShutdown(int32_t socket, ShutdownReason reason)116 void SoftbusAdapter::OnShutdown(int32_t socket, ShutdownReason reason)
117 {
118     LOGD("Session OnShutdown, sessionId:%{public}d, reason:%{public}d", socket, reason);
119     string sessionName = SoftbusAdapter::GetInstance().GetSessionNameFromMap(socket);
120     if (sessionName.empty()) {
121         LOGE("get session name failed");
122         return;
123     }
124 
125     auto listener = SoftbusAdapter::GetInstance().GetListener(sessionName);
126     if (!listener) {
127         LOGD("UnRegisterListener for session %{public}d", socket);
128         return;
129     }
130 
131     listener->OnSessionClosed(socket);
132     SoftbusAdapter::GetInstance().RemoveSesion(socket);
133 }
134 
OnBytes(int socket, const void *data, unsigned int dataLen)135 void SoftbusAdapter::OnBytes(int socket, const void *data, unsigned int dataLen)
136 {
137     LOGD("OnBytes invoked, dataLen:%{public}d", dataLen);
138     string sessionName = SoftbusAdapter::GetInstance().GetSessionNameFromMap(socket);
139     if (sessionName.empty()) {
140         LOGE("get session name failed");
141         return;
142     }
143 
144     string peerDeviceId = SoftbusAdapter::GetInstance().GetPeerNetworkId(socket);
145     if (peerDeviceId.empty()) {
146         LOGE("get peerDeviceId name failed");
147         return;
148     }
149 
150     auto listener = SoftbusAdapter::GetInstance().GetListener(sessionName);
151     if (!listener) {
152         LOGD("UnRegisterListener for session %{public}d", socket);
153         return;
154     }
155 
156     listener->OnDataReceived(peerDeviceId, socket, data, dataLen);
157 }
158 
OnReceiveFileProcess(int sessionId, const char *firstFile, uint64_t bytesUpload, uint64_t bytesTotal)159 int SoftbusAdapter::OnReceiveFileProcess(int sessionId,
160                                          const char *firstFile,
161                                          uint64_t bytesUpload,
162                                          uint64_t bytesTotal)
163 {
164     LOGD(
165         "File receive process sessionId = %{public}d, first file:%{public}s, bytesUpload:%{public}" PRIu64 ", "
166         "bytesTotal:%{public}" PRIu64 "",
167         sessionId, GetAnonyString(firstFile).c_str(), bytesUpload, bytesTotal);
168     return E_OK;
169 }
170 
OnReceiveFileFinished(int sessionId, const char *files, int fileCnt)171 void SoftbusAdapter::OnReceiveFileFinished(int sessionId, const char *files, int fileCnt)
172 {
173     LOGD("OnReceiveFileFinished invoked, files:%{public}s, fileCnt:%{public}d", files, fileCnt);
174     string sessionName = SoftbusAdapter::GetInstance().GetSessionNameFromMap(sessionId);
175     if (sessionName.empty()) {
176         LOGE("get session name failed");
177         return;
178     }
179 
180     string peerNetworkId = SoftbusAdapter::GetInstance().GetPeerNetworkId(sessionId);
181     if (peerNetworkId.empty()) {
182         LOGE("get peerDeviceId name failed");
183         return;
184     }
185 
186     auto listener = SoftbusAdapter::GetInstance().GetListener(sessionName);
187     if (!listener) {
188         LOGD("UnRegisterListener for session %{public}d", sessionId);
189         return;
190     }
191 
192     listener->OnFileReceived(peerNetworkId, files, E_OK);
193 }
194 
GetRecvPath()195 const char* SoftbusAdapter::GetRecvPath()
196 {
197     return "/mnt/hmdfs/100/account/device_view/local/data/";
198 }
199 
OnFile(int32_t socket, FileEvent *event)200 void SoftbusAdapter::OnFile(int32_t socket, FileEvent *event)
201 {
202     if (event->type == FILE_EVENT_RECV_UPDATE_PATH) {
203         event->UpdateRecvPath = GetRecvPath;
204     }
205 }
206 
OpenSession(char *sessionName, char *peerDeviceId, char *groupId, TransDataType dataType)207 int SoftbusAdapter::OpenSession(char *sessionName,
208                                 char *peerDeviceId,
209                                 char *groupId,
210                                 TransDataType dataType)
211 {
212     SocketInfo info = {
213         .name = sessionName,
214         .peerName = sessionName,
215         .peerNetworkId = peerDeviceId,
216         .pkgName = const_cast<char*>(SERVICE_NAME.c_str()),
217         .dataType = dataType,
218     };
219     int32_t socket = Socket(info);
220     if (socket <= 0) {
221         return ERR_BAD_VALUE;
222     }
223     std::string saveKey = std::string(sessionName) + std::string(SERVICE_NAME);
224     {
225         lock_guard<mutex> lock(sessionMutex_);
226         auto sessionAndPackage = sessionAndPackageMap_.find(socket);
227         if (sessionAndPackage == sessionAndPackageMap_.end()) {
228             sessionAndPackageMap_.insert({socket, saveKey});
229         }
230     }
231     QosTV clientQos[] = {
232         { .qos = QOS_TYPE_MIN_BW,            .value = MIN_BW},
233         { .qos = QOS_TYPE_MAX_WAIT_TIMEOUT,      .value = MAX_WAIT_TIMEOUT },
234         { .qos = QOS_TYPE_MIN_LATENCY,       .value = MIN_LATENCY},
235     };
236 
237     ISocketListener listener = {
238         .OnBind = SoftbusAdapter::OnBind,
239         .OnShutdown = SoftbusAdapter::OnShutdown,
240         .OnBytes = SoftbusAdapter::OnBytes,
241         .OnFile = SoftbusAdapter::OnFile,
242     };
243     SoftbusAdapter::GetInstance().AcceptSesion(socket, sessionName, peerDeviceId);
244     int32_t ret = ::Bind(socket, clientQos, QOS_COUNT, &listener);
245     if (ret != 0) {
246         ::Shutdown(socket);
247     }
248     return ret;
249 }
250 
OpenSessionByP2P(char *sessionName, char *peerDeviceId, char *groupId, bool isFileType)251 int SoftbusAdapter::OpenSessionByP2P(char *sessionName,
252                                      char *peerDeviceId,
253                                      char *groupId,
254                                      bool isFileType)
255 {
256     TransDataType dataType;
257     if (isFileType) {
258         dataType = DATA_TYPE_FILE;
259     } else {
260         dataType = DATA_TYPE_BYTES;
261     }
262     return OpenSession(sessionName, peerDeviceId, groupId, dataType);
263 }
264 
CloseSession(int sessionId)265 void SoftbusAdapter::CloseSession(int sessionId)
266 {
267     ::CloseSession(sessionId);
268 }
269 
SendBytes(int sessionId, const void *data, unsigned int dataLen)270 int SoftbusAdapter::SendBytes(int sessionId, const void *data, unsigned int dataLen)
271 {
272     return ::SendBytes(sessionId, data, dataLen);
273 }
274 
SendFile(int sessionId, const std::vector<std::string> &sFileList, const std::vector<std::string> &dFileList)275 int SoftbusAdapter::SendFile(int sessionId,
276                              const std::vector<std::string> &sFileList,
277                              const std::vector<std::string> &dFileList)
278 {
279     vector<const char *> sourceFileList;
280     vector<const char *> destFileList;
281 
282     for (const string &file : sFileList) {
283         sourceFileList.push_back(file.data());
284     }
285 
286     for (const string &file : dFileList) {
287         destFileList.push_back(file.data());
288     }
289 
290     return ::SendFile(sessionId, sourceFileList.data(), destFileList.data(), sourceFileList.size());
291 }
292 
293 /* should use this interface when session closed */
GetSessionNameFromMap(int sessionId)294 std::string SoftbusAdapter::GetSessionNameFromMap(int sessionId)
295 {
296     lock_guard<mutex> lock(sessionMutex_);
297     auto iter = sessionNameMap_.find(sessionId);
298     if (iter != sessionNameMap_.end()) {
299         return iter->second;
300     }
301     return "";
302 }
303 
GetSocketNameFromMap(std::string sessionAndPack)304 int32_t SoftbusAdapter::GetSocketNameFromMap(std::string sessionAndPack)
305 {
306     lock_guard<mutex> lock(sessionMutex_);
307     int32_t socket = -1;
308     for (const auto& pair : sessionAndPackageMap_) {
309         if (pair.second == sessionAndPack) {
310             socket = pair.first;
311             break;
312         }
313     }
314     return socket;
315 }
316 
GetPeerNetworkId(int sessionId)317 std::string SoftbusAdapter::GetPeerNetworkId(int sessionId)
318 {
319     lock_guard<mutex> lock(sessionMutex_);
320     auto iter = networkIdMap_.find(sessionId);
321     if (iter != networkIdMap_.end()) {
322         return iter->second;
323     }
324     return "";
325 }
326 
RegisterSessionListener(std::string sessionName, std::shared_ptr<ISoftbusListener> listener)327 void SoftbusAdapter::RegisterSessionListener(std::string sessionName, std::shared_ptr<ISoftbusListener> listener)
328 {
329     std::unique_lock<shared_mutex> lock(listenerMutex_);
330     listeners_[sessionName] = listener;
331 }
332 
UnRegisterSessionListener(std::string sessionName)333 void SoftbusAdapter::UnRegisterSessionListener(std::string sessionName)
334 {
335     std::unique_lock<shared_mutex> lock(listenerMutex_);
336     listeners_.erase(sessionName);
337 }
338 
GetListener(std::string sessionName)339 std::shared_ptr<ISoftbusListener> SoftbusAdapter::GetListener(std::string sessionName)
340 {
341     shared_lock<shared_mutex> lock(listenerMutex_);
342     if (listeners_.count(sessionName) == 0) {
343         return nullptr;
344     }
345     return listeners_[sessionName];
346 }
347 
IsSessionOpened(int sessionId)348 bool SoftbusAdapter::IsSessionOpened(int sessionId)
349 {
350     lock_guard<mutex> lock(sessionMutex_);
351     auto iter = sessionOpenedMap_.find(sessionId);
352     if (iter == sessionOpenedMap_.end()) {
353         return false;
354     }
355     return iter->second;
356 }
357 
AcceptSesion(int sessionId, const std::string &sessionName, const std::string &networkId)358 void SoftbusAdapter::AcceptSesion(int sessionId, const std::string &sessionName, const std::string &networkId)
359 {
360     lock_guard<mutex> lock(sessionMutex_);
361     auto iter = sessionOpenedMap_.find(sessionId);
362     if (iter == sessionOpenedMap_.end()) {
363         sessionOpenedMap_.insert({sessionId, true});
364     }
365 
366     auto sessionNameMap = sessionNameMap_.find(sessionId);
367     if (sessionNameMap == sessionNameMap_.end()) {
368         sessionNameMap_.insert({sessionId, sessionName});
369     }
370 
371     auto networkIdMap = networkIdMap_.find(sessionId);
372     if (networkIdMap == networkIdMap_.end()) {
373         networkIdMap_.insert({sessionId, networkId});
374     }
375 }
376 
RemoveSesion(int sessionId)377 void SoftbusAdapter::RemoveSesion(int sessionId)
378 {
379     lock_guard<mutex> lock(sessionMutex_);
380     auto iter = sessionOpenedMap_.find(sessionId);
381     if (iter != sessionOpenedMap_.end()) {
382         sessionOpenedMap_.erase(iter);
383     }
384 
385     auto sessionNameMap = sessionNameMap_.find(sessionId);
386     if (sessionNameMap != sessionNameMap_.end()) {
387         sessionNameMap_.erase(sessionNameMap);
388     }
389 
390     auto networkIdMap = networkIdMap_.find(sessionId);
391     if (networkIdMap != networkIdMap_.end()) {
392         networkIdMap_.erase(networkIdMap);
393     }
394 }
395 } // namespace OHOS::FileManagement::CloudSync