1e509ee18Sopenharmony_ci/*
2e509ee18Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
3e509ee18Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4e509ee18Sopenharmony_ci * you may not use this file except in compliance with the License.
5e509ee18Sopenharmony_ci * You may obtain a copy of the License at
6e509ee18Sopenharmony_ci *
7e509ee18Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8e509ee18Sopenharmony_ci *
9e509ee18Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10e509ee18Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11e509ee18Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12e509ee18Sopenharmony_ci * See the License for the specific language governing permissions and
13e509ee18Sopenharmony_ci * limitations under the License.
14e509ee18Sopenharmony_ci */
15e509ee18Sopenharmony_ci
16e509ee18Sopenharmony_ci#if defined(PANDA_TARGET_WINDOWS)
17e509ee18Sopenharmony_ci#include <ws2tcpip.h>
18e509ee18Sopenharmony_ci#else
19e509ee18Sopenharmony_ci#include <arpa/inet.h>
20e509ee18Sopenharmony_ci#endif
21e509ee18Sopenharmony_ci
22e509ee18Sopenharmony_ci#include <fcntl.h>
23e509ee18Sopenharmony_ci#include "common/log_wrapper.h"
24e509ee18Sopenharmony_ci#include "frame_builder.h"
25e509ee18Sopenharmony_ci#include "handshake_helper.h"
26e509ee18Sopenharmony_ci#include "network.h"
27e509ee18Sopenharmony_ci#include "server/websocket_server.h"
28e509ee18Sopenharmony_ci#include "string_utils.h"
29e509ee18Sopenharmony_ci
30e509ee18Sopenharmony_ci#include <mutex>
31e509ee18Sopenharmony_ci#include <thread>
32e509ee18Sopenharmony_ci
33e509ee18Sopenharmony_cinamespace OHOS::ArkCompiler::Toolchain {
34e509ee18Sopenharmony_cistatic bool ValidateHandShakeMessage(const HttpRequest& req)
35e509ee18Sopenharmony_ci{
36e509ee18Sopenharmony_ci    std::string upgradeHeaderValue = req.upgrade;
37e509ee18Sopenharmony_ci    // Switch to lower case in order to support obsolete versions of WebSocket protocol.
38e509ee18Sopenharmony_ci    ToLowerCase(upgradeHeaderValue);
39e509ee18Sopenharmony_ci    return req.connection.find("Upgrade") != std::string::npos &&
40e509ee18Sopenharmony_ci        upgradeHeaderValue.find("websocket") != std::string::npos &&
41e509ee18Sopenharmony_ci        req.version.compare("HTTP/1.1") == 0;
42e509ee18Sopenharmony_ci}
43e509ee18Sopenharmony_ci
44e509ee18Sopenharmony_ciWebSocketServer::~WebSocketServer() noexcept
45e509ee18Sopenharmony_ci{
46e509ee18Sopenharmony_ci    if (serverFd_ != -1) {
47e509ee18Sopenharmony_ci        LOGW("WebSocket server is closed while destructing the object");
48e509ee18Sopenharmony_ci        close(serverFd_);
49e509ee18Sopenharmony_ci        // Reset directly in order to prevent static analyzer warnings.
50e509ee18Sopenharmony_ci        serverFd_ = -1;
51e509ee18Sopenharmony_ci    }
52e509ee18Sopenharmony_ci}
53e509ee18Sopenharmony_ci
54e509ee18Sopenharmony_cibool WebSocketServer::DecodeMessage(WebSocketFrame& wsFrame) const
55e509ee18Sopenharmony_ci{
56e509ee18Sopenharmony_ci    const uint64_t msgLen = wsFrame.payloadLen;
57e509ee18Sopenharmony_ci    if (msgLen == 0) {
58e509ee18Sopenharmony_ci        // receiving empty data is OK
59e509ee18Sopenharmony_ci        return true;
60e509ee18Sopenharmony_ci    }
61e509ee18Sopenharmony_ci    auto& buffer = wsFrame.payload;
62e509ee18Sopenharmony_ci    buffer.resize(msgLen, 0);
63e509ee18Sopenharmony_ci
64e509ee18Sopenharmony_ci    if (!RecvUnderLock(wsFrame.maskingKey, sizeof(wsFrame.maskingKey))) {
65e509ee18Sopenharmony_ci        LOGE("DecodeMessage: Recv maskingKey failed");
66e509ee18Sopenharmony_ci        return false;
67e509ee18Sopenharmony_ci    }
68e509ee18Sopenharmony_ci
69e509ee18Sopenharmony_ci    if (!RecvUnderLock(buffer)) {
70e509ee18Sopenharmony_ci        LOGE("DecodeMessage: Recv message with mask failed");
71e509ee18Sopenharmony_ci        return false;
72e509ee18Sopenharmony_ci    }
73e509ee18Sopenharmony_ci
74e509ee18Sopenharmony_ci    for (uint64_t i = 0; i < msgLen; i++) {
75e509ee18Sopenharmony_ci        const auto j = i % WebSocketFrame::MASK_LEN;
76e509ee18Sopenharmony_ci        buffer[i] = static_cast<uint8_t>(buffer[i]) ^ wsFrame.maskingKey[j];
77e509ee18Sopenharmony_ci    }
78e509ee18Sopenharmony_ci
79e509ee18Sopenharmony_ci    return true;
80e509ee18Sopenharmony_ci}
81e509ee18Sopenharmony_ci
82e509ee18Sopenharmony_cibool WebSocketServer::ProtocolUpgrade(const HttpRequest& req)
83e509ee18Sopenharmony_ci{
84e509ee18Sopenharmony_ci    unsigned char encodedKey[WebSocketKeyEncoder::ENCODED_KEY_LEN + 1];
85e509ee18Sopenharmony_ci    if (!WebSocketKeyEncoder::EncodeKey(req.secWebSocketKey, encodedKey)) {
86e509ee18Sopenharmony_ci        LOGE("ProtocolUpgrade: failed to encode WebSocket-Key");
87e509ee18Sopenharmony_ci        return false;
88e509ee18Sopenharmony_ci    }
89e509ee18Sopenharmony_ci
90e509ee18Sopenharmony_ci    ProtocolUpgradeBuilder requestBuilder(encodedKey);
91e509ee18Sopenharmony_ci    if (!SendUnderLock(requestBuilder.GetUpgradeMessage(), requestBuilder.GetLength())) {
92e509ee18Sopenharmony_ci        LOGE("ProtocolUpgrade: Send failed");
93e509ee18Sopenharmony_ci        return false;
94e509ee18Sopenharmony_ci    }
95e509ee18Sopenharmony_ci    return true;
96e509ee18Sopenharmony_ci}
97e509ee18Sopenharmony_ci
98e509ee18Sopenharmony_cibool WebSocketServer::ResponseInvalidHandShake() const
99e509ee18Sopenharmony_ci{
100e509ee18Sopenharmony_ci    const std::string response(BAD_REQUEST_RESPONSE);
101e509ee18Sopenharmony_ci    return SendUnderLock(response);
102e509ee18Sopenharmony_ci}
103e509ee18Sopenharmony_ci
104e509ee18Sopenharmony_cibool WebSocketServer::HttpHandShake()
105e509ee18Sopenharmony_ci{
106e509ee18Sopenharmony_ci    std::string msgBuf(HTTP_HANDSHAKE_MAX_LEN, 0);
107e509ee18Sopenharmony_ci    ssize_t msgLen = 0;
108e509ee18Sopenharmony_ci    {
109e509ee18Sopenharmony_ci        std::shared_lock lock(GetConnectionMutex());
110e509ee18Sopenharmony_ci        while ((msgLen = recv(GetConnectionSocket(), msgBuf.data(), HTTP_HANDSHAKE_MAX_LEN, 0)) < 0 &&
111e509ee18Sopenharmony_ci            (errno == EINTR || errno == EAGAIN)) {
112e509ee18Sopenharmony_ci            LOGW("HttpHandShake recv failed, errno = %{public}d", errno);
113e509ee18Sopenharmony_ci        }
114e509ee18Sopenharmony_ci    }
115e509ee18Sopenharmony_ci    if (msgLen <= 0) {
116e509ee18Sopenharmony_ci        LOGE("ReadMsg failed, msgLen = %{public}ld, errno = %{public}d", static_cast<long>(msgLen), errno);
117e509ee18Sopenharmony_ci        return false;
118e509ee18Sopenharmony_ci    }
119e509ee18Sopenharmony_ci    // reduce to received size
120e509ee18Sopenharmony_ci    msgBuf.resize(msgLen);
121e509ee18Sopenharmony_ci
122e509ee18Sopenharmony_ci    HttpRequest req;
123e509ee18Sopenharmony_ci    if (!HttpRequest::Decode(msgBuf, req)) {
124e509ee18Sopenharmony_ci        LOGE("HttpHandShake: Upgrade failed");
125e509ee18Sopenharmony_ci        return false;
126e509ee18Sopenharmony_ci    }
127e509ee18Sopenharmony_ci    if (validateCb_ && !validateCb_(req)) {
128e509ee18Sopenharmony_ci        LOGE("HttpHandShake: Validation failed");
129e509ee18Sopenharmony_ci        return false;
130e509ee18Sopenharmony_ci    }
131e509ee18Sopenharmony_ci
132e509ee18Sopenharmony_ci    if (ValidateHandShakeMessage(req)) {
133e509ee18Sopenharmony_ci        return ProtocolUpgrade(req);
134e509ee18Sopenharmony_ci    }
135e509ee18Sopenharmony_ci
136e509ee18Sopenharmony_ci    LOGE("HttpHandShake: HTTP upgrade parameters failure");
137e509ee18Sopenharmony_ci    if (!ResponseInvalidHandShake()) {
138e509ee18Sopenharmony_ci        LOGE("HttpHandShake: failed to send 'bad request' response");
139e509ee18Sopenharmony_ci    }
140e509ee18Sopenharmony_ci    return false;
141e509ee18Sopenharmony_ci}
142e509ee18Sopenharmony_ci
143e509ee18Sopenharmony_cibool WebSocketServer::MoveToConnectingState()
144e509ee18Sopenharmony_ci{
145e509ee18Sopenharmony_ci    if (!serverUp_.load()) {
146e509ee18Sopenharmony_ci        // Server `Close` happened, must not accept new connections.
147e509ee18Sopenharmony_ci        return false;
148e509ee18Sopenharmony_ci    }
149e509ee18Sopenharmony_ci    auto expected = ConnectionState::CLOSED;
150e509ee18Sopenharmony_ci    if (!CompareExchangeConnectionState(expected, ConnectionState::CONNECTING)) {
151e509ee18Sopenharmony_ci        switch (expected) {
152e509ee18Sopenharmony_ci            case ConnectionState::CLOSING:
153e509ee18Sopenharmony_ci                LOGW("MoveToConnectingState during closing connection");
154e509ee18Sopenharmony_ci                break;
155e509ee18Sopenharmony_ci            case ConnectionState::OPEN:
156e509ee18Sopenharmony_ci                LOGW("MoveToConnectingState during already established connection");
157e509ee18Sopenharmony_ci                break;
158e509ee18Sopenharmony_ci            case ConnectionState::CONNECTING:
159e509ee18Sopenharmony_ci                LOGE("MoveToConnectingState during opening connection, which violates WebSocketServer guarantees");
160e509ee18Sopenharmony_ci                break;
161e509ee18Sopenharmony_ci            default:
162e509ee18Sopenharmony_ci                break;
163e509ee18Sopenharmony_ci        }
164e509ee18Sopenharmony_ci        return false;
165e509ee18Sopenharmony_ci    }
166e509ee18Sopenharmony_ci    // Must check once again because of `Close` method implementation.
167e509ee18Sopenharmony_ci    if (!serverUp_.load()) {
168e509ee18Sopenharmony_ci        // Server `Close` happened, `serverFd_` was closed, new connection must not be opened.
169e509ee18Sopenharmony_ci        expected = SetConnectionState(ConnectionState::CLOSED);
170e509ee18Sopenharmony_ci        if (expected != ConnectionState::CONNECTING) {
171e509ee18Sopenharmony_ci            LOGE("AcceptNewConnection: Close guarantees violated");
172e509ee18Sopenharmony_ci        }
173e509ee18Sopenharmony_ci        return false;
174e509ee18Sopenharmony_ci    }
175e509ee18Sopenharmony_ci    return true;
176e509ee18Sopenharmony_ci}
177e509ee18Sopenharmony_ci
178e509ee18Sopenharmony_cibool WebSocketServer::AcceptNewConnection()
179e509ee18Sopenharmony_ci{
180e509ee18Sopenharmony_ci    if (!MoveToConnectingState()) {
181e509ee18Sopenharmony_ci        return false;
182e509ee18Sopenharmony_ci    }
183e509ee18Sopenharmony_ci
184e509ee18Sopenharmony_ci    const int newConnectionFd = accept(serverFd_, nullptr, nullptr);
185e509ee18Sopenharmony_ci    if (newConnectionFd < SOCKET_SUCCESS) {
186e509ee18Sopenharmony_ci        LOGI("AcceptNewConnection accept has exited");
187e509ee18Sopenharmony_ci
188e509ee18Sopenharmony_ci        auto expected = SetConnectionState(ConnectionState::CLOSED);
189e509ee18Sopenharmony_ci        if (expected != ConnectionState::CONNECTING) {
190e509ee18Sopenharmony_ci            LOGE("AcceptNewConnection: violation due to concurrent close and accept: got %{public}d",
191e509ee18Sopenharmony_ci                 EnumToNumber(expected));
192e509ee18Sopenharmony_ci        }
193e509ee18Sopenharmony_ci        return false;
194e509ee18Sopenharmony_ci    }
195e509ee18Sopenharmony_ci    {
196e509ee18Sopenharmony_ci        std::unique_lock lock(GetConnectionMutex());
197e509ee18Sopenharmony_ci        SetConnectionSocket(newConnectionFd);
198e509ee18Sopenharmony_ci    }
199e509ee18Sopenharmony_ci
200e509ee18Sopenharmony_ci    if (!HttpHandShake()) {
201e509ee18Sopenharmony_ci        LOGW("AcceptNewConnection HttpHandShake failed");
202e509ee18Sopenharmony_ci
203e509ee18Sopenharmony_ci        auto expected = SetConnectionState(ConnectionState::CLOSING);
204e509ee18Sopenharmony_ci        if (expected != ConnectionState::CONNECTING) {
205e509ee18Sopenharmony_ci            LOGE("AcceptNewConnection: violation due to concurrent close and accept: got %{public}d",
206e509ee18Sopenharmony_ci                 EnumToNumber(expected));
207e509ee18Sopenharmony_ci        }
208e509ee18Sopenharmony_ci        CloseConnectionSocket(ConnectionCloseReason::FAIL);
209e509ee18Sopenharmony_ci        return false;
210e509ee18Sopenharmony_ci    }
211e509ee18Sopenharmony_ci
212e509ee18Sopenharmony_ci    OnNewConnection();
213e509ee18Sopenharmony_ci    return true;
214e509ee18Sopenharmony_ci}
215e509ee18Sopenharmony_ci
216e509ee18Sopenharmony_cibool WebSocketServer::InitTcpWebSocket(int port, uint32_t timeoutLimit)
217e509ee18Sopenharmony_ci{
218e509ee18Sopenharmony_ci    if (port < 0) {
219e509ee18Sopenharmony_ci        LOGE("InitTcpWebSocket invalid port");
220e509ee18Sopenharmony_ci        return false;
221e509ee18Sopenharmony_ci    }
222e509ee18Sopenharmony_ci    if (serverUp_.load()) {
223e509ee18Sopenharmony_ci        LOGI("InitTcpWebSocket websocket has inited");
224e509ee18Sopenharmony_ci        return true;
225e509ee18Sopenharmony_ci    }
226e509ee18Sopenharmony_ci#if defined(WINDOWS_PLATFORM)
227e509ee18Sopenharmony_ci    WORD sockVersion = MAKEWORD(2, 2); // 2: version 2.2
228e509ee18Sopenharmony_ci    WSADATA wsaData;
229e509ee18Sopenharmony_ci    if (WSAStartup(sockVersion, &wsaData) != 0) {
230e509ee18Sopenharmony_ci        LOGE("InitTcpWebSocket WSA init failed");
231e509ee18Sopenharmony_ci        return false;
232e509ee18Sopenharmony_ci    }
233e509ee18Sopenharmony_ci#endif
234e509ee18Sopenharmony_ci    serverFd_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
235e509ee18Sopenharmony_ci    if (serverFd_ < SOCKET_SUCCESS) {
236e509ee18Sopenharmony_ci        LOGE("InitTcpWebSocket socket init failed, errno = %{public}d", errno);
237e509ee18Sopenharmony_ci        return false;
238e509ee18Sopenharmony_ci    }
239e509ee18Sopenharmony_ci    // allow specified port can be used at once and not wait TIME_WAIT status ending
240e509ee18Sopenharmony_ci    int sockOptVal = 1;
241e509ee18Sopenharmony_ci    if ((setsockopt(serverFd_, SOL_SOCKET, SO_REUSEADDR,
242e509ee18Sopenharmony_ci        reinterpret_cast<char *>(&sockOptVal), sizeof(sockOptVal))) != SOCKET_SUCCESS) {
243e509ee18Sopenharmony_ci        LOGE("InitTcpWebSocket setsockopt SO_REUSEADDR failed, errno = %{public}d", errno);
244e509ee18Sopenharmony_ci        CloseServerSocket();
245e509ee18Sopenharmony_ci        return false;
246e509ee18Sopenharmony_ci    }
247e509ee18Sopenharmony_ci    if (!SetWebSocketTimeOut(serverFd_, timeoutLimit)) {
248e509ee18Sopenharmony_ci        LOGE("InitTcpWebSocket SetWebSocketTimeOut failed");
249e509ee18Sopenharmony_ci        CloseServerSocket();
250e509ee18Sopenharmony_ci        return false;
251e509ee18Sopenharmony_ci    }
252e509ee18Sopenharmony_ci    return BindAndListenTcpWebSocket(port);
253e509ee18Sopenharmony_ci}
254e509ee18Sopenharmony_ci
255e509ee18Sopenharmony_cibool WebSocketServer::BindAndListenTcpWebSocket(int port)
256e509ee18Sopenharmony_ci{
257e509ee18Sopenharmony_ci    sockaddr_in addrSin = {};
258e509ee18Sopenharmony_ci    addrSin.sin_family = AF_INET;
259e509ee18Sopenharmony_ci    addrSin.sin_port = htons(port);
260e509ee18Sopenharmony_ci    if (inet_pton(AF_INET, "127.0.0.1", &addrSin.sin_addr) != NET_SUCCESS) {
261e509ee18Sopenharmony_ci        LOGE("BindAndListenTcpWebSocket inet_pton failed, error = %{public}d", errno);
262e509ee18Sopenharmony_ci        return false;
263e509ee18Sopenharmony_ci    }
264e509ee18Sopenharmony_ci    if (bind(serverFd_, reinterpret_cast<struct sockaddr*>(&addrSin), sizeof(addrSin)) != SOCKET_SUCCESS ||
265e509ee18Sopenharmony_ci        listen(serverFd_, 1) != SOCKET_SUCCESS) {
266e509ee18Sopenharmony_ci        LOGE("BindAndListenTcpWebSocket bind/listen failed, errno = %{public}d", errno);
267e509ee18Sopenharmony_ci        CloseServerSocket();
268e509ee18Sopenharmony_ci        return false;
269e509ee18Sopenharmony_ci    }
270e509ee18Sopenharmony_ci    serverUp_.store(true);
271e509ee18Sopenharmony_ci    return true;
272e509ee18Sopenharmony_ci}
273e509ee18Sopenharmony_ci
274e509ee18Sopenharmony_ci#if !defined(WINDOWS_PLATFORM)
275e509ee18Sopenharmony_cibool WebSocketServer::InitUnixWebSocket(const std::string& sockName, uint32_t timeoutLimit)
276e509ee18Sopenharmony_ci{
277e509ee18Sopenharmony_ci    if (serverUp_.load()) {
278e509ee18Sopenharmony_ci        LOGI("InitUnixWebSocket websocket has inited");
279e509ee18Sopenharmony_ci        return true;
280e509ee18Sopenharmony_ci    }
281e509ee18Sopenharmony_ci    serverFd_ = socket(AF_UNIX, SOCK_STREAM, 0); // 0: default protocol
282e509ee18Sopenharmony_ci    if (serverFd_ < SOCKET_SUCCESS) {
283e509ee18Sopenharmony_ci        LOGE("InitUnixWebSocket socket init failed, errno = %{public}d", errno);
284e509ee18Sopenharmony_ci        return false;
285e509ee18Sopenharmony_ci    }
286e509ee18Sopenharmony_ci    // set send and recv timeout
287e509ee18Sopenharmony_ci    if (!SetWebSocketTimeOut(serverFd_, timeoutLimit)) {
288e509ee18Sopenharmony_ci        LOGE("InitUnixWebSocket SetWebSocketTimeOut failed");
289e509ee18Sopenharmony_ci        CloseServerSocket();
290e509ee18Sopenharmony_ci        return false;
291e509ee18Sopenharmony_ci    }
292e509ee18Sopenharmony_ci
293e509ee18Sopenharmony_ci    struct sockaddr_un un;
294e509ee18Sopenharmony_ci    if (memset_s(&un, sizeof(un), 0, sizeof(un)) != EOK) {
295e509ee18Sopenharmony_ci        LOGE("InitUnixWebSocket memset_s failed");
296e509ee18Sopenharmony_ci        CloseServerSocket();
297e509ee18Sopenharmony_ci        return false;
298e509ee18Sopenharmony_ci    }
299e509ee18Sopenharmony_ci    un.sun_family = AF_UNIX;
300e509ee18Sopenharmony_ci    if (strcpy_s(un.sun_path + 1, sizeof(un.sun_path) - 1, sockName.c_str()) != EOK) {
301e509ee18Sopenharmony_ci        LOGE("InitUnixWebSocket strcpy_s failed");
302e509ee18Sopenharmony_ci        CloseServerSocket();
303e509ee18Sopenharmony_ci        return false;
304e509ee18Sopenharmony_ci    }
305e509ee18Sopenharmony_ci    un.sun_path[0] = '\0';
306e509ee18Sopenharmony_ci    uint32_t len = offsetof(struct sockaddr_un, sun_path) + strlen(sockName.c_str()) + 1;
307e509ee18Sopenharmony_ci    if (bind(serverFd_, reinterpret_cast<struct sockaddr*>(&un), static_cast<int32_t>(len)) != SOCKET_SUCCESS) {
308e509ee18Sopenharmony_ci        LOGE("InitUnixWebSocket bind failed, errno = %{public}d", errno);
309e509ee18Sopenharmony_ci        CloseServerSocket();
310e509ee18Sopenharmony_ci        return false;
311e509ee18Sopenharmony_ci    }
312e509ee18Sopenharmony_ci    if (listen(serverFd_, 1) != SOCKET_SUCCESS) { // 1: connection num
313e509ee18Sopenharmony_ci        LOGE("InitUnixWebSocket listen failed, errno = %{public}d", errno);
314e509ee18Sopenharmony_ci        CloseServerSocket();
315e509ee18Sopenharmony_ci        return false;
316e509ee18Sopenharmony_ci    }
317e509ee18Sopenharmony_ci    serverUp_.store(true);
318e509ee18Sopenharmony_ci    return true;
319e509ee18Sopenharmony_ci}
320e509ee18Sopenharmony_ci
321e509ee18Sopenharmony_cibool WebSocketServer::InitUnixWebSocket(int socketfd)
322e509ee18Sopenharmony_ci{
323e509ee18Sopenharmony_ci    if (serverUp_.load()) {
324e509ee18Sopenharmony_ci        LOGI("InitUnixWebSocket websocket has inited");
325e509ee18Sopenharmony_ci        return true;
326e509ee18Sopenharmony_ci    }
327e509ee18Sopenharmony_ci    if (socketfd < SOCKET_SUCCESS) {
328e509ee18Sopenharmony_ci        LOGE("InitUnixWebSocket socketfd is invalid");
329e509ee18Sopenharmony_ci        return false;
330e509ee18Sopenharmony_ci    }
331e509ee18Sopenharmony_ci    SetConnectionSocket(socketfd);
332e509ee18Sopenharmony_ci    const int flag = fcntl(socketfd, F_GETFL, 0);
333e509ee18Sopenharmony_ci    if (flag == -1) {
334e509ee18Sopenharmony_ci        LOGE("InitUnixWebSocket get client state is failed");
335e509ee18Sopenharmony_ci        return false;
336e509ee18Sopenharmony_ci    }
337e509ee18Sopenharmony_ci    fcntl(socketfd, F_SETFL, static_cast<size_t>(flag) & ~O_NONBLOCK);
338e509ee18Sopenharmony_ci    serverUp_.store(true);
339e509ee18Sopenharmony_ci    return true;
340e509ee18Sopenharmony_ci}
341e509ee18Sopenharmony_ci
342e509ee18Sopenharmony_cibool WebSocketServer::ConnectUnixWebSocketBySocketpair()
343e509ee18Sopenharmony_ci{
344e509ee18Sopenharmony_ci    if (!MoveToConnectingState()) {
345e509ee18Sopenharmony_ci        return false;
346e509ee18Sopenharmony_ci    }
347e509ee18Sopenharmony_ci
348e509ee18Sopenharmony_ci    if (!HttpHandShake()) {
349e509ee18Sopenharmony_ci        LOGE("ConnectUnixWebSocket HttpHandShake failed");
350e509ee18Sopenharmony_ci
351e509ee18Sopenharmony_ci        auto expected = SetConnectionState(ConnectionState::CLOSING);
352e509ee18Sopenharmony_ci        if (expected != ConnectionState::CONNECTING) {
353e509ee18Sopenharmony_ci            LOGE("ConnectUnixWebSocketBySocketpair: violation due to concurrent close and accept: got %{public}d",
354e509ee18Sopenharmony_ci                 EnumToNumber(expected));
355e509ee18Sopenharmony_ci        }
356e509ee18Sopenharmony_ci        CloseConnectionSocket(ConnectionCloseReason::FAIL);
357e509ee18Sopenharmony_ci        return false;
358e509ee18Sopenharmony_ci    }
359e509ee18Sopenharmony_ci
360e509ee18Sopenharmony_ci    OnNewConnection();
361e509ee18Sopenharmony_ci    return true;
362e509ee18Sopenharmony_ci}
363e509ee18Sopenharmony_ci#endif  // WINDOWS_PLATFORM
364e509ee18Sopenharmony_ci
365e509ee18Sopenharmony_civoid WebSocketServer::CloseServerSocket()
366e509ee18Sopenharmony_ci{
367e509ee18Sopenharmony_ci    close(serverFd_);
368e509ee18Sopenharmony_ci    serverFd_ = -1;
369e509ee18Sopenharmony_ci}
370e509ee18Sopenharmony_ci
371e509ee18Sopenharmony_civoid WebSocketServer::OnNewConnection()
372e509ee18Sopenharmony_ci{
373e509ee18Sopenharmony_ci    LOGI("New client connected");
374e509ee18Sopenharmony_ci    if (openCb_) {
375e509ee18Sopenharmony_ci        openCb_();
376e509ee18Sopenharmony_ci    }
377e509ee18Sopenharmony_ci
378e509ee18Sopenharmony_ci    auto expected = SetConnectionState(ConnectionState::OPEN);
379e509ee18Sopenharmony_ci    if (expected != ConnectionState::CONNECTING) {
380e509ee18Sopenharmony_ci        LOGE("OnNewConnection violation: expected CONNECTING, but got %{public}d",
381e509ee18Sopenharmony_ci             EnumToNumber(expected));
382e509ee18Sopenharmony_ci    }
383e509ee18Sopenharmony_ci}
384e509ee18Sopenharmony_ci
385e509ee18Sopenharmony_civoid WebSocketServer::SetValidateConnectionCallback(ValidateConnectionCallback cb)
386e509ee18Sopenharmony_ci{
387e509ee18Sopenharmony_ci    validateCb_ = std::move(cb);
388e509ee18Sopenharmony_ci}
389e509ee18Sopenharmony_ci
390e509ee18Sopenharmony_civoid WebSocketServer::SetOpenConnectionCallback(OpenConnectionCallback cb)
391e509ee18Sopenharmony_ci{
392e509ee18Sopenharmony_ci    openCb_ = std::move(cb);
393e509ee18Sopenharmony_ci}
394e509ee18Sopenharmony_ci
395e509ee18Sopenharmony_cibool WebSocketServer::ValidateIncomingFrame(const WebSocketFrame& wsFrame) const
396e509ee18Sopenharmony_ci{
397e509ee18Sopenharmony_ci    // "The server MUST close the connection upon receiving a frame that is not masked."
398e509ee18Sopenharmony_ci    // https://www.rfc-editor.org/rfc/rfc6455#section-5.1
399e509ee18Sopenharmony_ci    return wsFrame.mask == 1;
400e509ee18Sopenharmony_ci}
401e509ee18Sopenharmony_ci
402e509ee18Sopenharmony_cistd::string WebSocketServer::CreateFrame(bool isLast, FrameType frameType) const
403e509ee18Sopenharmony_ci{
404e509ee18Sopenharmony_ci    ServerFrameBuilder builder(isLast, frameType);
405e509ee18Sopenharmony_ci    return builder.Build();
406e509ee18Sopenharmony_ci}
407e509ee18Sopenharmony_ci
408e509ee18Sopenharmony_cistd::string WebSocketServer::CreateFrame(bool isLast, FrameType frameType, const std::string& payload) const
409e509ee18Sopenharmony_ci{
410e509ee18Sopenharmony_ci    ServerFrameBuilder builder(isLast, frameType);
411e509ee18Sopenharmony_ci    return builder.SetPayload(payload).Build();
412e509ee18Sopenharmony_ci}
413e509ee18Sopenharmony_ci
414e509ee18Sopenharmony_cistd::string WebSocketServer::CreateFrame(bool isLast, FrameType frameType, std::string&& payload) const
415e509ee18Sopenharmony_ci{
416e509ee18Sopenharmony_ci    ServerFrameBuilder builder(isLast, frameType);
417e509ee18Sopenharmony_ci    return builder.SetPayload(std::move(payload)).Build();
418e509ee18Sopenharmony_ci}
419e509ee18Sopenharmony_ci
420e509ee18Sopenharmony_ciWebSocketServer::ConnectionState WebSocketServer::WaitConnectingStateEnds(ConnectionState connection)
421e509ee18Sopenharmony_ci{
422e509ee18Sopenharmony_ci    auto shutdownSocketUnderLock = [this]() {
423e509ee18Sopenharmony_ci        auto fd = GetConnectionSocket();
424e509ee18Sopenharmony_ci        if (fd == -1) {
425e509ee18Sopenharmony_ci            return false;
426e509ee18Sopenharmony_ci        }
427e509ee18Sopenharmony_ci        int err = ShutdownSocket(fd);
428e509ee18Sopenharmony_ci        if (err != 0) {
429e509ee18Sopenharmony_ci            LOGW("Failed to shutdown client socket, errno = %{public}d", errno);
430e509ee18Sopenharmony_ci        }
431e509ee18Sopenharmony_ci        return true;
432e509ee18Sopenharmony_ci    };
433e509ee18Sopenharmony_ci
434e509ee18Sopenharmony_ci    auto connectionSocketWasShutdown = false;
435e509ee18Sopenharmony_ci    while (connection == ConnectionState::CONNECTING) {
436e509ee18Sopenharmony_ci        if (!connectionSocketWasShutdown) {
437e509ee18Sopenharmony_ci            // Try to shutdown the already accepted connection socket,
438e509ee18Sopenharmony_ci            // otherwise thread can infinitely hang on handshake recv.
439e509ee18Sopenharmony_ci            std::shared_lock lock(GetConnectionMutex());
440e509ee18Sopenharmony_ci            connectionSocketWasShutdown = shutdownSocketUnderLock();
441e509ee18Sopenharmony_ci        }
442e509ee18Sopenharmony_ci
443e509ee18Sopenharmony_ci        std::this_thread::yield();
444e509ee18Sopenharmony_ci        connection = GetConnectionState();
445e509ee18Sopenharmony_ci    }
446e509ee18Sopenharmony_ci    return connection;
447e509ee18Sopenharmony_ci}
448e509ee18Sopenharmony_ci
449e509ee18Sopenharmony_civoid WebSocketServer::Close()
450e509ee18Sopenharmony_ci{
451e509ee18Sopenharmony_ci    // Firstly stop accepting new connections.
452e509ee18Sopenharmony_ci    if (!serverUp_.exchange(false)) {
453e509ee18Sopenharmony_ci        return;
454e509ee18Sopenharmony_ci    }
455e509ee18Sopenharmony_ci
456e509ee18Sopenharmony_ci    int err = ShutdownSocket(serverFd_);
457e509ee18Sopenharmony_ci    if (err != 0) {
458e509ee18Sopenharmony_ci        LOGW("Failed to shutdown server socket, errno = %{public}d", errno);
459e509ee18Sopenharmony_ci    }
460e509ee18Sopenharmony_ci
461e509ee18Sopenharmony_ci    // If there is a concurrent call to `CloseConnection`, we can immediately close `serverFd_`.
462e509ee18Sopenharmony_ci    // This is because new connections are already prevented, hence no reads of `serverFd_` will be done,
463e509ee18Sopenharmony_ci    // and the connection itself will be closed by someone else.
464e509ee18Sopenharmony_ci    auto connection = GetConnectionState();
465e509ee18Sopenharmony_ci    if (connection == ConnectionState::CLOSING || connection == ConnectionState::CLOSED) {
466e509ee18Sopenharmony_ci        CloseServerSocket();
467e509ee18Sopenharmony_ci        return;
468e509ee18Sopenharmony_ci    }
469e509ee18Sopenharmony_ci
470e509ee18Sopenharmony_ci    connection = WaitConnectingStateEnds(connection);
471e509ee18Sopenharmony_ci
472e509ee18Sopenharmony_ci    // Can safely close server socket, as there will be no more new connections attempts.
473e509ee18Sopenharmony_ci    CloseServerSocket();
474e509ee18Sopenharmony_ci    // Must check once again after finished `AcceptNewConnection`.
475e509ee18Sopenharmony_ci    if (connection == ConnectionState::CLOSING || connection == ConnectionState::CLOSED) {
476e509ee18Sopenharmony_ci        return;
477e509ee18Sopenharmony_ci    }
478e509ee18Sopenharmony_ci
479e509ee18Sopenharmony_ci    // If we reached this point, connection can be `OPEN`, `CLOSING` or `CLOSED`. Try to close it anyway.
480e509ee18Sopenharmony_ci    CloseConnection(CloseStatusCode::SERVER_GO_AWAY);
481e509ee18Sopenharmony_ci}
482e509ee18Sopenharmony_ci} // namespace OHOS::ArkCompiler::Toolchain
483