!11 replace the boost websocket

Merge pull request !11 from huangfeijie/master
This commit is contained in:
openharmony_ci 2022-10-26 11:26:28 +00:00 committed by Gitee
commit e33a2ffd0c
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
7 changed files with 620 additions and 100 deletions

View File

@ -82,10 +82,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\"" ]
@ -94,11 +91,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",

View File

@ -19,6 +19,7 @@
#include <iostream>
#include <shared_mutex>
#include <sys/types.h>
#include <unistd.h>
#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<WebSocket>();
#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<boost::asio::io_context>();
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;
while (!terminateExecution_) {
std::optional<std::string> message = webSocket_->Decode();
if (message.has_value()) {
wsOnMessage_(std::move(message.value()));
}
webSocket_ = std::unique_ptr<websocket::stream<CommProtocol::socket>>(
std::make_unique<websocket::stream<CommProtocol::socket>>(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));
}
} 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

View File

@ -16,29 +16,12 @@
#ifndef ARKCOMPILER_TOOLCHAIN_INSPECTOR_WS_SERVER_H
#define ARKCOMPILER_TOOLCHAIN_INSPECTOR_WS_SERVER_H
#include <boost/asio/error.hpp>
#if !defined(OHOS_PLATFORM)
#include <boost/asio/ip/tcp.hpp>
#else
#include <boost/asio/local/stream_protocol.hpp>
#endif
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include "websocket.h"
#include <functional>
#include <iostream>
#include <queue>
#include <pthread.h>
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<void(std::string&&)>& onMessage, int32_t instanceId)
@ -50,14 +33,14 @@ public:
void SendReply(const std::string& message) const;
private:
std::atomic<bool> connectState_ {false};
std::atomic<bool> terminateExecution_ { false };
[[maybe_unused]] int32_t instanceId_ {0};
#if defined(OHOS_PLATFORM)
pthread_t tid_ {0};
#endif
std::string componentName_ {};
std::function<void(std::string&&)> wsOnMessage_ {};
std::unique_ptr<websocket::stream<CommProtocol::socket>> webSocket_ { nullptr };
std::unique_ptr<boost::asio::io_context> ioContext_ { nullptr };
std::unique_ptr<WebSocket> webSocket_ { nullptr };
};
} // namespace OHOS::ArkCompiler::Toolchain

100
websocket/BUILD.gn Normal file
View File

@ -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"
}

58
websocket/define.h Normal file
View File

@ -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 <fstream>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <securec.h>
#include <sstream>
#include <string>
#if defined(WINDOWS_PLATFORM)
#include <winsock2.h>
#include <windows.h>
#else
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#endif
#include <unistd.h>
#include <vector>
namespace OHOS::ArkCompiler::Toolchain {
std::vector<std::string> ProtocolSplit(const std::string& str, const std::string& input)
{
std::vector<std::string> 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

356
websocket/websocket.cpp Normal file
View File

@ -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<char []> msgBuf = std::make_unique<char []>(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<std::string> reqStr = ProtocolSplit(request, EOL);
for (size_t i = 0; i < reqStr.size(); i++) {
if (i == 0) {
std::vector<std::string> headers = ProtocolSplit(reqStr.at(i), " ");
req.version = headers.at(2); // 2: to get the version param
} else if (i < reqStr.size() - 1) {
std::vector<std::string> 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<char []>(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<unsigned const char*>(std::move(rawKey).c_str());
unsigned char hash[SHA_DIGEST_LENGTH + 1];
SHA1(webSocketKey, strlen(reinterpret_cast<const char*>(webSocketKey)), hash);
hash[SHA_DIGEST_LENGTH] = '\0';
unsigned char encodedKey[ENCODED_KEY_LEN];
EVP_EncodeBlock(encodedKey, reinterpret_cast<const unsigned char*>(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<std::string> 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<uint8_t>(recvbuf[index] >> 7); // 7: shift right by 7 bits to get the fin
wsFrame.opcode = static_cast<uint8_t>(recvbuf[index] & 0xf);
if (wsFrame.opcode == 0x1) { // 0x1: 0x1 means a text frame
index++;
wsFrame.mask = static_cast<uint8_t>((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<struct sockaddr*>(&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<struct sockaddr*>(&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

70
websocket/websocket.h Normal file
View File

@ -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 <iostream>
#include <optional>
namespace OHOS::ArkCompiler::Toolchain {
struct WebSocketFrame {
uint8_t fin;
uint8_t opcode;
uint8_t mask;
uint64_t payloadLen;
char maskingkey[5];
std::unique_ptr<char []> payload;
};
struct HttpProtocol {
std::string connection;
std::string upgrade;
std::string version;
std::string secWebSocketKey;
};
class WebSocket {
public:
WebSocket() = default;
~WebSocket() = default;
std::optional<std::string> 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<bool> 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