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_client.h"
17 #include <cinttypes>
18 #include "util.h"
19
20 namespace OHOS {
21 namespace MMI {
22 namespace {
23 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, MMI_LOG_DOMAIN, "UDSClient" }; // namepace
24 }
25
UDSClient()26 UDSClient::UDSClient()
27 {
28 MMI_LOGD("enter");
29 }
30
~UDSClient()31 UDSClient::~UDSClient()
32 {
33 MMI_LOGD("enter");
34 Stop();
35 MMI_LOGD("leave");
36 }
37
ConnectTo()38 int32_t UDSClient::ConnectTo()
39 {
40 CHKR(Socket() >= 0, SOCKET_CREATE_FAIL, RET_ERR);
41 if (epollFd_ < 0) {
42 CHKR(EpollCreat(MAX_EVENT_SIZE) >= 0, EPOLL_CREATE_FAIL, RET_ERR);
43 }
44 SetNonBlockMode(fd_);
45
46 struct epoll_event ev;
47 ev.events = EPOLLIN;
48 ev.data.fd = fd_;
49 CHKR(EpollCtl(fd_, EPOLL_CTL_ADD, ev) >= 0, EPOLL_CREATE_FAIL, RET_ERR);
50 OnConnected();
51 return RET_OK;
52 }
53
SendMsg(const char * buf,size_t size) const54 bool UDSClient::SendMsg(const char *buf, size_t size) const
55 {
56 CHKPF(buf);
57 if ((size == 0) || (size > MAX_PACKET_BUF_SIZE)) {
58 MMI_LOGE("Stream buffer size out of range");
59 return false;
60 }
61 if (fd_ < 0) {
62 MMI_LOGE("fd_ is less than 0");
63 return false;
64 }
65
66 int32_t idx = 0;
67 int32_t retryCount = 0;
68 const int32_t bufSize = static_cast<int32_t>(size);
69 int32_t remSize = bufSize;
70 while (remSize > 0 && retryCount < SEND_RETRY_LIMIT) {
71 retryCount += 1;
72 auto count = send(fd_, &buf[idx], remSize, MSG_DONTWAIT | MSG_NOSIGNAL);
73 if (count < 0) {
74 if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
75 MMI_LOGW("continue for errno EAGAIN|EINTR|EWOULDBLOCK, errno:%{public}d", errno);
76 usleep(SEND_RETRY_SLEEP_TIME);
77 continue;
78 }
79 MMI_LOGE("Send return failed,error:%{public}d fd:%{public}d", errno, fd_);
80 return false;
81 }
82 idx += count;
83 remSize -= count;
84 if (remSize > 0) {
85 usleep(SEND_RETRY_SLEEP_TIME);
86 }
87 }
88 if (retryCount >= SEND_RETRY_LIMIT || remSize != 0) {
89 MMI_LOGE("Send too many times:%{public}d/%{public}d,size:%{public}d/%{public}d fd:%{public}d",
90 retryCount, SEND_RETRY_LIMIT, idx, bufSize, fd_);
91 return false;
92 }
93 return true;
94 }
95
SendMsg(const NetPacket & pkt) const96 bool UDSClient::SendMsg(const NetPacket& pkt) const
97 {
98 CHKF(!pkt.ChkRWError(), PACKET_WRITE_FAIL);
99 StreamBuffer buf;
100 pkt.MakeData(buf);
101 return SendMsg(buf.Data(), buf.Size());
102 }
103
StartClient(MsgClientFunCallback fun,bool detachMode)104 bool UDSClient::StartClient(MsgClientFunCallback fun, bool detachMode)
105 {
106 MMI_LOGD("enter detachMode = %d", detachMode);
107 recvFun_ = fun;
108 isRunning_ = true;
109 isConnected_ = true;
110 if (ConnectTo() < 0) {
111 MMI_LOGW("Client connection failed, Try again later");
112 isConnected_ = false;
113
114 if (IsFirstConnectFailExit()) {
115 MMI_LOGE("first connection faild");
116 return false;
117 }
118 }
119 t_ = std::thread(std::bind(&UDSClient::OnThread, this));
120 if (detachMode) {
121 MMI_LOGW("uds client thread detach");
122 t_.detach();
123 } else {
124 MMI_LOGW("uds client thread join");
125 }
126 return true;
127 }
128
Disconnected(int32_t fd)129 void UDSClient::Disconnected(int32_t fd)
130 {
131 OnDisconnected();
132 struct epoll_event event = {};
133 EpollCtl(fd, EPOLL_CTL_DEL, event);
134 close(fd);
135 fd_ = -1;
136 isConnected_ = false;
137 }
138
Stop()139 void UDSClient::Stop()
140 {
141 MMI_LOGD("enter");
142 Close();
143 isRunning_ = false;
144 struct epoll_event ev = {};
145 if (fd_ >= 0) {
146 EpollCtl(fd_, EPOLL_CTL_DEL, ev);
147 }
148 EpollClose();
149 if (t_.joinable()) {
150 MMI_LOGD("thread join");
151 t_.join();
152 }
153 MMI_LOGD("leave");
154 }
155
OnPacket(NetPacket & pkt)156 void UDSClient::OnPacket(NetPacket& pkt)
157 {
158 recvFun_(*this, pkt);
159 }
160
OnRecvMsg(const char * buf,size_t size)161 void UDSClient::OnRecvMsg(const char *buf, size_t size)
162 {
163 CHKPV(buf);
164 if (size == 0 || size > MAX_PACKET_BUF_SIZE) {
165 MMI_LOGE("Invalid input param size. size:%{public}zu", size);
166 return;
167 }
168 if (!circBuf_.Write(buf, size)) {
169 MMI_LOGW("Write data faild. size:%{public}zu", size);
170 }
171 OnReadPackets(circBuf_, std::bind(&UDSClient::OnPacket, this, std::placeholders::_1));
172 }
173
OnEvent(const struct epoll_event & ev)174 void UDSClient::OnEvent(const struct epoll_event& ev)
175 {
176 auto fd = ev.data.fd;
177 if ((ev.events & EPOLLERR) || (ev.events & EPOLLHUP)) {
178 MMI_LOGI("ev.events:0x%{public}x,fd:%{public}d same as fd_:%{public}d", ev.events, fd, fd_);
179 Disconnected(fd);
180 return;
181 }
182
183 char szBuff[MAX_PACKET_BUF_SIZE] = {};
184 for (size_t j = 0; j < MAX_RECV_LIMIT; j++) {
185 auto size = recv(fd, szBuff, MAX_PACKET_BUF_SIZE, MSG_DONTWAIT | MSG_NOSIGNAL);
186 if (size > 0) {
187 OnRecvMsg(szBuff, size);
188 } else if (size < 0) {
189 if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
190 MMI_LOGD("continue for errno EAGAIN|EINTR|EWOULDBLOCK size:%{public}zu errno:%{public}d",
191 size, errno);
192 continue;
193 }
194 MMI_LOGE("recv return %{public}zu errno:%{public}d", size, errno);
195 break;
196 } else {
197 MMI_LOGE("The server side disconnect with the client. size:0 errno:%{public}d", errno);
198 Disconnected(fd);
199 break;
200 }
201
202 if (size < MAX_PACKET_BUF_SIZE) {
203 break;
204 }
205 }
206 }
207
OnThread()208 void UDSClient::OnThread()
209 {
210 MMI_LOGD("begin");
211 SetThreadName("uds_client");
212 isThreadHadRun_ = true;
213 struct epoll_event events[MAX_EVENT_SIZE] = {};
214 while (isRunning_) {
215 if (isConnected_) {
216 auto count = EpollWait(events[0], MAX_EVENT_SIZE, DEFINE_EPOLL_TIMEOUT);
217 for (auto i = 0; i < count; i++) {
218 OnEvent(events[i]);
219 }
220 } else {
221 if (ConnectTo() < 0) {
222 MMI_LOGW("Client reconnection failed, Try again after %{public}d ms",
223 CLIENT_RECONNECT_COOLING_TIME);
224 std::this_thread::sleep_for(std::chrono::milliseconds(CLIENT_RECONNECT_COOLING_TIME));
225 continue;
226 }
227 isConnected_ = true;
228 }
229 if (isToExit_) {
230 isRunning_ = false;
231 MMI_LOGW("Client thread exit");
232 break;
233 }
234 }
235 MMI_LOGD("end");
236 }
237
SetToExit()238 void UDSClient::SetToExit()
239 {
240 isToExit_ = true;
241 }
242 } // namespace MMI
243 } // namespace OHOS
244