• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "rs_profiler_socket.h"
17 
18 #include <fcntl.h>
19 #include <netinet/in.h>
20 #include <netinet/tcp.h>
21 #include <securec.h>
22 #include <sys/select.h>
23 #include <sys/ioctl.h>
24 #include <sys/un.h>
25 #include <unistd.h>
26 #include <poll.h>
27 
28 #include "rs_profiler_log.h"
29 #include "rs_profiler_utils.h"
30 
31 namespace OHOS::Rosen {
32 
GetTimeoutDesc(uint32_t milliseconds)33 static timeval GetTimeoutDesc(uint32_t milliseconds)
34 {
35     const uint32_t millisecondsInSecond = 1000u;
36 
37     timeval timeout = {};
38     timeout.tv_sec = milliseconds / millisecondsInSecond;
39     timeout.tv_usec = (milliseconds % millisecondsInSecond) * millisecondsInSecond;
40     return timeout;
41 }
42 
GetTimeout(int32_t socket)43 static timeval GetTimeout(int32_t socket)
44 {
45     timeval timeout = {};
46     socklen_t size = sizeof(timeout);
47     getsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<char*>(&timeout), &size);
48     return timeout;
49 }
50 
SetTimeout(int32_t socket,const timeval & timeout)51 static void SetTimeout(int32_t socket, const timeval& timeout)
52 {
53     setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<const char*>(&timeout), sizeof(timeout));
54 }
55 
SetTimeout(int32_t socket,uint32_t milliseconds)56 static void SetTimeout(int32_t socket, uint32_t milliseconds)
57 {
58     SetTimeout(socket, GetTimeoutDesc(milliseconds));
59 }
60 
ToggleFlag(uint32_t flags,uint32_t flag,bool enable)61 static int32_t ToggleFlag(uint32_t flags, uint32_t flag, bool enable)
62 {
63     return enable ? (flags | flag) : (flags & ~flag);
64 }
65 
SetBlocking(int32_t socket,bool enable)66 static void SetBlocking(int32_t socket, bool enable)
67 {
68     fcntl(socket, F_SETFL, ToggleFlag(fcntl(socket, F_GETFL, 0), O_NONBLOCK, !enable));
69 }
70 
SetCloseOnExec(int32_t socket,bool enable)71 static void SetCloseOnExec(int32_t socket, bool enable)
72 {
73     fcntl(socket, F_SETFD, ToggleFlag(fcntl(socket, F_GETFD, 0), FD_CLOEXEC, enable));
74 }
75 
~Socket()76 Socket::~Socket()
77 {
78     Shutdown();
79 }
80 
Connected() const81 bool Socket::Connected() const
82 {
83     return (socket_ != -1) && (client_ != -1) && (state_ == SocketState::CONNECTED);
84 }
85 
GetState() const86 SocketState Socket::GetState() const
87 {
88     return state_;
89 }
90 
Shutdown()91 void Socket::Shutdown()
92 {
93     shutdown(socket_, SHUT_RDWR);
94     close(socket_);
95     socket_ = -1;
96 
97     shutdown(client_, SHUT_RDWR);
98     close(client_);
99     client_ = -1;
100 
101     state_ = SocketState::SHUTDOWN;
102 }
103 
Open(uint16_t port)104 void Socket::Open(uint16_t port)
105 {
106     socket_ = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
107     if (socket_ == -1) {
108         Shutdown();
109         return;
110     }
111 
112     const std::string socketName = "render_service_" + std::to_string(port);
113     sockaddr_un address {};
114     address.sun_family = AF_UNIX;
115     address.sun_path[0] = 0;
116     ::memmove_s(address.sun_path + 1, sizeof(address.sun_path) - 1, socketName.data(), socketName.size());
117 
118     const size_t addressSize = offsetof(sockaddr_un, sun_path) + socketName.size() + 1;
119     if (bind(socket_, reinterpret_cast<sockaddr*>(&address), addressSize) == -1) {
120         Shutdown();
121         return;
122     }
123 
124     const int32_t maxConnections = 5;
125     if (listen(socket_, maxConnections) != 0) {
126         Shutdown();
127         return;
128     }
129 
130     SetBlocking(socket_, false);
131     SetCloseOnExec(socket_, true);
132 
133     state_ = SocketState::CREATE;
134 }
135 
AcceptClient()136 void Socket::AcceptClient()
137 {
138     client_ = accept4(socket_, nullptr, nullptr, SOCK_CLOEXEC);
139     if (client_ == -1) {
140         if ((errno != EWOULDBLOCK) && (errno != EAGAIN) && (errno != EINTR)) {
141             Shutdown();
142         }
143         return;
144     }
145 
146     SetBlocking(client_, false);
147     SetCloseOnExec(client_, true);
148 
149     int32_t nodelay = 1;
150     setsockopt(client_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&nodelay), sizeof(nodelay));
151 
152     state_ = SocketState::CONNECTED;
153 }
154 
Available()155 size_t Socket::Available()
156 {
157     int32_t size = 0;
158     const auto result = ioctl(client_, FIONREAD, &size);
159     if (result == -1) {
160         HRPE("Socket: Available failed: %d", errno);
161         return 0u;
162     }
163     return static_cast<size_t>(size);
164 }
165 
SendWhenReady(const void * data,size_t size)166 bool Socket::SendWhenReady(const void* data, size_t size)
167 {
168     if (!data || (size == 0)) {
169         return true;
170     }
171 
172     SetBlocking(client_, true);
173 
174     const timeval previousTimeout = GetTimeout(client_);
175 
176     const uint32_t timeoutMilliseconds = 40;
177     SetTimeout(client_, timeoutMilliseconds);
178 
179     const char* bytes = reinterpret_cast<const char*>(data);
180     size_t sent = 0;
181     while (sent < size) {
182         if (PollSend(1) == 0) {
183             // wait for 1ms in worst case to have socket ready for sending
184             continue;
185         }
186         const ssize_t sentBytes = send(client_, bytes, size - sent, 0);
187         if ((sentBytes <= 0) && (errno != EINTR)) {
188             HRPE("Socket: SendWhenReady: Invoke shutdown: %d", errno);
189             Shutdown();
190             return false;
191         }
192         auto actualSentBytes = static_cast<size_t>(sentBytes);
193         sent += actualSentBytes;
194         bytes += actualSentBytes;
195     }
196 
197     SetTimeout(client_, previousTimeout);
198     SetBlocking(client_, false);
199     return true;
200 }
201 
Receive(void * data,size_t & size)202 bool Socket::Receive(void* data, size_t& size)
203 {
204     if (!data || (size == 0)) {
205         return true;
206     }
207 
208     SetBlocking(client_, false);
209 
210     const ssize_t receivedBytes = recv(client_, static_cast<char*>(data), size, 0);
211     if (receivedBytes > 0) {
212         size = static_cast<size_t>(receivedBytes);
213     } else {
214         size = 0;
215         if ((errno == EWOULDBLOCK) || (errno == EAGAIN) || (errno == EINTR)) {
216             return true;
217         }
218         HRPE("Socket: Receive: Invoke shutdown: %d", errno);
219         Shutdown();
220         return false;
221     }
222     return true;
223 }
224 
ReceiveWhenReady(void * data,size_t size)225 bool Socket::ReceiveWhenReady(void* data, size_t size)
226 {
227     if (!data || (size == 0)) {
228         return true;
229     }
230 
231     const timeval previousTimeout = GetTimeout(client_);
232     const uint32_t bandwitdth = 10000; // KB/ms
233     const uint32_t timeoutPad = 100;
234     const uint32_t timeout = size / bandwitdth + timeoutPad;
235 
236     SetBlocking(client_, true);
237     SetTimeout(client_, timeout);
238 
239     size_t received = 0;
240     char* bytes = static_cast<char*>(data);
241     while (received < size) {
242         // receivedBytes can only be -1 or [0, size - received] (from recv man)
243         const ssize_t receivedBytes = recv(client_, bytes, size - received, 0);
244         if ((receivedBytes == -1) && (errno != EINTR)) {
245             HRPE("Socket: ReceiveWhenReady: Invoke shutdown: %d", errno);
246             Shutdown();
247             return false;
248         }
249 
250         // so receivedBytes here always [0, size - received]
251         // then received can't be > `size` and it can't be overflowed
252         auto actualReceivedBytes = static_cast<size_t>(receivedBytes);
253         received += actualReceivedBytes;
254         bytes += actualReceivedBytes;
255     }
256 
257     SetTimeout(client_, previousTimeout);
258     SetBlocking(client_, false);
259     return true;
260 }
261 
PollReceive(int timeout)262 int Socket::PollReceive(int timeout)
263 {
264     struct pollfd pollFd = {0};
265     pollFd.fd = client_;
266     pollFd.events = POLLIN;
267     return poll(&pollFd, 1, timeout);
268 }
269 
PollSend(int timeout)270 int Socket::PollSend(int timeout)
271 {
272     struct pollfd pollFd = {0};
273     pollFd.fd = client_;
274     pollFd.events = POLLOUT;
275     return poll(&pollFd, 1, timeout);
276 }
277 
278 } // namespace OHOS::Rosen