1 /*
2  * Copyright (c) 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 "mmi_fd_listener.h"
17 
18 #include <cinttypes>
19 
20 #include "config_multimodal.h"
21 #include "mmi_log.h"
22 #include "stream_buffer.h"
23 #include "uds_socket.h"
24 
25 #undef MMI_LOG_TAG
26 #define MMI_LOG_TAG "MMIFdListener"
27 
28 namespace OHOS {
29 namespace MMI {
30 using namespace AppExecFwk;
MMIFdListener(MMIClientPtr client)31 MMIFdListener::MMIFdListener(MMIClientPtr client) : mmiClient_(client)
32 {
33     CALL_DEBUG_ENTER;
34 }
35 
OnReadable(int32_t fd)36 void MMIFdListener::OnReadable(int32_t fd)
37 {
38     if (fd < 0) {
39         MMI_HILOGE("Invalid fd:%{public}d", fd);
40         return;
41     }
42     CHKPV(mmiClient_);
43     char szBuf[MAX_PACKET_BUF_SIZE] = {};
44     ssize_t recvSize = 0;
45     bool shouldTry = true;
46     while (shouldTry) {
47         ssize_t oneRecvSize = 0;
48         while (oneRecvSize < MAX_PACKET_BUF_SIZE) {
49             ssize_t size = recv(fd, szBuf + oneRecvSize, MAX_PACKET_BUF_SIZE - oneRecvSize,
50                                 MSG_DONTWAIT | MSG_NOSIGNAL);
51             if (size > 0) {
52                 recvSize += size;
53                 oneRecvSize += size;
54                 continue;
55             }
56 
57             // size 0 means it the fd may be closed.
58             if (size == 0) {
59                 shouldTry = false;
60                 MMI_HILOGE("received %{public}zu, now received 0 from fd %{public}d, wait for next readable", recvSize,
61                            fd);
62                 break;
63             }
64 
65             // size < 0 means there is an error occurred, need to handle the error.
66             int32_t recvError = errno;
67             if (recvError == EAGAIN || recvError == EWOULDBLOCK) {
68                 shouldTry = false;
69                 break;
70             } else if (recvError == EINTR) {
71                 MMI_HILOGW("received %{public}zu, fd %{public}d is interrupted by signal, continue to recv", recvSize,
72                            fd);
73                 continue;
74             } else {
75                 shouldTry = false;
76                 MMI_HILOGE("received %{public}zu, unexpected errno %{public}d on fd %{public}d, wait for next readable",
77                            recvSize, recvError, fd);
78                 break;
79             }
80         }
81         if (oneRecvSize > 0) {
82             mmiClient_->OnRecvMsg(szBuf, oneRecvSize);
83         }
84     }
85 }
86 
OnShutdown(int32_t fd)87 void MMIFdListener::OnShutdown(int32_t fd)
88 {
89     CHK_PID_AND_TID();
90     if (fd < 0) {
91         MMI_HILOGE("Invalid fd:%{public}d", fd);
92     }
93     CHKPV(mmiClient_);
94     mmiClient_->OnDisconnect();
95 }
96 
OnException(int32_t fd)97 void MMIFdListener::OnException(int32_t fd)
98 {
99     CHK_PID_AND_TID();
100     if (fd < 0) {
101         MMI_HILOGE("Invalid fd:%{public}d", fd);
102     }
103     CHKPV(mmiClient_);
104     mmiClient_->OnDisconnect();
105 }
106 } // namespace MMI
107 } // namespace OHOS
108