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 "event_server.h"
17
18#include <fstream>
19#include <memory>
20#include <string>
21#include <vector>
22
23#include <fcntl.h>
24#include <sys/epoll.h>
25#include <sys/socket.h>
26#include <sys/stat.h>
27#include <sys/types.h>
28#include <sys/un.h>
29#include <unistd.h>
30
31#include <securec.h>
32
33#include "base/raw_data_base_def.h"
34#include "decoded/decoded_event.h"
35#include "device_node.h"
36#include "init_socket.h"
37#include "hiview_logger.h"
38#include "socket_util.h"
39
40#define SOCKET_FILE_DIR "/dev/unix/socket/hisysevent"
41
42namespace OHOS {
43namespace HiviewDFX {
44DEFINE_LOG_TAG("HiView-EventServer");
45namespace {
46constexpr int BUFFER_SIZE = 384 * 1024;
47#ifndef KERNEL_DEVICE_BUFFER
48constexpr int EVENT_READ_BUFFER = 2048;
49#else
50constexpr int EVENT_READ_BUFFER = KERNEL_DEVICE_BUFFER;
51#endif
52
53struct Header {
54    unsigned short len;
55    unsigned short headerSize;
56    char msg[0];
57};
58
59void InitSocketBuf(int socketId, int optName)
60{
61    int bufferSizeOld = 0;
62    socklen_t sizeOfInt = static_cast<socklen_t>(sizeof(int));
63    if (getsockopt(socketId, SOL_SOCKET, optName, static_cast<void *>(&bufferSizeOld), &sizeOfInt) < 0) {
64        HIVIEW_LOGE("get socket buffer error=%{public}d, msg=%{public}s", errno, strerror(errno));
65    }
66
67    int bufferSizeSet = BUFFER_SIZE;
68    if (setsockopt(socketId, SOL_SOCKET, optName, static_cast<void *>(&bufferSizeSet), sizeof(int)) < 0) {
69        HIVIEW_LOGE("set socket buffer error=%{public}d, msg=%{public}s", errno, strerror(errno));
70    }
71
72    int bufferSizeNew = 0;
73    sizeOfInt = static_cast<socklen_t>(sizeof(int));
74    if (getsockopt(socketId, SOL_SOCKET, optName, static_cast<void *>(&bufferSizeNew), &sizeOfInt) < 0) {
75        HIVIEW_LOGE("get new socket buffer error=%{public}d, msg=%{public}s", errno, strerror(errno));
76    }
77    HIVIEW_LOGI("reset buffer size old=%{public}d, new=%{public}d", bufferSizeOld, bufferSizeNew);
78}
79
80void InitRecvBuffer(int socketId)
81{
82    InitSocketBuf(socketId, SO_RCVBUF);
83}
84
85std::shared_ptr<EventRaw::RawData> ConverRawData(char* source)
86{
87    if (source == nullptr) {
88        HIVIEW_LOGE("invalid source.");
89        return nullptr;
90    }
91    uint32_t sourceLen = *(reinterpret_cast<uint32_t*>(source));
92    uint32_t desLen = sourceLen + sizeof(uint8_t);
93    uint8_t* des = reinterpret_cast<uint8_t*>(malloc(desLen));
94    if (des == nullptr) {
95        HIVIEW_LOGE("malloc failed.");
96        return nullptr;
97    }
98    uint32_t sourceHeaderLen = sizeof(int32_t) + sizeof(EventRaw::HiSysEventHeader) - sizeof(uint8_t);
99    if (memcpy_s(des, desLen, source, sourceHeaderLen) != EOK) {
100        HIVIEW_LOGE("copy failed.");
101        free(des);
102        return nullptr;
103    }
104    *(reinterpret_cast<uint8_t*>(des + sourceHeaderLen)) = 0; // init header.log flag
105    uint32_t desPos = sourceHeaderLen + sizeof(uint8_t);
106    if (memcpy_s(des + desPos, desLen - desPos, source + sourceHeaderLen, sourceLen - sourceHeaderLen) != EOK) {
107        HIVIEW_LOGE("copy failed.");
108        free(des);
109        return nullptr;
110    }
111    *(reinterpret_cast<int32_t*>(des)) = desLen;
112    auto rawData = std::make_shared<EventRaw::RawData>(des, desLen);
113    free(des);
114    return rawData;
115}
116
117void InitMsgh(char* buffer, int bufferLen, std::array<char, CMSG_SPACE(sizeof(struct ucred))>& control,
118    struct msghdr& msgh, struct iovec& iov)
119{
120    iov.iov_base = buffer;
121    iov.iov_len = static_cast<uint32_t>(bufferLen);
122    msgh.msg_iov = &iov;
123    msgh.msg_iovlen = 1; // 1 is length of io vector
124
125    msgh.msg_control = control.data();
126    msgh.msg_controllen = control.size();
127
128    msgh.msg_name = nullptr;
129    msgh.msg_namelen = 0;
130    msgh.msg_flags = 0;
131}
132
133pid_t ReadPidFromMsgh(struct msghdr& msgh)
134{
135    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msgh);
136    if (cmsg == nullptr) {
137        return UN_INIT_INT_TYPE_VAL;
138    }
139    struct ucred* uCredRecv = reinterpret_cast<struct ucred*>(CMSG_DATA(cmsg));
140    if (uCredRecv == nullptr) {
141        return UN_INIT_INT_TYPE_VAL;
142    }
143    return uCredRecv->pid;
144}
145}
146
147void SocketDevice::InitSocket(int &socketId)
148{
149    struct sockaddr_un serverAddr;
150    serverAddr.sun_family = AF_UNIX;
151    if (strcpy_s(serverAddr.sun_path, sizeof(serverAddr.sun_path), SOCKET_FILE_DIR) != EOK) {
152        socketId = -1;
153        HIVIEW_LOGE("copy hisysevent dev path failed, error=%{public}d, msg=%{public}s", errno, strerror(errno));
154        return;
155    }
156    serverAddr.sun_path[sizeof(serverAddr.sun_path) - 1] = '\0';
157    socketId = TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
158    if (socketId < 0) {
159        HIVIEW_LOGE("create hisysevent socket failed, error=%{public}d, msg=%{public}s", errno, strerror(errno));
160        return;
161    }
162    InitRecvBuffer(socketId_);
163    unlink(serverAddr.sun_path);
164    if (TEMP_FAILURE_RETRY(bind(socketId, reinterpret_cast<sockaddr*>(&serverAddr), sizeof(serverAddr))) < 0) {
165        close(socketId);
166        socketId = -1;
167        HIVIEW_LOGE("bind hisysevent socket failed, error=%{public}d, msg=%{public}s", errno, strerror(errno));
168        return;
169    }
170}
171
172int SocketDevice::Open()
173{
174    socketId_ = GetControlSocket("hisysevent");
175    if (socketId_ < 0) {
176        HIVIEW_LOGI("create hisysevent socket");
177        InitSocket(socketId_);
178    } else {
179        InitRecvBuffer(socketId_);
180        HIVIEW_LOGI("use hisysevent exist socket");
181    }
182
183    if (socketId_ < 0) {
184        HIVIEW_LOGE("hisysevent create socket failed");
185        return -1;
186    }
187    return socketId_;
188}
189
190int SocketDevice::Close()
191{
192    if (socketId_ > 0) {
193        close(socketId_);
194        socketId_ = -1;
195    }
196    return 0;
197}
198
199uint32_t SocketDevice::GetEvents()
200{
201    return EPOLLIN | EPOLLET;
202}
203
204std::string SocketDevice::GetName()
205{
206    return "SysEventSocket";
207}
208
209bool SocketDevice::IsValidMsg(char* msg, int32_t len)
210{
211    if (len < static_cast<int32_t>(EventRaw::GetValidDataMinimumByteCount())) {
212        HIVIEW_LOGD("the data length=%{public}d is invalid", len);
213        return false;
214    }
215    int32_t dataByteCnt = *(reinterpret_cast<int32_t*>(msg));
216    if (dataByteCnt != len) {
217        HIVIEW_LOGW("the data byte count=%{public}d are not equal to read length %{public}d", dataByteCnt, len);
218        return false;
219    }
220    int32_t pid = *(reinterpret_cast<int32_t*>(msg + sizeof(int32_t) + EventRaw::POS_OF_PID_IN_HEADER));
221    if (uCredPid_ > 0 && pid != uCredPid_) {
222        HIVIEW_LOGW("failed to verify the consistensy of process id: [%{public}" PRId32
223            ", %{public}" PRId32 "]", pid, uCredPid_);
224        return false;
225    }
226    msg[len] = '\0';
227    return true;
228}
229
230void SocketDevice::SetUCredPid(const pid_t pid)
231{
232    uCredPid_ = pid;
233}
234
235int SocketDevice::ReceiveMsg(std::vector<std::shared_ptr<EventReceiver>> &receivers)
236{
237    char* buffer = new char[BUFFER_SIZE + 1]();
238    std::array<char, CMSG_SPACE(sizeof(struct ucred))> control = {0};
239    struct msghdr msgh = {0};
240    struct iovec iov = {
241        .iov_base = nullptr,
242        .iov_len = 0
243    };
244    InitMsgh(buffer, BUFFER_SIZE, control, msgh, iov);
245    while (true) {
246        int ret = recvmsg(socketId_, &msgh, 0);
247        if (ret <= 0) {
248            HIVIEW_LOGD("failed to recv msg from socket");
249            break;
250        }
251        pid_t uCredPid = ReadPidFromMsgh(msgh);
252        SetUCredPid(uCredPid);
253        if (!IsValidMsg(buffer, ret)) {
254            break;
255        }
256        for (auto receiver = receivers.begin(); receiver != receivers.end(); receiver++) {
257            (*receiver)->HandlerEvent(ConverRawData(buffer));
258        }
259    }
260    delete[] buffer;
261    return 0;
262}
263
264int BBoxDevice::Close()
265{
266    if (fd_ > 0) {
267        close(fd_);
268        fd_ = -1;
269    }
270    return 0;
271}
272
273int BBoxDevice::Open()
274{
275    fd_ = open("/dev/sysevent", O_RDONLY | O_NONBLOCK, 0);
276    if (fd_ < 0) {
277        fd_ = open("/dev/bbox", O_RDONLY | O_NONBLOCK, 0);
278    } else {
279        hasBbox_ = true;
280    }
281
282    if (fd_ < 0) {
283        HIVIEW_LOGE("open bbox failed, error=%{public}d, msg=%{public}s", errno, strerror(errno));
284        return -1;
285    }
286    return fd_;
287}
288
289uint32_t BBoxDevice::GetEvents()
290{
291    return EPOLLIN;
292}
293
294std::string BBoxDevice::GetName()
295{
296    return "BBox";
297}
298
299bool BBoxDevice::IsValidMsg(char* msg, int32_t len)
300{
301    if (len < static_cast<int32_t>(EventRaw::GetValidDataMinimumByteCount())) {
302        HIVIEW_LOGW("the data length=%{public}d is invalid", len);
303        return false;
304    }
305    int32_t dataByteCnt = *(reinterpret_cast<int32_t*>(msg));
306    if ((hasBbox_ && dataByteCnt != len) ||
307        (!hasBbox_ && dataByteCnt != (len - sizeof(struct Header) - 1))) { // extra bytes in kernel write
308        HIVIEW_LOGW("the data lengths=%{public}d are not equal", len);
309        return false;
310    }
311    msg[EVENT_READ_BUFFER - 1] = '\0';
312    return true;
313}
314
315int BBoxDevice::ReceiveMsg(std::vector<std::shared_ptr<EventReceiver>> &receivers)
316{
317    char buffer[EVENT_READ_BUFFER];
318    (void)memset_s(buffer, sizeof(buffer), 0, sizeof(buffer));
319    int ret = read(fd_, buffer, EVENT_READ_BUFFER);
320    if (!IsValidMsg(buffer, ret)) {
321        return -1;
322    }
323    for (auto receiver = receivers.begin(); receiver != receivers.end(); receiver++) {
324        (*receiver)->HandlerEvent(ConverRawData(buffer));
325    }
326    return 0;
327}
328
329void EventServer::AddDev(std::shared_ptr<DeviceNode> dev)
330{
331    int fd = dev->Open();
332    if (fd < 0) {
333        HIVIEW_LOGI("open device %{public}s failed", dev->GetName().c_str());
334        return;
335    }
336    devs_[fd] = dev;
337}
338
339int EventServer::OpenDevs()
340{
341    AddDev(std::make_shared<SocketDevice>());
342    AddDev(std::make_shared<BBoxDevice>());
343    if (devs_.empty()) {
344        HIVIEW_LOGE("can not open any device");
345        return -1;
346    }
347    HIVIEW_LOGI("has open %{public}zu devices", devs_.size());
348    return 0;
349}
350
351int EventServer::AddToMonitor(int pollFd, struct epoll_event pollEvents[])
352{
353    int index = 0;
354    auto it = devs_.begin();
355    while (it != devs_.end()) {
356        HIVIEW_LOGI("add to poll device %{public}s, fd=%{public}d", it->second->GetName().c_str(), it->first);
357        pollEvents[index].data.fd = it->first;
358        pollEvents[index].events = it->second->GetEvents();
359        int ret = epoll_ctl(pollFd, EPOLL_CTL_ADD, it->first, &pollEvents[index]);
360        if (ret < 0) {
361            HIVIEW_LOGE("add to poll fail device %{public}s error=%{public}d, msg=%{public}s",
362                it->second->GetName().c_str(), errno, strerror(errno));
363            it->second->Close();
364            it = devs_.erase(it);
365        } else {
366            it++;
367        }
368        index++;
369    }
370
371    if (devs_.empty()) {
372        HIVIEW_LOGE("can not monitor any device");
373        return -1;
374    }
375    HIVIEW_LOGI("monitor devices %{public}zu", devs_.size());
376    return 0;
377}
378
379void EventServer::Start()
380{
381    HIVIEW_LOGD("start event server");
382    if (OpenDevs() < 0) {
383        return;
384    }
385
386    int pollFd = epoll_create1(EPOLL_CLOEXEC);
387    if (pollFd < 0) {
388        HIVIEW_LOGE("create poll failed, error=%{public}d, msg=%{public}s", errno, strerror(errno));
389        return;
390    }
391
392    struct epoll_event pollEvents[devs_.size()];
393    if (AddToMonitor(pollFd, pollEvents) < 0) {
394        return;
395    }
396
397    HIVIEW_LOGI("go into event loop");
398    isStart_ = true;
399    while (isStart_) {
400        struct epoll_event chkPollEvents[devs_.size()];
401        int eventCount = epoll_wait(pollFd, chkPollEvents, devs_.size(), -1); // -1: Wait indefinitely
402        if (eventCount <= 0) {
403            HIVIEW_LOGD("read event timeout");
404            continue;
405        }
406        for (int ii = 0; ii < eventCount; ii++) {
407            auto it = devs_.find(chkPollEvents[ii].data.fd);
408            it->second->ReceiveMsg(receivers_);
409        }
410    }
411    CloseDevs();
412}
413
414void EventServer::CloseDevs()
415{
416    for (auto devItem : devs_) {
417        devItem.second->Close();
418    }
419}
420
421void EventServer::Stop()
422{
423    isStart_ = false;
424}
425
426void EventServer::AddReceiver(std::shared_ptr<EventReceiver> receiver)
427{
428    receivers_.emplace_back(receiver);
429}
430} // namespace HiviewDFX
431} // namespace OHOS
432