1 /*
2  * Copyright (c) 2021-2024 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 "network/softbus/softbus_agent.h"
17 
18 #include <sstream>
19 
20 #include "device_manager.h"
21 #include "dfs_daemon_event_dfx.h"
22 #include "dfs_error.h"
23 #include "dfsu_exception.h"
24 #include "dm_device_info.h"
25 #include "ipc_skeleton.h"
26 #include "ipc/i_daemon.h"
27 #include "network/softbus/softbus_session_dispatcher.h"
28 #include "network/softbus/softbus_session_name.h"
29 #include "network/softbus/softbus_session.h"
30 #include "softbus_error_code.h"
31 #include "utils_directory.h"
32 #include "utils_log.h"
33 
34 namespace OHOS {
35 namespace Storage {
36 namespace DistributedFile {
37 namespace {
38     constexpr int MAX_RETRY_COUNT = 7;
39 }
40 using namespace std;
41 const int32_t DFS_QOS_TYPE_MIN_BW = 90 * 1024 * 1024;
42 const int32_t DFS_QOS_TYPE_MAX_LATENCY = 10000;
43 const int32_t DFS_QOS_TYPE_MIN_LATENCY = 2000;
44 #ifdef SUPPORT_SAME_ACCOUNT
45 const uint32_t MAX_ONLINE_DEVICE_SIZE = 10000;
46 #endif
SoftbusAgent(weak_ptr<MountPoint> mountPoint)47 SoftbusAgent::SoftbusAgent(weak_ptr<MountPoint> mountPoint) : NetworkAgentTemplate(mountPoint)
48 {
49     auto spt = mountPoint.lock();
50     if (spt == nullptr) {
51         LOGE("mountPoint is not exist! bad weak_ptr");
52         sessionName_ = "";
53         return;
54     }
55 
56     string path = spt->GetMountArgument().GetFullDst();
57     SoftbusSessionName sessionName(path);
58     sessionName_ = sessionName.ToString();
59 }
60 
IsSameAccount(const std::string & networkId)61 bool SoftbusAgent::IsSameAccount(const std::string &networkId)
62 {
63 #ifdef SUPPORT_SAME_ACCOUNT
64     std::vector<DistributedHardware::DmDeviceInfo> deviceList;
65     DistributedHardware::DeviceManager::GetInstance().GetTrustedDeviceList(IDaemon::SERVICE_NAME, "", deviceList);
66     if (deviceList.size() == 0 || deviceList.size() > MAX_ONLINE_DEVICE_SIZE) {
67         LOGE("trust device list size is invalid, size=%zu", deviceList.size());
68         return false;
69     }
70     for (const auto &deviceInfo : deviceList) {
71         if (std::string(deviceInfo.networkId) == networkId) {
72             return (deviceInfo.authForm == DistributedHardware::DmAuthForm::IDENTICAL_ACCOUNT);
73         }
74     }
75     LOGI("The source and sink device is not same account, not support.");
76     return false;
77 #else
78     return true;
79 #endif
80 }
81 
JudgeNetworkTypeIsWifi(const DeviceInfo & info)82 int32_t SoftbusAgent::JudgeNetworkTypeIsWifi(const DeviceInfo &info)
83 {
84     int32_t networkType;
85     auto &deviceManager = DistributedHardware::DeviceManager::GetInstance();
86     int errCode = deviceManager.GetNetworkTypeByNetworkId(IDaemon::SERVICE_NAME, info.GetCid(), networkType);
87     if (errCode) {
88         LOGE("failed to get network type by network id errCode = %{public}d", errCode);
89         return FileManagement::ERR_BAD_VALUE;
90     }
91     if (!(static_cast<uint32_t>(networkType) & (1 << DistributedHardware::BIT_NETWORK_TYPE_WIFI))) {
92         LOGI("not wifi network networkType = %{public}d == %{public}d", networkType,
93              1 << DistributedHardware::BIT_NETWORK_TYPE_WIFI);
94         return FileManagement::ERR_BAD_VALUE;
95     }
96     return FileManagement::ERR_OK;
97 }
98 
JoinDomain()99 void SoftbusAgent::JoinDomain()
100 {
101     LOGI("JoinDomain Enter.");
102     ISocketListener sessionListener = {
103         .OnBind = SoftbusSessionDispatcher::OnSessionOpened,
104         .OnShutdown = SoftbusSessionDispatcher::OnSessionClosed,
105         .OnBytes = nullptr,
106         .OnMessage = nullptr,
107         .OnStream = nullptr,
108     };
109 
110     SoftbusSessionDispatcher::RegisterSessionListener(sessionName_, shared_from_this());
111     SocketInfo serverInfo = {
112         .name = const_cast<char*>(sessionName_.c_str()),
113         .pkgName = const_cast<char*>(IDaemon::SERVICE_NAME.c_str()),
114         .dataType = DATA_TYPE_BYTES,
115     };
116     int32_t socketId = Socket(serverInfo);
117     if (socketId < 0) {
118         LOGE("Create Socket fail socketId, socketId = %{public}d", socketId);
119         return;
120     }
121     QosTV qos[] = {
122         {.qos = QOS_TYPE_MIN_BW,        .value = DFS_QOS_TYPE_MIN_BW},
123         {.qos = QOS_TYPE_MAX_LATENCY,        .value = DFS_QOS_TYPE_MAX_LATENCY},
124         {.qos = QOS_TYPE_MIN_LATENCY,        .value = DFS_QOS_TYPE_MIN_LATENCY},
125     };
126 
127     int32_t ret = Listen(socketId, qos, sizeof(qos) / sizeof(qos[0]), &sessionListener);
128     if (ret != FileManagement::E_OK) {
129         Shutdown(socketId);
130         stringstream ss;
131         ss << "Failed to CreateSessionServer, errno:" << ret;
132         LOGE("%{public}s, sessionName:%{public}s", ss.str().c_str(), sessionName_.c_str());
133         throw runtime_error(ss.str());
134     }
135     {
136         std::lock_guard<std::mutex> lock(serverIdMapMutex_);
137         serverIdMap_.insert(std::make_pair(sessionName_, socketId));
138     }
139     LOGI("Succeed to JoinDomain, busName:%{public}s", sessionName_.c_str());
140 }
141 
QuitDomain()142 void SoftbusAgent::QuitDomain()
143 {
144     std::lock_guard<std::mutex> lock(serverIdMapMutex_);
145     if (!serverIdMap_.empty()) {
146         for (auto it = serverIdMap_.begin(); it != serverIdMap_.end(); it++) {
147             if ((it->first).find(sessionName_) != std::string::npos) {
148                 int32_t serverId = serverIdMap_[sessionName_];
149                 Shutdown(serverId);
150                 LOGI("RemoveSessionServer success.");
151             }
152         }
153     }
154     SoftbusSessionDispatcher::UnregisterSessionListener(sessionName_.c_str());
155     LOGI("Succeed to QuitDomain, busName:%{public}s", sessionName_.c_str());
156 }
157 
StopTopHalf()158 void SoftbusAgent::StopTopHalf()
159 {
160     QuitDomain();
161 }
162 
StopBottomHalf()163 void SoftbusAgent::StopBottomHalf() {}
164 
OpenSession(const DeviceInfo & info,const uint8_t & linkType)165 int32_t SoftbusAgent::OpenSession(const DeviceInfo &info, const uint8_t &linkType)
166 {
167     LOGI("Start to OpenSession, cid:%{public}s", Utils::GetAnonyString(info.GetCid()).c_str());
168     if (!IsSameAccount(info.GetCid())) {
169         return FileManagement::E_INVAL_ARG;
170     }
171     ISocketListener sessionListener = {
172         .OnBind = SoftbusSessionDispatcher::OnSessionOpened,
173         .OnShutdown = SoftbusSessionDispatcher::OnSessionClosed,
174         .OnBytes = nullptr,
175         .OnMessage = nullptr,
176         .OnStream = nullptr,
177     };
178     QosTV qos[] = {
179         {.qos = QOS_TYPE_MIN_BW,        .value = DFS_QOS_TYPE_MIN_BW},
180         {.qos = QOS_TYPE_MAX_LATENCY,        .value = DFS_QOS_TYPE_MAX_LATENCY},
181         {.qos = QOS_TYPE_MIN_LATENCY,        .value = DFS_QOS_TYPE_MIN_LATENCY},
182     };
183     SocketInfo clientInfo = {
184         .name = const_cast<char*>((sessionName_.c_str())),
185         .peerName = const_cast<char*>(sessionName_.c_str()),
186         .peerNetworkId = const_cast<char*>(info.GetCid().c_str()),
187         .pkgName = const_cast<char*>(IDaemon::SERVICE_NAME.c_str()),
188         .dataType = DATA_TYPE_BYTES,
189     };
190     int32_t socketId = Socket(clientInfo);
191     if (socketId < FileManagement::E_OK) {
192         LOGE("Create OpenSoftbusChannel Socket error");
193         return FileManagement::E_CONTEXT;
194     }
195     if (FindSocketId(socketId)) {
196         LOGW("Has find socketId:%{public}d", socketId);
197         return FileManagement::E_OK;
198     }
199     int32_t ret = Bind(socketId, qos, sizeof(qos) / sizeof(qos[0]), &sessionListener);
200     if (ret != FileManagement::E_OK) {
201         LOGE("Bind SocketClient error");
202         RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_BUILD__LINK, RadarReporter::DFX_FAILED,
203             RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::ERROR_CODE,
204             RadarReporter::BIND_SOCKET_ERROR, RadarReporter::PACKAGE_NAME, RadarReporter::dSoftBus + to_string(ret));
205         Shutdown(socketId);
206         return FileManagement::E_CONTEXT;
207     }
208     auto session = make_shared<SoftbusSession>(socketId, info.GetCid());
209     session->DisableSessionListener();
210     session->SetFromServer(false);
211     AcceptSession(session, "Client");
212     LOGI("Suc OpenSession socketId:%{public}d, cid:%{public}s", socketId, Utils::GetAnonyString(info.GetCid()).c_str());
213     return FileManagement::E_OK;
214 }
215 
CloseSession(shared_ptr<BaseSession> session)216 void SoftbusAgent::CloseSession(shared_ptr<BaseSession> session)
217 {
218     if (session == nullptr) {
219         LOGE("Failed to close session, error:invalid session");
220         return;
221     }
222     session->Release();
223 }
224 
IsContinueRetry(const string & cid)225 bool SoftbusAgent::IsContinueRetry(const string &cid)
226 {
227     auto retriedTimesMap = OpenSessionRetriedTimesMap_.find(cid);
228     if (retriedTimesMap != OpenSessionRetriedTimesMap_.end()) {
229         if (retriedTimesMap->second >= MAX_RETRY_COUNT) {
230             return false;
231         }
232     } else {
233         OpenSessionRetriedTimesMap_[cid] = 0;
234     }
235     OpenSessionRetriedTimesMap_[cid]++;
236     return true;
237 }
238 
OnSessionOpened(const int32_t sessionId,PeerSocketInfo info)239 void SoftbusAgent::OnSessionOpened(const int32_t sessionId, PeerSocketInfo info)
240 {
241     LOGI("OnSessionOpened sessionId = %{public}d", sessionId);
242     std::string peerDeviceId = info.networkId;
243     auto session = make_shared<SoftbusSession>(sessionId, peerDeviceId);
244     session->DisableSessionListener();
245     session->SetFromServer(true);
246     AcceptSession(session, "Server");
247 }
248 
OnSessionClosed(int32_t sessionId,const std::string peerDeviceId)249 void SoftbusAgent::OnSessionClosed(int32_t sessionId, const std::string peerDeviceId)
250 {
251     LOGI("OnSessionClosed Enter.");
252     Shutdown(sessionId);
253 }
254 } // namespace DistributedFile
255 } // namespace Storage
256 } // namespace OHOS
257