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