• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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