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 "websocket.h"
17
18 #include "define.h"
19 #include "log_wrapper.h"
20 #include "securec.h"
21
22 namespace OHOS::ArkCompiler::Toolchain {
23 /**
24 * SendMessage in WebSocket has 3 situations:
25 * 1. message's length <= 125
26 * 2. message's length >= 126 && messages's length < 65536
27 * 3. message's length >= 65536
28 */
29
SendReply(const std::string & message) const30 void WebSocket::SendReply(const std::string& message) const
31 {
32 if (socketState_ != SocketState::CONNECTED) {
33 LOGE("SendReply failed, websocket not connected");
34 return;
35 }
36 const size_t msgLen = message.length();
37 const uint32_t headerSize = 11; // 11: the maximum expandable length
38 std::unique_ptr<char []> msgBuf = std::make_unique<char []>(msgLen + headerSize);
39 char* sendBuf = msgBuf.get();
40 uint32_t sendMsgLen;
41 sendBuf[0] = 0x81; // 0x81: the text message sent by the server should start with '0x81'.
42
43 // Depending on the length of the messages, server will use shift operation to get the res
44 // and store them in the buffer.
45 if (msgLen <= 125) { // 125: situation 1 when message's length <= 125
46 sendBuf[1] = msgLen;
47 sendMsgLen = 2; // 2: the length of header frame is 2
48 } else if (msgLen < 65536) { // 65536: message's length
49 sendBuf[1] = 126; // 126: payloadLen according to the spec
50 sendBuf[2] = ((msgLen >> 8) & 0xff); // 8: shift right by 8 bits => res * (256^1)
51 sendBuf[3] = (msgLen & 0xff); // 3: store len's data => res * (256^0)
52 sendMsgLen = 4; // 4: the length of header frame is 4
53 } else {
54 sendBuf[1] = 127; // 127: payloadLen according to the spec
55 for (int32_t i = 2; i <= 5; i++) { // 2 ~ 5: unused bits
56 sendBuf[i] = 0;
57 }
58 sendBuf[6] = ((msgLen & 0xff000000) >> 24); // 6: shift 24 bits => res * (256^3)
59 sendBuf[7] = ((msgLen & 0x00ff0000) >> 16); // 7: shift 16 bits => res * (256^2)
60 sendBuf[8] = ((msgLen & 0x0000ff00) >> 8); // 8: shift 8 bits => res * (256^1)
61 sendBuf[9] = (msgLen & 0x000000ff); // 9: res * (256^0)
62 sendMsgLen = 10; // 10: the length of header frame is 10
63 }
64 if (memcpy_s(sendBuf + sendMsgLen, msgLen, message.c_str(), msgLen) != EOK) {
65 LOGE("SendReply: memcpy_s failed");
66 return;
67 }
68 sendBuf[sendMsgLen + msgLen] = '\0';
69 if (!Send(client_, sendBuf, sendMsgLen + msgLen, 0)) {
70 LOGE("SendReply: send failed");
71 return;
72 }
73 }
74
HttpProtocolDecode(const std::string & request,HttpProtocol & req)75 bool WebSocket::HttpProtocolDecode(const std::string& request, HttpProtocol& req)
76 {
77 if (request.find("GET") == std::string::npos) {
78 LOGE("Handshake failed: lack of necessary info");
79 return false;
80 }
81 std::vector<std::string> reqStr = ProtocolSplit(request, EOL);
82 for (size_t i = 0; i < reqStr.size(); i++) {
83 if (i == 0) {
84 std::vector<std::string> headers = ProtocolSplit(reqStr.at(i), " ");
85 req.version = headers.at(2); // 2: to get the version param
86 } else if (i < reqStr.size() - 1) {
87 std::vector<std::string> headers = ProtocolSplit(reqStr.at(i), ": ");
88 if (reqStr.at(i).find("Connection") != std::string::npos) {
89 req.connection = headers.at(1); // 1: to get the connection param
90 } else if (reqStr.at(i).find("Upgrade") != std::string::npos) {
91 req.upgrade = headers.at(1); // 1: to get the upgrade param
92 } else if (reqStr.at(i).find("Sec-WebSocket-Key") != std::string::npos) {
93 req.secWebSocketKey = headers.at(1); // 1: to get the secWebSocketKey param
94 }
95 }
96 }
97 return true;
98 }
99
100 /**
101 * The wired format of this data transmission section is described in detail through ABNFRFC5234.
102 * When receive the message, we should decode it according the spec. The structure is as follows:
103 * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
104 * +-+-+-+-+-------+-+-------------+-------------------------------+
105 * |F|R|R|R| opcode|M| Payload len | Extended payload length |
106 * |I|S|S|S| (4) |A| (7) | (16/64) |
107 * |N|V|V|V| |S| | (if payload len==126/127) |
108 * | |1|2|3| |K| | |
109 * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
110 * | Extended payload length continued, if payload len == 127 |
111 * + - - - - - - - - - - - - - - - +-------------------------------+
112 * | |Masking-key, if MASK set to 1 |
113 * +-------------------------------+-------------------------------+
114 * | Masking-key (continued) | Payload Data |
115 * +-------------------------------- - - - - - - - - - - - - - - - +
116 * : Payload Data continued ... :
117 * + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
118 * | Payload Data continued ... |
119 * +---------------------------------------------------------------+
120 */
121
HandleFrame(WebSocketFrame & wsFrame)122 bool WebSocket::HandleFrame(WebSocketFrame& wsFrame)
123 {
124 if (wsFrame.payloadLen == 126) { // 126: the payloadLen read from frame
125 char recvbuf[PAYLOAD_LEN + 1] = {0};
126 if (!Recv(client_, recvbuf, PAYLOAD_LEN, 0)) {
127 LOGE("HandleFrame: Recv payloadLen == 126 failed");
128 return false;
129 }
130
131 uint16_t msgLen = 0;
132 if (memcpy_s(&msgLen, sizeof(recvbuf), recvbuf, sizeof(recvbuf) - 1) != EOK) {
133 LOGE("HandleFrame: memcpy_s failed");
134 return false;
135 }
136 wsFrame.payloadLen = ntohs(msgLen);
137 } else if (wsFrame.payloadLen > 126) { // 126: the payloadLen read from frame
138 char recvbuf[EXTEND_PAYLOAD_LEN + 1] = {0};
139 if (!Recv(client_, recvbuf, EXTEND_PAYLOAD_LEN, 0)) {
140 LOGE("HandleFrame: Recv payloadLen > 127 failed");
141 return false;
142 }
143 wsFrame.payloadLen = NetToHostLongLong(recvbuf, EXTEND_PAYLOAD_LEN);
144 }
145 return DecodeMessage(wsFrame);
146 }
147
DecodeMessage(WebSocketFrame & wsFrame)148 bool WebSocket::DecodeMessage(WebSocketFrame& wsFrame)
149 {
150 if (wsFrame.payloadLen == 0 || wsFrame.payloadLen > UINT64_MAX) {
151 LOGE("ReadMsg length error, expected greater than zero and less than UINT64_MAX");
152 return false;
153 }
154 uint64_t msgLen = wsFrame.payloadLen;
155 wsFrame.payload = std::make_unique<char []>(msgLen + 1);
156 if (wsFrame.mask == 1) {
157 char buf[msgLen + 1];
158 if (!Recv(client_, wsFrame.maskingkey, SOCKET_MASK_LEN, 0)) {
159 LOGE("DecodeMessage: Recv maskingkey failed");
160 return false;
161 }
162
163 if (!Recv(client_, buf, msgLen, 0)) {
164 LOGE("DecodeMessage: Recv message with mask failed");
165 return false;
166 }
167
168 for (uint64_t i = 0; i < msgLen; i++) {
169 uint64_t j = i % SOCKET_MASK_LEN;
170 wsFrame.payload.get()[i] = buf[i] ^ wsFrame.maskingkey[j];
171 }
172 } else {
173 char buf[msgLen + 1];
174 if (!Recv(client_, buf, msgLen, 0)) {
175 LOGE("DecodeMessage: Recv message without mask failed");
176 return false;
177 }
178
179 if (memcpy_s(wsFrame.payload.get(), msgLen, buf, msgLen) != EOK) {
180 LOGE("DecodeMessage: memcpy_s failed");
181 return false;
182 }
183 }
184 wsFrame.payload.get()[msgLen] = '\0';
185 return true;
186 }
187
ProtocolUpgrade(const HttpProtocol & req)188 bool WebSocket::ProtocolUpgrade(const HttpProtocol& req)
189 {
190 std::string rawKey = req.secWebSocketKey + WEB_SOCKET_GUID;
191 unsigned const char* webSocketKey = reinterpret_cast<unsigned const char*>(std::move(rawKey).c_str());
192 unsigned char hash[SHA_DIGEST_LENGTH + 1];
193 SHA1(webSocketKey, strlen(reinterpret_cast<const char*>(webSocketKey)), hash);
194 hash[SHA_DIGEST_LENGTH] = '\0';
195 unsigned char encodedKey[ENCODED_KEY_LEN];
196 EVP_EncodeBlock(encodedKey, reinterpret_cast<const unsigned char*>(hash), SHA_DIGEST_LENGTH);
197 std::string response;
198
199 std::ostringstream sstream;
200 sstream << "HTTP/1.1 101 Switching Protocols" << EOL;
201 sstream << "Connection: upgrade" << EOL;
202 sstream << "Upgrade: websocket" << EOL;
203 sstream << "Sec-WebSocket-Accept: " << encodedKey << EOL;
204 sstream << EOL;
205 response = sstream.str();
206 if (!Send(client_, response.c_str(), response.length(), 0)) {
207 LOGE("ProtocolUpgrade: Send failed");
208 return false;
209 }
210 return true;
211 }
212
Decode()213 std::string WebSocket::Decode()
214 {
215 if (socketState_ != SocketState::CONNECTED) {
216 LOGE("Decode failed, websocket not connected!");
217 return "";
218 }
219 char recvbuf[SOCKET_HEADER_LEN + 1];
220 if (!Recv(client_, recvbuf, SOCKET_HEADER_LEN, 0)) {
221 LOGE("Decode failed, client websocket disconnect");
222 socketState_ = SocketState::INITED;
223 #if defined(OHOS_PLATFORM)
224 shutdown(client_, SHUT_RDWR);
225 close(client_);
226 client_ = -1;
227 #else
228 close(client_);
229 client_ = -1;
230 #endif
231 return "";
232 }
233 WebSocketFrame wsFrame;
234 int32_t index = 0;
235 wsFrame.fin = static_cast<uint8_t>(recvbuf[index] >> 7); // 7: shift right by 7 bits to get the fin
236 wsFrame.opcode = static_cast<uint8_t>(recvbuf[index] & 0xf);
237 if (wsFrame.opcode == 0x1) { // 0x1: 0x1 means a text frame
238 index++;
239 wsFrame.mask = static_cast<uint8_t>((recvbuf[index] >> 7) & 0x1); // 7: to get the mask
240 wsFrame.payloadLen = recvbuf[index] & 0x7f;
241 if (HandleFrame(wsFrame)) {
242 return wsFrame.payload.get();
243 }
244 return "";
245 } else if (wsFrame.opcode == 0x9) { // 0x9: 0x9 means a ping frame
246 // send pong frame
247 char pongFrame[SOCKET_HEADER_LEN] = {0};
248 pongFrame[0] = 0x8a; // 0x8a: 0x8a means a pong frame
249 pongFrame[1] = 0x0;
250 if (!Send(client_, pongFrame, SOCKET_HEADER_LEN, 0)) {
251 LOGE("Decode: Send pong frame failed");
252 return "";
253 }
254 }
255 return "";
256 }
257
HttpHandShake()258 bool WebSocket::HttpHandShake()
259 {
260 char msgBuf[SOCKET_HANDSHAKE_LEN] = {0};
261 ssize_t msgLen = recv(client_, msgBuf, SOCKET_HANDSHAKE_LEN, 0);
262 if (msgLen <= 0) {
263 LOGE("ReadMsg failed, msgLen = %{public}ld, errno = %{public}d", static_cast<long>(msgLen), errno);
264 return false;
265 } else {
266 msgBuf[msgLen - 1] = '\0';
267 HttpProtocol req;
268 if (!HttpProtocolDecode(msgBuf, req)) {
269 LOGE("HttpHandShake: Upgrade failed");
270 return false;
271 } else if (req.connection.find("Upgrade") != std::string::npos &&
272 req.upgrade.find("websocket") != std::string::npos && req.version.compare("HTTP/1.1") == 0) {
273 ProtocolUpgrade(req);
274 }
275 }
276 return true;
277 }
278
279 #if !defined(OHOS_PLATFORM)
InitTcpWebSocket(int port,uint32_t timeoutLimit)280 bool WebSocket::InitTcpWebSocket(int port, uint32_t timeoutLimit)
281 {
282 if (port < 0) {
283 LOGE("InitTcpWebSocket invalid port");
284 return false;
285 }
286
287 if (socketState_ != SocketState::UNINITED) {
288 LOGI("InitTcpWebSocket websocket has inited");
289 return true;
290 }
291 #if defined(WINDOWS_PLATFORM)
292 WORD sockVersion = MAKEWORD(2, 2); // 2: version 2.2
293 WSADATA wsaData;
294 if (WSAStartup(sockVersion, &wsaData) != 0) {
295 LOGE("InitTcpWebSocket WSA init failed");
296 return false;
297 }
298 #endif
299 fd_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
300 if (fd_ < SOCKET_SUCCESS) {
301 LOGE("InitTcpWebSocket socket init failed, errno = %{public}d", errno);
302 return false;
303 }
304 // allow specified port can be used at once and not wait TIME_WAIT status ending
305 int sockOptVal = 1;
306 if ((setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR,
307 reinterpret_cast<char *>(&sockOptVal), sizeof(sockOptVal))) != SOCKET_SUCCESS) {
308 LOGE("InitTcpWebSocket setsockopt SO_REUSEADDR failed, errno = %{public}d", errno);
309 close(fd_);
310 fd_ = -1;
311 return false;
312 }
313
314 // set send and recv timeout
315 if (!SetWebSocketTimeOut(fd_, timeoutLimit)) {
316 LOGE("InitTcpWebSocket SetWebSocketTimeOut failed");
317 close(fd_);
318 fd_ = -1;
319 return false;
320 }
321
322 sockaddr_in addr_sin = {0};
323 addr_sin.sin_family = AF_INET;
324 addr_sin.sin_port = htons(port);
325 addr_sin.sin_addr.s_addr = INADDR_ANY;
326 if (bind(fd_, reinterpret_cast<struct sockaddr*>(&addr_sin), sizeof(addr_sin)) < SOCKET_SUCCESS) {
327 LOGE("InitTcpWebSocket bind failed, errno = %{public}d", errno);
328 close(fd_);
329 fd_ = -1;
330 return false;
331 }
332 if (listen(fd_, 1) < SOCKET_SUCCESS) {
333 LOGE("InitTcpWebSocket listen failed, errno = %{public}d", errno);
334 close(fd_);
335 fd_ = -1;
336 return false;
337 }
338 socketState_ = SocketState::INITED;
339 return true;
340 }
341
ConnectTcpWebSocket()342 bool WebSocket::ConnectTcpWebSocket()
343 {
344 if (socketState_ == SocketState::UNINITED) {
345 LOGE("ConnectTcpWebSocket failed, websocket not inited");
346 return false;
347 }
348 if (socketState_ == SocketState::CONNECTED) {
349 LOGI("ConnectTcpWebSocket websocket has connected");
350 return true;
351 }
352
353 if ((client_ = accept(fd_, nullptr, nullptr)) < SOCKET_SUCCESS) {
354 LOGI("ConnectTcpWebSocket accept has exited");
355 socketState_ = SocketState::UNINITED;
356 close(fd_);
357 fd_ = -1;
358 return false;
359 }
360
361 if (!HttpHandShake()) {
362 LOGE("ConnectTcpWebSocket HttpHandShake failed");
363 socketState_ = SocketState::UNINITED;
364 close(client_);
365 client_ = -1;
366 close(fd_);
367 fd_ = -1;
368 return false;
369 }
370 socketState_ = SocketState::CONNECTED;
371 return true;
372 }
373 #else
InitUnixWebSocket(const std::string & sockName,uint32_t timeoutLimit)374 bool WebSocket::InitUnixWebSocket(const std::string& sockName, uint32_t timeoutLimit)
375 {
376 if (socketState_ != SocketState::UNINITED) {
377 LOGI("InitUnixWebSocket websocket has inited");
378 return true;
379 }
380 fd_ = socket(AF_UNIX, SOCK_STREAM, 0); // 0: defautlt protocol
381 if (fd_ < SOCKET_SUCCESS) {
382 LOGE("InitUnixWebSocket socket init failed, errno = %{public}d", errno);
383 return false;
384 }
385 // set send and recv timeout
386 if (!SetWebSocketTimeOut(fd_, timeoutLimit)) {
387 LOGE("InitUnixWebSocket SetWebSocketTimeOut failed");
388 close(fd_);
389 fd_ = -1;
390 return false;
391 }
392
393 struct sockaddr_un un;
394 if (memset_s(&un, sizeof(un), 0, sizeof(un)) != EOK) {
395 LOGE("InitUnixWebSocket memset_s failed");
396 close(fd_);
397 fd_ = -1;
398 return false;
399 }
400 un.sun_family = AF_UNIX;
401 if (strcpy_s(un.sun_path + 1, sizeof(un.sun_path) - 1, sockName.c_str()) != EOK) {
402 LOGE("InitUnixWebSocket strcpy_s failed");
403 close(fd_);
404 fd_ = -1;
405 return false;
406 }
407 un.sun_path[0] = '\0';
408 uint32_t len = offsetof(struct sockaddr_un, sun_path) + strlen(sockName.c_str()) + 1;
409 if (bind(fd_, reinterpret_cast<struct sockaddr*>(&un), static_cast<int32_t>(len)) < SOCKET_SUCCESS) {
410 LOGE("InitUnixWebSocket bind failed, errno = %{public}d", errno);
411 close(fd_);
412 fd_ = -1;
413 return false;
414 }
415 if (listen(fd_, 1) < SOCKET_SUCCESS) { // 1: connection num
416 LOGE("InitUnixWebSocket listen failed, errno = %{public}d", errno);
417 close(fd_);
418 fd_ = -1;
419 return false;
420 }
421 socketState_ = SocketState::INITED;
422 return true;
423 }
424
ConnectUnixWebSocket()425 bool WebSocket::ConnectUnixWebSocket()
426 {
427 if (socketState_ == SocketState::UNINITED) {
428 LOGE("ConnectUnixWebSocket failed, websocket not inited");
429 return false;
430 }
431 if (socketState_ == SocketState::CONNECTED) {
432 LOGI("ConnectUnixWebSocket websocket has connected");
433 return true;
434 }
435
436 if ((client_ = accept(fd_, nullptr, nullptr)) < SOCKET_SUCCESS) {
437 LOGI("ConnectUnixWebSocket accept has exited");
438 socketState_ = SocketState::UNINITED;
439 close(fd_);
440 fd_ = -1;
441 return false;
442 }
443 if (!HttpHandShake()) {
444 LOGE("ConnectUnixWebSocket HttpHandShake failed");
445 socketState_ = SocketState::UNINITED;
446 shutdown(client_, SHUT_RDWR);
447 close(client_);
448 client_ = -1;
449 shutdown(fd_, SHUT_RDWR);
450 close(fd_);
451 fd_ = -1;
452 return false;
453 }
454 socketState_ = SocketState::CONNECTED;
455 return true;
456 }
457 #endif
458
IsConnected()459 bool WebSocket::IsConnected()
460 {
461 return socketState_ == SocketState::CONNECTED;
462 }
463
Close()464 void WebSocket::Close()
465 {
466 if (socketState_ == SocketState::UNINITED) {
467 return;
468 }
469 if (socketState_ == SocketState::CONNECTED) {
470 #if defined(OHOS_PLATFORM)
471 shutdown(client_, SHUT_RDWR);
472 #endif
473 close(client_);
474 client_ = -1;
475 }
476 socketState_ = SocketState::UNINITED;
477 usleep(10000); // 10000: time for websocket to enter the accept
478 #if defined(OHOS_PLATFORM)
479 shutdown(fd_, SHUT_RDWR);
480 #endif
481 close(fd_);
482 fd_ = -1;
483 }
484
NetToHostLongLong(char * buf,uint32_t len)485 uint64_t WebSocket::NetToHostLongLong(char* buf, uint32_t len)
486 {
487 uint64_t result = 0;
488 for (uint32_t i = 0; i < len; i++) {
489 result |= static_cast<unsigned char>(buf[i]);
490 if ((i + 1) < len) {
491 result <<= 8; // 8: result need shift left 8 bits in order to big endian convert to int
492 }
493 }
494 return result;
495 }
496
Recv(int32_t client,char * buf,size_t totalLen,int32_t flags) const497 bool WebSocket::Recv(int32_t client, char* buf, size_t totalLen, int32_t flags) const
498 {
499 size_t recvLen = 0;
500 while (recvLen < totalLen) {
501 ssize_t len = recv(client, buf + recvLen, totalLen - recvLen, flags);
502 if (len <= 0) {
503 LOGE("Recv payload in while failed, websocket disconnect, len = %{public}ld, errno = %{public}d",
504 static_cast<long>(len), errno);
505 return false;
506 }
507 recvLen += static_cast<size_t>(len);
508 }
509 buf[totalLen] = '\0';
510 return true;
511 }
512
Send(int32_t client,const char * buf,size_t totalLen,int32_t flags) const513 bool WebSocket::Send(int32_t client, const char* buf, size_t totalLen, int32_t flags) const
514 {
515 size_t sendLen = 0;
516 while (sendLen < totalLen) {
517 ssize_t len = send(client, buf + sendLen, totalLen - sendLen, flags);
518 if (len <= 0) {
519 LOGE("Send Message in while failed, websocket disconnect, len = %{public}ld, errno = %{public}d",
520 static_cast<long>(len), errno);
521 return false;
522 }
523 sendLen += static_cast<size_t>(len);
524 }
525 return true;
526 }
527
528 #if !defined(OHOS_PLATFORM)
SetWebSocketTimeOut(int32_t fd,uint32_t timeoutLimit)529 bool WebSocket::SetWebSocketTimeOut(int32_t fd, uint32_t timeoutLimit)
530 {
531 if (timeoutLimit > 0) {
532 struct timeval timeout = {timeoutLimit, 0};
533 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
534 reinterpret_cast<char *>(&timeout), sizeof(timeout)) != SOCKET_SUCCESS) {
535 LOGE("SetWebSocketTimeOut setsockopt SO_SNDTIMEO failed, errno = %{public}d", errno);
536 return false;
537 }
538 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
539 reinterpret_cast<char *>(&timeout), sizeof(timeout)) != SOCKET_SUCCESS) {
540 LOGE("SetWebSocketTimeOut setsockopt SO_RCVTIMEO failed, errno = %{public}d", errno);
541 return false;
542 }
543 }
544 return true;
545 }
546 #else
SetWebSocketTimeOut(int32_t fd,uint32_t timeoutLimit)547 bool WebSocket::SetWebSocketTimeOut(int32_t fd, uint32_t timeoutLimit)
548 {
549 if (timeoutLimit > 0) {
550 struct timeval timeout = {timeoutLimit, 0};
551 if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) != SOCKET_SUCCESS) {
552 LOGE("SetWebSocketTimeOut setsockopt SO_SNDTIMEO failed, errno = %{public}d", errno);
553 return false;
554 }
555 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) != SOCKET_SUCCESS) {
556 LOGE("SetWebSocketTimeOut setsockopt SO_RCVTIMEO failed, errno = %{public}d", errno);
557 return false;
558 }
559 }
560 return true;
561 }
562 #endif
563 } // namespace OHOS::ArkCompiler::Toolchain
564