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/kernel_talker.h"
17 #include "device/device_manager_agent.h"
18 #include "network/devsl_dispatcher.h"
19 #include "securec.h"
20 #include "utils_log.h"
21 
22 namespace OHOS {
23 namespace Storage {
24 namespace DistributedFile {
25 using namespace std;
26 
27 constexpr int KEY_MAX_LEN = 32;
28 constexpr int POLL_TIMEOUT_MS = 200;
29 constexpr int NONE_EVENT = -1;
30 constexpr int READ_EVENT = 1;
31 constexpr int TIME_OUT_EVENT = 0;
32 
33 struct UpdateSocketParam {
34     int32_t cmd;
35     int32_t newfd;
36     uint32_t devsl;
37     uint8_t status;
38     uint8_t masterKey[KEY_MAX_LEN];
39     uint8_t cid[CID_MAX_LEN];
40 } __attribute__((packed));
41 
42 struct UpdateDevslParam {
43     int32_t cmd;
44     uint32_t devsl;
45     uint8_t cid[CID_MAX_LEN];
46 } __attribute__((packed));
47 
48 struct OfflineParam {
49     int32_t cmd;
50     uint8_t remoteCid[CID_MAX_LEN];
51 } __attribute__((packed));
52 
53 enum CmdCode {
54     CMD_UPDATE_SOCKET = 0,
55     CMD_UPDATE_DEVSL,
56     CMD_OFF_LINE,
57     CMD_OFF_LINE_ALL,
58     CMD_CNT,
59 };
60 
61 enum SocketStat {
62     SOCKET_STAT_ACCEPT = 0,
63     SOCKET_STAT_OPEN,
64 };
65 
66 enum Notify {
67     NOTIFY_GET_SESSION = 0,
68     NOTIFY_OFFLINE,
69     NOTIFY_NONE,
70     NOTIFY_CNT,
71 };
72 
SinkSessionTokernel(shared_ptr<BaseSession> session,const std::string backStage)73 void KernelTalker::SinkSessionTokernel(shared_ptr<BaseSession> session, const std::string backStage)
74 {
75     int socketFd = session->GetHandle();
76     auto masterkey = session->GetKey();
77     auto cid = session->GetCid();
78     LOGI("sink session to kernel success, cid:%{public}s, socketFd:%{public}d",
79         Utils::GetAnonyString(cid).c_str(), socketFd);
80 
81     uint8_t status = (backStage == "Server" ? SOCKET_STAT_ACCEPT : SOCKET_STAT_OPEN);
82 
83     UpdateSocketParam cmd = {
84         .cmd = CMD_UPDATE_SOCKET,
85         .newfd = socketFd,
86         .devsl = 0,
87         .status = status,
88     };
89     if (memcpy_s(cmd.masterKey, KEY_MAX_LEN, masterkey.data(), KEY_MAX_LEN) != EOK) {
90         return;
91     }
92 
93     if (memcpy_s(cmd.cid, CID_MAX_LEN, cid.c_str(), cid.size())) {
94         return;
95     }
96     SetCmd(cmd);
97 
98     DevslDispatcher::DevslGetRegister(cid, shared_from_this());
99 }
100 
SinkDevslTokernel(const std::string & cid,uint32_t devsl)101 void KernelTalker::SinkDevslTokernel(const std::string &cid, uint32_t devsl)
102 {
103     LOGI("sink dsl to kernel success, cid:%{public}s, devsl:%{public}d", Utils::GetAnonyString(cid).c_str(), devsl);
104     UpdateDevslParam cmd = {
105         .cmd = CMD_UPDATE_DEVSL,
106         .devsl = devsl,
107     };
108 
109     if (memcpy_s(cmd.cid, CID_MAX_LEN, cid.c_str(), CID_MAX_LEN)) {
110         return;
111     }
112     SetCmd(cmd);
113 }
114 
SinkOfflineCmdToKernel(string cid)115 void KernelTalker::SinkOfflineCmdToKernel(string cid)
116 {
117     OfflineParam cmd = {
118         .cmd = CMD_OFF_LINE,
119     };
120 
121     if (cid.length() < CID_MAX_LEN) {
122         LOGE("cid lengh err, cid:%{public}s, length:%{public}zu", Utils::GetAnonyString(cid).c_str(), cid.length());
123         return;
124     }
125 
126     if (memcpy_s(cmd.remoteCid, CID_MAX_LEN, cid.c_str(), CID_MAX_LEN) != EOK) {
127         return;
128     }
129     SetCmd(cmd);
130 }
131 
CreatePollThread()132 void KernelTalker::CreatePollThread()
133 {
134     isRunning_ = true;
135     if (pollThread_ != nullptr) {
136         LOGE("pollTread is not null");
137         return;
138     }
139     pollThread_ = make_unique<thread>(&KernelTalker::PollRun, this);
140     LOGI("Create pollThread OK");
141 }
142 
WaitForPollThreadExited()143 void KernelTalker::WaitForPollThreadExited()
144 {
145     isRunning_ = false;
146     if (pollThread_ == nullptr) {
147         LOGE("pollTread is null");
148         return;
149     }
150 
151     if (pollThread_->joinable()) {
152         LOGI("pollThread->joinable is true");
153         pollThread_->join();
154     }
155     pollThread_ = nullptr;
156     LOGI("pollTread exit ok");
157 }
158 
PollRun()159 void KernelTalker::PollRun()
160 {
161     struct pollfd fileFd;
162     int cmdFd = -1;
163 
164     LOGI("entry");
165     auto spt = mountPoint_.lock();
166     if (spt == nullptr) {
167         LOGE("mountPoint is not exist! bad weak_ptr");
168         return;
169     }
170     string ctrlPath = spt->GetMountArgument().GetCtrlPath();
171     LOGI("Open node file ctrl path %{public}s", GetAnonyString(ctrlPath).c_str());
172     char resolvedPath[PATH_MAX] = {'\0'};
173     char *realPath = realpath(ctrlPath.c_str(), resolvedPath);
174     if (realPath == nullptr) {
175         return;
176     }
177     cmdFd = open(realPath, O_RDWR);
178     if (cmdFd < 0) {
179         LOGE("Open node file error %{public}d, ctrl path %{public}s", errno, GetAnonyString(ctrlPath).c_str());
180         return;
181     }
182 
183     LOGI("Open node file success");
184 
185     while (isRunning_) {
186         fileFd.fd = cmdFd;
187         fileFd.events = POLLPRI;
188         fileFd.revents = 0;
189         int ret = poll(&fileFd, 1, POLL_TIMEOUT_MS);
190         switch (ret) {
191             case NONE_EVENT:
192                 LOGI("none event, poll exit");
193                 break;
194             case TIME_OUT_EVENT:
195                 break;
196             case READ_EVENT:
197                 HandleAllNotify(cmdFd);
198                 break;
199             default:
200                 LOGI("poll exit");
201         }
202     }
203     close(cmdFd);
204     LOGI("exit");
205     return;
206 }
207 
HandleAllNotify(int fd)208 void KernelTalker::HandleAllNotify(int fd)
209 {
210     NotifyParam param;
211 
212     while (isRunning_) {
213         lseek(fd, 0, SEEK_SET);
214         param.notify = NOTIFY_NONE;
215         int readSize = read(fd, &param, sizeof(NotifyParam));
216         if ((readSize < (int)sizeof(NotifyParam)) || (param.notify == NOTIFY_NONE)) {
217             return;
218         }
219         NotifyHandler(param);
220     }
221 }
222 
NotifyHandler(NotifyParam & param)223 void KernelTalker::NotifyHandler(NotifyParam &param)
224 {
225     int cmd = param.notify;
226     string cidStr(param.remoteCid, CID_MAX_LEN);
227     switch (cmd) {
228         case NOTIFY_GET_SESSION:
229             GetSessionCallback_(param);
230             break;
231         case NOTIFY_OFFLINE:
232             CloseSessionCallback_(cidStr);
233             break;
234         default:
235             LOGI("cmd %{public}d not support now", cmd);
236             break;
237     }
238 }
239 } // namespace DistributedFile
240 } // namespace Storage
241 } // namespace OHOS
242