diff --git a/inspector/BUILD.gn b/inspector/BUILD.gn index 872061a4dc2918c0ac82d9b2408e7d7773ba214e..476797731c5fe1793d98ab23ffa8895524fec376 100644 --- a/inspector/BUILD.gn +++ b/inspector/BUILD.gn @@ -53,10 +53,7 @@ ohos_shared_library("ark_debugger") { ohos_source_set("ark_debugger_static") { deps = [] - defines = [ - "BOOST_ERROR_CODE_HEADER_ONLY", - "BOOST_CLANG", - ] + defines = [] defines += [ "ACE_LOG_TAG=\"ArkDebugger\"" ] @@ -85,11 +82,11 @@ ohos_source_set("ark_debugger_static") { } include_dirs = [ - ".", - "//third_party/boost", - "//third_party/boost/boost", + "$toolchain_root", + "$toolchain_root/websocket", ] + deps += [ "$toolchain_root/websocket:websocket" ] sources = [ "inspector.cpp", "library_loader.cpp", diff --git a/inspector/ws_server.cpp b/inspector/ws_server.cpp index 60de0a0fc1ab43b92d7d731f635dec77cc5cf2f9..a52ec2aa99d78dc75766f06158f1f31d96fff29a 100644 --- a/inspector/ws_server.cpp +++ b/inspector/ws_server.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "log_wrapper.h" @@ -28,62 +29,29 @@ std::shared_mutex g_mutex; void WsServer::RunServer() { terminateExecution_ = false; - try { - tid_ = pthread_self(); + webSocket_ = std::make_unique(); #if !defined(OHOS_PLATFORM) - constexpr int32_t DEFAULT_INSEPTOR_PORT = 9230; - CommProtocol::endpoint endPoint(CommProtocol::v4(), DEFAULT_INSEPTOR_PORT); + webSocket_->StartForSimulator(); #else - int appPid = getpid(); - std::string pidStr = std::to_string(appPid); - std::string instanceIdStr(""); - /** - * The old version of IDE is not compatible with the new images due to the connect server. - * The First instance will use "pid" instead of "pid + instanceId" to avoid this. - * If old version of IDE does not get the instanceId by connect server, it can still connect the debug server. - */ - if (instanceId_ != 0) { - instanceIdStr = std::to_string(instanceId_); - } - std::string sockName = '\0' + pidStr + instanceIdStr + componentName_; - LOGI("WsServer RunServer: %{public}d%{public}d%{public}s", appPid, instanceId_, componentName_.c_str()); - CommProtocol::endpoint endPoint(sockName); + tid_ = pthread_self(); + int appPid = getpid(); + std::string pidStr = std::to_string(appPid); + std::string instanceIdStr(""); + + if (instanceId_ != 0) { + instanceIdStr = std::to_string(instanceId_); + } + std::string sockName = pidStr + instanceIdStr + componentName_; + LOGI("WsServer RunServer: %{public}d%{public}s%{public}s", appPid, instanceIdStr.c_str(), componentName_.c_str()); + if (!webSocket_->StartWebSocket(sockName)) { + return; + } #endif - ioContext_ = std::make_unique(); - CommProtocol::socket socket(*ioContext_); - CommProtocol::acceptor acceptor(*ioContext_, endPoint); - auto& connectFlag = connectState_; - acceptor.async_accept(socket, [&connectFlag](const boost::system::error_code& error) { - if (!error) { - connectFlag = true; - } - }); - ioContext_->run(); - if (terminateExecution_ || !connectState_) { - return; - } - webSocket_ = std::unique_ptr>( - std::make_unique>(std::move(socket))); - webSocket_->accept(); - while (!terminateExecution_) { - beast::flat_buffer buffer; - boost::system::error_code error; - webSocket_->read(buffer, error); - if (error) { - webSocket_.reset(); - return; - } - std::string message = boost::beast::buffers_to_string(buffer.data()); - LOGI("WsServer OnMessage: %{public}s", message.c_str()); - wsOnMessage_(std::move(message)); + while (!terminateExecution_) { + std::optional message = webSocket_->Decode(); + if (message.has_value()) { + wsOnMessage_(std::move(message.value())); } - } catch (const beast::system_error& se) { - if (se.code() != websocket::error::closed) { - webSocket_.reset(); - LOGE("Error system_error, %{public}s", se.what()); - } - } catch (const std::exception& e) { - LOGE("Error exception, %{public}s", e.what()); } } @@ -91,13 +59,13 @@ void WsServer::StopServer() { LOGI("WsServer StopServer"); terminateExecution_ = true; - if (!connectState_) { - ioContext_->stop(); - } else if (webSocket_ != nullptr) { - boost::system::error_code error; - webSocket_->close(websocket::close_code::normal, error); + if (webSocket_ != nullptr) { + webSocket_->Close(); +#if defined(OHOS_PLATFORM) + pthread_join(tid_, nullptr); +#endif + webSocket_.reset(); } - pthread_join(tid_, nullptr); } void WsServer::SendReply(const std::string& message) const @@ -108,18 +76,6 @@ void WsServer::SendReply(const std::string& message) const return; } LOGI("WsServer SendReply: %{public}s", message.c_str()); - try { - boost::beast::multi_buffer buffer; - boost::beast::ostream(buffer) << message; - - webSocket_->text(webSocket_->got_text()); - webSocket_->write(buffer.data()); - } catch (const beast::system_error& se) { - if (se.code() != websocket::error::closed) { - LOGE("SendReply Error system_error"); - } - } catch (const std::exception& e) { - LOGE("SendReply Error exception"); - } + webSocket_->SendReply(message); } } // namespace OHOS::ArkCompiler::Toolchain diff --git a/inspector/ws_server.h b/inspector/ws_server.h index 752b6b0d65721b4c2832e290ca32a95f4287c9d9..2fc05ffadfbe00cd6423ea4bc6d5eb09417cfdb3 100644 --- a/inspector/ws_server.h +++ b/inspector/ws_server.h @@ -16,29 +16,12 @@ #ifndef ARKCOMPILER_TOOLCHAIN_INSPECTOR_WS_SERVER_H #define ARKCOMPILER_TOOLCHAIN_INSPECTOR_WS_SERVER_H -#include -#if !defined(OHOS_PLATFORM) -#include -#else -#include -#endif -#include -#include +#include "websocket.h" + #include #include -#include - -#include namespace OHOS::ArkCompiler::Toolchain { -namespace beast = boost::beast; -namespace websocket = beast::websocket; -#if !defined(OHOS_PLATFORM) -using CommProtocol = boost::asio::ip::tcp; -#else -using CommProtocol = boost::asio::local::stream_protocol; -#endif - class WsServer { public: WsServer(const std::string& component, const std::function& onMessage, int32_t instanceId) @@ -50,14 +33,14 @@ public: void SendReply(const std::string& message) const; private: - std::atomic connectState_ {false}; std::atomic terminateExecution_ { false }; [[maybe_unused]] int32_t instanceId_ {0}; +#if defined(OHOS_PLATFORM) pthread_t tid_ {0}; +#endif std::string componentName_ {}; std::function wsOnMessage_ {}; - std::unique_ptr> webSocket_ { nullptr }; - std::unique_ptr ioContext_ { nullptr }; + std::unique_ptr webSocket_ { nullptr }; }; } // namespace OHOS::ArkCompiler::Toolchain diff --git a/websocket/BUILD.gn b/websocket/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..3487612a3935b767a657f461801dc403405decde --- /dev/null +++ b/websocket/BUILD.gn @@ -0,0 +1,100 @@ +# Copyright (c) 2022 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//arkcompiler/toolchain/toolchain.gni") +import("//build/ohos.gni") + +config("websocket_config") { + cflags_cc = [ + "-fno-complete-member-pointers", + "-Wno-implicit-fallthrough", + "-fvisibility=default", + "-frtti", + ] +} + +config("websocket_platform_config") { + defines = [] + if (is_ohos) { + defines += [ + "OHOS_PLATFORM", + "UNIX_PLATFORM", + ] + } else if (is_mingw) { + defines += [ "WINDOWS_PLATFORM" ] + } else if (is_mac) { + defines += [ + "MAC_PLATFORM", + "UNIX_PLATFORM", + ] + } else if (target_os == "android") { + defines += [ + "ANDROID_PLATFORM", + "UNIX_PLATFORM", + ] + } else if (target_os == "ios") { + defines += [ + "UNIX_PLATFORM", + "IOS_PLATFORM", + ] + } else { + defines += [ "UNIX_PLATFORM" ] + } +} + +ohos_source_set("websocket") { + defines = [] + deps = [] + + configs = [ sdk_libc_secshared_config ] + if (is_mingw || is_mac) { + cflags = [ "-std=c++17" ] + if (is_mingw) { + platform = "windows" + } else { + platform = "mac" + } + deps += [ + "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog_$platform", + ] + } else if (target_os == "android") { + aosp_deps = [ "shared_library:liblog" ] + } else { + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + } + + include_dirs = [] + + include_dirs += [ + "$toolchain_root/inspector", + "//third_party/openssl/include", + "//third_party/openssl:libcrypto_static", + "//utils/native/base/include", + ] + + sources = [ "websocket.cpp" ] + + deps += [ + "//third_party/openssl:libcrypto_static", + "//third_party/openssl:ssl_source", + sdk_libc_secshared_dep, + ] + + configs += [ + ":websocket_config", + ":websocket_platform_config", + ] + + subsystem_name = "ark" + part_name = "toolchain" +} diff --git a/websocket/define.h b/websocket/define.h new file mode 100644 index 0000000000000000000000000000000000000000..b836d83edfbd91ced8a1bdf9800ba3a61a2eed2e --- /dev/null +++ b/websocket/define.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ARKCOMPILER_TOOLCHAIN_INSPECTOR_DEFINE_H +#define ARKCOMPILER_TOOLCHAIN_INSPECTOR_DEFINE_H + +#include +#include +#include +#include +#include +#include +#if defined(WINDOWS_PLATFORM) +#include +#include +#else +#include +#include +#include +#include +#endif +#include +#include + +namespace OHOS::ArkCompiler::Toolchain { +std::vector ProtocolSplit(const std::string& str, const std::string& input) +{ + std::vector result; + int32_t prev = 0; + int32_t len = input.length(); + int32_t cur = str.find(input); + while (cur != std::string::npos) { + std::string tmp = str.substr(prev, cur - prev); + result.push_back(tmp); + prev = cur + len; + cur = str.find(input, prev); + } + if (prev < str.size()) { + std::string tmp = str.substr(prev); + result.push_back(tmp); + } + return result; +} +} // namespace OHOS::ArkCompiler::Toolchain + +#endif // ARKCOMPILER_TOOLCHAIN_INSPECTOR_DEFINE_H diff --git a/websocket/websocket.cpp b/websocket/websocket.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6dccc4522af0ad1524aabaea2394e3636d20321f --- /dev/null +++ b/websocket/websocket.cpp @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "websocket.h" + +#include "define.h" +#include "log_wrapper.h" +#include "securec.h" + +namespace OHOS::ArkCompiler::Toolchain { +/** + * SendMessage in WebSocket has 3 situations: + * 1. message's length <= 125 + * 2. message's length >= 126 && messages's length < 65536 + * 3. message's length >= 65536 + */ + +void WebSocket::SendReply(const std::string& message) const +{ + int32_t msgLen = message.length(); + std::unique_ptr msgBuf = std::make_unique(msgLen + 11); // 11: the maximum expandable length + char* sendBuf = msgBuf.get(); + int32_t sendMsgLen; + sendBuf[0] = 0x81; // 0x81: the text message sent by the server should start with '0x81'. + + // Depending on the length of the messages, server will use shift operation to get the res + // and store them in the buffer. + if (msgLen <= 125) { // 125: situation 1 when message's length <= 125 + sendBuf[1] = msgLen; + sendMsgLen = 2; // 2: the length of header frame is 2 + } else if (msgLen < 65536) { // 65536: message's length + sendBuf[1] = 126; // 126: payloadLen according to the spec + sendBuf[2] = ((msgLen >> 8) & 0xff); // 8: shift right by 8 bits => res * (256^1) + sendBuf[3] = (msgLen & 0xff); // 3: store len's data => res * (256^0) + sendMsgLen = 4; // 4: the length of header frame is 4 + } else { + sendBuf[1] = 127; // 127: payloadLen according to the spec + for (int32_t i = 2; i <= 5; i++) { // 2 ~ 5: unused bits + sendBuf[i] = 0; + } + sendBuf[6] = ((msgLen & 0xff000000) >> 24); // 6: shift 24 bits => res * (256^3) + sendBuf[7] = ((msgLen & 0x00ff0000) >> 16); // 7: shift 16 bits => res * (256^2) + sendBuf[8] = ((msgLen & 0x0000ff00) >> 8); // 8: shift 8 bits => res * (256^1) + sendBuf[9] = (msgLen & 0x000000ff); // 9: res * (256^0) + sendMsgLen = 10; // 10: the length of header frame is 10 + } + if (memcpy_s(sendBuf + sendMsgLen, msgLen, message.c_str(), msgLen) != EOK) { + LOGE("SendReply: memcpy_s failed"); + return; + } + msgBuf[sendMsgLen + msgLen] = '\0'; + send(client_, sendBuf, sendMsgLen + msgLen, 0); +} + +bool WebSocket::HttpProtocolDecode(const std::string& request, HttpProtocol& req) +{ + if (request.find("GET") == std::string::npos) { + LOGE("Handshake failed: lack of necessary info"); + return false; + } + std::vector reqStr = ProtocolSplit(request, EOL); + for (size_t i = 0; i < reqStr.size(); i++) { + if (i == 0) { + std::vector headers = ProtocolSplit(reqStr.at(i), " "); + req.version = headers.at(2); // 2: to get the version param + } else if (i < reqStr.size() - 1) { + std::vector headers = ProtocolSplit(reqStr.at(i), ": "); + if (reqStr.at(i).find("Connection") != std::string::npos) { + req.connection = headers.at(1); // 1: to get the connection param + } else if (reqStr.at(i).find("Upgrade") != std::string::npos) { + req.upgrade = headers.at(1); // 1: to get the upgrade param + } else if (reqStr.at(i).find("Sec-WebSocket-Key") != std::string::npos) { + req.secWebSocketKey = headers.at(1); // 1: to get the secWebSocketKey param + } + } + } + return true; +} + +/** + * The wired format of this data transmission section is described in detail through ABNFRFC5234. + * When receive the message, we should decode it according the spec. The structure is as follows: + * 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 + * +-+-+-+-+-------+-+-------------+-------------------------------+ + * |F|R|R|R| opcode|M| Payload len | Extended payload length | + * |I|S|S|S| (4) |A| (7) | (16/64) | + * |N|V|V|V| |S| | (if payload len==126/127) | + * | |1|2|3| |K| | | + * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + * | Extended payload length continued, if payload len == 127 | + * + - - - - - - - - - - - - - - - +-------------------------------+ + * | |Masking-key, if MASK set to 1 | + * +-------------------------------+-------------------------------+ + * | Masking-key (continued) | Payload Data | + * +-------------------------------- - - - - - - - - - - - - - - - + + * : Payload Data continued ... : + * + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + * | Payload Data continued ... | + * +---------------------------------------------------------------+ + */ + +bool WebSocket::HandleFrame(WebSocketFrame& wsFrame) +{ + if (wsFrame.payloadLen == 126) { // 126: the payloadLen read from frame + char recvbuf[PAYLOAD_LEN + 1]; + int32_t bufLen = recv(client_, recvbuf, PAYLOAD_LEN, 0); + if (bufLen < PAYLOAD_LEN) { + LOGE("ReadMsg failed readRet=%{public}d", bufLen); + return false; + } + recvbuf[PAYLOAD_LEN] = '\0'; + uint16_t msgLen; + if (memcpy_s(&msgLen, sizeof(recvbuf), recvbuf, sizeof(recvbuf) - 1) != EOK) { + LOGE("HandleFrame: memcpy_s failed"); + return false; + } + wsFrame.payloadLen = ntohs(msgLen); + } else if (wsFrame.payloadLen > 126) { // 126: the payloadLen read from frame + char recvbuf[EXTEND_PATLOAD_LEN + 1]; + int32_t bufLen = recv(client_, recvbuf, EXTEND_PATLOAD_LEN, 0); + if (bufLen < EXTEND_PATLOAD_LEN) { + LOGE("ReadMsg failed readRet=%{public}d", bufLen); + return false; + } + recvbuf[EXTEND_PATLOAD_LEN] = '\0'; + uint64_t msgLen; + if (memcpy_s(&msgLen, sizeof(recvbuf), recvbuf, sizeof(recvbuf) - 1) != EOK) { + LOGE("HandleFrame: memcpy_s failed"); + return false; + } + wsFrame.payloadLen = ntohl(msgLen); + } + return DecodeMessage(wsFrame); +} + +bool WebSocket::DecodeMessage(WebSocketFrame& wsFrame) +{ + wsFrame.payload = std::make_unique(wsFrame.payloadLen + 1); + if (wsFrame.mask == 1) { + char buf[wsFrame.payloadLen + 1]; + char mask[SOCKET_MASK_LEN + 1]; + int32_t bufLen = recv(client_, mask, SOCKET_MASK_LEN, 0); + if (bufLen != SOCKET_MASK_LEN) { + LOGE("ReadMsg failed readRet=%{public}d", bufLen); + return false; + } + mask[SOCKET_MASK_LEN] = '\0'; + if (memcpy_s(wsFrame.maskingkey, SOCKET_MASK_LEN, mask, sizeof(mask) - 1) != EOK) { + LOGE("DecodeMessage: memcpy_s failed"); + return false; + } + uint64_t msgLen = recv(client_, buf, wsFrame.payloadLen, 0); + while (msgLen < wsFrame.payloadLen) { + uint64_t len = recv(client_, buf + msgLen, wsFrame.payloadLen - msgLen, 0); + msgLen += len; + } + buf[wsFrame.payloadLen] = '\0'; + for (uint64_t i = 0; i < wsFrame.payloadLen; i++) { + uint64_t j = i % SOCKET_MASK_LEN; + wsFrame.payload.get()[i] = buf[i] ^ wsFrame.maskingkey[j]; + } + } else { + char buf[wsFrame.payloadLen + 1]; + uint64_t msgLen = recv(client_, buf, wsFrame.payloadLen, 0); + if (msgLen != wsFrame.payloadLen) { + LOGE("ReadMsg failed"); + return false; + } + buf[wsFrame.payloadLen] = '\0'; + if (memcpy_s(wsFrame.payload.get(), wsFrame.payloadLen, buf, wsFrame.payloadLen) != EOK) { + LOGE("DecodeMessage: memcpy_s failed"); + return false; + } + } + wsFrame.payload.get()[wsFrame.payloadLen] = '\0'; + return true; +} + +bool WebSocket::ProtocolUpgrade(const HttpProtocol& req) +{ + std::string rawKey = req.secWebSocketKey + WEB_SOCKET_GUID; + unsigned const char* webSocketKey = reinterpret_cast(std::move(rawKey).c_str()); + unsigned char hash[SHA_DIGEST_LENGTH + 1]; + SHA1(webSocketKey, strlen(reinterpret_cast(webSocketKey)), hash); + hash[SHA_DIGEST_LENGTH] = '\0'; + unsigned char encodedKey[ENCODED_KEY_LEN]; + EVP_EncodeBlock(encodedKey, reinterpret_cast(hash), SHA_DIGEST_LENGTH); + std::string response; + + std::ostringstream sstream; + sstream << "HTTP/1.1 101 Switching Protocols" << EOL; + sstream << "Connection: upgrade" << EOL; + sstream << "Upgrade: websocket" << EOL; + sstream << "Sec-WebSocket-Accept: " << encodedKey << EOL; + sstream << EOL; + response = sstream.str(); + int32_t sendLen = send(client_, response.c_str(), response.length(), 0); + if (sendLen <= 0) { + LOGE("ProtocolUpgrade: Send failed"); + return false; + } + return true; +} + +std::optional WebSocket::Decode() +{ + char recvbuf[SOCKET_HEADER_LEN + 1]; + int32_t msgLen = recv(client_, recvbuf, SOCKET_HEADER_LEN, 0); + if (msgLen != SOCKET_HEADER_LEN) { + LOGE("Decode Failed: missing necessary header info"); + return {}; + } + recvbuf[SOCKET_HEADER_LEN] = '\0'; + WebSocketFrame wsFrame; + int32_t index = 0; + wsFrame.fin = static_cast(recvbuf[index] >> 7); // 7: shift right by 7 bits to get the fin + wsFrame.opcode = static_cast(recvbuf[index] & 0xf); + if (wsFrame.opcode == 0x1) { // 0x1: 0x1 means a text frame + index++; + wsFrame.mask = static_cast((recvbuf[index] >> 7) & 0x1); // 7: to get the mask + wsFrame.payloadLen = recvbuf[index] & 0x7f; + HandleFrame(wsFrame); + return wsFrame.payload.get(); + } + return {}; +} + +bool WebSocket::HttpHandShake() +{ + char msgBuf[SOCKET_HANDSHAKE_LEN]; + connectState_ = true; + int32_t msgLen = recv(client_, msgBuf, SOCKET_HANDSHAKE_LEN, 0); + if (msgLen <= 0) { + LOGE("ReadMsg failed readRet=%{public}d", msgLen); + return false; + } else { + msgBuf[msgLen - 1] = '\0'; + HttpProtocol req; + if (!HttpProtocolDecode(msgBuf, req)) { + LOGE("HttpHandShake: Upgrade failed"); + return false; + } else if (req.connection.find("Upgrade") != std::string::npos && + req.upgrade.find("websocket") != std::string::npos && req.version.compare("HTTP/1.1") == 0) { + ProtocolUpgrade(req); + } + } + return true; +} + +#if !defined(OHOS_PLATFORM) +bool WebSocket::StartForSimulator() +{ +#if defined(WINDOWS_PLATFORM) + WORD sockVersion = MAKEWORD(2, 2); // 2: version 2.2 + WSADATA wsaData; + if (WSAStartup(sockVersion, &wsaData) != 0) { + LOGE("StartWebSocket WSA init failed"); + return false; + } +#endif + fd_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (fd_ < SOCKET_SUCCESS) { + LOGE("StartWebSocket socket init failed"); + return false; + } + + sockaddr_in sin; + sin.sin_family = AF_INET; + sin.sin_port = htons(9230); // 9230: sockName for tcp + if (bind(fd_, reinterpret_cast(&sin), sizeof(sin)) < SOCKET_SUCCESS) { + LOGE("StartWebSocket bind failed"); + return false; + } + + if (listen(fd_, 1) < SOCKET_SUCCESS) { + LOGE("StartWebSocket listen failed"); + return false; + } + + if ((client_ = accept(fd_, nullptr, nullptr)) < SOCKET_SUCCESS) { + LOGE("StartWebSocket accept failed"); + return false; + } + + if (!HttpHandShake()) { + LOGE("StartWebSocket HttpHandShake failed"); + return false; + } + return true; +} +#else +bool WebSocket::StartWebSocket(std::string sockName) +{ + fd_ = socket(AF_UNIX, SOCK_STREAM, 0); // 0: defautlt protocol + if (fd_ < SOCKET_SUCCESS) { + LOGE("StartWebSocket socket init failed"); + return false; + } + struct sockaddr_un un; + if (memset_s(&un, sizeof(un), 0, sizeof(un)) != EOK) { + LOGE("StartWebSocket memset_s failed"); + return false; + } + un.sun_family = AF_UNIX; + if (strcpy_s(un.sun_path + 1, sizeof(un.sun_path) - 1, sockName.c_str()) != EOK) { + LOGE("StartWebSocket strcpy_s failed"); + return false; + } + un.sun_path[0] = '\0'; + int32_t len = offsetof(struct sockaddr_un, sun_path) + strlen(sockName.c_str()) + 1; + if (bind(fd_, reinterpret_cast(&un), len) < SOCKET_SUCCESS) { + LOGE("StartWebSocket bind failed"); + return false; + } + if (listen(fd_, 1) < SOCKET_SUCCESS) { // 1: connection num + LOGE("StartWebSocket listen failed"); + return false; + } + if ((client_ = accept(fd_, nullptr, nullptr)) < SOCKET_SUCCESS) { + LOGE("StartWebSocket accept failed"); + return false; + } + if (!HttpHandShake()) { + LOGE("StartWebSocket HttpHandShake failed"); + return false; + } + return true; +} +#endif + +void WebSocket::Close() +{ + if (fd_ >= SOCKET_SUCCESS) { +#if defined(OHOS_PLATFORM) + if (connectState_) { + shutdown(client_, SHUT_RDWR); + close(client_); + } + shutdown(fd_, SHUT_RDWR); +#endif + close(fd_); + } +} +} // namespace OHOS::ArkCompiler::Toolchain diff --git a/websocket/websocket.h b/websocket/websocket.h new file mode 100644 index 0000000000000000000000000000000000000000..e5146b577fc64fe4ae76a3b35370717b45abe335 --- /dev/null +++ b/websocket/websocket.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ARKCOMPILER_TOOLCHAIN_WEBSOCKET_WEBSOCKET_H +#define ARKCOMPILER_TOOLCHAIN_WEBSOCKET_WEBSOCKET_H + +#include +#include + +namespace OHOS::ArkCompiler::Toolchain { +struct WebSocketFrame { + uint8_t fin; + uint8_t opcode; + uint8_t mask; + uint64_t payloadLen; + char maskingkey[5]; + std::unique_ptr payload; +}; + +struct HttpProtocol { + std::string connection; + std::string upgrade; + std::string version; + std::string secWebSocketKey; +}; + +class WebSocket { +public: + WebSocket() = default; + ~WebSocket() = default; + std::optional Decode(); + void Close(); + bool DecodeMessage(WebSocketFrame& wsFrame); + bool HttpHandShake(); + bool HttpProtocolDecode(const std::string& request, HttpProtocol& req); + bool HandleFrame(WebSocketFrame& wsFrame); + bool ProtocolUpgrade(const HttpProtocol& req); + void SendReply(const std::string& message) const; + bool StartForSimulator(); + bool StartWebSocket(std::string sockName); + std::atomic connectState_; + +private: + int32_t client_ {0}; + int32_t fd_ {0}; + const int32_t ENCODED_KEY_LEN = 128; + const char* EOL = "\r\n"; + const int32_t SOCKET_HANDSHAKE_LEN = 1024; + const int32_t SOCKET_HEADER_LEN = 2; + const int32_t SOCKET_MASK_LEN = 4; + const int32_t SOCKET_SUCCESS = 0; + const int32_t PAYLOAD_LEN = 2; + const int32_t EXTEND_PATLOAD_LEN = 8; + const char* WEB_SOCKET_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; +}; +} // namespace OHOS::ArkCompiler::Toolchain + +#endif // ARKCOMPILER_TOOLCHAIN_WEBSOCKET_WEBSOCKET_H \ No newline at end of file