1/*
2 * Copyright (c) 2021-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 "uds_socket.h"
17
18#include <cinttypes>
19
20#include "error_multimodal.h"
21#include "mmi_log.h"
22
23#undef MMI_LOG_TAG
24#define MMI_LOG_TAG "UDSSocket"
25
26namespace OHOS {
27namespace MMI {
28UDSSocket::UDSSocket() {}
29
30UDSSocket::~UDSSocket()
31{
32    Close();
33    EpollClose();
34}
35
36int32_t UDSSocket::EpollCreate(int32_t size)
37{
38    epollFd_ = epoll_create(size);
39    if (epollFd_ < 0) {
40        MMI_HILOGE("epoll_create return %{public}d", epollFd_);
41    } else {
42        MMI_HILOGI("epoll_create, epollFd_:%{public}d", epollFd_);
43    }
44    return epollFd_;
45}
46
47int32_t UDSSocket::EpollCtl(int32_t fd, int32_t op, struct epoll_event &event, int32_t epollFd)
48{
49    if (fd < 0) {
50        MMI_HILOGE("Invalid fd");
51        return RET_ERR;
52    }
53    if (epollFd < 0) {
54        epollFd = epollFd_;
55    }
56    if (epollFd < 0) {
57        MMI_HILOGE("Invalid param epollFd");
58        return RET_ERR;
59    }
60    int32_t ret;
61    if (op == EPOLL_CTL_DEL) {
62        ret = epoll_ctl(epollFd, op, fd, nullptr);
63    } else {
64        ret = epoll_ctl(epollFd, op, fd, &event);
65    }
66    if (ret < 0) {
67        MMI_HILOGE("epoll_ctl return %{public}d,epollFd_:%{public}d,"
68                   "op:%{public}d,fd:%{public}d,errno:%{public}d",
69                   ret, epollFd, op, fd, errno);
70    }
71    return ret;
72}
73
74int32_t UDSSocket::EpollWait(struct epoll_event &events, int32_t maxevents, int32_t timeout, int32_t epollFd)
75{
76    if (epollFd < 0) {
77        epollFd = epollFd_;
78    }
79    if (epollFd < 0) {
80        MMI_HILOGE("Invalid param epollFd");
81        return RET_ERR;
82    }
83    auto ret = epoll_wait(epollFd, &events, maxevents, timeout);
84    if (ret < 0) {
85        MMI_HILOGE("epoll_wait ret:%{public}d,errno:%{public}d", ret, errno);
86    }
87    return ret;
88}
89
90void UDSSocket::OnReadPackets(CircleStreamBuffer &circBuf, UDSSocket::PacketCallBackFun callbackFun)
91{
92    constexpr int32_t headSize = static_cast<int32_t>(sizeof(PackHead));
93    while (!circBuf.IsEmpty()) {
94        const int32_t unreadSize = circBuf.UnreadSize();
95        if (unreadSize < headSize) {
96            break;
97        }
98        int32_t dataSize = unreadSize - headSize;
99        char *buf = const_cast<char *>(circBuf.ReadBuf());
100        CHKPB(buf);
101        PackHead *head = reinterpret_cast<PackHead *>(buf);
102        CHKPB(head);
103        if (head->size < 0 || head->size > MAX_PACKET_BUF_SIZE) {
104            MMI_HILOGF("Packet header parsing error, and this error cannot be recovered. The buffer will be reset."
105                " head->size:%{public}d, unreadSize:%{public}d", head->size, unreadSize);
106            circBuf.Reset();
107            break;
108        }
109        if (head->size > dataSize) {
110            break;
111        }
112        NetPacket pkt(head->idMsg);
113        if ((head->size > 0) && (!pkt.Write(&buf[headSize], head->size))) {
114            MMI_HILOGW("Error writing data in the NetPacket. It will be retried next time. messageid:%{public}d,"
115                "size:%{public}d", head->idMsg, head->size);
116            break;
117        }
118        if (!circBuf.SeekReadPos(pkt.GetPacketLength())) {
119            MMI_HILOGW("Set read position error, and this error cannot be recovered, and the buffer will be reset."
120                " packetSize:%{public}d unreadSize:%{public}d", pkt.GetPacketLength(), unreadSize);
121            circBuf.Reset();
122            break;
123        }
124        callbackFun(pkt);
125        if (circBuf.IsEmpty()) {
126            circBuf.Reset();
127            break;
128        }
129    }
130}
131
132void UDSSocket::EpollClose()
133{
134    if (epollFd_ >= 0) {
135        close(epollFd_);
136        epollFd_ = -1;
137    }
138}
139
140void UDSSocket::Close()
141{
142    if (fd_ >= 0) {
143        auto rf = close(fd_);
144        if (rf > 0) {
145            MMI_HILOGE("Socket close failed rf:%{public}d", rf);
146        }
147    }
148    fd_ = -1;
149}
150} // namespace MMI
151} // namespace OHOS