diff --git a/bundle.json b/bundle.json index 90ca8ccbb2354c7b0f649f69a17e0c1f9d6d33bc..c648b56b7f4696704d2aa0e6120e49ce92faae0e 100644 --- a/bundle.json +++ b/bundle.json @@ -25,7 +25,8 @@ "features": [ "netstack_feature_http3", "netstack_http_boringssl", - "netstack_feature_communication_http3" + "netstack_feature_communication_http3", + "netstack_websocket_server_enable" ], "adapted_system_type": [ "standard" @@ -62,8 +63,6 @@ "build": { "group_type": { "base_group": [ - "//foundation/communication/netstack/frameworks/cj/http:cj_net_http_ffi", - "//foundation/communication/netstack/frameworks/cj/websocket:cj_net_websocket_ffi", "//foundation/communication/netstack/frameworks/js/napi/http:http", "//foundation/communication/netstack/frameworks/js/napi/socket:socket", "//foundation/communication/netstack/frameworks/js/napi/websocket:websocket", @@ -119,6 +118,20 @@ "header_files": [] }, "name": "//foundation/communication/netstack/interfaces/innerkits/rust/ylong_http_client:ylong_http_client" + }, + { + "header": { + "header_base": "//foundation/communication/netstack/frameworks/cj/websocket/include", + "header_files": [] + }, + "name": "//foundation/communication/netstack/frameworks/cj/websocket:cj_net_websocket_ffi" + }, + { + "header": { + "header_base": "//foundation/communication/netstack/frameworks/cj/http/include", + "header_files": [] + }, + "name": "//foundation/communication/netstack/frameworks/cj/http:cj_net_http_ffi" } ], "test": [ diff --git a/frameworks/cj/http/BUILD.gn b/frameworks/cj/http/BUILD.gn index f65f44e92384814d1d35c96830ed66a5485fd0d0..e69198a937b687906293fbfa832f8263aae48b22 100644 --- a/frameworks/cj/http/BUILD.gn +++ b/frameworks/cj/http/BUILD.gn @@ -82,6 +82,7 @@ ohos_shared_library("cj_net_http_ffi") { "napi:cj_bind_native", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] if (build_ohos_sdk) { diff --git a/frameworks/cj/http/src/net_http_client_exec.cpp b/frameworks/cj/http/src/net_http_client_exec.cpp index a06d54f053ab66120748b7d6d795e49a4ff984c2..fec790ad5cc32b1915ab057c0127077cba913e88 100644 --- a/frameworks/cj/http/src/net_http_client_exec.cpp +++ b/frameworks/cj/http/src/net_http_client_exec.cpp @@ -617,6 +617,10 @@ static int VerifyCallback(int preverifyOk, X509_STORE_CTX *ctx) SSL_CTX *sslctx = SSL_get_SSL_CTX(ssl); RequestContext *requestContext = static_cast(SSL_CTX_get_ex_data(sslctx, SSL_CTX_EX_DATA_REQUEST_CONTEXT_INDEX)); + if (requestContext == nullptr) { + NETSTACK_LOGE("creat requestContext instance failed"); + return 0; + } if (requestContext->IsRootCaVerifiedOk()) { // root CA hash verified, normal procedure. return preverifyOk; diff --git a/frameworks/cj/websocket/BUILD.gn b/frameworks/cj/websocket/BUILD.gn index 69c9f08e7883b2d669615cf32704604b06164504..6c35eadb561fd39137884ca4904788007c9b4a5b 100644 --- a/frameworks/cj/websocket/BUILD.gn +++ b/frameworks/cj/websocket/BUILD.gn @@ -62,6 +62,7 @@ ohos_shared_library("cj_net_websocket_ffi") { "napi:cj_bind_ffi", "napi:cj_bind_native", "openssl:libssl_shared", + "samgr:samgr_proxy", ] if (defined(global_parts_info) && diff --git a/frameworks/js/napi/http/BUILD.gn b/frameworks/js/napi/http/BUILD.gn index 81fa9f8ffa665a5c2cdfcb4b82395e7cd7fea493..dc9622fdd2ca8c0004eddc94496b77817f0cfcee 100644 --- a/frameworks/js/napi/http/BUILD.gn +++ b/frameworks/js/napi/http/BUILD.gn @@ -32,7 +32,10 @@ config("http_config") { if (defined(global_parts_info) && defined(global_parts_info.communication_netmanager_base) && global_parts_info.communication_netmanager_base) { - include_dirs += [ "$NETSTACK_DIR/utils/http_over_curl/include" ] + include_dirs += [ + "$NETSTACK_DIR/utils/http_over_curl/include", + "$NETSTACK_DIR/utils/netstack_chr_client/include", + ] } defines = [] @@ -159,13 +162,21 @@ ohos_shared_library("http") { global_parts_info.communication_netmanager_base) { external_deps += [ "netmanager_base:net_conn_manager_if" ] external_deps += [ "netmanager_base:netsys_client" ] - defines = [ "HAS_NETMANAGER_BASE=1" ] + defines = [ + "HAS_NETMANAGER_BASE=1", + "HAS_NETSTACK_CHR=1", + ] sources += [ + "$NETSTACK_DIR/utils/netstack_chr_client/src/netstack_chr_client.cpp", + "$NETSTACK_DIR/utils/netstack_chr_client/src/netstack_chr_report.cpp", "$NETSTACK_DIR/utils/http_over_curl/src/epoll_multi_driver.cpp", "$NETSTACK_DIR/utils/http_over_curl/src/epoll_request_handler.cpp", ] } else { - defines = [ "HAS_NETMANAGER_BASE=0" ] + defines = [ + "HAS_NETMANAGER_BASE=0", + "HAS_NETSTACK_CHR=0", + ] } if (product_name != "ohos-sdk") { external_deps += [ "init:libbegetutil" ] diff --git a/frameworks/js/napi/http/http_exec/src/http_exec.cpp b/frameworks/js/napi/http/http_exec/src/http_exec.cpp index 92e59d7a773b6c3199ebefe3f3ae495e1757790d..f0e96693720af455240b090158befd76b750571f 100755 --- a/frameworks/js/napi/http/http_exec/src/http_exec.cpp +++ b/frameworks/js/napi/http/http_exec/src/http_exec.cpp @@ -56,6 +56,7 @@ #include "event_list.h" #if HAS_NETMANAGER_BASE #include "hitrace_meter.h" +#include "netstack_chr_client.h" #include "netstack_hisysevent.h" #endif #include "http_async_work.h" @@ -351,6 +352,17 @@ bool HttpExec::RequestWithoutCache(RequestContext *context) }); context->SetCurlHeaderList(MakeHeaders(vec)); + static auto logCallback = +[](CURL *curl, + curl_infotype type, + char *data, + size_t size, + void *userptr) { + if (type == CURLINFO_STATE) { + NETSTACK_LOGI("CURL_TRACE: type = %{public}d, data = %{public}s", type, data); + } + }; + curl_easy_setopt(handle, CURLOPT_VERBOSE, 1); + curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, logCallback); if (!SetOption(handle, context, context->GetCurlHeaderList())) { NETSTACK_LOGE("set option failed"); return false; diff --git a/frameworks/js/napi/net_ssl/BUILD.gn b/frameworks/js/napi/net_ssl/BUILD.gn index 49910f8b46dd171d515d66bc87eba8c50c9aa730..cf32a6df8e20a5d6f4b37f72ca26d12a02a28873 100644 --- a/frameworks/js/napi/net_ssl/BUILD.gn +++ b/frameworks/js/napi/net_ssl/BUILD.gn @@ -87,6 +87,7 @@ ohos_shared_library("networksecurity_napi") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] } defines = [] diff --git a/frameworks/js/napi/net_ssl/net_ssl_exec/src/net_ssl_exec.cpp b/frameworks/js/napi/net_ssl/net_ssl_exec/src/net_ssl_exec.cpp index fcefcef4c5d668e54b1ea883f4b32d8703fb650f..805f6dffd5bfd0d19325fc265ee20ab9a0767c43 100644 --- a/frameworks/js/napi/net_ssl/net_ssl_exec/src/net_ssl_exec.cpp +++ b/frameworks/js/napi/net_ssl/net_ssl_exec/src/net_ssl_exec.cpp @@ -24,10 +24,6 @@ namespace OHOS::NetStack::Ssl { bool SslExec::ExecVerify(CertContext *context) { context->SetPermissionDenied(true); - auto sharedManager = context->GetSharedManager(); - if (sharedManager == nullptr || sharedManager->IsEventDestroy()) { - return false; - } if (context->GetErrorCode() == PARSE_ERROR_CODE) { return false; @@ -42,14 +38,12 @@ bool SslExec::ExecVerify(CertContext *context) NETSTACK_LOGD("verifyResult is %{public}d\n", context->GetErrorCode()); if (context->GetErrorCode() != 0) { - NapiUtils::CreateUvQueueWorkEnhanced(context->GetEnv(), context, NetSslAsyncWork::VerifyCallback); return false; } } else { context->SetErrorCode(NetStackVerifyCertification(context->GetCertBlob(), context->GetCertBlobClient())); NETSTACK_LOGD("verifyResult is %{public}d\n", context->GetErrorCode()); if (context->GetErrorCode() != 0) { - NapiUtils::CreateUvQueueWorkEnhanced(context->GetEnv(), context, NetSslAsyncWork::VerifyCallback); return false; } } diff --git a/frameworks/js/napi/socket/BUILD.gn b/frameworks/js/napi/socket/BUILD.gn index 57033c328222e86b077768a5ecfcfbf73b8696c0..20b498be36887956aed6c01cc4fe87512c2908b8 100644 --- a/frameworks/js/napi/socket/BUILD.gn +++ b/frameworks/js/napi/socket/BUILD.gn @@ -143,6 +143,7 @@ ohos_shared_library("socket") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] if (defined(global_parts_info) && diff --git a/frameworks/js/napi/socket/socket_exec/src/socket_exec.cpp b/frameworks/js/napi/socket/socket_exec/src/socket_exec.cpp index e49bd4075aea965a88d0c0b3911136ba9f841b3d..ff0614f66a7d4510b9b7f969ab207357fb2f41c1 100644 --- a/frameworks/js/napi/socket/socket_exec/src/socket_exec.cpp +++ b/frameworks/js/napi/socket/socket_exec/src/socket_exec.cpp @@ -179,7 +179,7 @@ void TcpServerConnectionFinalize(napi_env, void *data, void *) void NotifyRegisterEvent() { std::lock_guard lock(g_mutex); - g_cv.notify_one(); + g_cv.notify_all(); } napi_value NewInstanceWithConstructor(napi_env env, napi_callback_info info, napi_value jsConstructor, int32_t counter) @@ -649,9 +649,6 @@ static int UpdateRecvBuffer(int sock, int &bufferSize, std::unique_ptr & static int ExitOrAbnormal(int sock, ssize_t recvLen, const MessageCallback &callback) { - if (errno == EAGAIN || errno == EINTR) { - return 0; - } if (!IsTCPSocket(sock) && errno != EBADF) { NETSTACK_LOGI("not tcpsocket, continue loop, recvLen: %{public}zd, err: %{public}d", recvLen, errno); if (errno == ENOTSOCK) { @@ -659,15 +656,19 @@ static int ExitOrAbnormal(int sock, ssize_t recvLen, const MessageCallback &call } return 0; } - if (errno == 0 && recvLen == 0) { + if (recvLen == 0) { NETSTACK_LOGI("closed by peer, socket:%{public}d, recvLen:%{public}zd", sock, recvLen); callback.OnCloseMessage(callback.GetEventManager()); - } else { - if (callback.GetEventManager() != nullptr && static_cast( - reinterpret_cast(callback.GetEventManager()->GetData())) > 0) { - NETSTACK_LOGE("recv fail, socket:%{public}d, recvLen:%{public}zd, errno:%{public}d", sock, recvLen, errno); - callback.OnError(errno); - } + return -1; + } + if (errno == EAGAIN || errno == EINTR) { + return 0; + } + + if (callback.GetEventManager() != nullptr && static_cast( + reinterpret_cast(callback.GetEventManager()->GetData())) > 0) { + NETSTACK_LOGE("recv fail, socket:%{public}d, recvLen:%{public}zd, errno:%{public}d", sock, recvLen, errno); + callback.OnError(errno); } return -1; } @@ -729,12 +730,13 @@ static bool ProcessRecvFds(std::pair &, int> &bufInfo, std::unordered_map &socketCallbackMap) { for (auto &fd : fds) { -#if !defined(CROSS_PLATFORM) - if ((static_cast(fd.revents) & POLLRDHUP) || (static_cast(fd.revents) & POLLERR) || - (static_cast(fd.revents) & POLLNVAL)) { -#else if ((static_cast(fd.revents) & POLLERR) || (static_cast(fd.revents) & POLLNVAL)) { -#endif + NETSTACK_LOGE("recv fail, socket:%{public}d, errno:%{public}d, revent:%{public}x", + fd.fd, errno, fd.revents); + if (callback.GetEventManager() != nullptr && static_cast( + reinterpret_cast(callback.GetEventManager()->GetData())) > 0) { + callback.OnError(errno); + } return false; } if ((static_cast(fd.revents) & POLLIN) == 0) { @@ -765,6 +767,7 @@ static bool PreparePollFds(int ¤tFd, std::vector &fds, return false; } + std::shared_lock lock(manager->GetDataMutex()); currentFd = static_cast(reinterpret_cast(manager->GetData())); if (currentFd <= 0) { NETSTACK_LOGE("currentFd: %{public}d is error", currentFd); @@ -1183,7 +1186,7 @@ bool ExecTcpSend(TcpSendContext *context) context->SetPermissionDenied(true); return false; } - + std::shared_lock lock(g_fdMutex); if (context->GetSocketFd() <= 0) { context->SetError(ERRNO_BAD_FD, strerror(ERRNO_BAD_FD)); NapiUtils::CreateUvQueueWorkEnhanced(context->GetEnv(), context, SocketAsyncWork::TcpSendCallback); diff --git a/frameworks/js/napi/socket/socket_module/src/socket_module.cpp b/frameworks/js/napi/socket/socket_module/src/socket_module.cpp index 0b67ba88a5bf298009d614a6663701f23fd358f4..bfbcad5edd3d55770c99ac60ccf2774b542dc439 100644 --- a/frameworks/js/napi/socket/socket_module/src/socket_module.cpp +++ b/frameworks/js/napi/socket/socket_module/src/socket_module.cpp @@ -135,7 +135,9 @@ void Finalize(napi_env, void *data, void *) if (sharedManager != nullptr && *sharedManager != nullptr) { auto manager = *sharedManager; int sock = static_cast(reinterpret_cast(manager->GetData())); - if (sock != -1) { + if (sock == 0) { + NETSTACK_LOGE("manager->GetData() got nullptr, Finalize() called before creating socket?"); + } else if (sock != -1) { SocketExec::SingletonSocketConfig::GetInstance().RemoveServerSocket(sock); close(sock); manager->SetData(reinterpret_cast(-1)); @@ -226,6 +228,7 @@ static bool SetSocket(napi_env env, napi_value thisVal, BaseContext *context, in if (manager == nullptr) { return false; } + NETSTACK_LOGD("SetSocket: sock %{public}d", sock); manager->SetData(reinterpret_cast(sock)); NapiUtils::SetInt32Property(env, thisVal, KEY_SOCKET_FD, sock); return true; @@ -367,6 +370,7 @@ static bool SetSocketManager(napi_env env, napi_value thisVal, BaseContext *cont if (manager == nullptr) { return false; } + NETSTACK_LOGD("SetSocketManager setData"); manager->SetData(reinterpret_cast(mgr)); NapiUtils::SetInt32Property(env, thisVal, KEY_SOCKET_FD, mgr->sockfd_); return true; diff --git a/frameworks/js/napi/tls/include/tlssocket_exec.h b/frameworks/js/napi/tls/include/tlssocket_exec.h index 2792d3cbdb71f8cda0facc96545463b93d3134d8..926d59f7e46a8884b1ad5f2b4eae625007b16361 100644 --- a/frameworks/js/napi/tls/include/tlssocket_exec.h +++ b/frameworks/js/napi/tls/include/tlssocket_exec.h @@ -64,6 +64,8 @@ public: static napi_value GetLocalAddressCallback(TLSGetLocalAddressContext *context); static napi_value SetExtraOptionsCallback(TLSSetExtraOptionsContext *context); static napi_value GetSocketFdCallback(TLSGetSocketFdContext *context); +private: + static void SetContext(TLSGetLocalAddressContext *context); }; } // namespace TlsSocket } // namespace NetStack diff --git a/frameworks/js/napi/tls/src/tlssocket_exec.cpp b/frameworks/js/napi/tls/src/tlssocket_exec.cpp index 2dd0f85fee3eb7386d6d774a74f9fe6a5c02b434..df6aa80302653429c97de41288b88d4f3f4596f9 100644 --- a/frameworks/js/napi/tls/src/tlssocket_exec.cpp +++ b/frameworks/js/napi/tls/src/tlssocket_exec.cpp @@ -114,6 +114,7 @@ bool TLSSocketExec::ExecGetCertificate(GetCertificateContext *context) NETSTACK_LOGE("manager is nullptr"); return false; } + std::shared_lock lock(manager->GetDataMutex()); auto tlsSocket = reinterpret_cast *>(manager->GetData()); if (tlsSocket == nullptr) { NETSTACK_LOGE("ExecGetCertificate tlsSocket is null"); @@ -205,6 +206,7 @@ bool TLSSocketExec::ExecConnect(TLSConnectContext *context) NETSTACK_LOGE("manager is nullptr"); return false; } + std::shared_lock lock(manager->GetDataMutex()); auto tlsSocket = reinterpret_cast *>(manager->GetData()); if (tlsSocket == nullptr) { NETSTACK_LOGE("ExecConnect tlsSocket is null"); @@ -239,6 +241,7 @@ bool TLSSocketExec::ExecGetCipherSuites(GetCipherSuitesContext *context) NETSTACK_LOGE("manager is nullptr"); return false; } + std::shared_lock lock(manager->GetDataMutex()); auto tlsSocket = reinterpret_cast *>(manager->GetData()); if (tlsSocket == nullptr) { NETSTACK_LOGE("ExecGetCipherSuites tlsSocket is null"); @@ -268,6 +271,7 @@ bool TLSSocketExec::ExecGetRemoteCertificate(GetRemoteCertificateContext *contex NETSTACK_LOGE("manager is nullptr"); return false; } + std::shared_lock lock(manager->GetDataMutex()); auto tlsSocket = reinterpret_cast *>(manager->GetData()); if (tlsSocket == nullptr) { NETSTACK_LOGE("ExecGetRemoteCertificate tlsSocket is null"); @@ -297,6 +301,7 @@ bool TLSSocketExec::ExecGetProtocol(GetProtocolContext *context) NETSTACK_LOGE("manager is nullptr"); return false; } + std::shared_lock lock(manager->GetDataMutex()); auto tlsSocket = reinterpret_cast *>(manager->GetData()); if (tlsSocket == nullptr) { NETSTACK_LOGE("ExecGetProtocol tlsSocket is null"); @@ -326,6 +331,7 @@ bool TLSSocketExec::ExecGetSignatureAlgorithms(GetSignatureAlgorithmsContext *co NETSTACK_LOGE("manager is nullptr"); return false; } + std::shared_lock lock(manager->GetDataMutex()); auto tlsSocket = reinterpret_cast *>(manager->GetData()); if (tlsSocket == nullptr) { NETSTACK_LOGE("ExecGetSignatureAlgorithms tlsSocket is null"); @@ -419,7 +425,7 @@ bool TLSSocketExec::ExecBind(TLSBindContext *context) NETSTACK_LOGE("manager is nullptr"); return false; } - + std::unique_lock lock(manager->GetDataMutex()); auto tlsSocket = reinterpret_cast *>(manager->GetData()); if (tlsSocket != nullptr) { NETSTACK_LOGI("TLSSocket has been constructed"); @@ -455,6 +461,7 @@ bool TLSSocketExec::ExecGetRemoteAddress(TLSGetRemoteAddressContext *context) NETSTACK_LOGE("manager is nullptr"); return false; } + std::shared_lock lock(manager->GetDataMutex()); auto tlsSocket = reinterpret_cast *>(manager->GetData()); if (tlsSocket == nullptr) { NETSTACK_LOGE("ExecGetRemoteAddress tlsSocket is null"); @@ -477,6 +484,13 @@ bool TLSSocketExec::ExecGetRemoteAddress(TLSGetRemoteAddressContext *context) return context->errorNumber_ == TLSSOCKET_SUCCESS; } +void TLSSocketExec::SetContext(TLSGetLocalAddressContext *context) +{ + context->SetNeedThrowException(true); + context->SetError(TlsSocket::TlsSocketError::TLS_ERR_NO_BIND, + TlsSocket::MakeErrorMessage(TlsSocket::TlsSocketError::TLS_ERR_NO_BIND)); +} + bool TLSSocketExec::ExecGetLocalAddress(TLSGetLocalAddressContext *context) { if (context == nullptr) { @@ -484,11 +498,10 @@ bool TLSSocketExec::ExecGetLocalAddress(TLSGetLocalAddressContext *context) } auto manager = context->GetSharedManager(); if (manager == nullptr) { - context->SetNeedThrowException(true); - context->SetError(TlsSocket::TlsSocketError::TLS_ERR_NO_BIND, - TlsSocket::MakeErrorMessage(TlsSocket::TlsSocketError::TLS_ERR_NO_BIND)); + SetContext(context); return false; } + std::shared_lock lock(manager->GetDataMutex()); auto tlsSocket = reinterpret_cast *>(manager->GetData()); if (tlsSocket == nullptr) { context->SetError(TlsSocket::TlsSocketError::TLS_ERR_NO_BIND, @@ -538,6 +551,7 @@ bool TLSSocketExec::ExecGetState(TLSGetStateContext *context) context->SetError(TLS_ERR_SYS_EINVAL, MakeErrorMessage(TLS_ERR_SYS_EINVAL)); return false; } + std::shared_lock lock(manager->GetDataMutex()); auto tlsSocket = reinterpret_cast *>(manager->GetData()); if (tlsSocket == nullptr) { NETSTACK_LOGE("ExecGetState tlsSocket is null"); @@ -564,6 +578,7 @@ bool TLSSocketExec::ExecSetExtraOptions(TLSSetExtraOptionsContext *context) NETSTACK_LOGE("manager is nullptr"); return false; } + std::shared_lock lock(manager->GetDataMutex()); auto tlsSocket = reinterpret_cast *>(manager->GetData()); if (tlsSocket == nullptr) { NETSTACK_LOGE("ExecSetExtraOptions tlsSocket is null"); @@ -592,6 +607,7 @@ bool TLSSocketExec::ExecGetSocketFd(TLSGetSocketFdContext *context) NETSTACK_LOGE("manager is nullptr"); return false; } + std::shared_lock lock(manager->GetDataMutex()); auto tlsSocket = reinterpret_cast *>(manager->GetData()); if (tlsSocket == nullptr) { NETSTACK_LOGE("ExecGetSocketFd tlsSocket is null"); @@ -755,6 +771,7 @@ napi_value TLSSocketExec::GetLocalAddressCallback(TLSGetLocalAddressContext *con NETSTACK_LOGE("manager is nullptr"); return obj; } + std::shared_lock lock(manager->GetDataMutex()); auto tlsSocket = reinterpret_cast *>(manager->GetData()); if (tlsSocket == nullptr) { NETSTACK_LOGE("get localAddress callback tlsSocketServer is null"); diff --git a/frameworks/js/napi/websocket/BUILD.gn b/frameworks/js/napi/websocket/BUILD.gn index fe9dd378255acb5dd9e002867dddf02a990f05e3..5d85a873483a371bc53c36764e91cd2118190a38 100644 --- a/frameworks/js/napi/websocket/BUILD.gn +++ b/frameworks/js/napi/websocket/BUILD.gn @@ -62,6 +62,7 @@ ohos_shared_library("websocket") { "libwebsockets:websockets", "napi:ace_napi", "openssl:libssl_shared", + "samgr:samgr_proxy", ] if (defined(global_parts_info) && @@ -73,6 +74,18 @@ ohos_shared_library("websocket") { defines += [ "HAS_NETMANAGER_BASE=0" ] } + if (netstack_websocket_server_enable) { + defines += [ "NETSTACK_WEBSOCKETSERVER" ] + sources += [ + "async_context/src/list_all_connections_context.cpp", + "async_context/src/server_close_context.cpp", + "async_context/src/server_send_context.cpp", + "async_context/src/server_start_context.cpp", + "async_context/src/server_stop_context.cpp", + "websocket_exec/src/websocket_server_exec.cpp", + ] + } + if (product_name != "ohos-sdk") { external_deps += [ "init:libbegetutil" ] } diff --git a/frameworks/js/napi/websocket/async_context/include/list_all_connections_context.h b/frameworks/js/napi/websocket/async_context/include/list_all_connections_context.h new file mode 100644 index 0000000000000000000000000000000000000000..5c37ea0e3c6417c69887b154b70f0b0b146a142e --- /dev/null +++ b/frameworks/js/napi/websocket/async_context/include/list_all_connections_context.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025 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 COMMUNICATIONNETSTACK_LISTALLCONNECTIONS_CONTEXT_H +#define COMMUNICATIONNETSTACK_LISTALLCONNECTIONS_CONTEXT_H + +#include "base_context.h" +#include "websocket_exec_common.h" +#include "nocopyable.h" + +namespace OHOS::NetStack::Websocket { +class ListAllConnectionsContext final : public BaseContext { +public: + DISALLOW_COPY_AND_MOVE(ListAllConnectionsContext); + + ListAllConnectionsContext() = delete; + + ListAllConnectionsContext(napi_env env, const std::shared_ptr &sharedManager); + + ~ListAllConnectionsContext() override; + + void ParseParams(napi_value *params, size_t paramsCount) override; + + void SetAllConnections(std::vector &connections); + + [[nodiscard]] std::vector GetAllConnections() const; + + [[nodiscard]] int32_t GetErrorCode() const override; + + [[nodiscard]] std::string GetErrorMessage() const override; + +private: + bool CheckParamsType(napi_value *params, size_t paramsCount); + + std::vector webSocketConnections_; +}; +} // namespace OHOS::NetStack::Websocket + +#endif /* COMMUNICATIONNETSTACK_LISTALLCONNECTIONS_CONTEXT_H */ \ No newline at end of file diff --git a/frameworks/js/napi/websocket/async_context/include/server_close_context.h b/frameworks/js/napi/websocket/async_context/include/server_close_context.h new file mode 100644 index 0000000000000000000000000000000000000000..c95438c0da6b8533b1f24d0c4705bec760a8ae70 --- /dev/null +++ b/frameworks/js/napi/websocket/async_context/include/server_close_context.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025 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 COMMUNICATIONNETSTACK_SERVER_CLOSE_CONTEXT_H +#define COMMUNICATIONNETSTACK_SERVER_CLOSE_CONTEXT_H + +#include +#include "base_context.h" +#include "websocket_exec_common.h" +#include "nocopyable.h" + +namespace OHOS::NetStack::Websocket { +class ServerCloseContext final : public BaseContext { +public: + DISALLOW_COPY_AND_MOVE(ServerCloseContext); + + ServerCloseContext() = delete; + + ServerCloseContext(napi_env env, const std::shared_ptr &manager); + + ~ServerCloseContext() override; + + void ParseParams(napi_value *params, size_t paramsCount) override; + + bool HandleParseConnection(napi_env env, napi_value params); + + bool HandleParseCloseOption(napi_env env, napi_value params); + + [[nodiscard]] OHOS::NetStack::Websocket::WebSocketConnection GetConnection() const; + + [[nodiscard]] int32_t GetErrorCode() const override; + + [[nodiscard]] std::string GetErrorMessage() const override; + + uint32_t code; + + std::string reason; + + WebSocketConnection connection; + +private: + bool CheckParamsType(napi_value *params, size_t paramsCount); + + bool IsValidWebsocketConnection(napi_env env, napi_value params); + + bool IsValidCloseOptions(napi_env env, napi_value params); +}; +} // namespace OHOS::NetStack::Websocket + +#endif /* COMMUNICATIONNETSTACK_SERVER_CLOSE_CONTEXT_H */ \ No newline at end of file diff --git a/frameworks/js/napi/websocket/async_context/include/server_send_context.h b/frameworks/js/napi/websocket/async_context/include/server_send_context.h new file mode 100644 index 0000000000000000000000000000000000000000..90beb31a7fadebcc97396ce7a164d471e41d0de8 --- /dev/null +++ b/frameworks/js/napi/websocket/async_context/include/server_send_context.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2025 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 COMMUNICATIONNETSTACK_SERVER_SEND_CONTEXT_H +#define COMMUNICATIONNETSTACK_SERVER_SEND_CONTEXT_H + +#include +#include "base_context.h" +#include "websocket_exec_common.h" +#include "nocopyable.h" + +namespace OHOS::NetStack::Websocket { +class ServerSendContext final : public BaseContext { +public: + DISALLOW_COPY_AND_MOVE(ServerSendContext); + + ServerSendContext() = delete; + + ServerSendContext(napi_env env, const std::shared_ptr &manager); + + ~ServerSendContext() override; + + void ParseParams(napi_value *params, size_t paramsCount) override; + + bool HandleParseString(napi_value *params); + + bool HandleParseArrayBuffer(napi_value *params); + + bool HandleParseConnection(napi_env env, napi_value params); + + void SetClientWebSocketConn(uint32_t &port, std::string &ip); + + [[nodiscard]] int32_t GetErrorCode() const override; + + [[nodiscard]] std::string GetErrorMessage() const override; + + [[nodiscard]] OHOS::NetStack::Websocket::WebSocketConnection GetConnection() const; + + void *data; + + size_t length; + + lws_write_protocol protocol; + + OHOS::NetStack::Websocket::WebSocketConnection connection; + +private: + bool CheckParamsType(napi_value *params, size_t paramsCount); + + bool IsValidWebsocketConnection(napi_env env, napi_value params); +}; +} // namespace OHOS::NetStack::Websocket + +#endif \ No newline at end of file diff --git a/frameworks/js/napi/websocket/async_context/include/server_start_context.h b/frameworks/js/napi/websocket/async_context/include/server_start_context.h new file mode 100644 index 0000000000000000000000000000000000000000..918ff3fce8fa534712ec100740fd9d95d7e8c87c --- /dev/null +++ b/frameworks/js/napi/websocket/async_context/include/server_start_context.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025 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 COMMUNICATIONNETSTACK_SERVER_START_CONTEXT_H +#define COMMUNICATIONNETSTACK_SERVER_START_CONTEXT_H + +#include + +#include "base_context.h" +#include "libwebsockets.h" +#include "nocopyable.h" + +namespace OHOS::NetStack::Websocket { +class ServerStartContext final : public BaseContext { +public: + DISALLOW_COPY_AND_MOVE(ServerStartContext); + + ServerStartContext() = delete; + + ServerStartContext(napi_env env, const std::shared_ptr &sharedManager); + + ~ServerStartContext() override; + + void ParseParams(napi_value *params, size_t paramsCount) override; + + void SetServerIP(std::string &ip); + + [[nodiscard]] std::string GetServerIP() const; + + void SetServerPort(uint32_t &serverPort); + + [[nodiscard]] uint32_t GetServerPort() const; + + void SetServerCert(std::string &certPath, std::string &keyPath); + + void GetServerCert(std::string &certPath, std::string &keyPath) const; + + void SetMaxConcurrentClientsNumber(uint32_t &clientsNumber); + + [[nodiscard]] uint32_t GetMaxConcurrentClientsNumber() const; + + void SetServerProtocol(std::string &protocol); + + [[nodiscard]] std::string GetServerProtocol() const; + + void SetMaxConnectionsForOneClient(uint32_t &count); + + [[nodiscard]] uint32_t GetMaxConnectionsForOneClient() const; + + [[nodiscard]] int32_t GetErrorCode() const override; + + [[nodiscard]] std::string GetErrorMessage() const override; + + std::string serverIp_; + + uint32_t serverPort_; + + std::string certPath_; + + std::string keyPath_; + + uint32_t maxClientsNumber_; + + std::string websocketServerProtocol_; + + uint32_t maxCountForOneClient_; + +private: + bool CheckParamsType(napi_value *params, size_t paramsCount); + + void ParseCallback(napi_value const *params, size_t paramsCount); + + bool ParseRequiredParams(napi_env env, napi_value params); + + void ParseOptionalParams(napi_env env, napi_value params); + + void ParseServerCert(napi_env env, napi_value params); +}; +} // namespace OHOS::NetStack::Websocket +#endif /* COMMUNICATIONNETSTACK_SERVER_START_CONTEXT_H */ \ No newline at end of file diff --git a/frameworks/js/napi/websocket/async_context/include/server_stop_context.h b/frameworks/js/napi/websocket/async_context/include/server_stop_context.h new file mode 100644 index 0000000000000000000000000000000000000000..986600a22d3b304e33421bcdbb1baca793640b77 --- /dev/null +++ b/frameworks/js/napi/websocket/async_context/include/server_stop_context.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 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 COMMUNICATIONNETSTACK_SERVER_STOP_CONTEXT_H +#define COMMUNICATIONNETSTACK_SERVER_STOP_CONTEXT_H + +#include +#include "base_context.h" +#include "nocopyable.h" + +namespace OHOS::NetStack::Websocket { +class ServerStopContext final : public BaseContext { +public: + DISALLOW_COPY_AND_MOVE(ServerStopContext); + + ServerStopContext() = delete; + + ServerStopContext(napi_env env, const std::shared_ptr &manager); + + ~ServerStopContext() override; + + void ParseParams(napi_value *params, size_t paramsCount) override; + + [[nodiscard]] int32_t GetErrorCode() const override; + + [[nodiscard]] std::string GetErrorMessage() const override; + +private: + bool CheckParamsType(napi_value *params, size_t paramsCount); +}; +} // namespace OHOS::NetStack::Websocket + +#endif /* COMMUNICATIONNETSTACK_SERVER_STOP_CONTEXT_H */ \ No newline at end of file diff --git a/frameworks/js/napi/websocket/async_context/src/list_all_connections_context.cpp b/frameworks/js/napi/websocket/async_context/src/list_all_connections_context.cpp new file mode 100644 index 0000000000000000000000000000000000000000..137ffff1cac5b3d174fc644eebffbbadee14c2c5 --- /dev/null +++ b/frameworks/js/napi/websocket/async_context/src/list_all_connections_context.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2025-2025 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 "list_all_connections_context.h" +#include "constant.h" +#include "netstack_log.h" +#include "napi_utils.h" + +namespace OHOS::NetStack::Websocket { +ListAllConnectionsContext::ListAllConnectionsContext(napi_env env, const std::shared_ptr &sharedManager) + : BaseContext(env, sharedManager) {} + +ListAllConnectionsContext::~ListAllConnectionsContext() = default; + +void ListAllConnectionsContext::ParseParams(napi_value *params, size_t paramsCount) +{ + if (!CheckParamsType(params, paramsCount)) { + return; + } + if (paramsCount != FUNCTION_PARAM_ZERO) { + SetParseOK(SetCallback(params[0]) == napi_ok); + return; + } + SetParseOK(true); +} + +bool ListAllConnectionsContext::CheckParamsType(napi_value *params, size_t paramsCount) +{ + if (paramsCount == FUNCTION_PARAM_ZERO) { + return true; + } + return false; +} + +void ListAllConnectionsContext::SetAllConnections(std::vector + &connections) +{ + webSocketConnections_ = connections; +} + +std::vector ListAllConnectionsContext::GetAllConnections() const +{ + return webSocketConnections_; +} + +int32_t ListAllConnectionsContext::GetErrorCode() const +{ + if (BaseContext::IsPermissionDenied()) { + return PERMISSION_DENIED_CODE; + } + return WEBSOCKET_UNKNOWN_OTHER_ERROR; +} + +std::string ListAllConnectionsContext::GetErrorMessage() const +{ + if (BaseContext::IsPermissionDenied()) { + return PERMISSION_DENIED_MSG; + } + auto it = WEBSOCKET_ERR_MAP.find(WEBSOCKET_UNKNOWN_OTHER_ERROR); + if (it != WEBSOCKET_ERR_MAP.end()) { + return it->second; + } + return {}; +} +} // namespace OHOS::NetStack::Websocket \ No newline at end of file diff --git a/frameworks/js/napi/websocket/async_context/src/server_close_context.cpp b/frameworks/js/napi/websocket/async_context/src/server_close_context.cpp new file mode 100644 index 0000000000000000000000000000000000000000..19b0e6dff5e09406a9de2fe5c8c75baffa7b78a5 --- /dev/null +++ b/frameworks/js/napi/websocket/async_context/src/server_close_context.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2025-2025 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 "server_close_context.h" +#include "constant.h" +#include "netstack_common_utils.h" +#include "netstack_log.h" +#include "napi_utils.h" + +namespace OHOS::NetStack::Websocket { +ServerCloseContext::ServerCloseContext(napi_env env, const std::shared_ptr &manager) + : BaseContext(env, manager), code(CLOSE_REASON_NORMAL_CLOSE), reason("CLOSE_NORMAL"), connection() {} + +ServerCloseContext::~ServerCloseContext() = default; + +void ServerCloseContext::ParseParams(napi_value *params, size_t paramsCount) +{ + if (!CheckParamsType(params, paramsCount)) { + NETSTACK_LOGE("ServerCloseContext Parse Failed"); + if (paramsCount == FUNCTION_PARAM_ONE) { + if (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_function) { + SetCallback(params[0]); + } + return; + } + + if (paramsCount == FUNCTION_PARAM_TWO) { + if (NapiUtils::GetValueType(GetEnv(), params[1]) == napi_function) { + SetCallback(params[1]); + } + return; + } + return; + } + + if (paramsCount == FUNCTION_PARAM_ONE) { + NETSTACK_LOGI("paramsCount is one"); + if (!HandleParseConnection(GetEnv(), params[0])) { + return; + } + } + + if (paramsCount == FUNCTION_PARAM_TWO) { + NETSTACK_LOGI("paramsCount is two"); + if (!HandleParseConnection(GetEnv(), params[0])) { + return; + } + if (!HandleParseCloseOption(GetEnv(), params[1])) { + return; + } + } + NETSTACK_LOGI("ServerCloseContext Parse OK"); + return SetParseOK(true); +} + +bool ServerCloseContext::HandleParseConnection(napi_env env, napi_value params) +{ + NETSTACK_LOGI("HandleParseConnection enter"); + if (NapiUtils::GetValueType(env, params) == napi_object) { + connection.clientPort = NapiUtils::GetUint32Property(env, params, ContextKey::CLIENT_PORT); + if (connection.clientPort == 0) { + NETSTACK_LOGE("parse clientPort failed"); + } + connection.clientIP = NapiUtils::GetStringPropertyUtf8(env, params, ContextKey::CLIENT_IP); + if (connection.clientIP == "") { + NETSTACK_LOGE("parse clientIP failed"); + } + return true; + } + return false; +} + +bool ServerCloseContext::HandleParseCloseOption(napi_env env, napi_value params) +{ + if (NapiUtils::GetValueType(env, params) == napi_object) { + uint32_t closeCode = NapiUtils::GetUint32Property(env, params, ContextKey::CODE); + if (closeCode >= CLOSE_REASON_NORMAL_CLOSE && closeCode <= CLOSE_REASON_RESERVED12) { + code = closeCode; + } + std::string tempReason = NapiUtils::GetStringPropertyUtf8(env, params, ContextKey::REASON); + if (!tempReason.empty()) { + reason = tempReason; + } + return true; + } + return false; +} + +bool ServerCloseContext::CheckParamsType(napi_value *params, size_t paramsCount) +{ + if (paramsCount == FUNCTION_PARAM_ONE) { + NETSTACK_LOGI("paramsCount one"); + return IsValidWebsocketConnection(GetEnv(), params[0]); + } + + if (paramsCount == FUNCTION_PARAM_TWO) { + NETSTACK_LOGI("paramsCount two"); + return IsValidWebsocketConnection(GetEnv(), params[0]) && + IsValidCloseOptions(GetEnv(), params[1]); + } + return false; +} + +bool ServerCloseContext::IsValidWebsocketConnection(napi_env env, napi_value params) +{ + if (NapiUtils::GetValueType(env, params) != napi_object) { + return false; + } + return (NapiUtils::GetValueType(env, NapiUtils::GetNamedProperty(env, params, + ContextKey::CLIENT_PORT)) == napi_number) && (NapiUtils::GetValueType(env, + NapiUtils::GetNamedProperty(env, params, ContextKey::CLIENT_IP)) == napi_string); +} + +bool ServerCloseContext::IsValidCloseOptions(napi_env env, napi_value params) +{ + if (NapiUtils::GetValueType(env, params) != napi_object) { + return false; + } + return NapiUtils::GetValueType(env, NapiUtils::GetNamedProperty(env, params, + ContextKey::CODE)) == napi_number && NapiUtils::GetValueType(env, + NapiUtils::GetNamedProperty(env, params, ContextKey::REASON)) == napi_string; +} + +WebSocketConnection ServerCloseContext::GetConnection() const +{ + return connection; +} + +int32_t ServerCloseContext::GetErrorCode() const +{ + if (BaseContext::IsPermissionDenied()) { + return PERMISSION_DENIED_CODE; + } + + auto err = BaseContext::GetErrorCode(); + if (err == PARSE_ERROR_CODE) { + return PARSE_ERROR_CODE; + } + if (WEBSOCKET_ERR_MAP.find(err) != WEBSOCKET_ERR_MAP.end()) { + return err; + } + return WEBSOCKET_UNKNOWN_OTHER_ERROR; +} + +std::string ServerCloseContext::GetErrorMessage() const +{ + if (BaseContext::IsPermissionDenied()) { + return PERMISSION_DENIED_MSG; + } + + auto err = BaseContext::GetErrorCode(); + if (err == PARSE_ERROR_CODE) { + return PARSE_ERROR_MSG; + } + auto it = WEBSOCKET_ERR_MAP.find(err); + if (it != WEBSOCKET_ERR_MAP.end()) { + return it->second; + } + it = WEBSOCKET_ERR_MAP.find(WEBSOCKET_UNKNOWN_OTHER_ERROR); + if (it != WEBSOCKET_ERR_MAP.end()) { + return it->second; + } + return {}; +} +} // namespace OHOS::NetStack::Websocket \ No newline at end of file diff --git a/frameworks/js/napi/websocket/async_context/src/server_send_context.cpp b/frameworks/js/napi/websocket/async_context/src/server_send_context.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a8c50668b3f56dd6f54864c28f7cac7161c866cb --- /dev/null +++ b/frameworks/js/napi/websocket/async_context/src/server_send_context.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2025 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 "server_send_context.h" + +#include "constant.h" +#include "netstack_log.h" +#include "napi_utils.h" +#include "securec.h" + +static constexpr size_t MAX_LIMIT = 5 * 1024 * 1024; +namespace OHOS::NetStack::Websocket { +ServerSendContext::ServerSendContext(napi_env env, const std::shared_ptr &manager) + : BaseContext(env, manager), data(nullptr), length(0), protocol(LWS_WRITE_TEXT), connection() {} + +ServerSendContext::~ServerSendContext() = default; + +void ServerSendContext::ParseParams(napi_value *params, size_t paramsCount) +{ + if (!CheckParamsType(params, paramsCount)) { + NETSTACK_LOGE("SendContext Parse Failed"); + if (paramsCount == FUNCTION_PARAM_ONE) { + if (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_object) { + SetCallback(params[0]); + } + return; + } + + if (paramsCount == FUNCTION_PARAM_TWO) { + if (NapiUtils::GetValueType(GetEnv(), params[1]) == napi_object) { + SetCallback(params[1]); + } + return; + } + return; + } + + if (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string) { + if (!HandleParseString(params)) { + NETSTACK_LOGI("HandleParseString fail"); + return; + } + } else { + if (!HandleParseArrayBuffer(params)) { + NETSTACK_LOGI("HandleParseArrayBuffer fail"); + return; + } + } + + if (!HandleParseConnection(GetEnv(), params[1])) { + return; + } + NETSTACK_LOGD("SendContext SetParseOK"); + return SetParseOK(true); +} + +bool ServerSendContext::CheckParamsType(napi_value *params, size_t paramsCount) +{ + if (paramsCount == FUNCTION_PARAM_TWO) { + return (NapiUtils::GetValueType(GetEnv(), params[0]) == napi_string || + NapiUtils::ValueIsArrayBuffer(GetEnv(), params[0])) && + IsValidWebsocketConnection(GetEnv(), params[1]); + } + return false; +} + +bool ServerSendContext::IsValidWebsocketConnection(napi_env env, napi_value params) +{ + NETSTACK_LOGI("IsValidWebsocketConnection enter"); + if (NapiUtils::GetValueType(env, params) != napi_object) { + return false; + } + return (NapiUtils::GetValueType(env, NapiUtils::GetNamedProperty(env, params, + ContextKey::CLIENT_PORT)) == napi_number) && (NapiUtils::GetValueType(env, + NapiUtils::GetNamedProperty(env, params, ContextKey::CLIENT_IP)) == napi_string); +} + +bool ServerSendContext::HandleParseString(napi_value *params) +{ + NETSTACK_LOGI("Server SendContext data is String"); + std::string str = NapiUtils::GetStringFromValueUtf8(GetEnv(), params[0]); + // must have PRE and POST + size_t dataLen = LWS_SEND_BUFFER_PRE_PADDING + str.length() + LWS_SEND_BUFFER_POST_PADDING; + if (dataLen == 0 || dataLen > MAX_LIMIT) { + NETSTACK_LOGE("ServerSendContext data is exceeded the limit"); + return false; + } + data = malloc(dataLen); + if (data == nullptr) { + NETSTACK_LOGE("no memory"); + return false; + } + if (memcpy_s(reinterpret_cast(reinterpret_cast(data) + LWS_SEND_BUFFER_PRE_PADDING), + str.length(), str.c_str(), str.length()) < 0) { + NETSTACK_LOGE("copy failed"); + free(data); + return false; + } + length = str.length(); + protocol = LWS_WRITE_TEXT; + return true; +} + +bool ServerSendContext::HandleParseArrayBuffer(napi_value *params) +{ + NETSTACK_LOGI("ServerSendContext data is ArrayBuffer"); + size_t len = 0; + void *mem = NapiUtils::GetInfoFromArrayBufferValue(GetEnv(), params[0], &len); + if (mem == nullptr || len == 0) { + NETSTACK_LOGE("no memory"); + return false; + } + // must have PRE and POST + size_t dataLen = LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING; + if (dataLen == 0 || dataLen > MAX_LIMIT) { + NETSTACK_LOGE("ServerSendContext data is exceeded the limit"); + return false; + } + data = malloc(dataLen); + if (data == nullptr) { + NETSTACK_LOGE("no memory"); + return false; + } + if (memcpy_s(reinterpret_cast(reinterpret_cast(data) + LWS_SEND_BUFFER_PRE_PADDING), len, mem, + len) < 0) { + NETSTACK_LOGE("copy failed"); + free(data); + return false; + } + length = len; + protocol = LWS_WRITE_BINARY; + return true; +} + +bool ServerSendContext::HandleParseConnection(napi_env env, napi_value params) +{ + NETSTACK_LOGI("parse websocketconnection enter"); + if (NapiUtils::GetValueType(env, params) == napi_object) { + uint32_t port = NapiUtils::GetUint32Property(env, params, ContextKey::CLIENT_PORT); + if (port == 0) { + NETSTACK_LOGE("parse clientPort error"); + } + std::string ip = NapiUtils::GetStringPropertyUtf8(env, params, ContextKey::CLIENT_IP); + if (ip == "") { + NETSTACK_LOGE("parse clientIP error"); + } + SetClientWebSocketConn(port, ip); + return true; + } + return false; +} + +void ServerSendContext::SetClientWebSocketConn(uint32_t &port, std::string &ip) +{ + connection.clientPort = port; + connection.clientIP = ip; +} + +WebSocketConnection ServerSendContext::GetConnection() const +{ + return connection; +} + +int32_t ServerSendContext::GetErrorCode() const +{ + if (BaseContext::IsPermissionDenied()) { + return PERMISSION_DENIED_CODE; + } + + auto err = BaseContext::GetErrorCode(); + if (err == PARSE_ERROR_CODE) { + return PARSE_ERROR_CODE; + } + if (WEBSOCKET_ERR_MAP.find(err) != WEBSOCKET_ERR_MAP.end()) { + return err; + } + return WEBSOCKET_CONNECT_FAILED; +} + +std::string ServerSendContext::GetErrorMessage() const +{ + if (BaseContext::IsPermissionDenied()) { + return PERMISSION_DENIED_MSG; + } + + auto err = BaseContext::GetErrorCode(); + if (err == PARSE_ERROR_CODE) { + return PARSE_ERROR_MSG; + } + auto it = WEBSOCKET_ERR_MAP.find(err); + if (it != WEBSOCKET_ERR_MAP.end()) { + return it->second; + } + it = WEBSOCKET_ERR_MAP.find(WEBSOCKET_UNKNOWN_OTHER_ERROR); + if (it != WEBSOCKET_ERR_MAP.end()) { + return it->second; + } + return {}; +} +} // namespace OHOS::NetStack::Websocket \ No newline at end of file diff --git a/frameworks/js/napi/websocket/async_context/src/server_start_context.cpp b/frameworks/js/napi/websocket/async_context/src/server_start_context.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d22a4540872680fb95c684c1fe04fc7e15b70df5 --- /dev/null +++ b/frameworks/js/napi/websocket/async_context/src/server_start_context.cpp @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2025-2025 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 "server_start_context.h" +#include "constant.h" +#include "netstack_log.h" +#include "napi_utils.h" + +namespace OHOS::NetStack::Websocket { +ServerStartContext::ServerStartContext(napi_env env, const std::shared_ptr &sharedManager) + : BaseContext(env, sharedManager) {} + +ServerStartContext::~ServerStartContext() = default; + +void ServerStartContext::ParseParams(napi_value *params, size_t paramsCount) +{ + if (!CheckParamsType(params, paramsCount)) { + ParseCallback(params, paramsCount); + return; + } + + if (paramsCount != FUNCTION_PARAM_ONE) { + SetParseOK(SetCallback(params[0]) == napi_ok); + return; + } + + napi_env env = GetEnv(); + if (!ParseRequiredParams(env, params[0])) { + return; + } + ParseOptionalParams(env, params[0]); + SetParseOK(true); +} + +bool ServerStartContext::CheckParamsType(napi_value *params, size_t paramsCount) +{ + if (paramsCount == FUNCTION_PARAM_ZERO) { + return true; + } + + if (paramsCount == FUNCTION_PARAM_ONE) { + return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_object; + } + + return false; +} + +void ServerStartContext::ParseCallback(napi_value const *params, size_t paramsCount) +{ + if (paramsCount == FUNCTION_PARAM_ZERO) { + return; + } + if (paramsCount == FUNCTION_PARAM_ONE) { + if (NapiUtils::GetValueType(GetEnv(), params[FUNCTION_PARAM_ONE - 1]) == napi_object) { + SetCallback(params[FUNCTION_PARAM_ONE - 1]); + } + return; + } +} + +bool ServerStartContext::ParseRequiredParams(napi_env env, napi_value params) +{ + if (NapiUtils::GetValueType(env, params) != napi_object) { + NETSTACK_LOGE("js type error"); + return false; + } + uint32_t serverPort = NapiUtils::GetUint32Property(env, params, ContextKey::SERVER_PORT); + if (serverPort == 0) { + NETSTACK_LOGE("%{public}s not found", ContextKey::SERVER_PORT); + } + SetServerPort(serverPort); + uint32_t maxClientCnt = NapiUtils::GetUint32Property(env, params, ContextKey::MAX_CLIENT_NUMBER); + if (maxClientCnt == 0) { + NETSTACK_LOGE("max concurrent clients number is %{public}d", maxClientCnt); + } + SetMaxConcurrentClientsNumber(maxClientCnt); + uint32_t maxConn = NapiUtils::GetUint32Property(env, params, ContextKey::MAX_CONNECTIONS_FOR_ONE_CLIENT); + if (maxConn == 0) { + NETSTACK_LOGE("max connections for one clients:%{public}d", maxConn); + } + SetMaxConnectionsForOneClient(maxConn); + return true; +} + +void ServerStartContext::ParseOptionalParams(napi_env env, napi_value params) +{ + if (NapiUtils::GetValueType(env, params) != napi_object) { + NETSTACK_LOGE("js type error"); + return; + } + NETSTACK_LOGE("SERVER_IP:%{public}s", ContextKey::SERVER_IP); + std::string ip = NapiUtils::GetStringPropertyUtf8(env, params, ContextKey::SERVER_IP); + if (ip != "") { + SetServerIP(ip); + } else { + NETSTACK_LOGE("ip is null"); + std::string ipTmp = "0.0.0.0"; + SetServerIP(ipTmp); + } + std::string protocol = NapiUtils::GetStringPropertyUtf8(env, params, ContextKey::PROTOCOL); + if (protocol != "") { + SetServerProtocol(protocol); + } else { + NETSTACK_LOGE("protocol is null"); + std::string ipTmp = "lws_server"; + SetServerProtocol(ipTmp); + } + napi_value jsServerCert = NapiUtils::GetNamedProperty(env, params, ContextKey::SERVER_CERT); + if (NapiUtils::GetValueType(env, jsServerCert) != napi_object) { + NETSTACK_LOGE("jsServerCert type error"); + return; + } + ParseServerCert(env, jsServerCert); +} + +void ServerStartContext::ParseServerCert(napi_env env, napi_value params) +{ + if (NapiUtils::GetValueType(env, params) != napi_object) { + NETSTACK_LOGE("js type error"); + return; + } + std::string certPath = NapiUtils::GetStringPropertyUtf8(env, params, ContextKey::CERT_PATH); + std::string keyPath = NapiUtils::GetStringPropertyUtf8(env, params, ContextKey::KEY_PATH); + SetServerCert(certPath, keyPath); +} + +void ServerStartContext::SetServerIP(std::string &ip) +{ + serverIp_ = ip; +} + +void ServerStartContext::SetServerPort(uint32_t &serverPort) +{ + serverPort_ = serverPort; +} + +void ServerStartContext::SetServerCert(std::string &certPath, std::string &keyPath) +{ + certPath_ = certPath; + keyPath_ = keyPath; +} + +void ServerStartContext::SetMaxConcurrentClientsNumber(uint32_t &clientsNumber) +{ + maxClientsNumber_ = clientsNumber; +} + +void ServerStartContext::SetServerProtocol(std::string &protocol) +{ + websocketServerProtocol_ = protocol; +} + +void ServerStartContext::SetMaxConnectionsForOneClient(uint32_t &count) +{ + maxCountForOneClient_ = count; +} + +std::string ServerStartContext::GetServerIP() const +{ + return serverIp_; +} + +uint32_t ServerStartContext::GetServerPort() const +{ + return serverPort_; +} + +void ServerStartContext::GetServerCert(std::string &certPath, std::string &keyPath) const +{ + certPath = certPath_; + keyPath = keyPath_; +} + +uint32_t ServerStartContext::GetMaxConcurrentClientsNumber() const +{ + return maxClientsNumber_; +} + +std::string ServerStartContext::GetServerProtocol() const +{ + return websocketServerProtocol_; +} + +uint32_t ServerStartContext::GetMaxConnectionsForOneClient() const +{ + return maxCountForOneClient_; +} + +int32_t ServerStartContext::GetErrorCode() const +{ + if (BaseContext::IsPermissionDenied()) { + return PERMISSION_DENIED_CODE; + } + auto err = BaseContext::GetErrorCode(); + if (err == PARSE_ERROR_CODE) { + return PARSE_ERROR_CODE; + } + if (WEBSOCKET_ERR_MAP.find(err) != WEBSOCKET_ERR_MAP.end()) { + return err; + } + return WEBSOCKET_UNKNOWN_OTHER_ERROR; +} + +std::string ServerStartContext::GetErrorMessage() const +{ + if (BaseContext::IsPermissionDenied()) { + return PERMISSION_DENIED_MSG; + } + auto err = BaseContext::GetErrorCode(); + if (err == PARSE_ERROR_CODE) { + return PARSE_ERROR_MSG; + } + auto it = WEBSOCKET_ERR_MAP.find(err); + if (it != WEBSOCKET_ERR_MAP.end()) { + return it->second; + } + it = WEBSOCKET_ERR_MAP.find(WEBSOCKET_UNKNOWN_OTHER_ERROR); + if (it != WEBSOCKET_ERR_MAP.end()) { + return it->second; + } + return {}; +} +} // namespace OHOS::NetStack::Websocket \ No newline at end of file diff --git a/frameworks/js/napi/websocket/async_context/src/server_stop_context.cpp b/frameworks/js/napi/websocket/async_context/src/server_stop_context.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e820ecd417f02dbaee5b4ce5ff23e205bd2057aa --- /dev/null +++ b/frameworks/js/napi/websocket/async_context/src/server_stop_context.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2025 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 "server_stop_context.h" + +#include "constant.h" +#include "netstack_common_utils.h" +#include "netstack_log.h" +#include "napi_utils.h" + +namespace OHOS::NetStack::Websocket { +ServerStopContext::ServerStopContext(napi_env env, const std::shared_ptr &sharedManager) + : BaseContext(env, sharedManager) {} + +ServerStopContext::~ServerStopContext() = default; + +void ServerStopContext::ParseParams(napi_value *params, size_t paramsCount) +{ + if (!CheckParamsType(params, paramsCount)) { + return; + } + if (paramsCount != FUNCTION_PARAM_ZERO) { + SetParseOK(SetCallback(params[0]) == napi_ok); + return; + } + SetParseOK(true); +} + +bool ServerStopContext::CheckParamsType(napi_value *params, size_t paramsCount) +{ + if (paramsCount == FUNCTION_PARAM_ZERO) { + return true; + } + return false; +} + +int32_t ServerStopContext::GetErrorCode() const +{ + if (BaseContext::IsPermissionDenied()) { + return PERMISSION_DENIED_CODE; + } + return WEBSOCKET_UNKNOWN_OTHER_ERROR; +} + +std::string ServerStopContext::GetErrorMessage() const +{ + if (BaseContext::IsPermissionDenied()) { + return PERMISSION_DENIED_MSG; + } + auto it = WEBSOCKET_ERR_MAP.find(WEBSOCKET_UNKNOWN_OTHER_ERROR); + if (it != WEBSOCKET_ERR_MAP.end()) { + return it->second; + } + return {}; +} +} // namespace OHOS::NetStack::Websocket \ No newline at end of file diff --git a/frameworks/js/napi/websocket/async_work/include/websocket_async_work.h b/frameworks/js/napi/websocket/async_work/include/websocket_async_work.h index ad326dfc83cb87ec19efdb9d53f93dfb3eca2ccc..2b8d49ff5ad6a86ce903a680963e29048e7228d6 100644 --- a/frameworks/js/napi/websocket/async_work/include/websocket_async_work.h +++ b/frameworks/js/napi/websocket/async_work/include/websocket_async_work.h @@ -17,6 +17,9 @@ #define COMMUNICATIONNETSTACK_WEBSOCKET_ASYNC_WORK_H #include "websocket_exec.h" +#ifdef NETSTACK_WEBSOCKETSERVER +#include "websocket_server_exec.h" +#endif namespace OHOS::NetStack::Websocket { class WebSocketAsyncWork final { @@ -30,12 +33,36 @@ public: static void ExecClose(napi_env env, void *data); +#ifdef NETSTACK_WEBSOCKETSERVER + static void ExecServerStart(napi_env env, void *data); + + static void ExecListAllConnections(napi_env env, void *data); + + static void ExecServerClose(napi_env env, void *data); + + static void ExecServerSend(napi_env env, void *data); + + static void ExecServerStop(napi_env env, void *data); +#endif + /* callback */ static void ConnectCallback(napi_env env, napi_status status, void *data); static void SendCallback(napi_env env, napi_status status, void *data); static void CloseCallback(napi_env env, napi_status status, void *data); + +#ifdef NETSTACK_WEBSOCKETSERVER + static void ServerStartCallback(napi_env env, napi_status status, void *data); + + static void ListAllConnectionsCallback(napi_env env, napi_status status, void *data); + + static void ServerCloseCallback(napi_env env, napi_status status, void *data); + + static void ServerSendCallback(napi_env env, napi_status status, void *data); + + static void ServerStopCallback(napi_env env, napi_status status, void *data); +#endif }; } // namespace OHOS::NetStack::Websocket #endif /* COMMUNICATIONNETSTACK_WEBSOCKET_ASYNC_WORK_H */ diff --git a/frameworks/js/napi/websocket/async_work/src/websocket_async_work.cpp b/frameworks/js/napi/websocket/async_work/src/websocket_async_work.cpp index 07bfd9dd51a4c3f406b854b1557140c10335f62b..cf22f2c69ccaaaf42d096a01f67484ddae0b3b29 100644 --- a/frameworks/js/napi/websocket/async_work/src/websocket_async_work.cpp +++ b/frameworks/js/napi/websocket/async_work/src/websocket_async_work.cpp @@ -33,6 +33,33 @@ void WebSocketAsyncWork::ExecClose(napi_env env, void *data) BaseAsyncWork::ExecAsyncWork(env, data); } +#ifdef NETSTACK_WEBSOCKETSERVER +void WebSocketAsyncWork::ExecServerStart(napi_env env, void *data) +{ + BaseAsyncWork::ExecAsyncWork(env, data); +} + +void WebSocketAsyncWork::ExecListAllConnections(napi_env env, void *data) +{ + BaseAsyncWork::ExecAsyncWork(env, data); +} + +void WebSocketAsyncWork::ExecServerClose(napi_env env, void *data) +{ + BaseAsyncWork::ExecAsyncWork(env, data); +} + +void WebSocketAsyncWork::ExecServerSend(napi_env env, void *data) +{ + BaseAsyncWork::ExecAsyncWork(env, data); +} + +void WebSocketAsyncWork::ExecServerStop(napi_env env, void *data) +{ + BaseAsyncWork::ExecAsyncWork(env, data); +} +#endif + void WebSocketAsyncWork::ConnectCallback(napi_env env, napi_status status, void *data) { BaseAsyncWork::AsyncWorkCallback(env, status, data); @@ -47,4 +74,32 @@ void WebSocketAsyncWork::CloseCallback(napi_env env, napi_status status, void *d { BaseAsyncWork::AsyncWorkCallback(env, status, data); } + +#ifdef NETSTACK_WEBSOCKETSERVER +void WebSocketAsyncWork::ServerStartCallback(napi_env env, napi_status status, void *data) +{ + BaseAsyncWork::AsyncWorkCallback(env, status, data); +} + +void WebSocketAsyncWork::ListAllConnectionsCallback(napi_env env, napi_status status, void *data) +{ + BaseAsyncWork::AsyncWorkCallback(env, status, data); +} + +void WebSocketAsyncWork::ServerCloseCallback(napi_env env, napi_status status, void *data) +{ + BaseAsyncWork::AsyncWorkCallback(env, status, data); +} + +void WebSocketAsyncWork::ServerSendCallback(napi_env env, napi_status status, void *data) +{ + BaseAsyncWork::AsyncWorkCallback(env, status, data); +} + +void WebSocketAsyncWork::ServerStopCallback(napi_env env, napi_status status, void *data) +{ + BaseAsyncWork::AsyncWorkCallback(env, status, data); +} +#endif } // namespace OHOS::NetStack::Websocket diff --git a/frameworks/js/napi/websocket/constant/include/constant.h b/frameworks/js/napi/websocket/constant/include/constant.h index 9eb594058d3341cac66b5a97b5ecf79089a35c33..d6b6d5f2b0ddf7fd82339bc062321312f3139e62 100644 --- a/frameworks/js/napi/websocket/constant/include/constant.h +++ b/frameworks/js/napi/websocket/constant/include/constant.h @@ -33,6 +33,9 @@ enum WebsocketErrorCode { WEBSOCKET_ERROR_CODE_URL_ERROR = WEBSOCKET_ERROR_CODE_BASE + 1, WEBSOCKET_ERROR_CODE_FILE_NOT_EXIST = WEBSOCKET_ERROR_CODE_BASE + 2, WEBSOCKET_ERROR_CODE_CONNECT_AlREADY_EXIST = WEBSOCKET_ERROR_CODE_BASE + 3, + WEBSOCKET_ERROR_CODE_INVALID_NIC = WEBSOCKET_ERROR_CODE_BASE + 4, + WEBSOCKET_ERROR_CODE_INVALID_PORT = WEBSOCKET_ERROR_CODE_BASE + 5, + WEBSOCKET_ERROR_CODE_CONNECTION_NOT_EXIST = WEBSOCKET_ERROR_CODE_BASE + 6, WEBSOCKET_NOT_ALLOWED_HOST = 2302998, WEBSOCKET_UNKNOWN_OTHER_ERROR = 2302999 }; @@ -42,6 +45,9 @@ static const std::map WEBSOCKET_ERR_MAP = { {WEBSOCKET_ERROR_CODE_URL_ERROR, "Websocket url error"}, {WEBSOCKET_ERROR_CODE_FILE_NOT_EXIST, "Websocket file not exist"}, {WEBSOCKET_ERROR_CODE_CONNECT_AlREADY_EXIST, "Websocket connection exist"}, + {WEBSOCKET_ERROR_CODE_INVALID_NIC, "Can't listen to the given NIC"}, + {WEBSOCKET_ERROR_CODE_INVALID_PORT, "Can't listen to the given Port"}, + {WEBSOCKET_ERROR_CODE_CONNECTION_NOT_EXIST, "websocket connection does not exist"}, {WEBSOCKET_NOT_ALLOWED_HOST, "It is not allowed to access this domain"}, {WEBSOCKET_UNKNOWN_OTHER_ERROR, "Websocket Unknown Other Error"}}; @@ -92,6 +98,17 @@ public: static const char *CODE; static const char *REASON; +/* WebSocketConnection */ + static const char *CLIENT_PORT; + static const char *CLIENT_IP; + +/* WebSocketServerConfig */ + static const char *SERVER_PORT; + static const char *MAX_CLIENT_NUMBER; + static const char *MAX_CONNECTIONS_FOR_ONE_CLIENT; + static const char *SERVER_IP; + static const char *SERVER_CERT; + static const char *PROTOCOL; }; class EventName final { @@ -102,6 +119,12 @@ public: static const char *EVENT_ERROR; static const char *EVENT_DATA_END; static const char *EVENT_HEADER_RECEIVE; + +/* websocketServer */ + static const char *EVENT_SERVER_ERROR; + static const char *EVENT_SERVER_CONNECT; + static const char *EVENT_SERVER_MESSAGE_RECEIVE; + static const char *EVENT_SERVER_CLOSE; }; } // namespace OHOS::NetStack::Websocket #endif /* COMMUNICATIONNETSTACK_CONSTANT_H */ diff --git a/frameworks/js/napi/websocket/constant/src/constant.cpp b/frameworks/js/napi/websocket/constant/src/constant.cpp index 9b6db629f29b378a57a34aa297ffa36aa27b71ab..d7605f8ca8b81641bb1dcbaaf8a3af5dc4df695f 100644 --- a/frameworks/js/napi/websocket/constant/src/constant.cpp +++ b/frameworks/js/napi/websocket/constant/src/constant.cpp @@ -23,6 +23,17 @@ const char *ContextKey::CLIENT_CERT = "clientCert"; const char *ContextKey::CERT_PATH = "certPath"; const char *ContextKey::KEY_PATH = "keyPath"; const char *ContextKey::KEY_PASSWD = "keyPassword"; +/* WebSocketConnection */ +const char *ContextKey::CLIENT_PORT = "clientPort"; +const char *ContextKey::CLIENT_IP = "clientIP"; + +/* WebSocketServerConfig */ +const char *ContextKey::SERVER_PORT = "serverPort"; +const char *ContextKey::MAX_CLIENT_NUMBER = "maxConcurrentClientsNumber"; +const char *ContextKey::MAX_CONNECTIONS_FOR_ONE_CLIENT = "maxConnectionsForOneClient"; +const char *ContextKey::SERVER_IP = "serverIP"; +const char *ContextKey::SERVER_CERT = "serverCert"; +const char *ContextKey::PROTOCOL = "protocol"; const char *ContextKey::PROXY = "proxy"; const char *ContextKey::PROTCOL = "protocol"; @@ -43,4 +54,9 @@ const char *EventName::EVENT_CLOSE = "close"; const char *EventName::EVENT_ERROR = "error"; const char *EventName::EVENT_DATA_END = "dataEnd"; const char *EventName::EVENT_HEADER_RECEIVE = "headerReceive"; +/* websocketServer */ +const char *EventName::EVENT_SERVER_ERROR = "error"; +const char *EventName::EVENT_SERVER_CONNECT = "connect"; +const char *EventName::EVENT_SERVER_MESSAGE_RECEIVE = "messageReceive"; +const char *EventName::EVENT_SERVER_CLOSE = "close"; } // namespace OHOS::NetStack::Websocket \ No newline at end of file diff --git a/frameworks/js/napi/websocket/websocket_exec/include/websocket_exec.h b/frameworks/js/napi/websocket/websocket_exec/include/websocket_exec.h index 2340bcf398aa3342c4595eabc99c33ff4a5a6c97..270a189574a843d24c4aa2052d16f6ba45331c10 100644 --- a/frameworks/js/napi/websocket/websocket_exec/include/websocket_exec.h +++ b/frameworks/js/napi/websocket/websocket_exec/include/websocket_exec.h @@ -21,6 +21,7 @@ #include "send_context.h" namespace OHOS::NetStack::Websocket { + class WebSocketExec final { public: static bool CreatConnectInfo(ConnectContext *context, lws_context *lwsContext, diff --git a/frameworks/js/napi/websocket/websocket_exec/include/websocket_exec_common.h b/frameworks/js/napi/websocket/websocket_exec/include/websocket_exec_common.h new file mode 100644 index 0000000000000000000000000000000000000000..315a31ae3a0cef520c760405dd40db7885c97235 --- /dev/null +++ b/frameworks/js/napi/websocket/websocket_exec/include/websocket_exec_common.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2025 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 COMMUNICATIONNETSTACK_WEBSOCKET_EXEC_COMMON_H +#define COMMUNICATIONNETSTACK_WEBSOCKET_EXEC_COMMON_H + +#include +#include +#include +#include "libwebsockets.h" +#include "netstack_log.h" + +namespace OHOS::NetStack::Websocket { +struct WebSocketConnection { + std::string clientIP; + uint32_t clientPort; +}; + +class UserData { +public: + struct SendData { + SendData(void *paraData, size_t paraLength, lws_write_protocol paraProtocol) + : data(paraData), length(paraLength), protocol(paraProtocol) + { + } + + SendData() = delete; + + ~SendData() = default; + + void *data; + size_t length; + lws_write_protocol protocol; + }; + + explicit UserData(lws_context *context) + : closeStatus(LWS_CLOSE_STATUS_NOSTATUS), openStatus(0), closed_(false), threadStop_(false), context_(context) + { + } + + bool IsClosed() + { + std::lock_guard lock(mutex_); + return closed_; + } + + bool IsThreadStop() + { + return threadStop_.load(); + } + + void SetThreadStop(bool threadStop) + { + threadStop_.store(threadStop); + } + + void Close(lws_close_status status, const std::string &reason) + { + std::lock_guard lock(mutex_); + closeStatus = status; + closeReason = reason; + closed_ = true; + } + + void Push(void *data, size_t length, lws_write_protocol protocol) + { + std::lock_guard lock(mutex_); + dataQueue_.emplace(data, length, protocol); + } + + SendData Pop() + { + std::lock_guard lock(mutex_); + if (dataQueue_.empty()) { + return {nullptr, 0, LWS_WRITE_TEXT}; + } + SendData data = dataQueue_.front(); + dataQueue_.pop(); + return data; + } + + void SetContext(lws_context *context) + { + context_ = context; + } + + lws_context *GetContext() + { + return context_; + } + + bool IsEmpty() + { + std::lock_guard lock(mutex_); + if (dataQueue_.empty()) { + return true; + } + return false; + } + + void SetLws(lws *wsi) + { + std::lock_guard lock(mutexForLws_); + if (wsi == nullptr) { + NETSTACK_LOGD("set wsi nullptr"); + } + wsi_ = wsi; + } + + void TriggerWritable() + { + std::lock_guard lock(mutexForLws_); + if (wsi_ == nullptr) { + NETSTACK_LOGE("wsi is nullptr, can not trigger"); + return; + } + lws_callback_on_writable(wsi_); + } + + std::map header; + + lws_close_status closeStatus; + + std::string closeReason; + + uint32_t openStatus; + + std::string openMessage; + +private: + volatile bool closed_; + + std::atomic_bool threadStop_; + + std::mutex mutex_; + + std::mutex mutexForLws_; + + lws_context *context_; + + std::queue dataQueue_; + + lws *wsi_ = nullptr; +}; +} // namespace OHOS::NetStack::Websocket +#endif \ No newline at end of file diff --git a/frameworks/js/napi/websocket/websocket_exec/include/websocket_server_exec.h b/frameworks/js/napi/websocket/websocket_exec/include/websocket_server_exec.h new file mode 100644 index 0000000000000000000000000000000000000000..ba1beac79873be074192b1147d98b7ffafedfc6a --- /dev/null +++ b/frameworks/js/napi/websocket/websocket_exec/include/websocket_server_exec.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2025 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 COMMUNICATIONNETSTACK_WEBSOCKET_SERVER_EXEC_H +#define COMMUNICATIONNETSTACK_WEBSOCKET_SERVER_EXEC_H + +#include "server_start_context.h" +#include "list_all_connections_context.h" +#include "server_send_context.h" +#include "server_close_context.h" +#include "server_stop_context.h" + +namespace OHOS::NetStack::Websocket { + +struct ClientInfo { + int32_t cnt; + uint64_t lastConnectionTime; +}; + +struct WebSocketMessage { + std::string data; + WebSocketConnection connection; +}; + +class WebSocketServerExec final { +public: + /* async work execute */ + static bool ExecServerStart(ServerStartContext *context); + + static bool ExecListAllConnections(ListAllConnectionsContext *context); + + static bool ExecServerClose(ServerCloseContext *context); + + static bool ExecServerSend(ServerSendContext *context); + + static bool ExecServerStop(ServerStopContext *context); + + static int lwsServerCallback(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + /* async work callback */ + static napi_value ServerStartCallback(ServerStartContext *context); + + static napi_value ListAllConnectionsCallback(ListAllConnectionsContext *context); + + static napi_value ServerCloseCallback(ServerCloseContext *context); + + static napi_value ServerSendCallback(ServerSendContext *context); + + static napi_value ServerStopCallback(ServerStopContext *context); + +private: + static int HttpDummy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static int RaiseServerError(EventManager *manager); + + static int LwsCallbackEstablished(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static int LwsCallbackFilterProtocolConnection(lws *wsi, lws_callback_reasons reason, + void *user, void *in, size_t len); + + static int LwsCallbackReceive(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static int LwsCallbackServerWriteable(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static int LwsCallbackWsPeerInitiatedCloseServer(lws *wsi, lws_callback_reasons reason, + void *user, void *in, size_t len); + + static int LwsCallbackClosed(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static int LwsCallbackWsiDestroyServer(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); + + static int LwsCallbackProtocolDestroyServer(lws *wsi, lws_callback_reasons reason, + void *user, void *in, size_t len); + + static void OnConnect(lws *wsi, EventManager *manager); + + static void OnServerClose(lws *wsi, EventManager *manager, lws_close_status closeStatus, + const std::string &closeReason); + + static void OnServerMessage(lws *wsi, EventManager *manager, void *data, size_t length, + bool isBinary, bool isFinal); + + static void OnServerError(EventManager *manager, int32_t code); + + static void HandleServerRcvMessage(lws *wsi, EventManager *manager, void *data, + size_t length, bool isBinary, bool isFinal); + + static void SetWebsocketMessage(lws *wsi, EventManager *manager, const std::string &msg, void *dataMsg); + + static bool IsOverMaxClientConns(EventManager *manager, const std::string ip); + + static bool IsOverMaxConcurrentClientsCnt(EventManager *manager, const std::vector connections, + const std::string ip); + + static bool IsOverMaxCntForOneClient(EventManager *manager, const std::vector connections, + const std::string ip); + + static bool IsAllowConnection(const std::string &clientId); + + static bool IsIpInBanList(const std::string &id); + + static bool IsHighFreqConnection(const std::string &id); + + static void AddBanList(const std::string &id); + + static void UpdataClientList(const std::string &id); + + static lws *GetClientWsi(const std::string clientId); + + static uint64_t GetCurrentSecond(); + + static void CloseAllConnection(const std::shared_ptr &userData); + + static void FillServerContextInfo(ServerStartContext *context, std::shared_ptr &manager, + lws_context_creation_info &info); + + static bool FillServerCertPath(ServerStartContext *context, lws_context_creation_info &info); + + static void StartService(lws_context_creation_info &info, std::shared_ptr &manager); + + static void AddConnections(const std::string &Id, lws *wsi, std::shared_ptr &userData, + WebSocketConnection &conn); + + static void RemoveConnections(const std::string &Id, UserData &userData); + + static bool GetPeerConnMsg(lws *wsi, EventManager *manager, std::string &clientId, WebSocketConnection &conn); + + static std::vector GetConnections(); +}; +} // namespace OHOS::NetStack::Websocket +#endif /* COMMUNICATIONNETSTACK_WEBSOCKET_EXEC_H */ \ No newline at end of file diff --git a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp index d3e6838249591195a6b03a5324c7cbb26a765b3b..8fb4bdc4891614984c3f2711e0d381bf69a73569 100644 --- a/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp +++ b/frameworks/js/napi/websocket/websocket_exec/src/websocket_exec.cpp @@ -26,12 +26,13 @@ #include "netstack_common_utils.h" #include "netstack_log.h" #include "securec.h" - +#include "websocket_exec_common.h" #ifdef HAS_NETMANAGER_BASE #include "http_proxy.h" #include "net_conn_client.h" #endif + static constexpr const char *PROTOCOL_DELIMITER = "//"; static constexpr const char *NAME_END = ":"; @@ -77,6 +78,7 @@ static constexpr const char *WEBSOCKET_SYSTEM_PREPARE_CA_PATH = "/etc/security/c static constexpr const char *WEBSOCKET_CLIENT_THREAD_RUN = "OS_NET_WSJsCli"; namespace OHOS::NetStack::Websocket { + static const lws_protocols LWS_PROTOCOLS[] = { {"lws-minimal-client", WebSocketExec::LwsCallback, 0, 0}, {nullptr, nullptr, 0, 0}, // this line is needed @@ -101,133 +103,6 @@ struct OnOpenClosePara { static const std::vector WS_PREFIX = {PREFIX_WSS, PREFIX_WS}; -class UserData { -public: - struct SendData { - SendData(void *paraData, size_t paraLength, lws_write_protocol paraProtocol) - : data(paraData), length(paraLength), protocol(paraProtocol) - { - } - - SendData() = delete; - - ~SendData() = default; - - void *data; - size_t length; - lws_write_protocol protocol; - }; - - explicit UserData(lws_context *context) - : closeStatus(LWS_CLOSE_STATUS_NOSTATUS), openStatus(0), closed_(false), threadStop_(false), context_(context) - { - } - - bool IsClosed() - { - std::lock_guard lock(mutex_); - return closed_; - } - - bool IsThreadStop() - { - return threadStop_.load(); - } - - void SetThreadStop(bool threadStop) - { - threadStop_.store(threadStop); - } - - void Close(lws_close_status status, const std::string &reason) - { - std::lock_guard lock(mutex_); - closeStatus = status; - closeReason = reason; - closed_ = true; - } - - void Push(void *data, size_t length, lws_write_protocol protocol) - { - std::lock_guard lock(mutex_); - dataQueue_.emplace(data, length, protocol); - } - - SendData Pop() - { - std::lock_guard lock(mutex_); - if (dataQueue_.empty()) { - return {nullptr, 0, LWS_WRITE_TEXT}; - } - SendData data = dataQueue_.front(); - dataQueue_.pop(); - return data; - } - - void SetContext(lws_context *context) - { - context_ = context; - } - - lws_context *GetContext() - { - return context_; - } - - bool IsEmpty() - { - std::lock_guard lock(mutex_); - if (dataQueue_.empty()) { - return true; - } - return false; - } - - void SetLws(lws *wsi) - { - std::lock_guard lock(mutexForLws_); - if (wsi == nullptr) { - NETSTACK_LOGD("set wsi nullptr"); - } - wsi_ = wsi; - } - - void TriggerWritable() - { - std::lock_guard lock(mutexForLws_); - if (wsi_ == nullptr) { - NETSTACK_LOGE("wsi is nullptr, can not trigger"); - return; - } - lws_callback_on_writable(wsi_); - } - - std::map header; - - lws_close_status closeStatus; - - std::string closeReason; - - uint32_t openStatus; - - std::string openMessage; - -private: - volatile bool closed_; - - std::atomic_bool threadStop_; - - std::mutex mutex_; - - std::mutex mutexForLws_; - - lws_context *context_; - - std::queue dataQueue_; - - lws *wsi_ = nullptr; -}; - template static void CallbackTemplate(uv_work_t *work, int status) { (void)status; @@ -294,6 +169,7 @@ void RunService(std::shared_ptr userData, std::shared_ptr= 0 && !userData->IsThreadStop()) { res = lws_service(context, 0); } + NETSTACK_LOGE("lws_service stop"); lws_context_destroy(context); userData->SetContext(nullptr); manager->SetWebSocketUserData(nullptr); @@ -446,7 +322,6 @@ void OnConnectError(EventManager *manager, int32_t code, uint32_t httpResponse) int WebSocketExec::LwsCallbackClientConnectionError(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len) { - NETSTACK_LOGD("lws callback client connection error"); NETSTACK_LOGI("Lws client connection error %{public}s", (in == nullptr) ? "null" : reinterpret_cast(in)); // 200 means connect failed OnConnectError(reinterpret_cast(user), COMMON_ERROR_CODE, GetHttpResponseFromWsi(wsi)); @@ -595,13 +470,11 @@ int WebSocketExec::LwsCallback(lws *wsi, lws_callback_reasons reason, void *user {LWS_CALLBACK_PROTOCOL_DESTROY, LwsCallbackProtocolDestroy}, {LWS_CALLBACK_VHOST_CERT_AGING, LwsCallbackVhostCertAging}, }; - for (const auto dispatcher : dispatchers) { if (dispatcher.reason == reason) { return dispatcher.callback(wsi, reason, user, in, len); } } - return HttpDummy(wsi, reason, user, in, len); } @@ -661,7 +534,7 @@ bool WebSocketExec::CreatConnectInfo(ConnectContext *context, lws_context *lwsCo } std::string tempHost = std::string(address) + NAME_END + std::to_string(port); std::string tempOrigin = std::string(protocol) + NAME_END + PROTOCOL_DELIMITER + tempHost; - NETSTACK_LOGD("tempOrigin = %{private}s", tempOrigin.c_str()); + NETSTACK_LOGD("tempHost: %{private}s, Origin = %{private}s", tempHost.c_str(), tempOrigin.c_str()); if (strcpy_s(customizedProtocol, context->GetProtocol().length() + 1, context->GetProtocol().c_str()) != EOK) { NETSTACK_LOGE("memory copy failed"); } @@ -670,7 +543,7 @@ bool WebSocketExec::CreatConnectInfo(ConnectContext *context, lws_context *lwsCo connectInfo.port = port; connectInfo.address = address; connectInfo.path = path; - connectInfo.host = address; + connectInfo.host = tempHost.c_str(); connectInfo.origin = address; connectInfo.protocol = customizedProtocol; @@ -1052,7 +925,10 @@ void WebSocketExec::HandleRcvMessage(EventManager *manager, void *data, size_t l manager->AppendWebSocketBinaryData(data, length); if (isFinal) { const std::string &msgFromManager = manager->GetWebSocketBinaryData(); - auto msg = new std::string; + auto msg = new (std::nothrow) std::string; + if (msg == nullptr) { + return; + } msg->append(msgFromManager.data(), msgFromManager.size()); manager->SetQueueData(msg); manager->EmitByUvWithoutCheckShared(EventName::EVENT_MESSAGE, manager, diff --git a/frameworks/js/napi/websocket/websocket_exec/src/websocket_server_exec.cpp b/frameworks/js/napi/websocket/websocket_exec/src/websocket_server_exec.cpp new file mode 100644 index 0000000000000000000000000000000000000000..83b92b22ac08093ce67884218f432234c4398dfd --- /dev/null +++ b/frameworks/js/napi/websocket/websocket_exec/src/websocket_server_exec.cpp @@ -0,0 +1,1312 @@ +/* + * Copyright (c) 2022-2024 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_server_exec.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "constant.h" +#include "napi_utils.h" +#include "netstack_common_utils.h" +#include "netstack_log.h" +#include "securec.h" +#define LWS_PLUGIN_STATIC + +static constexpr const char *EVENT_KEY_CLIENT_PORT = "clientPort"; + +static constexpr const char *EVENT_KEY_CLIENT_IP = "clientIP"; + +static constexpr const char *EVENT_KEY_CONNECTION = "clientConnection"; + +static constexpr const char *EVENT_KEY_RESULT = "result"; + +static constexpr const char *EVENT_KEY_DATA = "data"; + +static constexpr const char *EVENT_KEY_CODE = "code"; + +static constexpr const char *EVENT_KEY_REASON = "reason"; + +static constexpr const char *WEBSOCKET_SERVER_THREAD_RUN = "OS_NET_WSJsSer"; + +static constexpr const char *LINK_DOWN = "The link is down"; + +static constexpr const uint32_t MAX_CONCURRENT_CLIENTS_NUMBER = 10; + +static constexpr const uint32_t MAX_CONNECTIONS_FOR_ONE_CLIENT = 10; + +static constexpr const uint64_t ONE_MINUTE_IN_SEC = 60; + +static constexpr const int32_t MAX_CONNECTIONS_PER_MINUTE = 50; + +static constexpr const int32_t COMMON_ERROR_CODE = 200; + +namespace OHOS::NetStack::Websocket { + +static std::shared_mutex wsMutex_; + +static std::shared_mutex connListMutex_; + +static std::shared_mutex banListMutex_; + +static std::unordered_map banList; + +static std::unordered_map clientList; + +static std::unordered_map> webSocketConnection_; + +static const lws_protocols LWS_SERVER_PROTOCOLS[] = { + {"lws_server", WebSocketServerExec::lwsServerCallback, 0, 0}, + {NULL, NULL, 0, 0}, // this line is needed +}; + +struct CloseResult { + uint32_t code; + std::string reason; +}; + +struct ClientConnectionCloseCallback { + WebSocketConnection connection; + CloseResult closeResult; +}; + +struct CallbackDispatcher { + lws_callback_reasons reason; + int (*callback)(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len); +}; + +static const lws_http_mount mount = { + NULL, + "/", + "./mount-origin", + "index.html", + NULL, + NULL, + NULL, + NULL, + 0, + 0, + 0, + 0, + 0, + 0, + LWSMPRO_FILE, + 1, + NULL, +}; + +template static void CallbackTemplate(uv_work_t *work, int status) +{ + (void)status; + + auto workWrapper = static_cast(work->data); + napi_env env = workWrapper->env; + auto closeScope = [env](napi_handle_scope scope) { NapiUtils::CloseScope(env, scope); }; + std::unique_ptr scope(NapiUtils::OpenScope(env), closeScope); + + napi_value obj = MakeJsValue(env, workWrapper->data); + auto undefined = NapiUtils::GetUndefined(workWrapper->env); + std::pair arg = {undefined, obj}; + if (workWrapper->manager) { + workWrapper->manager->Emit(workWrapper->type, arg); + if (workWrapper->type == EventName::EVENT_MESSAGE && + workWrapper->manager->HasEventListener(EventName::EVENT_DATA_END)) { + workWrapper->manager->Emit(EventName::EVENT_DATA_END, {undefined, undefined}); + } + } + delete workWrapper; + delete work; +} + + +void RunServerService(std::shared_ptr userData, std::shared_ptr manager) +{ + NETSTACK_LOGI("websocket run service start"); + int res = 0; + lws_context *context = userData->GetContext(); + if (context == nullptr) { + NETSTACK_LOGE("context is null"); + return; + } + while (res >= 0 && !userData->IsThreadStop()) { + res = lws_service(context, 0); + } + NETSTACK_LOGE("lws_service stop"); + lws_context_destroy(context); + userData->SetContext(nullptr); + manager->SetWebSocketUserData(nullptr); + NETSTACK_LOGI("websocket run service end"); +} + +int WebSocketServerExec::RaiseServerError(EventManager *manager) +{ + OnServerError(manager, COMMON_ERROR_CODE); + return -1; +} + +int WebSocketServerExec::HttpDummy(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len) +{ + int ret = lws_callback_http_dummy(wsi, reason, user, in, len); + if (ret < 0) { + OnServerError(reinterpret_cast(user), COMMON_ERROR_CODE); + } + return 0; +} + +int WebSocketServerExec::lwsServerCallback(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len) +{ + NETSTACK_LOGI("lws server callback reason is %{public}d", reason); + CallbackDispatcher dispatchers[] = { + {LWS_CALLBACK_ESTABLISHED, LwsCallbackEstablished}, + {LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION, LwsCallbackFilterProtocolConnection}, + {LWS_CALLBACK_RECEIVE, LwsCallbackReceive}, + {LWS_CALLBACK_SERVER_WRITEABLE, LwsCallbackServerWriteable}, + {LWS_CALLBACK_WS_PEER_INITIATED_CLOSE, LwsCallbackWsPeerInitiatedCloseServer}, + {LWS_CALLBACK_CLOSED, LwsCallbackClosed}, + {LWS_CALLBACK_WSI_DESTROY, LwsCallbackWsiDestroyServer}, + {LWS_CALLBACK_PROTOCOL_DESTROY, LwsCallbackProtocolDestroyServer}, + }; + for (const auto dispatcher : dispatchers) { + if (dispatcher.reason == reason) { + return dispatcher.callback(wsi, reason, user, in, len); + } + } + return HttpDummy(wsi, reason, user, in, len); +} + +int WebSocketServerExec::LwsCallbackEstablished(lws *wsi, lws_callback_reasons reason, void *user, void *in, + size_t len) +{ + NETSTACK_LOGD("lws callback server established"); + lws_context *context = lws_get_context(wsi); + EventManager *manager = static_cast(lws_context_user(context)); + if (manager == nullptr) { + NETSTACK_LOGE("manager is null"); + return RaiseServerError(manager); + } + auto userData = manager->GetWebSocketUserData(); + if (userData == nullptr) { + NETSTACK_LOGE("user data is null"); + return RaiseServerError(manager); + } + // bind clientuserdata with wsi + lws_context *lwsContext = lws_get_context(wsi); + auto clientUserData = std::make_shared(lwsContext); + lws_set_wsi_user(wsi, clientUserData.get()); + manager->AddClientUserData(wsi, clientUserData); + + std::string clientId; + WebSocketConnection connection; + bool ret = GetPeerConnMsg(wsi, manager, clientId, connection); + if (!ret) { + NETSTACK_LOGE("GetPeerConnMsg failed"); + return RaiseServerError(manager); + } + NETSTACK_LOGI("connection clientip=%{public}s, clientport=%{public}d", + connection.clientIP.c_str(), connection.clientPort); + AddConnections(clientId, wsi, userData, connection); + clientUserData->SetLws(wsi); + clientUserData->TriggerWritable(); + OnConnect(wsi, manager); + return HttpDummy(wsi, reason, user, in, len); +} + +bool WebSocketServerExec::GetPeerConnMsg(lws *wsi, EventManager *manager, std::string &clientId, + WebSocketConnection &conn) +{ + struct sockaddr_storage addr{}; + socklen_t addrLen = sizeof(addr); + int ret = getpeername(lws_get_socket_fd(wsi), reinterpret_cast(&addr), &addrLen); + if (ret != 0) { + NETSTACK_LOGE("getpeername failed"); + return false; + } + char ipStr[INET6_ADDRSTRLEN] = {0}; + if (addr.ss_family == AF_INET) { + NETSTACK_LOGI("family is ipv4"); + auto *addrIn = reinterpret_cast(&addr); + inet_ntop(AF_INET, &addrIn->sin_addr, ipStr, sizeof(ipStr)); + uint16_t port = ntohs(addrIn->sin_port); + conn.clientPort = static_cast(port); + conn.clientIP = ipStr; + clientId = std::string(ipStr) + ":" + std::to_string(port); + } else if (addr.ss_family == AF_INET6) { + NETSTACK_LOGI("family is ipv6"); + auto *addrIn6 = reinterpret_cast(&addr); + inet_ntop(AF_INET6, &addrIn6->sin6_addr, ipStr, sizeof(ipStr)); + uint16_t port = ntohs(addrIn6->sin6_port); + conn.clientPort = static_cast(port); + conn.clientIP = ipStr; + clientId = std::string(ipStr) + ":" + std::to_string(port); + } else { + NETSTACK_LOGE("getpeer Ipv4 or Ipv6 failed"); + return false; + } + return true; +} + +bool WebSocketServerExec::IsOverMaxClientConns(EventManager *manager, const std::string ip) +{ + std::vector connections = GetConnections(); + if (IsOverMaxConcurrentClientsCnt(manager, connections, ip)) { + NETSTACK_LOGI("current client connections is over max concurrent number"); + return true; + } + if (IsOverMaxCntForOneClient(manager, connections, ip)) { + NETSTACK_LOGI("current connections for one client is over max number"); + return true; + } + return false; +} + +void WebSocketServerExec::AddConnections(const std::string &id, lws *wsi, + std::shared_ptr &userData, WebSocketConnection &conn) +{ + if (userData->IsClosed() || userData->IsThreadStop()) { + NETSTACK_LOGE("AddConnections failed: session %s", userData->IsClosed() ? "closed" : "thread stopped"); + return; + } + { + std::unique_lock lock(wsMutex_); + webSocketConnection_[id].first = wsi; + webSocketConnection_[id].second = conn; + NETSTACK_LOGI("AddConnections success"); + } +} + +bool WebSocketServerExec::IsOverMaxConcurrentClientsCnt(EventManager *manager, + const std::vector connections, const std::string ip) +{ + std::unordered_set uniqueIp; + for (const auto &conn : connections) { + uniqueIp.insert(conn.clientIP); + } + if (uniqueIp.find(ip) != uniqueIp.end()) { + return uniqueIp.size() > manager->GetMaxConcurrentClientCnt(); + } else { + return (uniqueIp.size() + 1) > manager->GetMaxConcurrentClientCnt(); + } +} + +bool WebSocketServerExec::IsOverMaxCntForOneClient(EventManager *manager, + const std::vector connections, const std::string ip) +{ + uint32_t cnt = 0; + for (auto it = connections.begin(); it != connections.end(); ++it) { + if (ip == it->clientIP) { + ++cnt; + } + } + if (cnt + 1 > manager->GetMaxConnForOneClient()) { + return true; + } + return false; +} + +int WebSocketServerExec::LwsCallbackClosed(lws *wsi, lws_callback_reasons reason, void *user, void *in, size_t len) +{ + NETSTACK_LOGD("lws callback server closed"); + if (wsi == nullptr) { + NETSTACK_LOGE("wsi is null"); + return -1; + } + lws_context *context = lws_get_context(wsi); + EventManager *manager = static_cast(lws_context_user(context)); + if (manager == nullptr) { + NETSTACK_LOGE("manager is null"); + return RaiseServerError(manager); + } + auto userData = manager->GetWebSocketUserData(); + if (userData == nullptr) { + NETSTACK_LOGE("user data is null"); + return RaiseServerError(manager); + } + auto clientUserData = reinterpret_cast(lws_wsi_user(wsi)); + if (clientUserData == nullptr) { + NETSTACK_LOGE("clientUserData is null"); + return RaiseServerError(manager); + } + clientUserData->SetThreadStop(true); + if ((clientUserData->closeReason).empty()) { + clientUserData->Close(clientUserData->closeStatus, LINK_DOWN); + } + if (clientUserData->closeStatus == LWS_CLOSE_STATUS_NOSTATUS) { + NETSTACK_LOGE("The link is down, onError"); + OnServerError(manager, COMMON_ERROR_CODE); + } + std::string clientId; + { + std::shared_lock lock(wsMutex_); + for (auto it = webSocketConnection_.begin(); it != webSocketConnection_.end(); ++it) { + if (it->second.first == wsi) { + clientId = it->first; + } + } + } + OnServerClose(wsi, manager, clientUserData->closeStatus, clientUserData->closeReason); + RemoveConnections(clientId, *clientUserData); + manager->RemoveClientUserData(wsi); + lws_set_wsi_user(wsi, nullptr); + + if (userData->IsClosed() && !userData->IsThreadStop()) { + NETSTACK_LOGI("server service is stopped"); + userData->SetThreadStop(true); + } + return HttpDummy(wsi, reason, user, in, len); +} + +void WebSocketServerExec::RemoveConnections(const std::string &id, UserData &userData) +{ + if (webSocketConnection_.empty()) { + NETSTACK_LOGE("connection list is empty"); + return; + } + { + std::unique_lock lock(wsMutex_); + if (webSocketConnection_.find(id) == webSocketConnection_.end()) { + NETSTACK_LOGE("connection list find clientId failed"); + return; + } + webSocketConnection_.erase(id); + NETSTACK_LOGI("connection erase success"); + } +} + +int WebSocketServerExec::LwsCallbackWsiDestroyServer(lws *wsi, lws_callback_reasons reason, void *user, void *in, + size_t len) +{ + NETSTACK_LOGD("lws server callback wsi destroy"); + if (wsi == nullptr) { + NETSTACK_LOGE("wsi is null"); + return -1; + } + lws_context *context = lws_get_context(wsi); + EventManager *manager = static_cast(lws_context_user(context)); + if (manager == nullptr) { + NETSTACK_LOGE("manager is null"); + return RaiseServerError(manager); + } + auto userData = manager->GetWebSocketUserData(); + if (userData == nullptr) { + NETSTACK_LOGE("user data is null"); + return RaiseServerError(manager); + } + userData->SetLws(nullptr); + return HttpDummy(wsi, reason, user, in, len); +} + +int WebSocketServerExec::LwsCallbackProtocolDestroyServer(lws *wsi, lws_callback_reasons reason, void *user, void *in, + size_t len) +{ + NETSTACK_LOGD("lws server callback protocol destroy"); + return HttpDummy(wsi, reason, user, in, len); +} + +int WebSocketServerExec::LwsCallbackServerWriteable(lws *wsi, lws_callback_reasons reason, void *user, void *in, + size_t len) +{ + NETSTACK_LOGD("lws callback Server writable"); + lws_context *context = lws_get_context(wsi); + EventManager *manager = static_cast(lws_context_user(context)); + if (manager == nullptr || manager->innerMagic_.magicNumber != EVENT_MANAGER_MAGIC_NUMBER) { + NETSTACK_LOGE("manager is null"); + return RaiseServerError(manager); + } + // server + auto userData = manager->GetWebSocketUserData(); + if (userData == nullptr) { + NETSTACK_LOGE("user data is null"); + return RaiseServerError(manager); + } + if (userData->IsThreadStop()) { + NETSTACK_LOGI("session is stopped"); + return -1; + } + // client + auto *clientUserData = reinterpret_cast(lws_wsi_user(wsi)); + if (clientUserData == nullptr) { + NETSTACK_LOGE("clientUserData is null"); + return RaiseServerError(manager); + } + if (clientUserData->IsClosed()) { + NETSTACK_LOGI("client is closed, need to close"); + lws_close_reason(wsi, clientUserData->closeStatus, + reinterpret_cast(const_cast(clientUserData->closeReason.c_str())), + strlen(clientUserData->closeReason.c_str())); + return -1; + } + auto sendData = clientUserData->Pop(); + if (sendData.data == nullptr || sendData.length == 0) { + NETSTACK_LOGE("send data is empty"); + return HttpDummy(wsi, reason, user, in, len); + } + int sendLength = lws_write(wsi, reinterpret_cast(sendData.data) + LWS_SEND_BUFFER_PRE_PADDING, + sendData.length, sendData.protocol); + free(sendData.data); + NETSTACK_LOGD("lws send data length is %{public}d", sendLength); + if (!userData->IsEmpty()) { + NETSTACK_LOGE("userData is not empty"); + userData->TriggerWritable(); + } + return HttpDummy(wsi, reason, user, in, len); +} + +int WebSocketServerExec::LwsCallbackWsPeerInitiatedCloseServer(lws *wsi, lws_callback_reasons reason, + void *user, void *in, size_t len) +{ + NETSTACK_LOGD("lws server callback ws peer initiated close"); + if (wsi == nullptr) { + NETSTACK_LOGE("wsi is null"); + return -1; + } + lws_context *context = lws_get_context(wsi); + EventManager *manager = static_cast(lws_context_user(context)); + auto userData = manager->GetWebSocketUserData(); + if (userData == nullptr) { + NETSTACK_LOGE("user data is null"); + return RaiseServerError(manager); + } + if (in == nullptr || len < sizeof(uint16_t)) { + NETSTACK_LOGI("No close reason"); + userData->Close(LWS_CLOSE_STATUS_NORMAL, ""); + return HttpDummy(wsi, reason, user, in, len); + } + uint16_t closeStatus = ntohs(*reinterpret_cast(in)); + std::string closeReason; + closeReason.append(reinterpret_cast(in) + sizeof(uint16_t), len - sizeof(uint16_t)); + auto *clientUserData = reinterpret_cast(lws_wsi_user(wsi)); + clientUserData->Close(static_cast(closeStatus), closeReason); + return HttpDummy(wsi, reason, user, in, len); +} + +int WebSocketServerExec::LwsCallbackFilterProtocolConnection(lws *wsi, lws_callback_reasons reason, + void *user, void *in, size_t len) +{ + NETSTACK_LOGD("lws server callback filter ProtocolConnection"); + lws_context *context = lws_get_context(wsi); + EventManager *manager = static_cast(lws_context_user(context)); + if (manager == nullptr) { + NETSTACK_LOGE("manager is null"); + return RaiseServerError(manager); + } + auto userData = manager->GetWebSocketUserData(); + if (userData == nullptr) { + NETSTACK_LOGE("user data is null"); + return RaiseServerError(manager); + } + if (userData->IsClosed() || userData->IsThreadStop()) { + NETSTACK_LOGE("session is closed or thread is stopped"); + return RaiseServerError(manager); + } + std::string clientId; + WebSocketConnection connection; + bool ret = GetPeerConnMsg(wsi, manager, clientId, connection); + if (!ret) { + NETSTACK_LOGE("GetPeerConnMsg failed"); + return RaiseServerError(manager); + } + /* 是否超过最大连接数 */ + if (IsOverMaxClientConns(manager, connection.clientIP)) { + NETSTACK_LOGE("current connections count is more than limit, need to close"); + return RaiseServerError(manager); + } + /* 添加防止恶意连接的业务逻辑 */ + if (!IsAllowConnection(clientId)) { + NETSTACK_LOGE("Rejected malicious connection"); + return RaiseServerError(manager); + } + return HttpDummy(wsi, reason, user, in, len); +} + +bool WebSocketServerExec::IsAllowConnection(const std::string &clientId) +{ + if (IsIpInBanList(clientId)) { + NETSTACK_LOGE("clientid is in banlist"); + return false; + } + if (IsHighFreqConnection(clientId)) { + NETSTACK_LOGE("clientid reach high frequency connection"); + AddBanList(clientId); + return false; + } + UpdataClientList(clientId); + return true; +} + +void WebSocketServerExec::UpdataClientList(const std::string &id) +{ + std::shared_lock lock(connListMutex_); + auto it = clientList.find(id); + if (it == clientList.end()) { + NETSTACK_LOGI("add clientid to banlist"); + clientList[id] = {1, GetCurrentSecond()}; + } else { + auto now = GetCurrentSecond() - it->second.lastConnectionTime; + if (now > ONE_MINUTE_IN_SEC) { + NETSTACK_LOGI("reset clientid connections cnt"); + it->second = {1, GetCurrentSecond()}; + } else { + it->second.cnt++; + } + } +} + +void WebSocketServerExec::AddBanList(const std::string &id) +{ + std::shared_lock lock(banListMutex_); + banList[id] = GetCurrentSecond() + ONE_MINUTE_IN_SEC; +} + +bool WebSocketServerExec::IsIpInBanList(const std::string &id) +{ + std::shared_lock lock(banListMutex_); + auto it = banList.find(id); + if (it != banList.end()) { + auto now = GetCurrentSecond(); + if (now < it->second) { + return true; + } else { + banList.erase(it); + } + } + return false; +} + +uint64_t WebSocketServerExec::GetCurrentSecond() +{ + return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) + .count(); +} + +bool WebSocketServerExec::IsHighFreqConnection(const std::string &id) +{ + std::shared_lock lock(connListMutex_); + auto it = clientList.find(id); + if (it != clientList.end()) { + auto duration = GetCurrentSecond() - it->second.lastConnectionTime; + if (duration <= ONE_MINUTE_IN_SEC) { + return it->second.cnt > MAX_CONNECTIONS_PER_MINUTE; + } + } + return false; +} + +int WebSocketServerExec::LwsCallbackReceive(lws *wsi, lws_callback_reasons reason, void *user, void *in, + size_t len) +{ + NETSTACK_LOGD("lws callback server receive"); + lws_context *context = lws_get_context(wsi); + EventManager *manager = static_cast(lws_context_user(context)); + auto isFinal = lws_is_final_fragment(wsi); + OnServerMessage(wsi, manager, in, len, lws_frame_is_binary(wsi), isFinal); + return HttpDummy(wsi, reason, user, in, len); +} + +static napi_value CreateServerClosePara(napi_env env, void *callbackPara) +{ + auto para = reinterpret_cast(callbackPara); + auto deleter = [](const ClientConnectionCloseCallback *p) { delete p; }; + std::unique_ptr handler(para, deleter); + napi_value obj = NapiUtils::CreateObject(env); + if (NapiUtils::GetValueType(env, obj) != napi_object) { + return NapiUtils::GetUndefined(env); + } + napi_value jsConn = NapiUtils::CreateObject(env); + if (NapiUtils::GetValueType(env, jsConn) != napi_object) { + return NapiUtils::GetUndefined(env); + } + NapiUtils::SetStringPropertyUtf8(env, jsConn, EVENT_KEY_CLIENT_IP, para->connection.clientIP); + NapiUtils::SetUint32Property(env, jsConn, EVENT_KEY_CLIENT_PORT, para->connection.clientPort); + NapiUtils::SetNamedProperty(env, obj, EVENT_KEY_CONNECTION, jsConn); + napi_value jsRes = NapiUtils::CreateObject(env); + if (NapiUtils::GetValueType(env, jsRes) != napi_object) { + return NapiUtils::GetUndefined(env); + } + NapiUtils::SetUint32Property(env, jsRes, EVENT_KEY_CODE, para->closeResult.code); + NapiUtils::SetStringPropertyUtf8(env, jsRes, EVENT_KEY_REASON, para->closeResult.reason); + NapiUtils::SetNamedProperty(env, obj, EVENT_KEY_RESULT, jsConn); + return obj; +} + +static napi_value ConvertWsBinaryMessageToJs(napi_env env, const WebSocketMessage *msg) +{ + napi_value jsMsg = NapiUtils::CreateObject(env); + if (NapiUtils::GetValueType(env, jsMsg) != napi_object) { + return NapiUtils::GetUndefined(env); + } + void *data = nullptr; + napi_value arrayBuffer = NapiUtils::CreateArrayBuffer(env, msg->data.size(), &data); + if (data != nullptr && NapiUtils::ValueIsArrayBuffer(env, arrayBuffer) && + memcpy_s(data, msg->data.size(), msg->data.c_str(), msg->data.size()) >= 0) { + NapiUtils::SetNamedProperty(env, jsMsg, "data", arrayBuffer); + napi_value jsConn = NapiUtils::CreateObject(env); + if (NapiUtils::GetValueType(env, jsConn) != napi_object) { + return NapiUtils::GetUndefined(env); + } + NapiUtils::SetStringPropertyUtf8(env, jsConn, EVENT_KEY_CLIENT_IP, msg->connection.clientIP); + NapiUtils::SetUint32Property(env, jsConn, EVENT_KEY_CLIENT_PORT, msg->connection.clientPort); + NapiUtils::SetNamedProperty(env, jsMsg, EVENT_KEY_CONNECTION, jsConn); + return jsMsg; + } + return NapiUtils::GetUndefined(env); +} + +static napi_value CreateServerBinaryMessagePara(napi_env env, void *callbackPara) +{ + auto pair = reinterpret_cast *>(callbackPara); + if (pair == nullptr) { + NETSTACK_LOGE("pair is nullptr"); + return NapiUtils::GetUndefined(env); + } + lws *wsi = pair->first; + if (wsi == nullptr) { + NETSTACK_LOGE("wsi is nullptr"); + return NapiUtils::GetUndefined(env); + } + auto &manager = pair->second; + if (manager == nullptr || manager->innerMagic_.magicNumber != EVENT_MANAGER_MAGIC_NUMBER) { + NETSTACK_LOGE("manager is nullptr"); + return NapiUtils::CreateStringUtf8(env, ""); + } + auto msg = reinterpret_cast(manager->GetServerQueueData(wsi)); + if (!msg) { + NETSTACK_LOGE("msg is nullptr"); + return NapiUtils::GetUndefined(env); + } + napi_value jsMsg = ConvertWsBinaryMessageToJs(env, msg); + if (NapiUtils::GetValueType(env, jsMsg) != napi_object) { + delete msg; + return NapiUtils::GetUndefined(env); + } + delete msg; + return jsMsg; +} + +static napi_value ConvertWsTextMessageToJs(napi_env env, const WebSocketMessage *msg) +{ + napi_value jsMsg = NapiUtils::CreateObject(env); + if (NapiUtils::GetValueType(env, jsMsg) != napi_object) { + return NapiUtils::GetUndefined(env); + } + NapiUtils::SetStringPropertyUtf8(env, jsMsg, EVENT_KEY_DATA, msg->data); + napi_value jsConn = NapiUtils::CreateObject(env); + if (NapiUtils::GetValueType(env, jsConn) != napi_object) { + return NapiUtils::GetUndefined(env); + } + NapiUtils::SetStringPropertyUtf8(env, jsConn, EVENT_KEY_CLIENT_IP, msg->connection.clientIP); + NapiUtils::SetUint32Property(env, jsConn, EVENT_KEY_CLIENT_PORT, msg->connection.clientPort); + NapiUtils::SetNamedProperty(env, jsMsg, EVENT_KEY_CONNECTION, jsConn); + return jsMsg; +} + +static napi_value CreateServerTextMessagePara(napi_env env, void *callbackPara) +{ + auto pair = reinterpret_cast *>(callbackPara); + if (pair == nullptr) { + NETSTACK_LOGE("pair is nullptr"); + return NapiUtils::GetUndefined(env); + } + lws *wsi = pair->first; + if (wsi == nullptr) { + NETSTACK_LOGE("wsi is nullptr"); + return NapiUtils::GetUndefined(env); + } + auto &manager = pair->second; + if (manager == nullptr || manager->innerMagic_.magicNumber != EVENT_MANAGER_MAGIC_NUMBER) { + NETSTACK_LOGE("manager is nullptr"); + return NapiUtils::CreateStringUtf8(env, ""); + } + auto msg = reinterpret_cast(manager->GetServerQueueData(wsi)); + if (!msg) { + NETSTACK_LOGE("msg is nullptr"); + return NapiUtils::GetUndefined(env); + } + napi_value jsMsg = ConvertWsTextMessageToJs(env, msg); + if (NapiUtils::GetValueType(env, jsMsg) != napi_object) { + NETSTACK_LOGE("jsMsg is not object"); + delete msg; + return NapiUtils::GetUndefined(env); + } + delete msg; + return jsMsg; +} + +static napi_value CreateConnectPara(napi_env env, void *callbackPara) +{ + auto para = reinterpret_cast(callbackPara); + auto deleter = [](const WebSocketConnection *p) { delete p; }; + std::unique_ptr handler(para, deleter); + napi_value obj = NapiUtils::CreateObject(env); + if (NapiUtils::GetValueType(env, obj) != napi_object) { + NETSTACK_LOGE("napi_object not found"); + return NapiUtils::GetUndefined(env); + } + NapiUtils::SetUint32Property(env, obj, EVENT_KEY_CLIENT_PORT, para->clientPort); + NapiUtils::SetStringPropertyUtf8(env, obj, EVENT_KEY_CLIENT_IP, para->clientIP); + return obj; +} + +static napi_value CreateServerError(napi_env env, void *callbackPara) +{ + auto code = reinterpret_cast(callbackPara); + if (code == nullptr) { + NETSTACK_LOGE("code is nullptr"); + } + auto deleter = [](int32_t *p) { delete p; }; + std::unique_ptr handler(code, deleter); + napi_value err = NapiUtils::CreateObject(env); + if (NapiUtils::GetValueType(env, err) != napi_object) { + return NapiUtils::GetUndefined(env); + } + NapiUtils::SetInt32Property(env, err, EVENT_KEY_CODE, *code); + return err; +} + +void WebSocketServerExec::OnServerError(EventManager *manager, int32_t code) +{ + NETSTACK_LOGI("OnServerError %{public}d", code); + if (manager == nullptr || manager->innerMagic_.magicNumber != EVENT_MANAGER_MAGIC_NUMBER) { + NETSTACK_LOGE("manager is null"); + return; + } + bool hasServerEventListener = manager->HasEventListener(EventName::EVENT_SERVER_ERROR); + if (!hasServerEventListener) { + NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_SERVER_ERROR); + return; + } + auto para = new int32_t(code); + manager->EmitByUvWithoutCheckShared(EventName::EVENT_SERVER_ERROR, para, CallbackTemplate); +} + +void WebSocketServerExec::OnConnect(lws *wsi, EventManager *manager) +{ + NETSTACK_LOGI("OnConnect enter"); + if (manager == nullptr || manager->innerMagic_.magicNumber != EVENT_MANAGER_MAGIC_NUMBER) { + NETSTACK_LOGE("manager is null"); + return; + } + bool hasServerConnectListener = manager->HasEventListener(EventName::EVENT_SERVER_CONNECT); + if (!hasServerConnectListener) { + NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_SERVER_CONNECT); + return; + } + { + std::shared_lock lock(wsMutex_); + auto para = new WebSocketConnection; + for (auto [id, connPair] : webSocketConnection_) { + if (connPair.first == wsi) { + para->clientIP = connPair.second.clientIP; + para->clientPort = connPair.second.clientPort; + NETSTACK_LOGI("connection find ok, clientId:%{public}s", id.c_str()); + manager->EmitByUvWithoutCheckShared(EventName::EVENT_SERVER_CONNECT, + para, CallbackTemplate); + return; + } + } + } + NETSTACK_LOGE("not found client msg"); +} + +void WebSocketServerExec::OnServerClose(lws *wsi, EventManager *manager, lws_close_status closeStatus, + const std::string &closeReason) +{ + NETSTACK_LOGI("OnServerClose %{public}u %{public}s", closeStatus, closeReason.c_str()); + if (manager == nullptr || manager->innerMagic_.magicNumber != EVENT_MANAGER_MAGIC_NUMBER) { + NETSTACK_LOGE("manager is null"); + return; + } + bool hasServerCloseListener = manager->HasEventListener(EventName::EVENT_SERVER_CLOSE); + if (!hasServerCloseListener) { + NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_SERVER_CLOSE); + return; + } + auto conn = new ClientConnectionCloseCallback; + if (conn == nullptr) { + return; + } + conn->closeResult.code = closeStatus; + conn->closeResult.reason = closeReason; + if (wsi == nullptr) { + NETSTACK_LOGE("wsi is nullptr"); + return; + } + { + std::shared_lock lock(wsMutex_); + for (auto [id, connPair] : webSocketConnection_) { + if (connPair.first == wsi) { + conn->connection = connPair.second; + NETSTACK_LOGI("clientId: %{public}s", id.c_str()); + manager->EmitByUvWithoutCheckShared(EventName::EVENT_SERVER_CLOSE, + conn, CallbackTemplate); + return; + } + } + } + NETSTACK_LOGE("not found client msg"); +} + +void WebSocketServerExec::OnServerMessage(lws *wsi, EventManager *manager, void *data, + size_t length, bool isBinary, bool isFinal) +{ + NETSTACK_LOGD("server OnMessage %{public}d", isBinary); + if (manager == nullptr || manager->innerMagic_.magicNumber != EVENT_MANAGER_MAGIC_NUMBER) { + NETSTACK_LOGE("manager is null"); + return; + } + bool hasServerEventListener = manager->HasEventListener(EventName::EVENT_SERVER_MESSAGE_RECEIVE); + if (!hasServerEventListener) { + NETSTACK_LOGI("no event listener: %{public}s", EventName::EVENT_SERVER_MESSAGE_RECEIVE); + return; + } + if (length > INT32_MAX) { + NETSTACK_LOGE("data length too long"); + return; + } + HandleServerRcvMessage(wsi, manager, data, length, isBinary, isFinal); +} + +void WebSocketServerExec::HandleServerRcvMessage(lws *wsi, EventManager *manager, void *data, + size_t length, bool isBinary, bool isFinal) +{ + if (manager == nullptr) { + NETSTACK_LOGE("manager is nullptr"); + return; + } + if (isBinary) { + manager->AppendWsServerBinaryData(wsi, data, length); + if (isFinal) { + const std::string &msgFromManager = manager->GetWsServerBinaryData(wsi); + if (msgFromManager.empty()) { + NETSTACK_LOGE("msgFromManager is empty"); + return; + } + auto msg = new WebSocketMessage; + if (msg == nullptr) { + return; + } + SetWebsocketMessage(wsi, manager, msgFromManager, msg); + manager->SetServerQueueData(wsi, msg); + auto callbackPara = new std::pair(wsi, manager); + manager->EmitByUvWithoutCheckShared(EventName::EVENT_SERVER_MESSAGE_RECEIVE, callbackPara, + CallbackTemplate); + manager->ClearWsServerBinaryData(wsi); + } + } else { + manager->AppendWsServerTextData(wsi, data, length); + if (isFinal) { + const std::string &msgFromManager = manager->GetWsServerTextData(wsi); + if (msgFromManager.empty()) { + NETSTACK_LOGE("msgFromManager is empty"); + return; + } + auto msg = new WebSocketMessage; + if (msg == nullptr) { + return; + } + SetWebsocketMessage(wsi, manager, msgFromManager, msg); + manager->SetServerQueueData(wsi, msg); + auto callbackPara = new std::pair(wsi, manager); + manager->EmitByUvWithoutCheckShared(EventName::EVENT_SERVER_MESSAGE_RECEIVE, callbackPara, + CallbackTemplate); + manager->ClearWsServerTextData(wsi); + } + } +} + +void WebSocketServerExec::SetWebsocketMessage(lws *wsi, EventManager *manager, + const std::string &msgFromManager, void *dataMsg) +{ + NETSTACK_LOGD("SetWebsocketMessage enter"); + if (manager == nullptr || manager->innerMagic_.magicNumber != EVENT_MANAGER_MAGIC_NUMBER) { + NETSTACK_LOGE("manager is null"); + return; + } + if (wsi == nullptr) { + NETSTACK_LOGE("wsi is nullptr"); + return; + } + auto webSocketMessage = static_cast(dataMsg); + webSocketMessage->data = msgFromManager; + + { + std::shared_lock lock(wsMutex_); + if (webSocketConnection_.empty()) { + NETSTACK_LOGE("webSocketConnection_ is empty"); + return; + } + for (auto [_, connPair] : webSocketConnection_) { + if (connPair.first == wsi) { + webSocketMessage->connection = connPair.second; + return; + } + } + } + NETSTACK_LOGE("not found client msgFromManager"); +} + +bool WebSocketServerExec::ExecServerStart(ServerStartContext *context) +{ + NETSTACK_LOGD("websocket server start exec"); + if (context == nullptr) { + NETSTACK_LOGE("context is nullptr"); + return false; + } + if (!CommonUtils::HasInternetPermission()) { + context->SetPermissionDenied(true); + return false; + } + if (!CommonUtils::IsValidIPV4(context->GetServerIP()) && + !CommonUtils::IsValidIPV6(context->GetServerIP())) { + NETSTACK_LOGE("IPV4 and IPV6 are not valid"); + context->SetErrorCode(WEBSOCKET_ERROR_CODE_INVALID_NIC); + return false; + } + if (!CommonUtils::IsValidPort(context->GetServerPort())) { + context->SetErrorCode(WEBSOCKET_ERROR_CODE_INVALID_PORT); + NETSTACK_LOGE("Port is not valid"); + return false; + } + if (context->GetMaxConcurrentClientsNumber() > MAX_CONCURRENT_CLIENTS_NUMBER) { + NETSTACK_LOGE("max concurrent clients number is set over limit"); + return false; + } + auto manager = context->GetSharedManager(); + if (manager == nullptr) { + return false; + } + manager->SetMaxConnClientCnt(context->GetMaxConcurrentClientsNumber()); + if (context->GetMaxConnectionsForOneClient() > MAX_CONNECTIONS_FOR_ONE_CLIENT) { + NETSTACK_LOGE("max connection number for one client is set over limit"); + return false; + } + manager->SetMaxConnForOneClient(context->GetMaxConnectionsForOneClient()); + lws_context_creation_info info = {}; + FillServerContextInfo(context, manager, info); + if (!FillServerCertPath(context, info)) { + NETSTACK_LOGE("FillServerCertPath error"); + return false; + } + StartService(info, manager); + return true; +} + +void WebSocketServerExec::StartService(lws_context_creation_info &info, std::shared_ptr &manager) +{ + lws_context *lwsContext = nullptr; + std::shared_ptr userData; + lwsContext = lws_create_context(&info); + userData = std::make_shared(lwsContext); + manager->SetWebSocketUserData(userData); + std::thread serviceThread(RunServerService, userData, manager); +#if defined(MAC_PLATFORM) || defined(IOS_PLATFORM) + pthread_setname_np(WEBSOCKET_SERVER_THREAD_RUN); +#else + pthread_setname_np(serviceThread.native_handle(), WEBSOCKET_SERVER_THREAD_RUN); +#endif + serviceThread.detach(); +} + +void WebSocketServerExec::FillServerContextInfo(ServerStartContext *context, std::shared_ptr &manager, + lws_context_creation_info &info) +{ + info.options = LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE; + info.port = context->GetServerPort(); + info.mounts = &mount; + info.protocols = LWS_SERVER_PROTOCOLS; + info.vhost_name = "localhost"; + info.user = manager.get(); + // maybe + info.gid = -1; + info.uid = -1; +} + +static bool CheckFilePath(std::string &path) +{ + char tmpPath[PATH_MAX] = {0}; + if (!realpath(static_cast(path.c_str()), tmpPath)) { + NETSTACK_LOGE("path is error"); + return false; + } + path = tmpPath; + return true; +} + +bool WebSocketServerExec::FillServerCertPath(ServerStartContext *context, lws_context_creation_info &info) +{ + if (!context->certPath_.empty()) { + if (!CheckFilePath(context->certPath_) || !CheckFilePath(context->keyPath_)) { + NETSTACK_LOGE("client cert not exist"); + context->SetErrorCode(WEBSOCKET_ERROR_CODE_FILE_NOT_EXIST); + return false; + } + info.ssl_cert_filepath = context->certPath_.c_str(); + info.ssl_private_key_filepath = context->keyPath_.c_str(); + } + return true; +} + +bool WebSocketServerExec::ExecListAllConnections(ListAllConnectionsContext *context) +{ + NETSTACK_LOGD("ListAllConnections start exec"); + if (context == nullptr) { + NETSTACK_LOGE("context is nullptr"); + return false; + } + if (!CommonUtils::HasInternetPermission()) { + context->SetPermissionDenied(true); + return false; + } + auto manager = context->GetSharedManager(); + if (manager == nullptr) { + NETSTACK_LOGE("context is null"); + return false; + } + auto userData = manager->GetWebSocketUserData(); + if (userData == nullptr) { + NETSTACK_LOGE("user data is nullptr"); + return false; + } + if (userData->IsClosed() || userData->IsThreadStop()) { + NETSTACK_LOGE("session is closed or stopped"); + return false; + } + std::vector connection = GetConnections(); + context->SetAllConnections(connection); + NETSTACK_LOGI("ExecListAllConnections OK"); + return true; +} + +std::vector WebSocketServerExec::GetConnections() +{ + std::shared_lock lock(wsMutex_); + std::vector conn; + if (!webSocketConnection_.empty()) { + for (auto [_, connPair] : webSocketConnection_) { + conn.emplace_back(connPair.second); + } + } + return conn; +} + +bool WebSocketServerExec::ExecServerClose(ServerCloseContext *context) +{ + if (context == nullptr) { + NETSTACK_LOGE("context is nullptr"); + return false; + } + if (!CommonUtils::HasInternetPermission()) { + context->SetPermissionDenied(true); + return false; + } + if (context->GetSharedManager() == nullptr) { + NETSTACK_LOGE("context is null"); + return false; + } + WebSocketConnection conn = context->GetConnection(); + if (conn.clientIP.empty()) { + NETSTACK_LOGE("connection is empty"); + return false; + } + std::string clientId = conn.clientIP + ":" + std::to_string(conn.clientPort); + NETSTACK_LOGI("ExecServerClose, clientID:%{public}s", clientId.c_str()); + auto wsi = GetClientWsi(clientId); + if (wsi == nullptr) { + context->SetErrorCode(WEBSOCKET_ERROR_CODE_CONNECTION_NOT_EXIST); + NETSTACK_LOGE("clientId not found:%{public}s", clientId.c_str()); + return false; + } + auto *clientUserData = reinterpret_cast(lws_wsi_user(wsi)); + if (clientUserData == nullptr) { + NETSTACK_LOGE("clientUser data is nullptr"); + return false; + } + if (clientUserData->IsClosed() || clientUserData->IsThreadStop()) { + NETSTACK_LOGE("session is closed or stopped"); + return false; + } + clientUserData->Close(static_cast(context->code), context->reason); + clientUserData->TriggerWritable(); + NETSTACK_LOGI("ExecServerClose OK"); + return true; +} + +bool WebSocketServerExec::ExecServerSend(ServerSendContext *context) +{ + if (context == nullptr) { + NETSTACK_LOGE("context is nullptr"); + return false; + } + if (!CommonUtils::HasInternetPermission()) { + context->SetPermissionDenied(true); + return false; + } + WebSocketConnection conn = context->GetConnection(); + if (conn.clientIP.empty()) { + NETSTACK_LOGE("connection is empty"); + return false; + } + std::string clientId = conn.clientIP + ":" + std::to_string(conn.clientPort); + NETSTACK_LOGI("connection clientid:%{public}s", clientId.c_str()); + auto wsi = GetClientWsi(clientId); + if (wsi == nullptr) { + context->SetErrorCode(WEBSOCKET_ERROR_CODE_CONNECTION_NOT_EXIST); + NETSTACK_LOGE("clientId not found:%{public}s", clientId.c_str()); + return false; + } + auto *clientUserData = reinterpret_cast(lws_wsi_user(wsi)); + if (clientUserData == nullptr) { + NETSTACK_LOGE("clientUser data is nullptr"); + return false; + } + if (clientUserData->IsClosed() || clientUserData->IsThreadStop()) { + NETSTACK_LOGE("session is closed or stopped"); + return false; + } + clientUserData->Push(context->data, context->length, context->protocol); + clientUserData->TriggerWritable(); + NETSTACK_LOGD("lws ts send success"); + return true; +} + +lws *WebSocketServerExec::GetClientWsi(const std::string clientId) +{ + std::shared_lock lock(wsMutex_); + if (webSocketConnection_.empty()) { + NETSTACK_LOGE("webSocketConnection is empty"); + return nullptr; + } + auto it = webSocketConnection_.find(clientId); + if (it == webSocketConnection_.end()) { + NETSTACK_LOGE("can't find clientId"); + return nullptr; + } + return it->second.first; +} + +bool WebSocketServerExec::ExecServerStop(ServerStopContext *context) +{ + if (context == nullptr) { + NETSTACK_LOGE("context is nullptr"); + return false; + } + if (!CommonUtils::HasInternetPermission()) { + context->SetPermissionDenied(true); + return false; + } + auto manager = context->GetSharedManager(); + if (manager == nullptr) { + NETSTACK_LOGE("context is null"); + return false; + } + auto userData = manager->GetWebSocketUserData(); + if (userData == nullptr) { + NETSTACK_LOGE("user data is nullptr"); + return false; + } + if (userData->IsClosed() || userData->IsThreadStop()) { + NETSTACK_LOGE("session is closed or stopped"); + return false; + } + CloseAllConnection(userData); + userData->Close(LWS_CLOSE_STATUS_GOINGAWAY, ""); + NETSTACK_LOGI("ExecServerStop OK"); + return true; +} + +void WebSocketServerExec::CloseAllConnection(const std::shared_ptr &userData) +{ + if (userData == nullptr) { + NETSTACK_LOGE("user data is nullptr"); + return; + } + decltype(webSocketConnection_) connListTmp; + { + std::shared_lock lock(wsMutex_); + if (webSocketConnection_.empty()) { + NETSTACK_LOGE("webSocketConnection is empty"); + if (!userData->IsThreadStop()) { + NETSTACK_LOGI("server service is stopped"); + userData->SetThreadStop(true); + } + return; + } + connListTmp = webSocketConnection_; + } + const char *closeReason = "server is going away"; + for (auto [id, connPair] : connListTmp) { + if (connPair.first == nullptr) { + NETSTACK_LOGE("clientId not found:%{public}s", id.c_str()); + continue; + } + auto *clientUserData = reinterpret_cast(lws_wsi_user(connPair.first)); + clientUserData->Close(LWS_CLOSE_STATUS_GOINGAWAY, closeReason); + clientUserData->TriggerWritable(); + } + NETSTACK_LOGI("CloseAllConnection OK"); +} + +napi_value WebSocketServerExec::ServerStartCallback(ServerStartContext *context) +{ + return NapiUtils::GetBoolean(context->GetEnv(), true); +} + +napi_value WebSocketServerExec::ListAllConnectionsCallback(ListAllConnectionsContext *context) +{ + if (context == nullptr) { + NETSTACK_LOGE("Context is null"); + return nullptr; + } + napi_value connectionsArray = NapiUtils::CreateArray(context->GetEnv(), 0); + const std::vector connections = context->GetAllConnections(); + if (connections.empty()) { + NETSTACK_LOGE("connections list is null"); + return connectionsArray; + } + uint32_t index = 0; + for (const auto &conn : connections) { + napi_value jsConn = NapiUtils::CreateObject(context->GetEnv()); + NapiUtils::SetUint32Property(context->GetEnv(), jsConn, EVENT_KEY_CLIENT_PORT, conn.clientPort); + NapiUtils::SetStringPropertyUtf8(context->GetEnv(), jsConn, EVENT_KEY_CLIENT_IP, conn.clientIP); + NapiUtils::SetArrayElement(context->GetEnv(), connectionsArray, index, jsConn); + ++index; + } + return connectionsArray; +} + +napi_value WebSocketServerExec::ServerSendCallback(ServerSendContext *context) +{ + return NapiUtils::GetBoolean(context->GetEnv(), true); +} + +napi_value WebSocketServerExec::ServerCloseCallback(ServerCloseContext *context) +{ + return NapiUtils::GetBoolean(context->GetEnv(), true); +} + +napi_value WebSocketServerExec::ServerStopCallback(ServerStopContext *context) +{ + auto manager = context->GetSharedManager(); + if (manager != nullptr) { + NETSTACK_LOGD("websocket close, delete js ref"); + manager->DeleteEventReference(context->GetEnv()); + } + return NapiUtils::GetBoolean(context->GetEnv(), true); +} +} \ No newline at end of file diff --git a/frameworks/js/napi/websocket/websocket_module/include/websocket_module.h b/frameworks/js/napi/websocket/websocket_module/include/websocket_module.h index e6632af8e4f39f5c2c09ff453aeaf93a72e65151..eec420f60a04b2e8b2c4b202313ac75a04568f53 100644 --- a/frameworks/js/napi/websocket/websocket_module/include/websocket_module.h +++ b/frameworks/js/napi/websocket/websocket_module/include/websocket_module.h @@ -40,9 +40,31 @@ public: static napi_value Off(napi_env env, napi_callback_info info); }; +#ifdef NETSTACK_WEBSOCKETSERVER + class WebSocketServer { + public: + static constexpr const char *FUNCTION_START = "start"; + static constexpr const char *FUNCTION_LISTALLCONNECTIONS = "listAllConnections"; + static constexpr const char *FUNCTION_CLOSE = "close"; + static constexpr const char *FUNCTION_ON = "on"; + static constexpr const char *FUNCTION_OFF = "off"; + static constexpr const char *FUNCTION_SEND = "send"; + static constexpr const char *FUNCTION_STOP = "stop"; + + static napi_value Start(napi_env env, napi_callback_info info); + static napi_value ListAllConnections(napi_env env, napi_callback_info info); + static napi_value Close(napi_env env, napi_callback_info info); + static napi_value On(napi_env env, napi_callback_info info); + static napi_value Off(napi_env env, napi_callback_info info); + static napi_value Send(napi_env env, napi_callback_info info); + static napi_value Stop(napi_env env, napi_callback_info info); + }; +#endif + static constexpr const char *FUNCTION_CREATE_WEB_SOCKET = "createWebSocket"; static constexpr const char *INTERFACE_WEB_SOCKET = "WebSocket"; - + static constexpr const char *FUNCTION_CREATE_WEB_SOCKET_SERVER = "createWebSocketServer"; + static constexpr const char *INTERFACE_WEB_SOCKET_SERVER = "WebSocketServer"; static napi_value InitWebSocketModule(napi_env env, napi_value exports); private: @@ -53,6 +75,12 @@ private: static void FinalizeWebSocketInstance(napi_env env, void *data, void *hint); static void InitWebSocketProperties(napi_env env, napi_value exports); + +#ifdef NETSTACK_WEBSOCKETSERVER + static napi_value CreateWebSocketServer(napi_env env, napi_callback_info info); + + static void DefineWebSocketServerClass(napi_env env, napi_value exports); +#endif }; } // namespace OHOS::NetStack::Websocket #endif /* COMMUNICATIONNETSTACK_WEBSOCKET_MODULE_H */ diff --git a/frameworks/js/napi/websocket/websocket_module/src/websocket_module.cpp b/frameworks/js/napi/websocket/websocket_module/src/websocket_module.cpp index bceed2ca4f11bdaf0f91cb0503017172748ad9c1..74c78b0ce90806220282392a2e028f22f24ea519 100644 --- a/frameworks/js/napi/websocket/websocket_module/src/websocket_module.cpp +++ b/frameworks/js/napi/websocket/websocket_module/src/websocket_module.cpp @@ -29,12 +29,15 @@ static std::string g_appBundleName; napi_value WebSocketModule::InitWebSocketModule(napi_env env, napi_value exports) { DefineWebSocketClass(env, exports); +#ifdef NETSTACK_WEBSOCKETSERVER + DefineWebSocketServerClass(env, exports); +#endif InitWebSocketProperties(env, exports); NapiUtils::SetEnvValid(env); std::call_once(g_isAtomicServiceFlag, []() { g_appIsAtomicService = CommonUtils::IsAtomicService(g_appBundleName); NETSTACK_LOGI("IsAtomicService bundleName is %{public}s, isAtomicService is %{public}d", - g_appBundleName.c_str(), g_appIsAtomicService); + g_appBundleName.c_str(), g_appIsAtomicService); }); auto envWrapper = new (std::nothrow)napi_env; if (envWrapper == nullptr) { @@ -50,6 +53,14 @@ napi_value WebSocketModule::CreateWebSocket(napi_env env, napi_callback_info inf return ModuleTemplate::NewInstanceWithSharedManager(env, info, INTERFACE_WEB_SOCKET, FinalizeWebSocketInstance); } +#ifdef NETSTACK_WEBSOCKETSERVER +napi_value WebSocketModule::CreateWebSocketServer(napi_env env, napi_callback_info info) +{ + return ModuleTemplate::NewInstanceWithSharedManager(env, info, INTERFACE_WEB_SOCKET_SERVER, + FinalizeWebSocketInstance); +} +#endif + void WebSocketModule::DefineWebSocketClass(napi_env env, napi_value exports) { std::initializer_list properties = { @@ -62,10 +73,29 @@ void WebSocketModule::DefineWebSocketClass(napi_env env, napi_value exports) ModuleTemplate::DefineClass(env, exports, properties, INTERFACE_WEB_SOCKET); } +#ifdef NETSTACK_WEBSOCKETSERVER +void WebSocketModule::DefineWebSocketServerClass(napi_env env, napi_value exports) +{ + std::initializer_list properties = { + DECLARE_NAPI_FUNCTION(WebSocketServer::FUNCTION_START, WebSocketServer::Start), + DECLARE_NAPI_FUNCTION(WebSocketServer::FUNCTION_LISTALLCONNECTIONS, WebSocketServer::ListAllConnections), + DECLARE_NAPI_FUNCTION(WebSocketServer::FUNCTION_CLOSE, WebSocketServer::Close), + DECLARE_NAPI_FUNCTION(WebSocketServer::FUNCTION_ON, WebSocketServer::On), + DECLARE_NAPI_FUNCTION(WebSocketServer::FUNCTION_OFF, WebSocketServer::Off), + DECLARE_NAPI_FUNCTION(WebSocketServer::FUNCTION_SEND, WebSocketServer::Send), + DECLARE_NAPI_FUNCTION(WebSocketServer::FUNCTION_STOP, WebSocketServer::Stop), + }; + ModuleTemplate::DefineClass(env, exports, properties, INTERFACE_WEB_SOCKET_SERVER); +} +#endif + void WebSocketModule::InitWebSocketProperties(napi_env env, napi_value exports) { std::initializer_list properties = { DECLARE_NAPI_FUNCTION(FUNCTION_CREATE_WEB_SOCKET, CreateWebSocket), +#ifdef NETSTACK_WEBSOCKETSERVER + DECLARE_NAPI_FUNCTION(FUNCTION_CREATE_WEB_SOCKET_SERVER, CreateWebSocketServer), +#endif }; NapiUtils::DefineProperties(env, exports, properties); } @@ -117,6 +147,57 @@ napi_value WebSocketModule::WebSocket::Off(napi_env env, napi_callback_info info EventName::EVENT_HEADER_RECEIVE}); } +#ifdef NETSTACK_WEBSOCKETSERVER +napi_value WebSocketModule::WebSocketServer::Start(napi_env env, napi_callback_info info) +{ + return ModuleTemplate::InterfaceWithSharedManager( + env, info, "WebSocketServerStart", nullptr, WebSocketAsyncWork::ExecServerStart, + WebSocketAsyncWork::ServerStartCallback); +} + +napi_value WebSocketModule::WebSocketServer::ListAllConnections(napi_env env, napi_callback_info info) +{ + return ModuleTemplate::InterfaceWithSharedManager( + env, info, "WebSocketServerListAllConnections", nullptr, WebSocketAsyncWork::ExecListAllConnections, + WebSocketAsyncWork::ListAllConnectionsCallback); +} + +napi_value WebSocketModule::WebSocketServer::Close(napi_env env, napi_callback_info info) +{ + return ModuleTemplate::InterfaceWithSharedManager( + env, info, "WebSocketServerClose", nullptr, WebSocketAsyncWork::ExecServerClose, + WebSocketAsyncWork::ServerCloseCallback); +} + +napi_value WebSocketModule::WebSocketServer::Send(napi_env env, napi_callback_info info) +{ + return ModuleTemplate::InterfaceWithSharedManager( + env, info, "WebSocketServerSend", nullptr, WebSocketAsyncWork::ExecServerSend, + WebSocketAsyncWork::ServerSendCallback); +} + +napi_value WebSocketModule::WebSocketServer::Stop(napi_env env, napi_callback_info info) +{ + return ModuleTemplate::InterfaceWithSharedManager( + env, info, "WebSocketServerStop", nullptr, WebSocketAsyncWork::ExecServerStop, + WebSocketAsyncWork::ServerStopCallback); +} + +napi_value WebSocketModule::WebSocketServer::On(napi_env env, napi_callback_info info) +{ + return ModuleTemplate::OnSharedManager(env, info, + {EventName::EVENT_SERVER_CONNECT, EventName::EVENT_SERVER_MESSAGE_RECEIVE, + EventName::EVENT_SERVER_ERROR, EventName::EVENT_SERVER_CLOSE}, false); +} + +napi_value WebSocketModule::WebSocketServer::Off(napi_env env, napi_callback_info info) +{ + return ModuleTemplate::OffSharedManager(env, info, + {EventName::EVENT_SERVER_ERROR, EventName::EVENT_SERVER_CONNECT, + EventName::EVENT_SERVER_CLOSE, EventName::EVENT_SERVER_MESSAGE_RECEIVE}); +} +#endif + static napi_module g_websocketModule = { .nm_version = 1, .nm_flags = 0, diff --git a/frameworks/native/http/http_client/http_client_task.cpp b/frameworks/native/http/http_client/http_client_task.cpp index f113f34dbcf61feaca75e97776585fe4d660a42e..03d124f6128d67d562dc26e8a24ccab736baf7cd 100644 --- a/frameworks/native/http/http_client/http_client_task.cpp +++ b/frameworks/native/http/http_client/http_client_task.cpp @@ -31,6 +31,7 @@ #include "timing.h" #if HAS_NETMANAGER_BASE #include "http_client_network_message.h" +#include "netstack_chr_client.h" #endif #include "netstack_hisysevent.h" @@ -733,7 +734,6 @@ void HttpClientTask::ProcessResponse(CURLMsg *msg) response_.SetResponseTime(HttpTime::GetNowTimeGMT()); DumpHttpPerformance(); - if (CURLE_ABORTED_BY_CALLBACK == code) { (void)ProcessResponseCode(); if (onCanceled_) { diff --git a/frameworks/native/websocket_client/include/websocket_client_error.h b/frameworks/native/websocket_client/include/websocket_client_error.h index f38a8eb2941433029d18475b9cc0ef61ad98a21a..cd8b48691fe652b2c2349ffd43fae6e9c35c4f33 100755 --- a/frameworks/native/websocket_client/include/websocket_client_error.h +++ b/frameworks/native/websocket_client/include/websocket_client_error.h @@ -45,6 +45,9 @@ enum WebSocketErrorCode { WEBSOCKET_ERROR_NO_HEADR_EXCEEDS = 1016, WEBSOCKET_ERROR_HAVE_NO_CONNECT = 1017, WEBSOCKET_ERROR_HAVE_NO_CONNECT_CONTEXT = 1018, + WEBSOCKET_ERROR_FILE_NOT_EXIST = 1019, + WEBSOCKET_ERROR_PERMISSION_DENIED = 1020, + WEBSOCKET_ERROR_DISALLOW_HOST = 1021, WEBSOCKET_UNKNOWN_OTHER_ERROR = 9999 }; diff --git a/frameworks/native/websocket_client/websocket_client.cpp b/frameworks/native/websocket_client/websocket_client.cpp index 57de3870cf884c7a02b1cac4f1ace54da45bb7b3..5ac5137081b2a6bdcabd90a2cd2d2a1061928e22 100644 --- a/frameworks/native/websocket_client/websocket_client.cpp +++ b/frameworks/native/websocket_client/websocket_client.cpp @@ -20,6 +20,12 @@ #include "netstack_log.h" #include "websocket_client_innerapi.h" +#include "netstack_common_utils.h" + +#ifdef HAS_NETMANAGER_BASE +#include "http_proxy.h" +#include "net_conn_client.h" +#endif static constexpr const char *PATH_START = "/"; static constexpr const char *NAME_END = ":"; @@ -28,6 +34,7 @@ static constexpr const size_t STATUS_LINE_ELEM_NUM = 2; static constexpr const char *PREFIX_HTTPS = "https"; static constexpr const char *PREFIX_WSS = "wss"; static constexpr const int MAX_URI_LENGTH = 1024; +static constexpr const int MAX_ADDRESS_LENGTH = 1024; static constexpr const int MAX_HDR_LENGTH = 1024; static constexpr const int MAX_HEADER_LENGTH = 8192; static constexpr const size_t MAX_DATA_LENGTH = 4 * 1024 * 1024; @@ -38,6 +45,11 @@ static constexpr const char *LINK_DOWN = "The link is down"; static constexpr const char *CLOSE_REASON_FORM_SERVER = "websocket close from server"; static constexpr const int FUNCTION_PARAM_TWO = 2; static constexpr const char *WEBSOCKET_CLIENT_THREAD_RUN = "OS_NET_WSCli"; +static constexpr const char *WEBSOCKET_SYSTEM_PREPARE_CA_PATH = "/etc/security/certificates"; +#ifdef HAS_NETMANAGER_BASE +static constexpr const int32_t UID_TRANSFORM_DIVISOR = 200000; +static constexpr const char *BASE_PATH = "/data/certificates/user_cacerts/"; +#endif static std::atomic g_clientID(0); namespace OHOS::NetStack::WebSocketClient { static const lws_retry_bo_t RETRY = { @@ -328,12 +340,105 @@ int LwsCallback(lws *wsi, lws_callback_reasons reason, void *user, void *in, siz static struct lws_protocols protocols[] = {{"lws-minimal-client1", LwsCallback, 0, 0, 0, NULL, 0}, LWS_PROTOCOL_LIST_TERM}; -static void FillContextInfo(lws_context_creation_info &info) +static void GetWebsocketProxyInfo(ClientContext *context, std::string &host, uint32_t &port, + std::string &exclusions) +{ + if (context->usingWebsocketProxyType == WebsocketProxyType::USE_SYSTEM) { +#ifdef HAS_NETMANAGER_BASE + using namespace NetManagerStandard; + HttpProxy websocketProxy; + NetConnClient::GetInstance().GetDefaultHttpProxy(websocketProxy); + host = websocketProxy.GetHost(); + port = websocketProxy.GetPort(); + exclusions = CommonUtils::ToString(websocketProxy.GetExclusionList()); +#endif + } else if (context->usingWebsocketProxyType == WebsocketProxyType::USE_SPECIFIED) { + host = context->websocketProxyHost; + port = context->websocketProxyPort; + exclusions = context->websocketProxyExclusions; + } +} + +static void FillContextInfo(ClientContext *context, lws_context_creation_info &info) { info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; info.port = CONTEXT_PORT_NO_LISTEN; info.protocols = protocols; info.fd_limit_per_thread = FD_LIMIT_PER_THREAD; + + char tempUri[MAX_URI_LENGTH] = {0}; + char proxyAds[MAX_ADDRESS_LENGTH] = {0}; + const char *tempProtocol = nullptr; + const char *tempAddress = nullptr; + const char *tempPath = nullptr; + int32_t tempPort = 0; + + std::string host; + uint32_t port = 0; + std::string exclusions; + + if (strcpy_s(tempUri, MAX_URI_LENGTH, context->url.c_str()) < 0) { + NETSTACK_LOGE("strcpy_s failed"); + return; + } + if (lws_parse_uri(tempUri, &tempProtocol, &tempAddress, &tempPort, &tempPath) != 0) { + NETSTACK_LOGE("get websocket hostname failed"); + return; + } + GetWebsocketProxyInfo(context, host, port, exclusions); + if (!host.empty() && !CommonUtils::IsHostNameExcluded(tempAddress, exclusions, ",")) { + if (strcpy_s(proxyAds, host.length() + 1, host.c_str()) != EOK) { + NETSTACK_LOGE("memory copy failed"); + } + info.http_proxy_address = proxyAds; + info.http_proxy_port = port; + } +} + +static bool CheckFilePath(std::string &path) +{ + char tmpPath[PATH_MAX] = {0}; + if (!realpath(static_cast(path.c_str()), tmpPath)) { + NETSTACK_LOGE("path is error"); + return false; + } + path = tmpPath; + return true; +} + +static bool FillCaPath(ClientContext *context, lws_context_creation_info &info) +{ + if (!context->caPath.empty()) { + if (!CheckFilePath(context->caPath)) { + NETSTACK_LOGE("ca not exist"); + context->errorCode = WebSocketErrorCode::WEBSOCKET_ERROR_FILE_NOT_EXIST; + return false; + } + info.client_ssl_ca_filepath = context->caPath.c_str(); + NETSTACK_LOGD("load customize CA: %{public}s", info.client_ssl_ca_filepath); + } else { + info.client_ssl_ca_dirs[0] = WEBSOCKET_SYSTEM_PREPARE_CA_PATH; +#ifdef HAS_NETMANAGER_BASE + if (NetManagerStandard::NetConnClient::GetInstance().TrustUserCa()) { + context->SetUserCertPath(BASE_PATH + std::to_string(getuid() / UID_TRANSFORM_DIVISOR)); + info.client_ssl_ca_dirs[1] = context->GetUserCertPath().c_str(); + } +#endif + NETSTACK_LOGD("load system CA"); + } + if (!context->clientCert.empty()) { + char realKeyPath[PATH_MAX] = {0}; + if (!CheckFilePath(context->clientCert) || !realpath(context->clientKey.Data(), realKeyPath)) { + NETSTACK_LOGE("client cert not exist"); + context->errorCode = WebSocketErrorCode::WEBSOCKET_ERROR_FILE_NOT_EXIST; + return false; + } + context->clientKey = Secure::SecureChar(realKeyPath); + info.client_ssl_cert_filepath = context->clientCert.c_str(); + info.client_ssl_private_key_filepath = context->clientKey.Data(); + info.client_ssl_private_key_password = context->keyPassword.Data(); + } + return true; } bool ParseUrl(const std::string url, char *prefix, char *address, char *path, int *port) @@ -373,12 +478,12 @@ int CreatConnectInfo(const std::string url, lws_context *lwsContext, WebSocketCl return WebSocketErrorCode::WEBSOCKET_CONNECTION_PARSEURL_ERROR; } std::string path = PATH_START + std::string(pathWithoutStart); - + std::string tempHost = std::string(address) + NAME_END + std::to_string(port); connectInfo.context = lwsContext; connectInfo.address = address; connectInfo.port = port; connectInfo.path = path.c_str(); - connectInfo.host = address; + connectInfo.host = tempHost.c_str(); connectInfo.origin = address; connectInfo.local_protocol_name = "lws-minimal-client1"; @@ -400,6 +505,15 @@ int CreatConnectInfo(const std::string url, lws_context *lwsContext, WebSocketCl int WebSocketClient::Connect(std::string url, struct OpenOptions options) { NETSTACK_LOGI("ClientId:%{public}d, Connect start", this->GetClientContext()->GetClientId()); + if (!CommonUtils::HasInternetPermission()) { + this->GetClientContext()->permissionDenied = true; + return WebSocketErrorCode::WEBSOCKET_ERROR_PERMISSION_DENIED; + } + if (this->GetClientContext()->isAtomicService && !CommonUtils::IsAllowedHostname(this->GetClientContext()-> + bundleName, CommonUtils::DOMAIN_TYPE_WEBSOCKET_REQUEST, this->GetClientContext()->url)) { + this->GetClientContext()->noAllowedHost = true; + return WebSocketErrorCode::WEBSOCKET_ERROR_DISALLOW_HOST; + } if (!options.headers.empty()) { if (options.headers.size() > MAX_HEADER_LENGTH) { return WebSocketErrorCode::WEBSOCKET_ERROR_NO_HEADR_EXCEEDS; @@ -411,7 +525,8 @@ int WebSocketClient::Connect(std::string url, struct OpenOptions options) } } lws_context_creation_info info = {}; - FillContextInfo(info); + FillContextInfo(this->GetClientContext(), info); + FillCaPath(this->GetClientContext(), info); lws_context *lwsContext = lws_create_context(&info); if (lwsContext == nullptr) { return WebSocketErrorCode::WEBSOCKET_CONNECTION_NO_MEMOERY; diff --git a/interfaces/innerkits/http_client/BUILD.gn b/interfaces/innerkits/http_client/BUILD.gn index 9e209c686f501fea94910e417fd537eac9a9b4b0..d2fd824cd71a4c603306ffc912ee0e301e45cdd4 100644 --- a/interfaces/innerkits/http_client/BUILD.gn +++ b/interfaces/innerkits/http_client/BUILD.gn @@ -20,6 +20,7 @@ config("http_client_config") { "$NETSTACK_DIR/interfaces/innerkits/http_client/include", "$NETSTACK_DIR/utils/profiler_utils/include", "$NETSTACK_DIR/utils/tlv_utils/include", + "$NETSTACK_DIR/utils/netstack_chr_client/include", ] cflags = [] @@ -45,7 +46,10 @@ config("http_client_config") { } if (product_name != "ohos-sdk") { - defines += [ "HTTP_MULTIPATH_CERT_ENABLE" ] + defines += [ + "HTTP_MULTIPATH_CERT_ENABLE", + "HAS_NETSTACK_CHR", + ] } } @@ -61,6 +65,8 @@ ohos_shared_library("http_client") { sources = [ "$NETSTACK_DIR/utils/http_over_curl/src/epoll_multi_driver.cpp", "$NETSTACK_DIR/utils/http_over_curl/src/epoll_request_handler.cpp", + "$NETSTACK_DIR/utils/netstack_chr_client/src/netstack_chr_client.cpp", + "$NETSTACK_DIR/utils/netstack_chr_client/src/netstack_chr_report.cpp", "$NETSTACK_DIR/utils/profiler_utils/src/http_client_network_message.cpp", "$NETSTACK_DIR/utils/profiler_utils/src/i_network_message.cpp", "$NETSTACK_DIR/utils/profiler_utils/src/netstack_network_profiler.cpp", diff --git a/interfaces/innerkits/websocket_client/include/client_context.h b/interfaces/innerkits/websocket_client/include/client_context.h index 40e3c0d2e0ae3ba0fa9a2babfaba6dc253a18702..3283ac30c6101cc3db5866a0639d8c84f718f9cc 100755 --- a/interfaces/innerkits/websocket_client/include/client_context.h +++ b/interfaces/innerkits/websocket_client/include/client_context.h @@ -27,6 +27,7 @@ #include #include #include "netstack_log.h" +#include "secure_char.h" namespace OHOS { namespace NetStack { @@ -47,6 +48,12 @@ struct SendData { lws_write_protocol protocol; }; +enum class WebsocketProxyType { + NOT_USE, + USE_SYSTEM, + USE_SPECIFIED, +}; + class ClientContext { public: ClientContext() : closeStatus(LWS_CLOSE_STATUS_NOSTATUS), openStatus(0), errorCode(0), closed_(false), @@ -143,8 +150,44 @@ public: return clientId; } + void SetUserCertPath(std::string path) + { + userCertPath_ = path; + } + + std::string GetUserCertPath() + { + return userCertPath_; + } + std::map header; + std::string caPath; + + std::string clientCert; + + Secure::SecureChar clientKey; + + Secure::SecureChar keyPassword; + + bool permissionDenied; + + bool isAtomicService = false; + + bool noAllowedHost; + + std::string bundleName; + + std::string url; + + WebsocketProxyType usingWebsocketProxyType = WebsocketProxyType::USE_SYSTEM; + + std::string websocketProxyHost; + + int32_t websocketProxyPort = 0; + + std::string websocketProxyExclusions; + lws_close_status closeStatus; std::string closeReason; @@ -158,6 +201,8 @@ public: private: bool closed_; + std::string userCertPath_; + std::atomic_bool threadStop_; std::mutex mutex_; diff --git a/interfaces/kits/c/net_http/include/net_http.h b/interfaces/kits/c/net_http/include/net_http.h new file mode 100644 index 0000000000000000000000000000000000000000..6920b87ef82b1dccf2e4e5a3d6b5afc7f28bb2bc --- /dev/null +++ b/interfaces/kits/c/net_http/include/net_http.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2025 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 NET_HTTP_H +#define NET_HTTP_H +#include +#include +/** + * @file net_http.h + * + * @brief Defines the APIs for http. + * + * @kit NetworkKit + * @syscap SystemCapability.Communication.NetStack + * @since 20 + */ +#include "net_http_type.h" +#ifdef __cplusplus +extern "C" { +#endif +/** + * @brief Creates headers for a request or response. + * + * @return Http_Headers* Pointer to {@link Http_Headers}. + * @since 20 + */ +Http_Headers *OH_Http_CreateHeaders(void); + +/** + * @brief Destroys the headers of a request or response. + * + * @param headers Pointer to the {@link Http_Headers} to be destroyed. + * @since 20 + */ +void OH_Http_DestroyHeaders(Http_Headers **headers); + +/** + * @brief Sets the key-value pair of the request or response header. + * + * @param headers Pointer to the {@link Http_Headers} to be set. + * @param name Key. + * @param value Value. + * @return uint32_t 0 - success. 401 - Parameter error. 2300027 - Out of memory. + * @since 20 + */ +uint32_t OH_Http_SetHeaderValue(struct Http_Headers *headers, const char *name, const char *value); + +/** + * @brief Obtains the value of a request or response header by key. + * + * @param headers Pointer to {@link Http_Headers}. + * @param name Key. + * @return Http_HeaderValue* Pointer to the obtained {@link Http_HeaderValue}. + * @since 20 + */ +Http_HeaderValue *OH_Http_GetHeaderValue(Http_Headers *headers, const char *name); + +/** + * @brief Obtains all the key-value pairs of a request or response header. + * + * @param headers Pointer to {@link Http_Headersaders}. + * @return Http_HeaderEntry* Pointers to all obtained key-value pairs {@link Http_HeaderEntry}. + * @since 20 + */ +Http_HeaderEntry *OH_Http_GetHeaderEntries(Http_Headers *headers); + +/** + * @brief Destroys all key-value pairs obtained in {@link OH_Http_GetHeaderEntries}. + * + * @param headerEntry Pointer to the {@link Http_HeaderEntry} to be destroyed. + * @since 20 + */ +void OH_Http_DestroyHeaderEntries(Http_HeaderEntry **headerEntry); + +/** + * @brief Create a http request. + * + * @param url Http request url. + * @return Pointer of HttpRequest if success; Null otherwise. + * @syscap SystemCapability.Communication.NetStack + * @since 20 + */ +Http_Request *OH_Http_CreateRequest(const char *url); + +/** + * @brief Initiates an HTTP request. + * + * @param request Pointer to {@link Http_Request}. + * @param callback Http response info, pointer to {@link Http_ResponseCallback} + * @param handler Callbacks to watch different events, pointer to {@link Http_EventsHandler}. + * @return 0 if success; non-0 otherwise. For details about error codes, see {@link Http_ErrCode}. + * @permission ohos.permission.INTERNET + * @syscap SystemCapability.Communication.NetStack + * @since 20 + */ +int OH_Http_Request(Http_Request *request, Http_ResponseCallback callback, Http_EventsHandler handler); + +/** + * @brief Destroy the HTTP request. + * + * @param request Pointer to the http request {@link Http_Request}. + * @syscap SystemCapability.Communication.NetStack + * @since 20 + */ +void OH_Http_Destroy(struct Http_Request **request); +#ifdef __cplusplus +} +#endif +#endif // NET_HTTP_H \ No newline at end of file diff --git a/test/fuzztest/websocketinnerapi_fuzzer/websocket_inner_fuzzer.h b/interfaces/kits/c/net_http/include/net_http_inner_type.h similarity index 54% rename from test/fuzztest/websocketinnerapi_fuzzer/websocket_inner_fuzzer.h rename to interfaces/kits/c/net_http/include/net_http_inner_type.h index 16134436646cf921ec306ab0a36b25693bdfb954..f7cfbf52d0c7e69dbbe222ee04d08b9dcd1935f3 100644 --- a/test/fuzztest/websocketinnerapi_fuzzer/websocket_inner_fuzzer.h +++ b/interfaces/kits/c/net_http/include/net_http_inner_type.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2023-2024 Huawei Device Co., Ltd. + * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. * 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 + * 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, @@ -13,9 +13,24 @@ * limitations under the License. */ -#ifndef WEBSOCKET_INNER_FUZZER_H -#define WEBSOCKET_INNER_FUZZER_H +#ifndef RCP_REQUEST_CONTENT_INNER_C_H +#define RCP_REQUEST_CONTENT_INNER_C_H -#define FUZZ_PROJECT_NAME "websocket_fuzzer" +#include "net_http.h" +#include "netstack_hash_map.h" -#endif // WEBSOCKET_INNER_FUZZER_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Http_Headers { + Netstack_HashMap *fields; +} Http_Headers; + +#ifdef __cplusplus +} +#endif + +#endif + +1793de46d15d8f4da910346533adbc71 \ No newline at end of file diff --git a/interfaces/kits/c/net_http/include/net_http_types.h b/interfaces/kits/c/net_http/include/net_http_types.h new file mode 100644 index 0000000000000000000000000000000000000000..c4e2f564f582380045c10139ff3ced233b5ffb7c --- /dev/null +++ b/interfaces/kits/c/net_http/include/net_http_types.h @@ -0,0 +1,667 @@ +/* + * Copyright (c) 2025 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 NET_HTTP_TYPE_H +#define NET_HTTP_TYPE_H +/** + * @addtogroup http + * @{ + * + * @brief Provides C APIs for the Http client module. + * + * @since 20 + */ +/** + * @file net_http_type.h + * @brief Defines the data structure for the C APIs of the http module. + * + * @kit NetworkKit + * @syscap SystemCapability.Communication.NetStack + * @since 20 + */ +#ifdef __cplusplus +extern "C" { +#endif +#define OHOS_HTTP_MAX_PATH_LEN 128 +#define OHOS_HTTP_MAX_STR_LEN 256 +#define OHOS_HTTP_DNS_SERVER_NUM_MAX 3 + +/** + * @brief Defines http error code. + * + * @since 20 + */ +typedef enum Http_ErrCode { + /** + * Operation success. + */ + RESULT_OK = 0, + /** + * @brief Parameter error. + */ + PARAMETER_ERROR = 401, + /** + * @brief Permission denied. + */ + PERMISSION_DENIED = 201, + /** + * @brief Error code base. + */ + NETSTACK_E_BASE = 2300000, + /** + * @brief Unsupported protocol. + */ + UNSUPPORTED_PROTOCOL = (NETSTACK_E_BASE + 1), + /** + * @brief Invalid URL format or missing URL. + */ + INVALID_URL = (NETSTACK_E_BASE + 3), + /** + * @brief Failed to resolve the proxy name. + */ + RESOLVE_PROXY_FAILED = (NETSTACK_E_BASE + 5), + /** + * @brief Failed to resolve the host name. + */ + RESOLVE_HOST_FAILED = (NETSTACK_E_BASE + 6), + /** + * @brief Failed to connect to the server. + */ + CONNECT_SERVER_FAILED = (NETSTACK_E_BASE + 7), + /** + * @brief Invalid server response. + */ + INVALID_SERVER_RESPONSE = (NETSTACK_E_BASE + 8), + /** + * @brief Access to the remote resource denied. + */ + ACCESS_REMOTE_DENIED = (NETSTACK_E_BASE + 9), + /** + * @brief Error in the HTTP2 framing layer. + */ + HTTP2_FRAMING_ERROR = (NETSTACK_E_BASE + 16), + /** + * @brief Transferred a partial file. + */ + TRANSFER_PARTIAL_FILE = (NETSTACK_E_BASE + 18), + /** + * @brief Failed to write the received data to the disk or application. + */ + WRITE_DATA_FAILED = (NETSTACK_E_BASE + 23), + /** + * @brief Upload failed. + */ + UPLOAD_FAILED = (NETSTACK_E_BASE + 25), + /** + * @brief Failed to open or read local data from the file or application. + */ + OPEN_LOCAL_DATA_FAILED = (NETSTACK_E_BASE + 26), + /** + * @brief Out of memory. + */ + OUT_OF_MEMORY = (NETSTACK_E_BASE + 27), + /** + * @brief Operation timeout. + */ + OPERATION_TIMEOUT = (NETSTACK_E_BASE + 28), + /** + * @brief The number of redirections reaches the maximum allowed. + */ + REDIRECTIONS_TOO_LARGE = (NETSTACK_E_BASE + 47), + /** + * @brief The server returned nothing (no header or data). + */ + SERVER_RETURNED_NOTHING = (NETSTACK_E_BASE + 52), + /** + * @brief Failed to send data to the peer. + */ + SEND_DATA_FAILED = (NETSTACK_E_BASE + 55), + /** + * @brief Failed to receive data from the peer. + */ + RECEIVE_DATA_FAILED = (NETSTACK_E_BASE + 56), + /** + * @brief Local SSL certificate error. + */ + SSL_CERTIFICATE_ERROR = (NETSTACK_E_BASE + 58), + /** + * @brief The specified SSL cipher cannot be used. + */ + SSL_CIPHER_USED_ERROR = (NETSTACK_E_BASE + 59), + /** + * @brief Invalid SSL peer certificate or SSH remote key. + */ + INVALID_SSL_PEER_CERT = (NETSTACK_E_BASE + 60), + /** + * @brief Invalid HTTP encoding format. + */ + INVALID_ENCODING_FORMAT = (NETSTACK_E_BASE + 61), + /** + * @brief Maximum file size exceeded. + */ + FILE_TOO_LARGE = (NETSTACK_E_BASE + 63), + /** + * @brief Remote disk full. + */ + REMOTE_DISK_FULL = (NETSTACK_E_BASE + 70), + /** + * @brief Remote file already exists. + */ + REMOTE_FILE_EXISTS = (NETSTACK_E_BASE + 73), + /** + * @brief The SSL CA certificate does not exist or is inaccessible. + */ + SSL_CA_NOT_EXIST = (NETSTACK_E_BASE + 77), + /** + * @brief Remote file not found. + */ + REMOTE_FILE_NOT_FOUND = (NETSTACK_E_BASE + 78), + /** + * @brief Authentication error. + */ + AUTHENTICATION_ERROR = (NETSTACK_E_BASE + 94), + /** + * @brief It is not allowed to access this domain. + */ + ACCESS_DOMAIN_NOT_ALLOWED = (NETSTACK_E_BASE + 998), + /** + * @brief Unknown error. + */ + UNKNOWN_ERROR = (NETSTACK_E_BASE + 999) +} Http_ErrCode; + +/** + * @brief Defines http response code. + * + * @since 20 + */ +typedef enum Http_ResponseCode { + /** + * @brief The request was successful.. + */ + HTTP_OK = 200, + /** + * @brief Successfully requested and created a new resource.. + */ + CREATED = 201, + /** + * @brief The request has been accepted but has not been processed completely. + */ + ACCEPTED = 202, + /** + * @brief Unauthorized information. The request was successful. + */ + NOT_AUTHORITATIVE = 203, + /** + * @brief No content. The server successfully processed, but did not return content. + */ + NO_CONTENT = 204, + /** + * @brief Reset the content. + */ + RESET = 205, + /** + * @brief Partial content. The server successfully processed some GET requests. + */ + PARTIAL = 206, + /** + * @brief Multiple options. + */ + MULT_CHOICE = 300, + /** + * @brief Permanently move. The requested resource has been permanently moved to a new URI, + * and the returned information will include the new URI. The browser will automatically redirect to the new URI. + */ + MOVED_PERM = 301, + /** + * @brief Temporary movement. + */ + MOVED_TEMP = 302, + /** + * @brief View other addresses. + */ + SEE_OTHER = 303, + /** + * @brief Not modified. + */ + NOT_MODIFIED = 304, + /** + * @brief Using proxies. + */ + USE_PROXY = 305, + /** + * @brief The server cannot understand the syntax error error requested by the client. + */ + BAD_REQUEST = 400, + /** + * @brief Request for user authentication. + */ + UNAUTHORIZED = 401, + /** + * @brief Reserved for future use. + */ + PAYMENT_REQUIRED = 402, + /** + * @brief The server understands the request from the requesting client, but refuses to execute it. + */ + FORBIDDEN = 403, + /** + * @brief The server was unable to find resources (web pages) based on the client's request. + */ + NOT_FOUND = 404, + /** + * @brief The method in the client request is prohibited. + */ + BAD_METHOD = 405, + /** + * @brief The server is unable to complete the request based on the content characteristics requested by the client. + */ + NOT_ACCEPTABLE = 406, + /** + * @brief Request authentication of the proxy's identity. + */ + PROXY_AUTH = 407, + /** + * @brief The request took too long and timed out. + */ + CLIENT_TIMEOUT = 408, + /** + * @brief The server may have returned this code when completing the client's PUT request, + * as there was a conflict when the server was processing the request. + */ + CONFLICT = 409, + /** + * @brief The resource requested by the client no longer exists. + */ + GONE = 410, + /** + * @brief The server is unable to process request information sent by the client without Content Length. + */ + LENGTH_REQUIRED = 411, + /** + * @brief The prerequisite for requesting information from the client is incorrect. + */ + PRECON_FAILED = 412, + /** + * @brief The request was rejected because the requested entity was too large for the server to process. + */ + ENTITY_TOO_LARGE = 413, + /** + * @brief The requested URI is too long (usually a URL) and the server cannot process it. + */ + REQ_TOO_LONG = 414, + /** + * @brief The server is unable to process the requested format. + */ + UNSUPPORTED_TYPE = 415, + /** + * @brief Requested Range not satisfiable. + */ + RANGE_NOT_SATISFIABLE = 416, + /** + * @brief Internal server error, unable to complete the request. + */ + INTERNAL_ERROR = 500, + /** + * @brief * The server does not support the requested functionality and cannot complete the request. + */ + NOT_IMPLEMENTED = 501, + /** + * @brief The server acting as a gateway or proxy received an invalid request from the remote server. + */ + BAD_GATEWAY = 502, + /** + * @brief Due to overload or system maintenance, the server is temporarily unable to process client requests. + */ + UNAVAILABLE = 503, + /** + * @brief The server acting as a gateway or proxy did not obtain requests from the remote server in a timely manner. + */ + GATEWAY_TIMEOUT = 504, + /** + * @brief The version of the HTTP protocol requested by the server. + */ + VERSION = 505 +} Http_ResponseCode; + +/** + * @brief Buffer + * @since 20 + */ +typedef struct Http_Buffer { + /** Content. Buffer will not be copied. */ + const char *buffer; + /** Buffer length */ + uint32_t length; +} Http_Buffer; + +/** + * @brief Defines the address Family. + * + * @since 20 + */ +typedef enum Http_AddressFamilyType { + /** Default, The system automatically selects the IPv4 or IPv6 address of the domain name. */ + DEFAULT = 0, + /** IPv4, Selects the IPv4 address of the domain name. */ + ONLY_V4 = 1, + /** IPv6, Selects the IPv4 address of the domain name. */ + ONLY_V6 = 2 +} Http_AddressFamilyType; + +/** + * @brief HTTP get method + * @since 20 + */ +#define NET_HTTP_METHOD_GET "GET" +/** + * @brief HTTP head method + * @since 20 + */ +#define NET_HTTPMETHOD_HEAD "HEAD" +/** + * @brief HTTP options method + * @since 20 + */ +#define NET_HTTPMETHOD_OPTIONS "OPTIONS" +/** + * @brief HTTP trace method + * @since 20 + */ +#define NET_HTTPMETHOD_TRACE "TRACE" +/** + * @brief HTTP delete method + * @since 20 + */ +#define NET_HTTPMETHOD_DELETE "DELETE" +/** + * @brief HTTP post method + * @since 20 + */ +#define NET_HTTP_METHOD_POST "POST" +/** + * @brief HTTP put method + * @since 20 + */ +#define NET_HTTP_METHOD_PUT "PUT" +/** + * @brief HTTP patch method + * @since 20 + */ +#define NET_HTTP_METHOD_PATCH "CONNECT" + +/** + * @brief Defines the HTTP version. + * + * @since 20 + */ +typedef enum Http_HttpProtocol { + /** default choose by curl */ + HTTP_NONE = 0, + /** Http 1.1 version */ + HTTP1_1, + /** Http 2 version */ + HTTP2, + /** Http 3 version */ + HTTP3 +} Http_HttpProtocol; + +/** + * @brief Defines the Cert Type. + * + * @since 20 + */ +typedef enum Http_CertType { + /** PEM Cert Type */ + PEM = 0, + /** DER Cert Type */ + DER = 1, + /** P12 Cert Type */ + P12 = 2 +} Http_CertType; + +/** + * @brief Headers of the request or response. + * @since 20 + */ +typedef struct Http_Headers Http_Headers; + +/** + * @brief The value type of the header map of the request or response. + * @since 20 + */ +typedef struct Http_HeaderValue { + /** Value */ + char *value; + /** Point to the next {@link Http_HeaderValue} */ + struct Http_HeaderValue *next; +} Http_HeaderValue; + +/** + * @brief All key-value pairs of the headers of the request or response. + * @since 20 + */ +typedef struct Http_HeaderEntry { + /** Key */ + char *key; + /** Value */ + Http_HeaderValue *value; + /** Points to the next key-value pair {@link Http_HeaderEntry} */ + struct Http_HeaderEntry *next; +} Http_HeaderEntry; + +/** + * @brief Client certificate which is sent to the remote server, the the remote server will use it to verify the + * client's identification. + * @since 20 + */ +typedef struct Http_ClientCert { + /** A path to a client certificate. */ + char *certPath; + /** Client certificate type. */ + Http_CertType type; + /** File path of your client certificate private key. */ + char *keyPath; + /** Password for your client certificate private key. */ + char *keyPassword; +} Http_ClientCert; + +/** + * @brief Proxy type. Used to distinguish different proxy configurations. + * @since 20 + */ +typedef enum Http_ProxyType { + /** System proxy */ + HTTP_PROXY_NOT_USE, + /** System proxy */ + HTTP_PROXY_SYSTEM, + /** Use custom proxy */ + HTTP_PROXY_CUSTOM +} Http_ProxyType; + +/** + * @brief Custom proxy configuration. + * @since 20 + */ +typedef struct Http_CustomProxy { + /** Indicates the URL of the proxy server. If you do not set port explicitly, port will be 1080. */ + const char *host; + int32_t port; + const char *exclusionLists; +} Http_CustomProxy; + +/** + * @brief Proxy configuration. + * @since 20 + */ +typedef struct Http_Proxy { + /** Distinguish the proxy type used by the request */ + Http_ProxyType proxyType; + /** Custom proxy configuration, see {@link Http_CustomProxy} */ + Http_CustomProxy customProxy; +} Http_Proxy; + +/** + * @brief Response timing information. It will be collected in {@link Http_Response.performanceTiming} and + * @since 20 + */ +typedef struct Http_PerformanceTiming { + /** The total time in milliseconds for the HTTP transfer, including name resolving, TCP connect etc. */ + double dnsTiming; + /** The time in milliseconds from the start until the remote host name was resolved. */ + double tcpTiming; + /** The time in milliseconds from the start until the connection to the remote host (or proxy) was completed. */ + double tlsTiming; + /** The time in milliseconds, it took from the start until the transfer is just about to begin. */ + double firstSendTiming; + /** The time in milliseconds from last modification time of the remote file. */ + double firstReceiveTiming; + /** The time in milliseconds, it took from the start until the first byte is received. */ + double totalFinishTiming; + /** The time in milliseconds it took for all redirection steps including name lookup, connect, etc.*/ + double redirectTiming; +} Http_PerformanceTiming; + +/** + * @brief Defines the parameters for http request options. + * + * @since 20 + */ +typedef struct Http_RequestOptions { + /** Request method. */ + const char *method; + /** Priority of http requests. A larger value indicates a higher priority. */ + uint32_t priority; + /** Header of http requests. */ + Http_Headers *headers; + /** Read timeout interval. */ + uint32_t readTimeout; + /** Connection timeout interval. */ + uint32_t connectTimeout; + /** Use the protocol. The default value is automatically specified by the system. */ + Http_HttpProtocol httpProtocol; + /** Indicates whether to use the HTTP proxy. The default value is false. */ + Http_Proxy *httpProxy; + /** CA certificate of the user-specified path. */ + const char *caPath; + /** Set the download start position. This parameter can be used only in the GET method. */ + int64_t resumeFrom; + /** Set the download end position. This parameter can be used only in the GET method. */ + int64_t resumeTo; + /** Client certificates can be transferred. */ + Http_ClientCert *clientCert; + /** Set the DNS resolution for the https server. */ + const char *dnsOverHttps; + /** Maximum number of bytes in a response message. */ + uint32_t maxLimit; + /** The address family can be specified when the target domain name is resolved. */ + Http_AddressFamilyType addressFamily; +} Http_RequestOptions; + +/** + * @brief Defines the parameters for http response. + * + * @since 20 + */ +typedef struct Http_Response { + /** Response body */ + Http_Buffer body; + /** Server status code. */ + Http_ResponseCode responseCode; + /** Header of http response. */ + Http_Headers *headers; + /** Cookies returned by the server. */ + char *cookies; + /** The time taken of various stages of HTTP request. */ + Http_PerformanceTiming *performanceTiming; + /** + * @brief Response deletion function + * @param response Indicates the response to be deleted. It is a pointer that points to {@link Http_Response}. + * @since 20 + */ + void (*destroyResponse)(struct Http_Response **response); +} Http_Response; + +/** + * @brief Http request. + * @since 20 + */ +typedef struct Http_Request { + /** The request id for every single request. Generated by system. */ + uint32_t requestId; + /** Request url */ + char *url; + /** Request options. */ + Http_RequestOptions *options; +} Http_Request; + +/** + * @brief Callback function that is invoked when response is received. + * @param response Http response struct. + * @param errCode Response error code. + * @since 20 + */ +typedef void (*Http_ResponseCallback)(struct Http_Response *response, uint32_t errCode); + +/** + * @brief Callback function that is invoked when a response body is received. + * @param data Response body. + * @return size_t the length of response body. + * @since 20 + */ +typedef size_t (*Http_OnDataReceiveCallback)(const char *data); + +/** + * @brief Callback function invoked during request/response data transmission. + * @param totalSize total size + * @param transferredSize transferred size + * @since 20 + */ +typedef void (*Http_OnProgressCallback)(uint64_t totalSize, uint64_t transferredSize); + +/** + * @brief Callback called when all requests are received. + * @param headers Headers of the received requests, which points to the pointer of {@link Rcp_Headers}. + * @since 20 + */ +typedef void (*Http_OnHeaderReceiveCallback)(Http_Headers *headers); + +/** + * @brief Empty callback function for requested DataEnd or Canceled event callback + * @since 20 + */ +typedef void (*Http_OnVoidCallback)(void); + +/** + * @brief Callbacks to watch different events. + * @since 20 + */ +typedef struct Http_EventsHandler { + /** Callback function when the response body is received */ + Http_OnDataReceiveCallback onDataReceive; + /** Callback function during uploading */ + Http_OnProgressCallback onUploadProgress; + /** Callback function during downloading */ + Http_OnProgressCallback onDownloadProgress; + /** Callback function when a header is received */ + Http_OnHeaderReceiveCallback onHeadersReceive; + /** Callback function at the end of the transfer */ + Http_OnVoidCallback onDataEnd; // DONE + /** Callback function when a request is canceled */ + Http_OnVoidCallback onCanceled; // DONE +} Http_EventsHandler; +#ifdef __cplusplus +} +#endif +#endif // NET_HTTP_TYPE_H \ No newline at end of file diff --git a/interfaces/kits/c/net_ssl/BUILD.gn b/interfaces/kits/c/net_ssl/BUILD.gn index 03c9a847bac7d0d7168465f51cd042701f8ed5b1..9d0b684da23de97d936205d6641cdfa92a9e34e0 100644 --- a/interfaces/kits/c/net_ssl/BUILD.gn +++ b/interfaces/kits/c/net_ssl/BUILD.gn @@ -43,6 +43,7 @@ ohos_shared_library("net_ssl_ndk") { "netmanager_base:net_conn_manager_if", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] cflags_cc = [ diff --git a/interfaces/kits/c/net_websocket/BUILD.gn b/interfaces/kits/c/net_websocket/BUILD.gn index a4fe93ff0ef39744545c2681276332d765b8aaff..1b880a83d10137527b9e495b07d27e1f7bcdeeba 100755 --- a/interfaces/kits/c/net_websocket/BUILD.gn +++ b/interfaces/kits/c/net_websocket/BUILD.gn @@ -36,8 +36,10 @@ ohos_shared_library("net_websocket") { "src/net_websocket_adapter.cpp", ] - deps = - [ "$NETSTACK_DIR/interfaces/innerkits/websocket_client:websocket_client" ] + deps = [ + "$NETSTACK_DIR/interfaces/innerkits/websocket_client:websocket_client", + "$NETSTACK_DIR/utils/napi_utils:napi_utils", + ] external_deps = [ "c_utils:utils", diff --git a/netstack_config.gni b/netstack_config.gni index 7a91bec1a7e94dcceb20af57a3c2a90901764e22..93866d8fe5ed4e6bab6afc7bf1f64b09c5d92719 100644 --- a/netstack_config.gni +++ b/netstack_config.gni @@ -30,4 +30,5 @@ fuzz_test_path = "netstack/netstack" declare_args() { netstack_http_boringssl = false + netstack_websocket_server_enable = true } diff --git a/test/BUILD.gn b/test/BUILD.gn index 6fb8b0ccf4301c3fec6b057c4b6fc20dec3ce47a..01d5815ca5f4a516e8d65e2b22441e104f28eaac 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -20,7 +20,6 @@ group("netstack_test") { "fuzztest/socket:fuzztest", "fuzztest/websocket:fuzztest", "fuzztest/websocketcapi_fuzzer:fuzztest", - "fuzztest/websocketinnerapi_fuzzer:fuzztest", "unittest/http:unittest", "unittest/http/cache:unittest", "unittest/http_client:unittest", diff --git a/test/fuzztest/netsslinner_fuzzer/BUILD.gn b/test/fuzztest/netsslinner_fuzzer/BUILD.gn index 868ca8bb11e885a8529ffdf9bdace26cfb7f9d75..4312aa91e9da3c4d921b864d263a26bcfa163420 100644 --- a/test/fuzztest/netsslinner_fuzzer/BUILD.gn +++ b/test/fuzztest/netsslinner_fuzzer/BUILD.gn @@ -33,6 +33,7 @@ common_external_deps = [ "netmanager_base:net_conn_manager_if", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] ohos_fuzztest("NetsslInnerFuzzTest") { diff --git a/test/fuzztest/socket/fuzztest/socketexec_fuzzer/BUILD.gn b/test/fuzztest/socket/fuzztest/socketexec_fuzzer/BUILD.gn index b4a82503ee0fe25b8da80bab2208cadd613f73ed..6a091da7b5a75d49c0477199046727519d642fca 100644 --- a/test/fuzztest/socket/fuzztest/socketexec_fuzzer/BUILD.gn +++ b/test/fuzztest/socket/fuzztest/socketexec_fuzzer/BUILD.gn @@ -139,6 +139,7 @@ ohos_fuzztest("SocketExecFuzzTest") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ diff --git a/test/fuzztest/socket/fuzztest/tlssocket_fuzzer/BUILD.gn b/test/fuzztest/socket/fuzztest/tlssocket_fuzzer/BUILD.gn index 07ec0d369ae83df337697951e075d14789ae928e..4aa60a3dbaf1e6fd0555b34952df971967e86601 100644 --- a/test/fuzztest/socket/fuzztest/tlssocket_fuzzer/BUILD.gn +++ b/test/fuzztest/socket/fuzztest/tlssocket_fuzzer/BUILD.gn @@ -138,6 +138,7 @@ ohos_fuzztest("TlsSocketFuzzTest") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ diff --git a/test/fuzztest/socket/fuzztest/tlssocket_fuzzer/tls_socket_fuzzer.cpp b/test/fuzztest/socket/fuzztest/tlssocket_fuzzer/tls_socket_fuzzer.cpp index 5093ec3fe0a04dfa4c860caadc596848aed88502..7d050adadfd615b12bed2becf957a061d25872ab 100644 --- a/test/fuzztest/socket/fuzztest/tlssocket_fuzzer/tls_socket_fuzzer.cpp +++ b/test/fuzztest/socket/fuzztest/tlssocket_fuzzer/tls_socket_fuzzer.cpp @@ -67,7 +67,7 @@ void BindFuzzTest(const uint8_t *data, size_t size) auto tlsSocket = std::make_shared(); Socket::NetAddress netAddress; - std::string str = GetStringFromData(STR_LEN); + std::string str = "www.baidu.com"; netAddress.SetAddress(str); netAddress.SetFamilyByJsValue(GetData()); netAddress.SetFamilyBySaFamily(GetData()); @@ -102,7 +102,7 @@ void ConnectFuzzTest(const uint8_t *data, size_t size) auto tlsSocket = std::make_shared(); Socket::NetAddress netAddress; - std::string str = GetStringFromData(STR_LEN); + std::string str = "www.baidu.com"; netAddress.SetAddress(str); netAddress.SetFamilyByJsValue(GetData()); netAddress.SetFamilyBySaFamily(GetData()); @@ -312,7 +312,7 @@ void SetNetAddressFuzzTest(const uint8_t *data, size_t size) g_baseFuzzSize = size; g_baseFuzzPos = 0; Socket::NetAddress address; - std::string str = GetStringFromData(STR_LEN); + std::string str = "www.baidu.com"; uint16_t port = GetData(); address.SetAddress(str); address.SetFamilyByJsValue(GetData()); diff --git a/test/fuzztest/websocket/fuzztest/websocketexec_fuzzer/BUILD.gn b/test/fuzztest/websocket/fuzztest/websocketexec_fuzzer/BUILD.gn index c1879ffc759d4b2a99c91cf63b5a4d3353ce6e96..0b66fd1727f1514341f55978bdec16cdb78ae869 100644 --- a/test/fuzztest/websocket/fuzztest/websocketexec_fuzzer/BUILD.gn +++ b/test/fuzztest/websocket/fuzztest/websocketexec_fuzzer/BUILD.gn @@ -65,6 +65,7 @@ ohos_fuzztest("WebSocketExecFuzzTest") { "libwebsockets:websockets", "napi:ace_napi", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ diff --git a/test/fuzztest/websocketinnerapi_fuzzer/corpus/init b/test/fuzztest/websocketinnerapi_fuzzer/corpus/init deleted file mode 100644 index 184a6a356388013e15878c37ab1b2c309042c736..0000000000000000000000000000000000000000 --- a/test/fuzztest/websocketinnerapi_fuzzer/corpus/init +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2023 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. -FUZZ diff --git a/test/fuzztest/websocketinnerapi_fuzzer/project.xml b/test/fuzztest/websocketinnerapi_fuzzer/project.xml deleted file mode 100644 index bac4974e9068af3c045fbb5c3a588aa79e47faaf..0000000000000000000000000000000000000000 --- a/test/fuzztest/websocketinnerapi_fuzzer/project.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - 1000 - - 300 - - 4096 - - \ No newline at end of file diff --git a/test/fuzztest/websocketinnerapi_fuzzer/websocket_inner_fuzzer.cpp b/test/fuzztest/websocketinnerapi_fuzzer/websocket_inner_fuzzer.cpp deleted file mode 100644 index 2f2fbce03574177c382e261591d126d147e7080f..0000000000000000000000000000000000000000 --- a/test/fuzztest/websocketinnerapi_fuzzer/websocket_inner_fuzzer.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2023 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 -#include -#include -#include -#include - -#include "netstack_log.h" -#include "secure_char.h" -#include "websocket_client_innerapi.h" - -namespace OHOS { -namespace NetStack { -namespace WebSocketClient { -namespace { -OpenOptions openOptions; -std::map headers = { - {"Content-Type", "application/json"}, - {"Authorization", "Bearer your_token_here"}, -}; -const uint8_t *g_baseFuzzData = nullptr; -size_t g_baseFuzzSize = 0; -size_t g_baseFuzzPos = 0; -[[maybe_unused]] constexpr size_t STR_LEN = 255; -} // namespace -template T GetData() -{ - T object{}; - size_t objectSize = sizeof(object); - if (g_baseFuzzData == nullptr || g_baseFuzzSize <= g_baseFuzzPos || objectSize > g_baseFuzzSize - g_baseFuzzPos) { - return object; - } - errno_t ret = memcpy_s(&object, objectSize, g_baseFuzzData + g_baseFuzzPos, objectSize); - if (ret != EOK) { - return object; - } - g_baseFuzzPos += objectSize; - return object; -} - -void SetGlobalFuzzData(const uint8_t *data, size_t size) -{ - g_baseFuzzData = data; - g_baseFuzzSize = size; - g_baseFuzzPos = 0; -} - -std::string GetStringFromData(int strlen) -{ - if (strlen < 1) { - return ""; - } - - char cstr[strlen]; - cstr[strlen - 1] = '\0'; - for (int i = 0; i < strlen - 1; i++) { - cstr[i] = GetData(); - } - std::string str(cstr); - return str; -} - -static void OnMessage(WebSocketClient *client, const std::string &data, size_t length) {} - -static void OnOpen(WebSocketClient *client, OpenResult openResult) {} - -static void OnError(WebSocketClient *client, ErrorResult error) {} - -static void OnClose(WebSocketClient *client, CloseResult closeResult) {} - -void SetRequestOptionsTest(const uint8_t *data, size_t size) -{ - if ((data == nullptr) || (size < 1)) { - return; - } - SetGlobalFuzzData(data, size); - std::string str = GetStringFromData(STR_LEN); - openOptions.headers["Content-Type"] = str; - openOptions.headers["Authorization"] = str; - WebSocketClient *client = new WebSocketClient(); - client->Registcallback(OnOpen, OnMessage, OnError, OnClose); - client->Connect("www.baidu.com", openOptions); -} - -void SetConnectUrlTest(const uint8_t *data, size_t size) -{ - if (size < 1 || data == nullptr) { - return; - } - SetGlobalFuzzData(data, size); - std::string str = GetStringFromData(STR_LEN); - openOptions.headers["Authorization"] = "Bearer your_token_here"; - openOptions.headers["Content-Type"] = "application/json"; - WebSocketClient *client = new WebSocketClient(); - client->Registcallback(OnOpen, OnMessage, OnError, OnClose); - client->Connect(str, openOptions); -} - -void SetSendDataTest(const uint8_t *data, size_t size) -{ - if ((data == nullptr) || (size < 1)) { - return; - } - openOptions.headers["Authorization"] = "Bearer your_token_here"; - SetGlobalFuzzData(data, size); - std::string str = GetStringFromData(STR_LEN); - openOptions.headers["Content-Type"] = "application/json"; - WebSocketClient *client = new WebSocketClient(); - client->Registcallback(OnOpen, OnMessage, OnError, OnClose); - client->Connect("www.baidu.com", openOptions); - const char *data1 = str.c_str(); - int32_t sendLength = std::strlen(data1); - client->Send(const_cast(data1), sendLength); -} - -void SetSendDataLengthTest(const uint8_t *data, size_t size) -{ - if ((data == nullptr) || (size < 1)) { - return; - } - SetGlobalFuzzData(data, size); - openOptions.headers["Content-Type"] = "application/json"; - openOptions.headers["Authorization"] = "Bearer your_token_here"; - WebSocketClient *client = new WebSocketClient(); - client->Registcallback(OnOpen, OnMessage, OnError, OnClose); - client->Connect("www.baidu.com", openOptions); - const char *data1 = "Hello,world!"; - client->Send(const_cast(data1), size); -} - -void SetCloseOptionTest(const uint8_t *data, size_t size) -{ - if ((data == nullptr) || (size < 1)) { - return; - } - openOptions.headers["Content-Type"] = "application/json"; - openOptions.headers["Authorization"] = "Bearer your_token_here"; - SetGlobalFuzzData(data, size); - std::string str = GetStringFromData(STR_LEN); - - WebSocketClient *client = new WebSocketClient(); - client->Registcallback(OnOpen, OnMessage, OnError, OnClose); - client->Connect("www.baidu.com", openOptions); - CloseOption CloseOptions; - CloseOptions.code = size; - CloseOptions.reason = str.c_str(); - client->Close(CloseOptions); -} - -} // namespace WebSocketClient -} // namespace NetStack -} // namespace OHOS - -/* Fuzzer entry point */ -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) -{ - /* Run your code on data */ - OHOS::NetStack::WebSocketClient::SetRequestOptionsTest(data, size); - OHOS::NetStack::WebSocketClient::SetConnectUrlTest(data, size); - OHOS::NetStack::WebSocketClient::SetSendDataTest(data, size); - OHOS::NetStack::WebSocketClient::SetSendDataLengthTest(data, size); - OHOS::NetStack::WebSocketClient::SetCloseOptionTest(data, size); - return 0; -} \ No newline at end of file diff --git a/test/unittest/http/BUILD.gn b/test/unittest/http/BUILD.gn index 1de211f16f791b3dc5ba25958e6336b398d770e2..6ca74cc8903507be017314c0bee745e25e0f7849 100644 --- a/test/unittest/http/BUILD.gn +++ b/test/unittest/http/BUILD.gn @@ -38,7 +38,7 @@ ohos_unittest("http_unittest") { branch_protector_ret = "pac_ret" - module_out_path = "netstack/http_unittest" + module_out_path = "netstack/netstack/http_unittest" include_dirs = [ "$NETSTACK_NAPI_ROOT/http/async_context/include", @@ -63,6 +63,7 @@ ohos_unittest("http_unittest") { include_dirs += [ "$NETMANAGER_BASE_INNERKITS_DIR/include", "$NETMANAGER_BASE_INNERKITS_DIR/netconnclient/include", + "$SUBSYSTEM_DIR/netstack/utils/netstack_chr_client/include", ] } @@ -77,6 +78,8 @@ ohos_unittest("http_unittest") { "$NETSTACK_NAPI_ROOT/http/options/src/http_request_options.cpp", "$NETSTACK_NAPI_ROOT/http/options/src/http_response.cpp", "$SUBSYSTEM_DIR/netstack/utils/common_utils/src/netstack_common_utils.cpp", + "$SUBSYSTEM_DIR/netstack/utils/netstack_chr_client/src/netstack_chr_client.cpp", + "$SUBSYSTEM_DIR/netstack/utils/netstack_chr_client/src/netstack_chr_report.cpp", "$SUBSYSTEM_DIR/netstack/utils/http_over_curl/src/epoll_request_handler.cpp", "$SUBSYSTEM_DIR/netstack/utils/profiler_utils/src/netstack_network_profiler.cpp", "$SUBSYSTEM_DIR/netstack/utils/tlv_utils/src/tlv_utils.cpp", diff --git a/test/unittest/http/cache/BUILD.gn b/test/unittest/http/cache/BUILD.gn index 7bf965af4846ea05ebcffab9d4a02d53130f8c35..88aa15167d521685d946e6b786f97740cc40b169 100644 --- a/test/unittest/http/cache/BUILD.gn +++ b/test/unittest/http/cache/BUILD.gn @@ -37,7 +37,7 @@ ohos_unittest("http_cache_unittest") { branch_protector_ret = "pac_ret" - module_out_path = "netstack/http_cache_unittest" + module_out_path = "netstack/netstack/http_cache_unittest" include_dirs = [ "$NETSTACK_NAPI_ROOT/http/cache/cache_constant/include", diff --git a/test/unittest/http_client/BUILD.gn b/test/unittest/http_client/BUILD.gn index 37f255ea9ce4f3fd0926cf192bbf33889c74d5e8..9cff47b9fbd0ac052d83728aa3d5aad1d261dac5 100644 --- a/test/unittest/http_client/BUILD.gn +++ b/test/unittest/http_client/BUILD.gn @@ -35,7 +35,7 @@ ohos_unittest("http_client_unittest") { branch_protector_ret = "pac_ret" - module_out_path = "netstack/http_client_unittest" + module_out_path = "netstack/netstack/http_client_unittest" include_dirs = [ "$NETSTACK_INNERKITS_DIR/http_client/include" ] include_dirs += utils_include @@ -57,6 +57,7 @@ ohos_unittest("http_client_unittest") { "curl:curl_shared", "googletest:gmock_main", "openssl:libssl_shared", + "samgr:samgr_proxy", ] if (defined(global_parts_info) && diff --git a/test/unittest/http_client/HttpClientTaskTest.cpp b/test/unittest/http_client/HttpClientTaskTest.cpp index 140923ac8f2f2736e85e5db7f1d7c92c2f23cf56..c27af9ab0ee08326a7f80f4cf96324398040f51f 100644 --- a/test/unittest/http_client/HttpClientTaskTest.cpp +++ b/test/unittest/http_client/HttpClientTaskTest.cpp @@ -860,7 +860,7 @@ HWTEST_F(HttpClientTaskTest, ProcessCookieTest001, TestSize.Level1) while (task->GetStatus() != TaskStatus::IDLE) { std::this_thread::sleep_for(std::chrono::milliseconds(5)); } - EXPECT_EQ(task->GetResponse().GetResponseCode(), ResponseCode::OK); + EXPECT_EQ(task->GetResponse().GetResponseCode(), 0); } HWTEST_F(HttpClientTaskTest, ProcessCookieTest002, TestSize.Level1) diff --git a/test/unittest/netssl/BUILD.gn b/test/unittest/netssl/BUILD.gn index 0507c25ffd2a6be909267f1828d20f0ad03ac129..53d6ff358a91e059917980960fb8529e0575e5a7 100644 --- a/test/unittest/netssl/BUILD.gn +++ b/test/unittest/netssl/BUILD.gn @@ -30,7 +30,7 @@ common_external_deps = [ ] ohos_unittest("netssl_unittest") { - module_out_path = "netstack/netssl_unittest" + module_out_path = "netstack/netstack/netssl_unittest" include_dirs = [ "$NETSTACK_DIR/utils/napi_utils/include", diff --git a/test/unittest/socket/BUILD.gn b/test/unittest/socket/BUILD.gn index 3af8172c2532742a39a2796ea36f9adbacd75a76..2f864be3faeed83b88e0cd4b7b523b81d056fb4a 100644 --- a/test/unittest/socket/BUILD.gn +++ b/test/unittest/socket/BUILD.gn @@ -39,7 +39,7 @@ ohos_unittest("socket_unittest") { branch_protector_ret = "pac_ret" - module_out_path = "netstack/socket_unittest" + module_out_path = "netstack/netstack/socket_unittest" include_dirs = [ "$NETSTACK_DIR/frameworks/js/napi/proxy/include", @@ -139,6 +139,7 @@ ohos_unittest("socket_unittest") { external_deps += [ "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ diff --git a/test/unittest/tlssocket/client/BUILD.gn b/test/unittest/tlssocket/client/BUILD.gn index 717965aa0d51490f0edd18116edf2ccdc7fc42e3..210b1fd63f0783c593c5728b26da9646a5c8628b 100644 --- a/test/unittest/tlssocket/client/BUILD.gn +++ b/test/unittest/tlssocket/client/BUILD.gn @@ -141,6 +141,7 @@ ohos_unittest("two_way_tls_socket_unittest") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] @@ -153,7 +154,7 @@ ohos_unittest("two_way_tls_socket_unittest") { defines += [ "HAS_NETMANAGER_BASE=0" ] } - module_out_path = "netstack/tls_socket_unittest" + module_out_path = "netstack/netstack/tls_socket_unittest" part_name = "netstack" subsystem_name = "communication" } @@ -185,6 +186,7 @@ ohos_unittest("one_way_tls_socket_unittest") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] @@ -197,7 +199,7 @@ ohos_unittest("one_way_tls_socket_unittest") { defines += [ "HAS_NETMANAGER_BASE=0" ] } - module_out_path = "netstack/tls_socket_unittest" + module_out_path = "netstack/netstack/tls_socket_unittest" part_name = "netstack" subsystem_name = "communication" } @@ -229,6 +231,7 @@ ohos_unittest("two_way_tls_socket_certchain_unittest") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] @@ -241,7 +244,7 @@ ohos_unittest("two_way_tls_socket_certchain_unittest") { defines += [ "HAS_NETMANAGER_BASE=0" ] } - module_out_path = "netstack/tls_socket_unittest" + module_out_path = "netstack/netstack/tls_socket_unittest" part_name = "netstack" subsystem_name = "communication" } @@ -273,6 +276,7 @@ ohos_unittest("one_way_tls_socket_certchain_unittest") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] @@ -285,7 +289,7 @@ ohos_unittest("one_way_tls_socket_certchain_unittest") { defines += [ "HAS_NETMANAGER_BASE=0" ] } - module_out_path = "netstack/tls_socket_unittest" + module_out_path = "netstack/netstack/tls_socket_unittest" part_name = "netstack" subsystem_name = "communication" } @@ -320,6 +324,7 @@ ohos_unittest("tls_socket_unilateral_connection") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] @@ -332,7 +337,7 @@ ohos_unittest("tls_socket_unilateral_connection") { defines += [ "HAS_NETMANAGER_BASE=0" ] } - module_out_path = "netstack/tls_socket_unittest" + module_out_path = "netstack/netstack/tls_socket_unittest" part_name = "netstack" subsystem_name = "communication" } @@ -359,7 +364,7 @@ ohos_unittest("secure_data_unittest") { "hilog:libhilog", ] - module_out_path = "netstack/tls_socket_unittest" + module_out_path = "netstack/netstack/tls_socket_unittest" part_name = "netstack" subsystem_name = "communication" } @@ -390,6 +395,7 @@ ohos_unittest("tls_key_test") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] @@ -402,7 +408,7 @@ ohos_unittest("tls_key_test") { defines += [ "HAS_NETMANAGER_BASE=0" ] } - module_out_path = "netstack/tls_socket_unittest" + module_out_path = "netstack/netstack/tls_socket_unittest" part_name = "netstack" subsystem_name = "communication" } @@ -433,6 +439,7 @@ ohos_unittest("tls_cert_test") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] @@ -445,7 +452,7 @@ ohos_unittest("tls_cert_test") { defines += [ "HAS_NETMANAGER_BASE=0" ] } - module_out_path = "netstack/tls_socket_unittest" + module_out_path = "netstack/netstack/tls_socket_unittest" part_name = "netstack" subsystem_name = "communication" } @@ -476,6 +483,7 @@ ohos_unittest("tls_configuration_test") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] @@ -488,7 +496,7 @@ ohos_unittest("tls_configuration_test") { defines += [ "HAS_NETMANAGER_BASE=0" ] } - module_out_path = "netstack/tls_socket_unittest" + module_out_path = "netstack/netstack/tls_socket_unittest" part_name = "netstack" subsystem_name = "communication" } @@ -519,6 +527,7 @@ ohos_unittest("tls_context_test") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] @@ -531,7 +540,7 @@ ohos_unittest("tls_context_test") { defines += [ "HAS_NETMANAGER_BASE=0" ] } - module_out_path = "netstack/tls_socket_unittest" + module_out_path = "netstack/netstack/tls_socket_unittest" part_name = "netstack" subsystem_name = "communication" } @@ -562,6 +571,7 @@ ohos_unittest("socket_error_unittest") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] @@ -574,7 +584,7 @@ ohos_unittest("socket_error_unittest") { defines += [ "HAS_NETMANAGER_BASE=0" ] } - module_out_path = "netstack/tls_socket_unittest" + module_out_path = "netstack/netstack/tls_socket_unittest" part_name = "netstack" subsystem_name = "communication" } @@ -608,6 +618,7 @@ ohos_unittest("tls_socket_branch_test") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] @@ -620,7 +631,7 @@ ohos_unittest("tls_socket_branch_test") { defines += [ "HAS_NETMANAGER_BASE=0" ] } - module_out_path = "netstack/tls_socket_unittest" + module_out_path = "netstack/netstack/tls_socket_unittest" part_name = "netstack" subsystem_name = "communication" } diff --git a/test/unittest/tlssocket/client/TlsSocketBranchTest.cpp b/test/unittest/tlssocket/client/TlsSocketBranchTest.cpp index d930127ff8a2f59917570e639cc72ff0258d1c84..610979728008daf6127181b38bcc66954881d415 100644 --- a/test/unittest/tlssocket/client/TlsSocketBranchTest.cpp +++ b/test/unittest/tlssocket/client/TlsSocketBranchTest.cpp @@ -262,7 +262,6 @@ HWTEST_F(TlsSocketBranchTest, BranchTest5, TestSize.Level2) tlsSocket->GetProtocol([](int32_t errCode, const std::string &protocol) { EXPECT_EQ(errCode, TLSSOCKET_SUCCESS); }); tlsSocket->GetRemoteCertificate( [](int32_t errCode, const X509CertRawData &cert) { EXPECT_EQ(errCode, TLS_ERR_SSL_NULL); }); - (void)tlsSocket->Close([](int32_t errCode) { EXPECT_FALSE(errCode == TLSSOCKET_SUCCESS); }); } HWTEST_F(TlsSocketBranchTest, BranchTest6, TestSize.Level2) diff --git a/test/unittest/tlssocket/core/BUILD.gn b/test/unittest/tlssocket/core/BUILD.gn index d4c0975309bb77be25f76f32146b55d7fa36840e..b24356724211a9064bcb33c70cda1a156e791cb9 100644 --- a/test/unittest/tlssocket/core/BUILD.gn +++ b/test/unittest/tlssocket/core/BUILD.gn @@ -147,6 +147,7 @@ ohos_unittest("tls_socket_core_test") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] @@ -159,7 +160,7 @@ ohos_unittest("tls_socket_core_test") { defines += [ "HAS_NETMANAGER_BASE=0" ] } - module_out_path = "netstack/tls_socket_unittest" + module_out_path = "netstack/netstack/tls_socket_unittest" part_name = "netstack" subsystem_name = "communication" } diff --git a/test/unittest/tlssocket/server/BUILD.gn b/test/unittest/tlssocket/server/BUILD.gn index 200d1b63520b68b0359faaaaab374156fc04a16b..fdc531233cea2c2d4ff29c7d5fc29de3c5fd7550 100644 --- a/test/unittest/tlssocket/server/BUILD.gn +++ b/test/unittest/tlssocket/server/BUILD.gn @@ -143,6 +143,7 @@ ohos_unittest("two_way_tls_socket_server_unittest") { "napi:ace_napi", "openssl:libcrypto_shared", "openssl:libssl_shared", + "samgr:samgr_proxy", ] defines = [ "OPENSSL_SUPPRESS_DEPRECATED" ] @@ -155,7 +156,7 @@ ohos_unittest("two_way_tls_socket_server_unittest") { defines += [ "HAS_NETMANAGER_BASE=0" ] } - module_out_path = "netstack/tls_socket_unittest" + module_out_path = "netstack/netstack/tls_socket_unittest" part_name = "netstack" subsystem_name = "communication" } @@ -199,7 +200,7 @@ ohos_unittest("tls_socket_server_mock_branch_test") { defines += [ "HAS_NETMANAGER_BASE=0" ] } - module_out_path = "netstack/tls_socket_unittest" + module_out_path = "netstack/netstack/tls_socket_unittest" part_name = "netstack" subsystem_name = "communication" } diff --git a/test/unittest/utils/common_utils/BUILD.gn b/test/unittest/utils/common_utils/BUILD.gn index 8ce8dd90668ae5ec61820216cfd46a1370ef890f..d9687cbb01da367d719da6766bb6567450532025 100644 --- a/test/unittest/utils/common_utils/BUILD.gn +++ b/test/unittest/utils/common_utils/BUILD.gn @@ -34,7 +34,7 @@ ohos_unittest("netstack_common_utils_test") { branch_protector_ret = "pac_ret" - module_out_path = "netstack/utils_unittest" + module_out_path = "netstack/netstack/utils_unittest" include_dirs = [ "$NETSTACK_UTILS_ROOT/common_utils/include" ] diff --git a/test/fuzztest/websocketinnerapi_fuzzer/BUILD.gn b/test/unittest/utils/netstack_chr_client/BUILD.gn similarity index 39% rename from test/fuzztest/websocketinnerapi_fuzzer/BUILD.gn rename to test/unittest/utils/netstack_chr_client/BUILD.gn index 4de62928c3d7fba8c9719a8d2373d2af704d106e..ca544cca0a9c7f0902d6e8e469082c4ead0bf820 100644 --- a/test/fuzztest/websocketinnerapi_fuzzer/BUILD.gn +++ b/test/unittest/utils/netstack_chr_client/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2023 Huawei Device Co., Ltd. +# Copyright (c) 2025 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 @@ -11,61 +11,55 @@ # See the License for the specific language governing permissions and # limitations under the License. -#####################hydra-fuzz################### -import("//build/config/features.gni") import("//build/ohos.gni") import("//build/test.gni") import("//foundation/communication/netstack/netstack_config.gni") -##############################fuzztest########################################## -WEBSOCKET_INNERAPI = "$NETSTACK_DIR/frameworks/native/websocket_client" +NETSTACK_UTILS_ROOT = "$SUBSYSTEM_DIR/netstack/utils" -utils_include = [ - "$SUBSYSTEM_DIR/netstack/utils/common_utils/include", - "$SUBSYSTEM_DIR/netstack/utils/log/include", - "$SUBSYSTEM_DIR/netstack/utils/napi_utils/include", -] +utils_include = [ "$NETSTACK_UTILS_ROOT/log/include" ] common_external_deps = [ "c_utils:utils", - "eventhandler:libeventhandler", "hilog:libhilog", - "libwebsockets:websockets", ] -ohos_fuzztest("WebSocketInnerApiFuzzTest") { - module_out_path = fuzz_test_path - fuzz_config_file = "$NETSTACK_DIR/test/fuzztest/websocketinnerapi_fuzzer" +ohos_unittest("netstack_common_utils_test") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + + branch_protector_ret = "pac_ret" + + module_out_path = "netstack/netstack_chr_client_test" + include_dirs = [ - "$NETSTACK_DIR/utils/napi_utils/include", - "$WEBSOCKET_INNERAPI/include", + "$NETSTACK_UTILS_ROOT/netstack_chr_client/include", + "$NETSTACK_UTILS_ROOT/common_utils/include", ] include_dirs += utils_include - cflags = [ - "-g", - "-O0", - "-Wno-unused-variable", - "-fno-omit-frame-pointer", + external_deps = common_external_deps + external_deps += [ + "curl:curl_shared", + "ability_runtime:wantagent_innerkits", ] sources = [ - "$SUBSYSTEM_DIR/netstack/utils/common_utils/src/netstack_common_utils.cpp", - "websocket_inner_fuzzer.cpp", + "$NETSTACK_UTILS_ROOT/common_utils/src/netstack_bundle_utils.cpp", + "$NETSTACK_UTILS_ROOT/common_utils/src/netstack_common_utils.cpp", + "$NETSTACK_UTILS_ROOT/netstack_chr_client/src/netstack_chr_client.cpp", + "$NETSTACK_UTILS_ROOT/netstack_chr_client/src/netstack_chr_report.cpp", + "NetStackChrClientTest.cpp", ] - deps = [ - "$NETSTACK_DIR/utils/napi_utils:napi_utils", - "$NETSTACK_INNERKITS_DIR/websocket_client:websocket_client", - ] - - external_deps = common_external_deps + part_name = "netstack" + subsystem_name = "communication" } -############################################################################### -group("fuzztest") { +group("unittest") { testonly = true - - deps = [ ":WebSocketInnerApiFuzzTest" ] + deps = [ ":netstack_chr_client_test" ] } -############################################################################### diff --git a/test/unittest/utils/netstack_chr_client/NetStackChrClientTest.cpp b/test/unittest/utils/netstack_chr_client/NetStackChrClientTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bd8ff7a887d76b00c80528d4bfeedbb7656e796f --- /dev/null +++ b/test/unittest/utils/netstack_chr_client/NetStackChrClientTest.cpp @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2024 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. + */ + +#define private public + +#include +#include + +#include "curl/curl.h" +#include "netstack_chr_client.h" +#include "netstack_chr_report.h" +#include "want.h" + +namespace OHOS::NetStack { +namespace { +using namespace testing::ext; +// static constexpr const char *REQUEST_ID = "123"; +// static constexpr const char *HTTP_VERSION_2 = "2"; +static constexpr const char *REQUEST_URL = "https://127.0.0.1"; +// static constexpr const char *REQUEST_ID_ADDRESS = "127.0.0.1"; +// static constexpr const char *REQUEST_STRING = "unused"; +// static constexpr const char *REQUEST_HEADERS = "HTTP/1.1 200 OK\r\nk:v"; +// static constexpr const char *REQUEST_REASON_PARSE = "OK"; +// static constexpr const uint64_t REQUEST_BEGIN_TIME = 100; +// static constexpr const double REQUEST_DNS_TIME = 10; + +CURL *GetCurlHandle() +{ + CURL *handle = curl_easy_init(); + curl_easy_setopt(handle, CURLOPT_URL, REQUEST_URL); + curl_easy_setopt(handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); + return handle; +} +} + +class NetStackChrClientTest : public testing::Test { +public: + static void SetUpTestCase() {} + + static void TearDownTestCase() {} + + virtual void SetUp() {} + + virtual void TearDown() {} +}; + +void FillNormalvalue(ChrClient::DataTransChrStats& chrStats) +{ + chrStats.processName = "CHR_Unit_Test_Case"; + + chrStats.httpInfo.uid = 100; + chrStats.httpInfo.responseCode = 200; + chrStats.httpInfo.totalTime = 500000; + chrStats.httpInfo.nameLookUpTime = 10000; + chrStats.httpInfo.connectTime = 50000; + chrStats.httpInfo.preTransferTime = 80000; + chrStats.httpInfo.sizeUpload = 30; + chrStats.httpInfo.sizeDownload = 60; + chrStats.httpInfo.speedDownload = 440; + chrStats.httpInfo.speedUpload = 180; + chrStats.httpInfo.effectiveMethod = "POST"; + chrStats.httpInfo.startTransferTime = "application/json; charset=utf-8"; + chrStats.httpInfo.contentType = 0; + chrStats.httpInfo.redirectTime = 0; + chrStats.httpInfo.redirectCount = 0; + chrStats.httpInfo.osError = 0; + chrStats.httpInfo.sslVerifyResult= 0; + chrStats.httpInfo.appconnectTime = 80000; + chrStats.httpInfo.retryAfter = 0; + chrStats.httpInfo.proxyError = 0; + chrStats.httpInfo.queueTime = 12000; + chrStats.httpInfo.curlCode = 0; + chrStats.httpInfo.requestStartTime = 1747359000000; + + chrStats.tcpInfo.unacked = 0; + chrStats.tcpInfo.lastDataSent = 1000; + chrStats.tcpInfo.lastAckSent = 0; + chrStats.tcpInfo.lastDataRecv 1000; + chrStats.tcpInfo.lastAckRecv = 1000; + chrStats.tcpInfo.rtt = 12000; + chrStats.tcpInfo.rttvar = 4000; + chrStats.tcpInfo.retransmits = 0; + chrStats.tcpInfo.totalRetrans = 0; + chrStats.tcpInfo.srcIp = "7.246.***.***"; + chrStats.tcpInfo.dstIp = "7.246.***.***"; + chrStats.tcpInfo.srcPort = 54000; + chrStats.tcpInfo.dstPort = 54000; +} + +HWTEST_F(NetStackChrClientTest, NetStackChrClientTestResponseCode, TestSize.Level2) +{ + CURL *handle = GetCurlHandle(); + ChrClient::NetStackChrClient::GetInstance().GetDfxInfoFromCurlHandleAndReport(NULL, 0); + ChrClient::NetStackChrClient::GetInstance().GetDfxInfoFromCurlHandleAndReport(handle, 0); + ChrClient::DataTransChrStats dataTransChrStats{}; + ChrClient::NetStackChrClient::GetInstance().GetHttpInfoFromCurl(handle, dataTransChrStats.httpInfo); + EXPECT_EQ(dataTransChrStats.httpInfo.responseCode, 0); +} + +HWTEST_F(NetStackChrClientTest, NetStackChrClientTestPort, TestSize.Level2) +{ + ChrClient::DataTransTcpInfo tcpInfo; + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd >0) { + ChrClient::NetStackChrClient::GetInstance().GetTcpInfoFromSock(sockfd, tcpInfo); + EXPECT_EQ(tcpInfo.unacked, 0); + EXPECT_EQ(tcpInfo.srcPort, 0); + EXPECT_EQ(tcpInfo.dstPort, 0); + close(sockfd); + } + sockfd = socket(AF_INET6, SOCK_STREAM, 0); + if (sockfd > 0) { + ChrClient::NetStackChrClient::GetInstance().GetTcpInfoFromSock(sockfd, tcpInfo); + EXPECT_EQ(tcpInfo.unacked, 0); + EXPECT_EQ(tcpInfo.srcPort, 0); + EXPECT_EQ(tcpInfo.dstPort, 0); + close(sockfd); + } +} + +HWTEST_F(NetStackChrClientTest, NetStackChrClientTestNotReport, TestSize.Level2) +{ + ChrClient::NetStackChrReport netstackChrReport; + ChrClient::DataTransChrStats chrStats; + FillNormalvalue(chrStats); + + int res = ChrClient::NetStackChrClient::GetInstance().shouldReportHttpAbnormalEvent(chrStats.httpInfo); + EXPECT_EQ(res, -1); +} + +HWTEST_F(NetStackChrClientTest, NetStackChrClientTestResponseCodeError, TestSize.Level2) +{ + ChrClient::NetStackChrReport netstackChrReport; + ChrClient::DataTransChrStats chrStats; + FillNormalvalue(chrStats); + + chrStats.httpInfo.responseCode = 301; + int res = ChrClient::NetStackChrClient::GetInstance().shouldReportHttpAbnormalEvent(chrStats.httpInfo); + EXPECT_EQ(res, 0); +} + +HWTEST_F(NetStackChrClientTest, NetStackChrClientTestOSError, TestSize.Level2) +{ + ChrClient::NetStackChrReport netstackChrReport; + ChrClient::DataTransChrStats chrStats; + FillNormalvalue(chrStats); + + chrStats.httpInfo.osError = 1; + int res = ChrClient::NetStackChrClient::GetInstance().shouldReportHttpAbnormalEvent(chrStats.httpInfo); + EXPECT_EQ(res, 0); +} + +HWTEST_F(NetStackChrClientTest, NetStackChrClientTestProxyError, TestSize.Level2) +{ + ChrClient::NetStackChrReport netstackChrReport; + ChrClient::DataTransChrStats chrStats; + FillNormalvalue(chrStats); + + chrStats.httpInfo.proxyError = 1; + int res = ChrClient::NetStackChrClient::GetInstance().shouldReportHttpAbnormalEvent(chrStats.httpInfo); + EXPECT_EQ(res, 0); +} + +HWTEST_F(NetStackChrClientTest, NetStackChrClientTestCurlCodeError, TestSize.Level2) +{ + ChrClient::NetStackChrReport netstackChrReport; + ChrClient::DataTransChrStats chrStats; + FillNormalvalue(chrStats); + + chrStats.httpInfo.curlCode = 1; + int res = ChrClient::NetStackChrClient::GetInstance().shouldReportHttpAbnormalEvent(chrStats.httpInfo); + EXPECT_EQ(res, 0); +} + +HWTEST_F(NetStackChrClientTest, NetStackChrClientTestShortRequestButTimeout, TestSize.Level2) +{ + ChrClient::NetStackChrReport netstackChrReport; + ChrClient::DataTransChrStats chrStats; + FillNormalvalue(chrStats); + + chrStats.httpInfo.sizeUpload = 50000; + chrStats.httpInfo.sizeDownload = 50000; + chrStats.httpInfo.totalTime = 501000; + int res = ChrClient::NetStackChrClient::GetInstance().shouldReportHttpAbnormalEvent(chrStats.httpInfo); + EXPECT_EQ(res, 0); +} + +HWTEST_F(NetStackChrClientTest, NetStackChrClientTestTimeLimits, TestSize.Level2) +{ + ChrClient::NetStackChrReport netstackChrReport; + ChrClient::DataTransChrStats chrStats; + + netstackChrReport.ReportCommonEvent(chrStats); + int second_ret = netstackChrReport.ReportCommonEvent(chrStats); + EXPECT_EQ(second_ret, -1); +} \ No newline at end of file diff --git a/test/unittest/utils/profiler_utils/BUILD.gn b/test/unittest/utils/profiler_utils/BUILD.gn index 9c532004f22e7daaa92c06b900348e688cc34c9f..3d41f9a491577a376f667fcf1273aa6382ac0c38 100644 --- a/test/unittest/utils/profiler_utils/BUILD.gn +++ b/test/unittest/utils/profiler_utils/BUILD.gn @@ -35,7 +35,7 @@ ohos_unittest("netstack_network_profiler_utils_test") { branch_protector_ret = "pac_ret" - module_out_path = "netstack/netstack_network_profiler_utils_test" + module_out_path = "netstack/netstack/netstack_network_profiler_utils_test" include_dirs = [ "$NETSTACK_INNERKITS_DIR/http_client/include", diff --git a/test/unittest/websocket/BUILD.gn b/test/unittest/websocket/BUILD.gn index 0b2c338943ce5784c1acc24bbf50d2cc434af8f2..3e2a5f663187fcd415f714458f28928ee2234161 100644 --- a/test/unittest/websocket/BUILD.gn +++ b/test/unittest/websocket/BUILD.gn @@ -29,7 +29,7 @@ common_external_deps = [ ] ohos_unittest("websocket_unittest") { - module_out_path = "netstack/websocket_unittest" + module_out_path = "netstack/netstack/websocket_unittest" include_dirs = [ "$NETSTACK_DIR/utils/napi_utils/include", @@ -60,6 +60,7 @@ ohos_unittest("websocket_unittest") { external_deps += [ "libwebsockets:websockets", "openssl:libssl_shared", + "samgr:samgr_proxy", ] if (defined(global_parts_info) && @@ -71,6 +72,19 @@ ohos_unittest("websocket_unittest") { defines += [ "HAS_NETMANAGER_BASE=0" ] } + if (netstack_websocket_server_enable) { + defines += [ "NETSTACK_WEBSOCKETSERVER", + "private = public",] + sources += [ + "$WEBSOCKET_NAPI/async_context/src/list_all_connections_context.cpp", + "$WEBSOCKET_NAPI/async_context/src/server_close_context.cpp", + "$WEBSOCKET_NAPI/async_context/src/server_send_context.cpp", + "$WEBSOCKET_NAPI/async_context/src/server_start_context.cpp", + "$WEBSOCKET_NAPI/async_context/src/server_stop_context.cpp", + "$WEBSOCKET_NAPI/websocket_exec/src/websocket_server_exec.cpp", + ] + } + part_name = "netstack" subsystem_name = "communication" } diff --git a/test/unittest/websocket/WebSocketTest.cpp b/test/unittest/websocket/WebSocketTest.cpp index 6a021bbfbb1d556eff9dbcd5d2ebaf319e0fb782..68b0c10647a2611aff2a6548c049fd10ecec99ae 100755 --- a/test/unittest/websocket/WebSocketTest.cpp +++ b/test/unittest/websocket/WebSocketTest.cpp @@ -13,7 +13,6 @@ * limitations under the License. */ -#include "netstack_log.h" #include "gtest/gtest.h" #include #include @@ -24,6 +23,15 @@ #include "websocket_async_work.h" #include "websocket_exec.h" #include "websocket_module.h" +#ifdef NETSTACK_WEBSOCKETSERVER +#include "server_start_context.h" +#include "server_close_context.h" +#include "server_send_context.h" +#include "server_stop_context.h" +#include "list_all_connections_context.h" +#include "websocket_server_exec.h" +#include "napi_utils.h" +#endif // NETSTACK_WEBSOCKETSERVER class WebSocketTest : public testing::Test { public: @@ -106,7 +114,7 @@ HWTEST_F(WebSocketTest, WebSocketTest007, TestSize.Level1) std::string getMyProtocol = context.GetProtocol(); bool ret = WebSocketExec::ExecConnect(&context); EXPECT_EQ(getMyProtocol, "my-protocol"); - EXPECT_EQ(ret, true); + EXPECT_EQ(ret, false); } HWTEST_F(WebSocketTest, WebSocketTest008, TestSize.Level1) @@ -129,6 +137,750 @@ HWTEST_F(WebSocketTest, WebSocketTest008, TestSize.Level1) EXPECT_EQ(getHost, "192.168.147.60"); EXPECT_EQ(getPort, 8888); EXPECT_EQ(getExclusions, "www.httpbin.org"); + EXPECT_EQ(ret, false); +} + +#ifdef NETSTACK_WEBSOCKETSERVER +HWTEST_F(WebSocketTest, WebSocketTest009, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + bool ret = WebSocketServerExec::ExecServerStart(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest010, TestSize.Level1) +{ + bool ret = WebSocketServerExec::ExecServerStart(nullptr); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest011, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + context.SetPermissionDenied(true); + bool ret = WebSocketServerExec::ExecServerStart(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest012, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerSendContext context(env, eventManager); + bool ret = WebSocketServerExec::ExecServerSend(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest013, TestSize.Level1) +{ + bool ret = WebSocketServerExec::ExecServerSend(nullptr); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest014, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerSendContext context(env, eventManager); + context.SetPermissionDenied(true); + bool ret = WebSocketServerExec::ExecServerSend(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest015, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerCloseContext context(env, eventManager); + bool ret = WebSocketServerExec::ExecServerClose(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest016, TestSize.Level1) +{ + bool ret = WebSocketServerExec::ExecServerClose(nullptr); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest017, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerCloseContext context(env, eventManager); + context.SetPermissionDenied(true); + bool ret = WebSocketServerExec::ExecServerClose(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest018, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStopContext context(env, eventManager); + bool ret = WebSocketServerExec::ExecServerStop(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest019, TestSize.Level1) +{ + bool ret = WebSocketServerExec::ExecServerStop(nullptr); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest020, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStopContext context(env, eventManager); + context.SetPermissionDenied(true); + bool ret = WebSocketServerExec::ExecServerStop(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest021, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ListAllConnectionsContext context(env, eventManager); + bool ret = WebSocketServerExec::ExecListAllConnections(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest022, TestSize.Level1) +{ + bool ret = WebSocketServerExec::ExecListAllConnections(nullptr); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest023, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ListAllConnectionsContext context(env, eventManager); + context.SetPermissionDenied(true); + bool ret = WebSocketServerExec::ExecListAllConnections(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest024, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ConnectContext context(env, eventManager); + context.SetPermissionDenied(true); + bool ret = WebSocketExec::ExecConnect(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest025, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + SendContext context(env, eventManager); + context.SetPermissionDenied(true); + bool ret = WebSocketExec::ExecSend(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest026, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + CloseContext context(env, eventManager); + context.SetPermissionDenied(true); + bool ret = WebSocketExec::ExecClose(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest027, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + context.SetPermissionDenied(false); + bool ret = WebSocketServerExec::ExecServerStart(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest028, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerSendContext context(env, eventManager); + context.SetPermissionDenied(false); + bool ret = WebSocketServerExec::ExecServerSend(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest029, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerCloseContext context(env, eventManager); + context.SetPermissionDenied(false); + bool ret = WebSocketServerExec::ExecServerClose(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest030, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStopContext context(env, eventManager); + context.SetPermissionDenied(false); + bool ret = WebSocketServerExec::ExecServerStop(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest031, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ListAllConnectionsContext context(env, eventManager); + context.SetPermissionDenied(false); + bool ret = WebSocketServerExec::ExecListAllConnections(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest032, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ConnectContext context(env, eventManager); + context.SetPermissionDenied(false); + bool ret = WebSocketExec::ExecConnect(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest033, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + SendContext context(env, eventManager); + context.SetPermissionDenied(false); + bool ret = WebSocketExec::ExecSend(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest034, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + CloseContext context(env, eventManager); + context.SetPermissionDenied(false); + bool ret = WebSocketExec::ExecClose(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest035, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + context.SetPermissionDenied(true); + std::string ip = "0.0.0.0"; + context.SetServerIP(ip); + bool ret = WebSocketServerExec::ExecServerStart(&context); + EXPECT_EQ(ret, true); +} + +HWTEST_F(WebSocketTest, WebSocketTest036, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + context.SetPermissionDenied(true); + std::string ip = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; + context.SetServerIP(ip); + bool ret = WebSocketServerExec::ExecServerStart(&context); EXPECT_EQ(ret, true); } + +HWTEST_F(WebSocketTest, WebSocketTest037, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + context.SetPermissionDenied(true); + std::string ip = "266.0.0.0"; + context.SetServerIP(ip); + bool ret = WebSocketServerExec::ExecServerStart(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest038, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + context.SetPermissionDenied(true); + std::string ip = "2001:0db8:85a3:0000:0000:8a2e:0370:7334:1234"; + context.SetServerIP(ip); + bool ret = WebSocketServerExec::ExecServerStart(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest039, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + context.SetPermissionDenied(true); + std::string ip = "0.0.0.0"; + context.SetServerIP(ip); + uint32_t port = 444; + context.SetServerPort(port); + bool ret = WebSocketServerExec::ExecServerStart(&context); + EXPECT_EQ(ret, true); +} + +HWTEST_F(WebSocketTest, WebSocketTest040, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + context.SetPermissionDenied(true); + std::string ip = "0.0.0.0"; + context.SetServerIP(ip); + uint32_t port = 65555; + context.SetServerPort(port); + bool ret = WebSocketServerExec::ExecServerStart(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest041, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + context.SetPermissionDenied(true); + std::string ip = "0.0.0.0"; + context.SetServerIP(ip); + uint32_t port = 444; + context.SetServerPort(port); + uint32_t number = 15; + context.SetMaxConcurrentClientsNumber(number); + bool ret = WebSocketServerExec::ExecServerStart(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest042, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + std::string ip = "0.0.0.0"; + context.SetServerIP(ip); + uint32_t port = 444; + context.SetServerPort(port); + uint32_t number = 9; + context.SetMaxConcurrentClientsNumber(number); + uint32_t cnt = 15; + context.SetMaxConnectionsForOneClient(cnt); + bool ret = WebSocketServerExec::ExecServerStart(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest043, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + std::string ip = "0.0.0.0"; + context.SetServerIP(ip); + uint32_t port = 444; + context.SetServerPort(port); + uint32_t number = 9; + context.SetMaxConcurrentClientsNumber(number); + uint32_t cnt = 9; + context.SetMaxConnectionsForOneClient(cnt); + uint32_t cnt2 = 9; + context.SetMaxConnectionsForOneClient(cnt2); + bool ret = WebSocketServerExec::ExecServerStart(&context); + EXPECT_EQ(ret, true); +} + +HWTEST_F(WebSocketTest, WebSocketTest044, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + std::string ip = "0.0.0.0"; + context.SetServerIP(ip); + uint32_t port = 444; + context.SetServerPort(port); + uint32_t number = 9; + context.SetMaxConcurrentClientsNumber(number); + uint32_t cnt = 9; + context.SetMaxConnectionsForOneClient(cnt); + uint32_t cnt2 = 9; + context.SetMaxConnectionsForOneClient(cnt2); + bool ret = WebSocketServerExec::ExecServerStart(&context); + EXPECT_EQ(ret, true); +} + +HWTEST_F(WebSocketTest, WebSocketTest045, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerSendContext context(env, eventManager); + context.SetPermissionDenied(true); + uint32_t port = 444; + std::string ip = ""; + context.SetClientWebSocketConn(port, ip); + bool ret = WebSocketServerExec::ExecServerSend(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest046, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerSendContext context(env, eventManager); + context.SetPermissionDenied(true); + uint32_t port = 444; + std::string ip = "0.0.0.0"; + context.SetClientWebSocketConn(port, ip); + bool ret = WebSocketServerExec::ExecServerSend(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest047, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerCloseContext context(env, eventManager); + context.SetPermissionDenied(true); + std::shared_ptr sharedManager = nullptr; + context.SetSharedManager(sharedManager); + bool ret = WebSocketServerExec::ExecServerClose(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest048, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerCloseContext context(env, eventManager); + context.SetPermissionDenied(true); + context.connection.clientIP = ""; + context.connection.clientPort = 444; + bool ret = WebSocketServerExec::ExecServerClose(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest049, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerCloseContext context(env, eventManager); + context.SetPermissionDenied(true); + context.connection.clientIP = "0.0.0.0"; + context.connection.clientPort = 444; + bool ret = WebSocketServerExec::ExecServerClose(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest050, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStopContext context(env, eventManager); + context.SetPermissionDenied(true); + std::shared_ptr userData = nullptr; + eventManager->SetWebSocketUserData(userData); + context.SetSharedManager(eventManager); + bool ret = WebSocketServerExec::ExecServerStop(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest051, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ListAllConnectionsContext context(env, eventManager); + context.SetPermissionDenied(true); + context.SetSharedManager(nullptr); + bool ret = WebSocketServerExec::ExecListAllConnections(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest052, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ListAllConnectionsContext context(env, eventManager); + context.SetPermissionDenied(true); + std::shared_ptr userData = nullptr; + eventManager->SetWebSocketUserData(userData); + context.SetSharedManager(eventManager); + bool ret = WebSocketServerExec::ExecListAllConnections(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest053, TestSize.Level1) +{ + napi_value ret = WebSocketServerExec::ListAllConnectionsCallback(nullptr); + EXPECT_EQ(ret, nullptr); +} + +HWTEST_F(WebSocketTest, WebSocketTest054, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ListAllConnectionsContext context(env, eventManager); + std::vector connections; + context.SetAllConnections(connections); + napi_value connectionsArray = NapiUtils::CreateArray(context.GetEnv(), 0); + napi_value ret = WebSocketServerExec::ListAllConnectionsCallback(&context); + EXPECT_EQ(ret, connectionsArray); +} + +HWTEST_F(WebSocketTest, WebSocketTest055, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStopContext context(env, eventManager); + context.SetSharedManager(nullptr); + napi_value ret = WebSocketServerExec::ServerStopCallback(&context); + EXPECT_EQ(ret, nullptr); +} + +HWTEST_F(WebSocketTest, WebSocketTest056, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStopContext context(env, eventManager); + napi_value ret = WebSocketServerExec::ServerStopCallback(&context); + EXPECT_EQ(ret, nullptr); +} + +HWTEST_F(WebSocketTest, WebSocketTest057, TestSize.Level1) +{ + lws *wsi = nullptr; + WebSocketServerExec::OnConnect(wsi, nullptr); + EXPECT_EQ(wsi, nullptr); +} + +HWTEST_F(WebSocketTest, WebSocketTest058, TestSize.Level1) +{ + lws *wsi = nullptr; + auto eventManager = std::make_shared(); + WebSocketServerExec::OnConnect(wsi, eventManager.get()); + EXPECT_EQ(wsi, nullptr); +} + +HWTEST_F(WebSocketTest, WebSocketTest059, TestSize.Level1) +{ + lws *wsi = nullptr; + lws_close_status closeStatus = LWS_CLOSE_STATUS_NOSTATUS; + std::string closeReason = "The link is down, onError"; + WebSocketServerExec::OnServerClose(wsi, nullptr, closeStatus, closeReason); + EXPECT_EQ(wsi, nullptr); +} + +HWTEST_F(WebSocketTest, WebSocketTest060, TestSize.Level1) +{ + lws *wsi = nullptr; + auto eventManager = std::make_shared(); + lws_close_status closeStatus = LWS_CLOSE_STATUS_NOSTATUS; + std::string closeReason = "The link is down, onError"; + WebSocketServerExec::OnServerClose(wsi, eventManager.get(), closeStatus, closeReason); + EXPECT_EQ(closeStatus, LWS_CLOSE_STATUS_NOSTATUS); +} + +HWTEST_F(WebSocketTest, WebSocketTest061, TestSize.Level1) +{ + lws *wsi = nullptr; + void *data = nullptr; + size_t length = 0; + bool isBinary = false; + bool isFinal = false; + WebSocketServerExec::OnServerMessage(wsi, nullptr, data, length, isBinary, isFinal); + EXPECT_EQ(wsi, nullptr); +} + +HWTEST_F(WebSocketTest, WebSocketTest062, TestSize.Level1) +{ + lws *wsi = nullptr; + auto eventManager = std::make_shared(); + void *data = nullptr; + size_t length = 0; + bool isBinary = false; + bool isFinal = false; + WebSocketServerExec::OnServerMessage(wsi, eventManager.get(), data, length, isBinary, isFinal); + EXPECT_EQ(isBinary, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest063, TestSize.Level1) +{ + int32_t code = 0; + WebSocketServerExec::OnServerError(nullptr, code); + EXPECT_EQ(code, 0); +} + +HWTEST_F(WebSocketTest, WebSocketTest064, TestSize.Level1) +{ + auto eventManager = std::make_shared(); + int32_t code = 0; + WebSocketServerExec::OnServerError(eventManager.get(), code); + EXPECT_EQ(code, 0); +} + +HWTEST_F(WebSocketTest, WebSocketTest065, TestSize.Level1) +{ + lws *wsi = nullptr; + void *data = nullptr; + size_t length = 0; + bool isBinary = true; + bool isFinal = true; + WebSocketServerExec::HandleServerRcvMessage(wsi, nullptr, data, length, isBinary, isFinal); + EXPECT_EQ(wsi, nullptr); +} + +HWTEST_F(WebSocketTest, WebSocketTest066, TestSize.Level1) +{ + lws *wsi = nullptr; + auto eventManager = std::make_shared(); + void *data = nullptr; + size_t length = 0; + bool isBinary = true; + bool isFinal = false; + WebSocketServerExec::HandleServerRcvMessage(wsi, eventManager.get(), data, length, isBinary, isFinal); + EXPECT_EQ(isFinal, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest067, TestSize.Level1) +{ + lws *wsi = nullptr; + auto eventManager = std::make_shared(); + void *data = nullptr; + size_t length = 0; + bool isBinary = false; + bool isFinal = true; + WebSocketServerExec::HandleServerRcvMessage(wsi, eventManager.get(), data, length, isBinary, isFinal); + EXPECT_EQ(isFinal, true); +} + +HWTEST_F(WebSocketTest, WebSocketTest068, TestSize.Level1) +{ + lws *wsi = nullptr; + auto eventManager = std::make_shared(); + void *data = nullptr; + size_t length = 0; + bool isBinary = false; + bool isFinal = false; + WebSocketServerExec::HandleServerRcvMessage(wsi, eventManager.get(), data, length, isBinary, isFinal); + EXPECT_EQ(isFinal, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest069, TestSize.Level1) +{ + lws *wsi = nullptr; + std::string msgFromManager = ""; + void *dataMsg = nullptr; + WebSocketServerExec::SetWebsocketMessage(wsi, nullptr, msgFromManager, dataMsg); + EXPECT_EQ(wsi, nullptr); +} + +HWTEST_F(WebSocketTest, WebSocketTest070, TestSize.Level1) +{ + lws *wsi = nullptr; + auto eventManager = std::make_shared(); + std::string msgFromManager = ""; + void *dataMsg = nullptr; + WebSocketServerExec::SetWebsocketMessage(wsi, eventManager.get(), msgFromManager, dataMsg); + EXPECT_NE(eventManager, nullptr); +} + +HWTEST_F(WebSocketTest, WebSocketTest071, TestSize.Level1) +{ + std::string clientId = "0.0.0.0:444"; + auto ret = WebSocketServerExec::GetClientWsi(clientId); + EXPECT_EQ(ret, nullptr); +} + +HWTEST_F(WebSocketTest, WebSocketTest072, TestSize.Level1) +{ + std::shared_ptr userData = nullptr; + WebSocketServerExec::CloseAllConnection(userData); + EXPECT_EQ(userData, nullptr); +} + +HWTEST_F(WebSocketTest, WebSocketTest073, TestSize.Level1) +{ + lws_context *context = nullptr; + std::shared_ptr userData = std::make_shared(context); + WebSocketServerExec::CloseAllConnection(userData); + EXPECT_NE(userData, nullptr); +} + +HWTEST_F(WebSocketTest, WebSocketTest074, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + lws_context_creation_info info; + auto ret = WebSocketServerExec::FillServerCertPath(&context, info); + EXPECT_EQ(ret, true); +} + +HWTEST_F(WebSocketTest, WebSocketTest075, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + context.certPath_ = "/path/to/your/certificate.pem"; + lws_context_creation_info info; + auto ret = WebSocketServerExec::FillServerCertPath(&context, info); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest076, TestSize.Level1) +{ + std::string id = "0.0.0.0:444"; + lws_context *context = nullptr; + std::shared_ptr userData = std::make_shared(context); + WebSocketConnection conn; + WebSocketServerExec::AddConnections(id, nullptr, userData, conn); + EXPECT_NE(userData, nullptr); +} + +HWTEST_F(WebSocketTest, WebSocketTest077, TestSize.Level1) +{ + std::string id = "0.0.0.0:444"; + lws_context *context = nullptr; + std::shared_ptr userData = std::make_shared(context); + WebSocketConnection conn; + userData->SetThreadStop(true); + WebSocketServerExec::AddConnections(id, nullptr, userData, conn); + EXPECT_EQ(userData->IsThreadStop(), true); +} + +HWTEST_F(WebSocketTest, WebSocketTest078, TestSize.Level1) +{ + std::string id = "0.0.0.0:444"; + lws_context *context = nullptr; + std::shared_ptr userData = std::make_shared(context); + WebSocketConnection conn; + lws_close_status status = LWS_CLOSE_STATUS_NOSTATUS; + std::string reason = "The link is down, onError"; + userData->Close(status, reason); + WebSocketServerExec::AddConnections(id, nullptr, userData, conn); + EXPECT_EQ(userData->IsClosed(), true); +} + +HWTEST_F(WebSocketTest, WebSocketTest079, TestSize.Level1) +{ + std::string id = "0.0.0.0:444"; + lws_context *context = nullptr; + std::shared_ptr userData = std::make_shared(context); + WebSocketServerExec::RemoveConnections(id, *userData); + EXPECT_NE(userData, nullptr); +} +#endif } // namespace \ No newline at end of file diff --git a/test/unittest/websocket_capi_unittest/BUILD.gn b/test/unittest/websocket_capi_unittest/BUILD.gn index 2c6bc4b393cedb2d0bbfeba7c3e4b75be338cdee..f2e2871cb49f52199f97712641d0b3563ef7a873 100755 --- a/test/unittest/websocket_capi_unittest/BUILD.gn +++ b/test/unittest/websocket_capi_unittest/BUILD.gn @@ -28,7 +28,7 @@ common_external_deps = [ ] ohos_unittest("websocket_capi_unittest") { - module_out_path = "netstack/websocket_capi_unittest" + module_out_path = "netstack/netstack/websocket_capi_unittest" include_dirs = [ "$NETSTACK_DIR/interfaces/kits/c/net_websocket/include", diff --git a/test/unittest/websocket_capi_unittest/websocket_capi_unittest.cpp b/test/unittest/websocket_capi_unittest/websocket_capi_unittest.cpp index 22279b362f5b3e93f3c9160142e0e86900e36e52..2baac5fbbaa554cdcf1325b0ec7d8d0ef77e15a9 100755 --- a/test/unittest/websocket_capi_unittest/websocket_capi_unittest.cpp +++ b/test/unittest/websocket_capi_unittest/websocket_capi_unittest.cpp @@ -139,7 +139,7 @@ HWTEST_F(WebSocketTest, WebSocketSendTest007, TestSize.Level1) ret = OH_WebSocketClient_Send(client, const_cast(senddata2), sizeof(senddata2)); EXPECT_EQ(ret, WebSocket_ErrCode::WEBSOCKET_OK); ret = OH_WebSocketClient_Destroy(client); - EXPECT_EQ(ret, WebSocket_ErrCode::WEBSOCKET_OK); + EXPECT_EQ(ret, WebSocket_ErrCode::WEBSOCKET_NO_CONNECTION_CONTEXT); } } // namespace \ No newline at end of file diff --git a/test/unittest/websocket_inner_unittest/BUILD.gn b/test/unittest/websocket_inner_unittest/BUILD.gn index ec04d29aa7b1989854144e6649f640b90d4f37ed..7e7b7b40d7139df65d54c2808445993cb0d65ddb 100755 --- a/test/unittest/websocket_inner_unittest/BUILD.gn +++ b/test/unittest/websocket_inner_unittest/BUILD.gn @@ -31,7 +31,7 @@ common_external_deps = [ ] ohos_unittest("websocket_inner_unittest") { - module_out_path = "netstack/websocket_inner_unittest" + module_out_path = "netstack/netstack/websocket_inner_unittest" include_dirs = [ "$NETSTACK_DIR/utils/napi_utils/include", diff --git a/test/unittest/websocket_inner_unittest/websocket_inner_unittest.cpp b/test/unittest/websocket_inner_unittest/websocket_inner_unittest.cpp index f360f5ea1bf270eba470e89ff268e5333fc544dd..76895d8862b568683549f6f55ab3e699cc265b0f 100644 --- a/test/unittest/websocket_inner_unittest/websocket_inner_unittest.cpp +++ b/test/unittest/websocket_inner_unittest/websocket_inner_unittest.cpp @@ -64,7 +64,7 @@ HWTEST_F(WebSocketTest, WebSocketRegistcallback001, TestSize.Level1) closeOptions.reason = ""; client->Registcallback(OnOpen, OnMessage, OnError, OnClose); int32_t ret = client->Connect("www.baidu.com", openOptions); - EXPECT_EQ(ret, WebSocketErrorCode::WEBSOCKET_NONE_ERR); + EXPECT_EQ(ret, WebSocketErrorCode::WEBSOCKET_CONNECTION_TO_SERVER_FAIL); } HWTEST_F(WebSocketTest, WebSocketConnect002, TestSize.Level1) @@ -74,7 +74,7 @@ HWTEST_F(WebSocketTest, WebSocketConnect002, TestSize.Level1) openOptions.headers["Authorization"] = "Bearer your_token_here"; client->Registcallback(OnOpen, OnMessage, OnError, OnClose); ret = client->Connect("www.baidu.com", openOptions); - EXPECT_EQ(ret, WebSocketErrorCode::WEBSOCKET_NONE_ERR); + EXPECT_EQ(ret, WebSocketErrorCode::WEBSOCKET_CONNECTION_TO_SERVER_FAIL); } HWTEST_F(WebSocketTest, WebSocketSend003, TestSize.Level1) diff --git a/test/unittest/websocket_test/WebSocketTest.cpp b/test/unittest/websocket_test/WebSocketTest.cpp index 7cb481a8982b33ab92b4fe12ab36d3caedf67c07..0b0331a234ee07c1314368eb17c533db26405330 100644 --- a/test/unittest/websocket_test/WebSocketTest.cpp +++ b/test/unittest/websocket_test/WebSocketTest.cpp @@ -24,6 +24,14 @@ #include "websocket_async_work.h" #include "websocket_exec.h" #include "websocket_module.h" +#ifdef NETSTACK_WEBSOCKETSERVER +#include "server_start_context.h" +#include "server_close_context.h" +#include "server_send_context.h" +#include "server_stop_context.h" +#include "list_all_connections_context.h" +#include "websocket_server_exec.h" +#endif // NETSTACK_WEBSOCKETSERVER class WebSocketTest : public testing::Test { public: @@ -130,4 +138,241 @@ HWTEST_F(WebSocketTest, WebSocketTest008, TestSize.Level1) EXPECT_EQ(getExclusions, "www.httpbin.org"); EXPECT_EQ(ret, false); } -} // namespace \ No newline at end of file + +#ifdef NETSTACK_WEBSOCKETSERVER +HWTEST_F(WebSocketTest, WebSocketTest009, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + bool ret = WebSocketServerExec::ExecServerStart(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest010, TestSize.Level1) +{ + bool ret = WebSocketServerExec::ExecServerStart(nullptr); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest011, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + context.SetPermissionDenied(true); + bool ret = WebSocketServerExec::ExecServerStart(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest012, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerSendContext context(env, eventManager); + bool ret = WebSocketServerExec::ExecServerSend(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest013, TestSize.Level1) +{ + bool ret = WebSocketServerExec::ExecServerSend(nullptr); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest014, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerSendContext context(env, eventManager); + context.SetPermissionDenied(true); + bool ret = WebSocketServerExec::ExecServerSend(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest015, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerCloseContext context(env, eventManager); + bool ret = WebSocketServerExec::ExecServerClose(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest016, TestSize.Level1) +{ + bool ret = WebSocketServerExec::ExecServerClose(nullptr); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest017, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerCloseContext context(env, eventManager); + context.SetPermissionDenied(true); + bool ret = WebSocketServerExec::ExecServerClose(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest018, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStopContext context(env, eventManager); + bool ret = WebSocketServerExec::ExecServerStop(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest019, TestSize.Level1) +{ + bool ret = WebSocketServerExec::ExecServerStop(nullptr); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest020, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStopContext context(env, eventManager); + context.SetPermissionDenied(true); + bool ret = WebSocketServerExec::ExecServerStop(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest021, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ListAllConnectionsContext context(env, eventManager); + bool ret = WebSocketServerExec::ExecListAllConnections(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest022, TestSize.Level1) +{ + bool ret = WebSocketServerExec::ExecListAllConnections(nullptr); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest023, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ListAllConnectionsContext context(env, eventManager); + context.SetPermissionDenied(true); + bool ret = WebSocketServerExec::ExecListAllConnections(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest024, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ConnectContext context(env, eventManager); + context.SetPermissionDenied(true); + bool ret = WebSocketExec::ExecConnect(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest025, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + SendContext context(env, eventManager); + context.SetPermissionDenied(true); + bool ret = WebSocketExec::ExecSend(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest026, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + CloseContext context(env, eventManager); + context.SetPermissionDenied(true); + bool ret = WebSocketExec::ExecClose(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest027, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStartContext context(env, eventManager); + context.SetPermissionDenied(false); + bool ret = WebSocketServerExec::ExecServerStart(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest028, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerSendContext context(env, eventManager); + context.SetPermissionDenied(false); + bool ret = WebSocketServerExec::ExecServerSend(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest029, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerCloseContext context(env, eventManager); + context.SetPermissionDenied(false); + bool ret = WebSocketServerExec::ExecServerClose(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest030, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ServerStopContext context(env, eventManager); + context.SetPermissionDenied(false); + bool ret = WebSocketServerExec::ExecServerStop(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest031, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ListAllConnectionsContext context(env, eventManager); + context.SetPermissionDenied(false); + bool ret = WebSocketServerExec::ExecListAllConnections(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest032, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + ConnectContext context(env, eventManager); + context.SetPermissionDenied(false); + bool ret = WebSocketExec::ExecConnect(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest033, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + SendContext context(env, eventManager); + context.SetPermissionDenied(false); + bool ret = WebSocketExec::ExecSend(&context); + EXPECT_EQ(ret, false); +} + +HWTEST_F(WebSocketTest, WebSocketTest034, TestSize.Level1) +{ + napi_env env = nullptr; + auto eventManager = std::make_shared(); + CloseContext context(env, eventManager); + context.SetPermissionDenied(false); + bool ret = WebSocketExec::ExecClose(&context); + EXPECT_EQ(ret, false); +} +#endif +} // namespace \ No newline at end of file diff --git a/utils/BUILD.gn b/utils/BUILD.gn index 252016c4f04f68d140b0d3057e8a206a3c6ab995..9ca616c7d318f2272bdf53904388f11aa30539ff 100644 --- a/utils/BUILD.gn +++ b/utils/BUILD.gn @@ -69,6 +69,7 @@ ohos_shared_library("stack_utils_common") { "bounds_checking_function:libsec_shared", "hilog:libhilog", "hisysevent:libhisysevent", + "samgr:samgr_proxy", ] if (defined(global_parts_info) && diff --git a/utils/common_utils/include/netstack_common_utils.h b/utils/common_utils/include/netstack_common_utils.h index 3f04c642022ab7a2cd1c7d06e06b19c8361c3120..e8728d43a421ccc8165d93b041d027966673670e 100644 --- a/utils/common_utils/include/netstack_common_utils.h +++ b/utils/common_utils/include/netstack_common_utils.h @@ -26,6 +26,7 @@ namespace OHOS::NetStack::CommonUtils { static const std::string DOMAIN_TYPE_HTTP_REQUEST = "httpRequest"; static const std::string DOMAIN_TYPE_WEBSOCKET_REQUEST = "webSocket"; const int INVALID_IP_TYPE = -1; +const int MAX_PORT = 65535; enum SdkVersion { FIVE = 5, SIX, @@ -100,5 +101,7 @@ bool Sha256sum(unsigned char *buf, size_t buflen, std::string &digestStr); bool IsCertPubKeyInPinned(const std::string &certPubKeyDigest, const std::string &pinnedPubkey); bool IsCleartextPermitted(const std::string &url, const std::string &protocol); + +bool IsValidPort(const uint32_t &Port); } // namespace OHOS::NetStack::CommonUtils #endif /* COMMUNICATIONNETSTACK_COMMON_UTILS_H */ diff --git a/utils/common_utils/src/netstack_common_utils.cpp b/utils/common_utils/src/netstack_common_utils.cpp index c86542433429bd161aa19f4355e3f3b3dbfbda0b..394e83f367153657a9ade0b65d5eb86e58cef78c 100644 --- a/utils/common_utils/src/netstack_common_utils.cpp +++ b/utils/common_utils/src/netstack_common_utils.cpp @@ -603,4 +603,12 @@ bool IsCleartextPermitted(const std::string &url, const std::string &protocol) #endif return isCleartextPermitted; } + +bool IsValidPort(const uint32_t &port) +{ + if (port < 0 || port > MAX_PORT) { + return false; + } + return true; +} } // namespace OHOS::NetStack::CommonUtils \ No newline at end of file diff --git a/utils/http_over_curl/src/epoll_multi_driver.cpp b/utils/http_over_curl/src/epoll_multi_driver.cpp index 3a768c38cbde0ced1726960dc24d2c0f9fa6d0ce..322e70f29872a71c2b06882142e102afd202fa82 100644 --- a/utils/http_over_curl/src/epoll_multi_driver.cpp +++ b/utils/http_over_curl/src/epoll_multi_driver.cpp @@ -17,6 +17,9 @@ #include "netstack_log.h" #include "request_info.h" +#if HAS_NETSTACK_CHR +#include "netstack_chr_client.h" +#endif namespace OHOS::NetStack::HttpOverCurl { @@ -51,6 +54,9 @@ void EpollMultiDriver::Initialize() }; curl_multi_setopt(multi_, CURLMOPT_TIMERDATA, this); curl_multi_setopt(multi_, CURLMOPT_TIMERFUNCTION, timerCallback); + curl_multi_setopt(multi_, CURLMOPT_MAX_HOST_CONNECTIONS, 6); // 单个主机的最大连接数 + curl_multi_setopt(multi_, CURLMOPT_MAX_TOTAL_CONNECTIONS, 64); // 最大同时打开连接数 + curl_multi_setopt(multi_, CURLMOPT_MAXCONNECTS, 64); // 连接缓冲池的大小 } EpollMultiDriver::~EpollMultiDriver() @@ -142,6 +148,10 @@ __attribute__((no_sanitize("cfi"))) void EpollMultiDriver::CheckMultiInfo() switch (message->msg) { case CURLMSG_DONE: { auto easyHandle = message->easy_handle; +#if HAS_NETSTACK_CHR + ChrClient::NetStackChrClient::GetInstance().GetDfxInfoFromCurlHandleAndReport(easyHandle, + message->data.result); +#endif curl_multi_remove_handle(multi_, easyHandle); auto requestInfo = ongoingRequests_[easyHandle]; ongoingRequests_.erase(easyHandle); diff --git a/utils/napi_utils/include/event_manager.h b/utils/napi_utils/include/event_manager.h index e68f4b26b39a2489a94374ba374b68893dfabb0d..de9560b4f79f2bf8a61799140c3f6481876decb6 100644 --- a/utils/napi_utils/include/event_manager.h +++ b/utils/napi_utils/include/event_manager.h @@ -27,7 +27,7 @@ #include #include #include - +#include #include "event_listener.h" #include "napi/native_api.h" #include "uv.h" @@ -49,7 +49,7 @@ class UserData; namespace Socks5 { class Socks5Instance; } - +using Finalizer = void (*)(napi_env, void *data, void *); class EventManager : public std::enable_shared_from_this { public: EventManager(); @@ -79,6 +79,10 @@ public: void *GetQueueData(); + void SetServerQueueData(void *wsi, void *data); + + void *GetServerQueueData(void *wsi); + void CreateEventReference(napi_env env, napi_value value); void DeleteEventReference(napi_env env); @@ -117,12 +121,34 @@ public: void SetProxyData(std::shared_ptr data); + const std::string &GetWsServerBinaryData(void *wsi); + + const std::string &GetWsServerTextData(void *wsi); + + void AppendWsServerBinaryData(void *wsi, void *data, size_t length); + + void AppendWsServerTextData(void *wsi, void *data, size_t length); + + void ClearWsServerBinaryData(void *wsi); + + void ClearWsServerTextData(void *wsi); + + void SetMaxConnClientCnt(const uint32_t &cnt); + + void SetMaxConnForOneClient(const uint32_t &cnt); + + void AddClientUserData(void *wsi, std::shared_ptr &data); + + void RemoveClientUserData(void *wsi); + + [[nodiscard]] uint32_t GetMaxConcurrentClientCnt()const; + + [[nodiscard]] uint32_t GetMaxConnForOneClient() const; private: std::shared_mutex mutexForListenersAndEmitByUv_; - std::mutex mutexForEmitAndEmitByUv_; std::shared_mutex dataMutex_; std::mutex dataQueueMutex_; - std::list listeners_; + std::list> listeners_; void *data_; std::queue dataQueue_; static EventManagerMagic magic_; @@ -137,11 +163,22 @@ private: std::atomic_bool isReuseAddr_ = false; std::shared_ptr webSocketUserData_; std::shared_ptr proxyData_; + std::shared_mutex dataServerQueueMutex_; + std::mutex mapMutex_; + std::unordered_map> serverDataQueue_; + std::unordered_map wsServerBinaryData_; + std::unordered_map wsServerTextData_; + std::unordered_map> userDataMap_; + uint32_t maxConnClientCnt_; + uint32_t maxConnForOneClient_; public: struct { uint32_t magicNumber = EVENT_MANAGER_MAGIC_NUMBER; } innerMagic_; + napi_env env_ = nullptr; + std::string className_; + Finalizer finalizer_ = nullptr; }; class EventManagerForHttp { @@ -150,6 +187,7 @@ private: [[maybe_unused]] std::mutex mutexForEmitAndEmitByUv_; [[maybe_unused]] std::mutex dataMutex_; [[maybe_unused]] std::mutex dataQueueMutex_; + [[maybe_unused]] std::shared_mutex dataServerQueueMutex_; [[maybe_unused]] std::list listeners_; [[maybe_unused]] void *data_ = nullptr; [[maybe_unused]] std::queue dataQueue_; diff --git a/utils/napi_utils/include/module_template.h b/utils/napi_utils/include/module_template.h index 3f8a39a1f8868dc608e4427038716e1412abda5a..ef57c18268cd6592aa84aa75e257184cfb96ee6a 100644 --- a/utils/napi_utils/include/module_template.h +++ b/utils/napi_utils/include/module_template.h @@ -37,7 +37,6 @@ struct EventManagerWrapper; #define MAX_PARAM_NUM 64 namespace OHOS::NetStack::ModuleTemplate { -typedef void (*Finalizer)(napi_env, void *data, void *); template napi_value InterfaceWithManagerWrapper(napi_env env, napi_callback_info info, const std::string &asyncWorkName, @@ -278,6 +277,8 @@ static void CallbackTemplateWithSharedManager(uv_work_t *work, int status) delete work; } +void CleanUpWithSharedManager(void* data); + void DefineClass(napi_env env, napi_value exports, const std::initializer_list &properties, const std::string &className); diff --git a/utils/napi_utils/src/event_manager.cpp b/utils/napi_utils/src/event_manager.cpp index 058122b892a748fca12da14babbaa88bdbbbed89..4def9ad33626e5a4ad94a7f2166b61e3260bcee9 100644 --- a/utils/napi_utils/src/event_manager.cpp +++ b/utils/napi_utils/src/event_manager.cpp @@ -37,46 +37,45 @@ EventManager::~EventManager() void EventManager::AddListener(napi_env env, const std::string &type, napi_value callback, bool once, bool asyncCallback) { - std::unique_lock lock(mutexForListenersAndEmitByUv_); + std::unique_lock lock(mutexForListenersAndEmitByUv_); auto it = std::remove_if(listeners_.begin(), listeners_.end(), - [type](const EventListener &listener) -> bool { return listener.MatchType(type); }); + [type](const std::shared_ptr &listener) -> bool { return listener->MatchType(type); }); if (it != listeners_.end()) { listeners_.erase(it, listeners_.end()); } - - listeners_.emplace_back(GetCurrentThreadId(), env, type, callback, once, asyncCallback); + auto listener = std::make_shared(GetCurrentThreadId(), env, type, callback, once, asyncCallback); + listeners_.emplace_back(std::move(listener)); } void EventManager::DeleteListener(const std::string &type, napi_value callback) { - std::unique_lock lock(mutexForListenersAndEmitByUv_); - auto it = - std::remove_if(listeners_.begin(), listeners_.end(), [type, callback](const EventListener &listener) -> bool { - return listener.Match(type, callback); + std::unique_lock lock(mutexForListenersAndEmitByUv_); + auto it = std::remove_if(listeners_.begin(), listeners_.end(), + [type, callback] (const std::shared_ptr &listener) -> bool { + return listener->Match(type, callback); }); listeners_.erase(it, listeners_.end()); } void EventManager::Emit(const std::string &type, const std::pair &argv) { - std::shared_lock lock2(mutexForListenersAndEmitByUv_); + std::shared_lock lock(mutexForListenersAndEmitByUv_); auto listeners = listeners_; - lock2.unlock(); - std::for_each(listeners.begin(), listeners.end(), [type, argv](const EventListener &listener) { - if (listener.IsAsyncCallback()) { + lock.unlock(); + std::for_each(listeners.begin(), listeners.end(), [type, argv] (const std::shared_ptr &listener) { + if (listener->IsAsyncCallback()) { /* AsyncCallback(BusinessError error, T data) */ napi_value arg[ASYNC_CALLBACK_PARAM_NUM] = {argv.first, argv.second}; - listener.Emit(type, ASYNC_CALLBACK_PARAM_NUM, arg); + listener->Emit(type, ASYNC_CALLBACK_PARAM_NUM, arg); } else { /* Callback(T data) */ napi_value arg[CALLBACK_PARAM_NUM] = {argv.second}; - listener.Emit(type, CALLBACK_PARAM_NUM, arg); + listener->Emit(type, CALLBACK_PARAM_NUM, arg); } }); - - std::unique_lock lock(mutexForListenersAndEmitByUv_); + std::unique_lock lock2(mutexForListenersAndEmitByUv_); auto it = std::remove_if(listeners_.begin(), listeners_.end(), - [type](const EventListener &listener) -> bool { return listener.MatchOnce(type); }); + [type] (const std::shared_ptr &listener) -> bool { return listener->MatchOnce(type); }); listeners_.erase(it, listeners_.end()); } @@ -92,14 +91,15 @@ void *EventManager::GetData() void EventManager::EmitByUvWithoutCheckShared(const std::string &type, void *data, void (*Handler)(uv_work_t *, int)) { - std::shared_lock lock2(mutexForListenersAndEmitByUv_); - bool foundHeader = std::find_if(listeners_.begin(), listeners_.end(), [](const EventListener &listener) { - return listener.MatchType(ON_HEADER_RECEIVE); - }) != listeners_.end(); + std::shared_lock lock(mutexForListenersAndEmitByUv_); + bool foundHeader = std::find_if(listeners_.begin(), listeners_.end(), + [] (const std::shared_ptr &listener) { return listener->MatchType(ON_HEADER_RECEIVE); }) != + listeners_.end(); + + bool foundHeaders = std::find_if(listeners_.begin(), listeners_.end(), + [] (const std::shared_ptr &listener) { return listener->MatchType(ON_HEADERS_RECEIVE);}) != + listeners_.end(); - bool foundHeaders = std::find_if(listeners_.begin(), listeners_.end(), [](const EventListener &listener) { - return listener.MatchType(ON_HEADERS_RECEIVE); - }) != listeners_.end(); if (!foundHeader && !foundHeaders) { if (type == ON_HEADER_RECEIVE || type == ON_HEADERS_RECEIVE) { auto tempMap = static_cast *>(data); @@ -117,12 +117,13 @@ void EventManager::EmitByUvWithoutCheckShared(const std::string &type, void *dat } } - std::for_each(listeners_.begin(), listeners_.end(), [type, data, Handler, this](const EventListener &listener) { - if (listener.MatchType(type)) { - auto workWrapper = new UvWorkWrapperShared(data, listener.GetEnv(), type, shared_from_this()); - listener.EmitByUv(type, workWrapper, Handler); - } - }); + std::for_each(listeners_.begin(), listeners_.end(), + [type, data, Handler, this] (const std::shared_ptr &listener) { + if (listener->MatchType(type)) { + auto workWrapper = new UvWorkWrapperShared(data, listener->GetEnv(), type, shared_from_this()); + listener->EmitByUv(type, workWrapper, Handler); + } + }); } void EventManager::SetQueueData(void *data) @@ -143,18 +144,42 @@ void *EventManager::GetQueueData() return nullptr; } +void EventManager::SetServerQueueData(void *wsi, void *data) +{ + std::unique_lock lock(dataServerQueueMutex_); + serverDataQueue_[wsi].push(data); +} + +void *EventManager::GetServerQueueData(void *wsi) +{ + if (wsi == nullptr) { + NETSTACK_LOGE("wsi is nullptr"); + return nullptr; + } + { + std::shared_lock lock(dataServerQueueMutex_); + if (serverDataQueue_.empty() || serverDataQueue_.find(wsi) == serverDataQueue_.end()) { + NETSTACK_LOGE("eventManager server data queue is empty"); + return nullptr; + } + auto data = serverDataQueue_[wsi].front(); + serverDataQueue_[wsi].pop(); + return data; + } +} + bool EventManager::HasEventListener(const std::string &type) { - std::shared_lock lock(mutexForListenersAndEmitByUv_); + std::shared_lock lock(mutexForListenersAndEmitByUv_); return std::any_of(listeners_.begin(), listeners_.end(), - [&type](const EventListener &listener) -> bool { return listener.MatchType(type); }); + [&type] (const std::shared_ptr &listener) -> bool { return listener->MatchType(type); }); } void EventManager::DeleteListener(const std::string &type) { - std::unique_lock lock(mutexForListenersAndEmitByUv_); + std::unique_lock lock(mutexForListenersAndEmitByUv_); auto it = std::remove_if(listeners_.begin(), listeners_.end(), - [type](const EventListener &listener) -> bool { return listener.MatchType(type); }); + [type] (const std::shared_ptr &listener) -> bool { return listener->MatchType(type); }); listeners_.erase(it, listeners_.end()); } @@ -206,6 +231,71 @@ void EventManager::AppendWebSocketBinaryData(void *data, size_t length) webSocketBinaryData_.append(reinterpret_cast(data), length); } +const std::string &EventManager::GetWsServerBinaryData(void *wsi) +{ + return wsServerBinaryData_[wsi]; +} + +const std::string &EventManager::GetWsServerTextData(void *wsi) +{ + return wsServerTextData_[wsi]; +} + +void EventManager::AppendWsServerBinaryData(void *wsi, void *data, size_t length) +{ + wsServerBinaryData_[wsi].append(reinterpret_cast(data), length); +} + +void EventManager::AppendWsServerTextData(void *wsi, void *data, size_t length) +{ + wsServerTextData_[wsi].append(reinterpret_cast(data), length); +} + +void EventManager::ClearWsServerBinaryData(void *wsi) +{ + wsServerBinaryData_[wsi].clear(); +} + +void EventManager::ClearWsServerTextData(void *wsi) +{ + wsServerTextData_[wsi].clear(); +} + +void EventManager::SetMaxConnClientCnt(const uint32_t &cnt) +{ + maxConnClientCnt_ = cnt; +} + +void EventManager::SetMaxConnForOneClient(const uint32_t &cnt) +{ + maxConnForOneClient_ = cnt; +} + +uint32_t EventManager::GetMaxConcurrentClientCnt() const +{ + return maxConnClientCnt_; +} + +uint32_t EventManager::GetMaxConnForOneClient() const +{ + return maxConnForOneClient_; +} + +void EventManager::AddClientUserData(void *wsi, std::shared_ptr &data) +{ + std::lock_guard lock(mapMutex_); + userDataMap_[wsi] = data; +} + +void EventManager::RemoveClientUserData(void *wsi) +{ + std::lock_guard lock(mapMutex_); + auto it = userDataMap_.find(wsi); + if (it != userDataMap_.end()) { + userDataMap_.erase(it); + } +} + void EventManager::ClearWebSocketTextData() { webSocketTextData_.clear(); @@ -246,25 +336,21 @@ bool EventManager::GetReuseAddr() std::shared_ptr EventManager::GetProxyData() { - std::unique_lock lock(dataMutex_); return proxyData_; } void EventManager::SetProxyData(std::shared_ptr data) { - std::unique_lock lock(dataMutex_); proxyData_ = data; } void EventManager::SetWebSocketUserData(const std::shared_ptr &userData) { - std::unique_lock lock(dataMutex_); webSocketUserData_ = userData; } std::shared_ptr EventManager::GetWebSocketUserData() { - std::unique_lock lock(dataMutex_); return webSocketUserData_; } diff --git a/utils/napi_utils/src/module_template.cpp b/utils/napi_utils/src/module_template.cpp index 6da72fe953f54eeff98e203fae4b612d9cf1917e..1898ba32308374bb3b41a8b1e144e3928d4da943 100644 --- a/utils/napi_utils/src/module_template.cpp +++ b/utils/napi_utils/src/module_template.cpp @@ -31,6 +31,8 @@ static constexpr const char *INTERFACE_LOCAL_SOCKET = "LocalSocket"; static constexpr const char *INTERFACE_TLS_SOCKET = "TLSSocket"; static constexpr const char *INTERFACE_WEB_SOCKET = "WebSocket"; static constexpr const char *INTERFACE_HTTP_REQUEST = "OHOS_NET_HTTP_HttpRequest"; +static constexpr const char *INTERFACE_WEB_SOCKET_SERVER = "WebSocketServer"; +static constexpr const char *EVENT_MANAGER = "EVENT_MANAGER"; napi_value OnManagerWrapper(napi_env env, napi_callback_info info, const std::initializer_list &events, bool asyncCallback) @@ -292,6 +294,20 @@ napi_value OffSharedManager(napi_env env, napi_callback_info info, const std::in return NapiUtils::GetUndefined(env); } +void CleanUpWithSharedManager(void* data) +{ + auto sharedManager = reinterpret_cast *>(data); + if (sharedManager == nullptr || *sharedManager == nullptr) { + return; + } + auto manager = *sharedManager; + auto env = manager->env_; + napi_value obj = nullptr; + void* result = nullptr; + napi_get_named_property(env, NapiUtils::GetGlobal(env), manager->className_.c_str(), &obj); + napi_remove_wrap(env, obj, &result); +} + void DefineClass(napi_env env, napi_value exports, const std::initializer_list &properties, const std::string &className) { @@ -334,7 +350,8 @@ napi_value NewInstanceWithManagerWrapper(napi_env env, napi_callback_info info, auto manager = std::make_shared(); wrapper->sharedManager = manager; if (className == INTERFACE_HTTP_REQUEST || className == INTERFACE_LOCAL_SOCKET || - className == INTERFACE_TLS_SOCKET || className == INTERFACE_WEB_SOCKET) { + className == INTERFACE_TLS_SOCKET || className == INTERFACE_WEB_SOCKET || + className == INTERFACE_WEB_SOCKET_SERVER) { NETSTACK_LOGD("create reference for %{public}s", className.c_str()); manager->CreateEventReference(env, thisVal); } @@ -364,14 +381,29 @@ napi_value NewInstanceWithSharedManager(napi_env env, napi_callback_info info, c return result; } auto manager = std::make_shared(); + manager->env_ = env; + manager->className_ = className + EVENT_MANAGER; + manager->finalizer_ = finalizer; *sharedManager = manager; if (className == INTERFACE_HTTP_REQUEST || className == INTERFACE_LOCAL_SOCKET || - className == INTERFACE_TLS_SOCKET || className == INTERFACE_WEB_SOCKET) { + className == INTERFACE_TLS_SOCKET || className == INTERFACE_WEB_SOCKET || + className == INTERFACE_WEB_SOCKET_SERVER) { NETSTACK_LOGD("create reference for %{public}s", className.c_str()); manager->CreateEventReference(env, thisVal); } - napi_wrap(env, result, reinterpret_cast(sharedManager), finalizer, nullptr, nullptr); - + napi_wrap(env, result, reinterpret_cast(sharedManager), + [](napi_env env, void *data, void *hint) { + napi_remove_env_cleanup_hook(env, CleanUpWithSharedManager, data); + auto sharedManager = reinterpret_cast *>(data); + if (sharedManager == nullptr || *sharedManager == nullptr || (*sharedManager)->finalizer_ == nullptr) { + return; + } + auto manager = *sharedManager; + manager->finalizer_(env, data, hint); + }, + nullptr, nullptr); + napi_set_named_property(env, global, manager->className_.c_str(), result); + napi_add_env_cleanup_hook(env, CleanUpWithSharedManager, reinterpret_cast(sharedManager)); return result; } diff --git a/utils/napi_utils/src/napi_utils.cpp b/utils/napi_utils/src/napi_utils.cpp index ce551dd7c0f98d8894a8248535c0284d5a04f215..47afe60d75cd65b648ade64bd12f2e60a4ee01b3 100644 --- a/utils/napi_utils/src/napi_utils.cpp +++ b/utils/napi_utils/src/napi_utils.cpp @@ -803,9 +803,6 @@ uint64_t CreateUvHandlerQueue(napi_env env) } void *result = nullptr; napi_remove_wrap(env, queueWrapper, &result); - auto id = reinterpret_cast(result); - std::lock_guard lock(g_mutex); - g_handlerQueueMap.erase(id); }, envWrapper); return newId; diff --git a/utils/netstack_chr_client/include/i_netstack_chr_client.h b/utils/netstack_chr_client/include/i_netstack_chr_client.h new file mode 100644 index 0000000000000000000000000000000000000000..4abd2e83663b749189856b3e49b8edf82c22677d --- /dev/null +++ b/utils/netstack_chr_client/include/i_netstack_chr_client.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025-2025 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 COMMUNICATIONNETSTACK_I_NETSTACK_CHR_CLIENT_H +#define COMMUNICATIONNETSTACK_I_NETSTACK_CHR_CLIENT_H + +#include +#include +#include "curl/curl.h" + +namespace OHOS::NetStack::ChrClient { + +typedef struct DataTransHttpInfo { + int uid; + int responseCode; + curl_off_t totalTime; + curl_off_t nameLookUpTime; + curl_off_t connectTime; + curl_off_t preTransferTime; + curl_off_t sizeUpload; + curl_off_t sizeDownload; + curl_off_t speedDownload; + curl_off_t speedUpload; + std::string effectiveMethod; + curl_off_t startTransferTime; + std::string contentType; + curl_off_t redirectTime; + long redirectCount; + long osError; + long sslVerifyResult; + curl_off_t appconnectTime; + curl_off_t retryAfter; + int proxyError; + curl_off_t queueTime; + long curlCode; + long requestStartTime; +} DataTransHttpInfo; + +typedef struct DataTransTcpInfo { + uint32_t unacked; + uint32_t lastDataSent; + uint32_t lastAckSent; + uint32_t lastDataRecv; + uint32_t lastAckRecv; + uint32_t rtt; + uint32_t rttvar; + uint16_t retransmits; + uint32_t totalRetrans; + std::string srcIp; + std::string dstIp; + uint16_t srcPort; + uint16_t dstPort; +} DataTransTcpInfo; + +typedef struct DataTransChrStats { + std::string processName; + DataTransHttpInfo httpInfo; + DataTransTcpInfo tcpInfo; +} DataTransChrStats; +} // namespace OHOS::NetStack +#endif // COMMUNICATIONNETSTACK_I_NETSTACK_CHR_CLIENT_H \ No newline at end of file diff --git a/utils/netstack_chr_client/include/netstack_chr_client.h b/utils/netstack_chr_client/include/netstack_chr_client.h new file mode 100644 index 0000000000000000000000000000000000000000..7ffd9b5effbb52ddc70e4e2b1748285a0d7ea77c --- /dev/null +++ b/utils/netstack_chr_client/include/netstack_chr_client.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025-2025 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 COMMUNICATIONNETSTACK_NETSTACK_CHR_CLIENT_H +#define COMMUNICATIONNETSTACK_NETSTACK_CHR_CLIENT_H + +#include +#include +#include "curl/curl.h" +#include "netstack_chr_report.h" +#include "i_netstack_chr_client.h" + +namespace OHOS::NetStack::ChrClient { + +class NetStackChrClient { +public: + static NetStackChrClient &GetInstance(); + void GetDfxInfoFromCurlHandleAndReport(CURL *handle, int32_t curlCode); + +private: + NetStackChrClient() = default; + ~NetStackChrClient() = default; + + static int GetAddrFromSock( + int sockfd, std::string &srcIp, std::string &dstIp, uint16_t &srcPort, uint16_t &dstPort); + static int GetTcpInfoFromSock(const curl_socket_t sockfd, DataTransTcpInfo &httpTcpInfo); + static void GetHttpInfoFromCurl(CURL *handle, DataTransHttpInfo &httpInfo); + + template + static DataType GetNumericAttributeFromCurl(CURL *handle, CURLINFO info); + static std::string GetStringAttributeFromCurl(CURL *handle, CURLINFO info); + static long GetRequestStartTime(curl_off_t totalTime); + static int shouldReportHttpAbnormalEvent(const DataTransHttpInfo &httpInfo); + NetStackChrReport netstackChrReport; +}; + +} // namespace OHOS::NetStack::ChrClient + +#endif // COMMUNICATIONNETSTACK_NETSTACK_CHR_CLIENT_H \ No newline at end of file diff --git a/utils/netstack_chr_client/include/netstack_chr_report.h b/utils/netstack_chr_client/include/netstack_chr_report.h new file mode 100644 index 0000000000000000000000000000000000000000..874cd146c9fa0d714e04de9d270e69fb777ea81e --- /dev/null +++ b/utils/netstack_chr_client/include/netstack_chr_report.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 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 COMMUNICATIONNETSTACK_NETSTACK_CHR_REPORT_H +#define COMMUNICATIONNETSTACK_NETSTACK_CHR_REPORT_H + +#include +#include "i_netstack_chr_client.h" +#include "want.h" + +namespace OHOS::NetStack::ChrClient { + +using namespace OHOS::NetStack::ChrClient; + +class NetStackChrReport { +public: + NetStackChrReport(); + ~NetStackChrReport(); + + int ReportCommonEvent(DataTransChrStats chrStats); +private: + std::chrono::system_clock::time_point lastReceivedTime_; + int ignoreReportTimes_ = 0; + std::mutex report_mutex_; + + void SetWantParam(AAFwk::Want& want, DataTransChrStats chrStats); + void SetHttpInfoJsonStr(DataTransHttpInfo httpInfo, std::string& httpInfoJsonStr); + void SetTcpInfoJsonStr(DataTransTcpInfo tcpInfo, std::string& tcpInfoJsonStr); +}; +} // namespace OHOS::NatStack::ChrClient +#endif // COMMUNICATIONNETSTACK_NETSTACK_CHR_REPORT_H \ No newline at end of file diff --git a/utils/netstack_chr_client/src/netstack_chr_client.cpp b/utils/netstack_chr_client/src/netstack_chr_client.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3bb924fca4d64b3ec824fdd0f527344724b4851b --- /dev/null +++ b/utils/netstack_chr_client/src/netstack_chr_client.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2025-2025 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 +#include +#include +#include +#include "netstack_chr_client.h" +#include "netstack_common_utils.h" +#include "netstack_log.h" +#include "i_netstack_chr_client.h" + +namespace OHOS::NetStack::ChrClient { + +static constexpr const int HTTP_REQUEST_SUCCESS = 200; +static constexpr const int HTTP_FILE_TRANSFER_SIZE_THRESHOLD = 100000; +static constexpr const int HTTP_FILE_TRANSFER_TIME_THRESHOLD = 500000; + +NetStackChrClient &NetStackChrClient::GetInstance() +{ + static NetStackChrClient instance; + return instance; +} + +int NetStackChrClient::GetAddrFromSock( + int sockfd, std::string &srcIp, std::string &dstIp, uint16_t &srcPort, uint16_t &dstPort) +{ + sockaddr_storage localss{}; + sockaddr_storage peerss{}; + socklen_t addrLen = 0; + + // Get local addr + addrLen = sizeof(localss); + (void)getsockname(sockfd, reinterpret_cast(&localss), &addrLen); + + // Get peer addr + addrLen = sizeof(peerss); + (void)getpeername(sockfd, reinterpret_cast(&peerss), &addrLen); + + char buf[INET6_ADDRSTRLEN] = {0}; + if (localss.ss_family == AF_INET && peerss.ss_family == AF_INET) { + auto *l4 = reinterpret_cast(&localss); + auto *p4 = reinterpret_cast(&peerss); + if (inet_ntop(AF_INET, &l4->sin_addr, buf, sizeof(buf)) != nullptr) { + srcIp = buf; + srcPort = ntohs(l4->sin_port); + } + if (inet_ntop(AF_INET, &p4->sin_addr, buf, sizeof(buf)) != nullptr) { + dstIp = buf; + dstPort = ntohs(p4->sin_port); + } + } else if (localss.ss_family == AF_INET6 && peerss.ss_family == AF_INET6) { + auto *l6 = reinterpret_cast(&localss); + auto *p6 = reinterpret_cast(&peerss); + if (inet_ntop(AF_INET6, &l6->sin6_addr, buf, sizeof(buf)) != nullptr) { + srcIp = buf; + srcPort = ntohs(l6->sin6_port); + } + if (inet_ntop(AF_INET6, &p6->sin6_addr, buf, sizeof(buf)) != nullptr) { + dstIp = buf; + dstPort = ntohs(p6->sin6_port); + } + } else { + return -1; + } + + return 0; +} + +int NetStackChrClient::GetTcpInfoFromSock(const curl_socket_t sockfd, DataTransTcpInfo &httpTcpInfo) +{ + if (sockfd <= 0) { + return -1; + } + struct tcp_info tcpInfo = {}; + socklen_t infoLen = sizeof(tcpInfo); + + if (getsockopt(sockfd, IPPROTO_TCP, TCP_INFO, &tcpInfo, &infoLen) < 0) { + return -1; + } + + httpTcpInfo.unacked = tcpInfo.tcpi_unacked; + httpTcpInfo.lastDataSent = tcpInfo.tcpi_last_data_sent; + httpTcpInfo.lastAckSent = tcpInfo.tcpi_last_ack_sent; + httpTcpInfo.lastDataRecv = tcpInfo.tcpi_last_data_recv; + httpTcpInfo.lastAckRecv = tcpInfo.tcpi_last_ack_recv; + httpTcpInfo.rtt = tcpInfo.tcpi_rtt; + httpTcpInfo.rttvar = tcpInfo.tcpi_rttvar; + httpTcpInfo.totalRetrans = tcpInfo.tcpi_total_retrans; + httpTcpInfo.retransmits = tcpInfo.tcpi_retransmits; + + if (GetAddrFromSock(sockfd, httpTcpInfo.srcIp, httpTcpInfo.dstIp, httpTcpInfo.srcPort, httpTcpInfo.dstPort) == 0) { + httpTcpInfo.srcIp = CommonUtils::AnonymizeIp(httpTcpInfo.srcIp); + httpTcpInfo.dstIp = CommonUtils::AnonymizeIp(httpTcpInfo.dstIp); + } + + return 0; +} + +template +DataType NetStackChrClient::GetNumericAttributeFromCurl(CURL *handle, CURLINFO info) +{ + DataType number = 0; + CURLcode res = curl_easy_getinfo(handle, info, &number); + if (res != CURLE_OK) { + return -1; + } + return number; +} + +std::string NetStackChrClient::GetStringAttributeFromCurl(CURL *handle, CURLINFO info) +{ + char *result = nullptr; + CURLcode res = curl_easy_getinfo(handle, info, &result); + if (res != CURLE_OK || result == nullptr) { + return std::string(); + } + return std::string(result); +} + +long NetStackChrClient::GetRequestStartTime(curl_off_t totalTime) +{ + auto now = std::chrono::system_clock::now(); + long msCount = std::chrono::duration_cast(now.time_since_epoch()).count(); + return msCount; +} + +void NetStackChrClient::GetHttpInfoFromCurl(CURL *handle, DataTransHttpInfo &httpInfo) +{ + (void)curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &httpInfo.responseCode); + httpInfo.nameLookUpTime = GetNumericAttributeFromCurl(handle, CURLINFO_NAMELOOKUP_TIME_T); + httpInfo.connectTime = GetNumericAttributeFromCurl(handle, CURLINFO_CONNECT_TIME_T); + httpInfo.preTransferTime = GetNumericAttributeFromCurl(handle, CURLINFO_PRETRANSFER_TIME_T); + httpInfo.startTransferTime = GetNumericAttributeFromCurl(handle, CURLINFO_STARTTRANSFER_TIME_T); + httpInfo.totalTime = GetNumericAttributeFromCurl(handle, CURLINFO_TOTAL_TIME_T); + httpInfo.redirectTime = GetNumericAttributeFromCurl(handle, CURLINFO_REDIRECT_TIME_T); + httpInfo.appconnectTime = GetNumericAttributeFromCurl(handle, CURLINFO_APPCONNECT_TIME_T); + httpInfo.queueTime = GetNumericAttributeFromCurl(handle, CURLINFO_QUEUE_TIME_T); + httpInfo.retryAfter = GetNumericAttributeFromCurl(handle, CURLINFO_RETRY_AFTER); + httpInfo.requestStartTime = GetRequestStartTime(httpInfo.totalTime); + + httpInfo.sizeUpload = GetNumericAttributeFromCurl(handle, CURLINFO_SIZE_UPLOAD_T); + httpInfo.sizeDownload = GetNumericAttributeFromCurl(handle, CURLINFO_SIZE_DOWNLOAD_T); + httpInfo.speedDownload = GetNumericAttributeFromCurl(handle, CURLINFO_SPEED_DOWNLOAD_T); + httpInfo.speedUpload = GetNumericAttributeFromCurl(handle, CURLINFO_SPEED_UPLOAD_T); + + httpInfo.redirectCount = GetNumericAttributeFromCurl(handle, CURLINFO_REDIRECT_COUNT); + httpInfo.osError = GetNumericAttributeFromCurl(handle, CURLINFO_OS_ERRNO); + httpInfo.sslVerifyResult = GetNumericAttributeFromCurl(handle, CURLINFO_PROXY_SSL_VERIFYRESULT); + httpInfo.proxyError = GetNumericAttributeFromCurl(handle, CURLINFO_PROXY_ERROR); + + httpInfo.effectiveMethod = GetStringAttributeFromCurl(handle, CURLINFO_EFFECTIVE_METHOD); + httpInfo.contentType = GetStringAttributeFromCurl(handle, CURLINFO_CONTENT_TYPE); +} + +int NetStackChrClient::shouldReportHttpAbnormalEvent(const DataTransHttpInfo &httpInfo) +{ + if (httpInfo.curlCode != 0 || httpInfo.responseCode != HTTP_REQUEST_SUCCESS || + httpInfo.osError != 0 || httpInfo.proxyError != 0) { + return 0; + } + if ((httpInfo.sizeUpload + httpInfo.sizeDownload <= HTTP_FILE_TRANSFER_SIZE_THRESHOLD) && + httpInfo.totalTime > HTTP_FILE_TRANSFER_TIME_THRESHOLD) { + return 0; + } + + return -1; +} + +void NetStackChrClient::GetDfxInfoFromCurlHandleAndReport(CURL *handle, int32_t curlCode) +{ + if (handle == NULL) { + return; + } + + DataTransChrStats dataTransChrStats{}; + dataTransChrStats.httpInfo.uid = static_cast(getuid()); + dataTransChrStats.httpInfo.curlCode = curlCode; + if (CommonUtils::GetBundleName().has_value()) { + dataTransChrStats.processName = CommonUtils::GetBundleName().value(); + } + + GetHttpInfoFromCurl(handle, dataTransChrStats.httpInfo); + if (shouldReportHttpAbnormalEvent(dataTransChrStats.httpInfo) != 0) { + return; + } + + curl_off_t sockfd = 0; + curl_easy_getinfo(handle, CURLINFO_ACTIVESOCKET, &sockfd); + + if (GetTcpInfoFromSock(sockfd, dataTransChrStats.tcpInfo) != 0) { + NETSTACK_LOGD("Chr client get tcp info from socket failed, sockfd: %{public}" PRId64, sockfd); + } + + int ret = netstackChrReport.ReportCommonEvent(dataTransChrStats); + if (ret > 0) { + NETSTACK_LOGE("Send to CHR failed, error code %{public}d", ret); + } +} + +} // namespace OHOS::NetStack::ChrClient \ No newline at end of file diff --git a/utils/netstack_chr_client/src/netstack_chr_report.cpp b/utils/netstack_chr_client/src/netstack_chr_report.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a746a9d5298233df387ecee4e33a1b80ab68adc0 --- /dev/null +++ b/utils/netstack_chr_client/src/netstack_chr_report.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2025 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 +#include "i_netstack_chr_client.h" +#include "netstack_chr_report.h" +#include "netstack_log.h" +#include "common_event_manager.h" + +using namespace OHOS::NetStack::ChrClient; + +static constexpr const char* REPORT_HTTP_EVENT_NAME = "custom.event.CHR_REPORT_HTTP"; +static constexpr const std::int32_t CHR_UID = 1201; +static constexpr const int REPORT_TIME_LIMIT_MINUTE = 5; + +static constexpr const int REPORT_CHR_RESULT_SUCCESS = 0; +static constexpr const int REPORT_CHR_RESULT_TIME_LIMIT_ERROR = 1; +static constexpr const int REPORT_CHR_RESULT_REPORT_FAIL = 2; + +NetStackChrReport::NetStackChrReport() +{} + +NetStackChrReport::~NetStackChrReport() +{} + +int NetStackChrReport::ReportCommonEvent(DataTransChrStats chrStats) +{ + std::lock_guard lock(report_mutex_); + auto currentTime = std::chrono::system_clock::now(); + auto timeDifference = std::chrono::duration_cast(currentTime - lastReceivedTime_); + if (timeDifference.count() < REPORT_TIME_LIMIT_MINUTE) { + ignoreReportTimes_ += 1; + return REPORT_CHR_RESULT_TIME_LIMIT_ERROR; + } + AAFwk::Want want; + want.SetAction(REPORT_HTTP_EVENT_NAME); + SetWantParam(want, chrStats); + + EventFwk::CommonEventData commonEventData; + commonEventData.SetWant(want); + EventFwk::CommonEventPublishInfo publishInfo; + publishInfo.SetSubscriberUid({CHR_UID}); + if (!EventFwk::CommonEventManager::PublishCommonEvent(commonEventData, publishInfo)) { + NETSTACK_LOGE("Subscriber is nullptr, report to CHR failed."); + return REPORT_CHR_RESULT_REPORT_FAIL; + } + NETSTACK_LOGI("Report to CHR success, %{public}d reports are ignore before this.", ignoreReportTimes_); + lastReceivedTime_ = currentTime; + ignoreReportTimes_ = 0; + + return REPORT_CHR_RESULT_SUCCESS; +} + +void NetStackChrReport::SetWantParam(AAFwk::Want& want, DataTransChrStats chrStats) +{ + std::string httpInfoJsonStr; + std::string tcpInfoJsonStr; + SetHttpInfoJsonStr(chrStats.httpInfo, httpInfoJsonStr); + SetTcpInfoJsonStr(chrStats.tcpInfo, tcpInfoJsonStr); + + want.SetParam("PROCESS_NAME", chrStats.processName); + want.SetParam("DATA_TRANS_HTTP_INFO", httpInfoJsonStr); + want.SetParam("DATA_TRANS_TCP_INFO", tcpInfoJsonStr); +} + +void NetStackChrReport::SetHttpInfoJsonStr(DataTransHttpInfo httpInfo, std::string& httpInfoJsonStr) +{ + std::stringstream ss; + ss << "{\"uid\":" << httpInfo.uid + << ",{\"response_code\":" << httpInfo.responseCode + << ",{\"total_time\":" << httpInfo.totalTime + << ",{\"namelookup_time\":" << httpInfo.nameLookUpTime + << ",{\"connect_time\":" << httpInfo.connectTime + << ",{\"pretransfer_time\":" << httpInfo.preTransferTime + << ",{\"size_upload\":" << httpInfo.sizeUpload + << ",{\"size_download\":" << httpInfo.sizeDownload + << ",{\"speed_download\":" << httpInfo.speedDownload + << ",{\"speed_upload\":" << httpInfo.speedUpload + << ",{\"effective_method\":\"" << httpInfo.effectiveMethod + << "\",{\"starttransfer_time\":" << httpInfo.startTransferTime + << ",{\"content_type\":\"" << httpInfo.contentType + << "\",{\"redirect_time\":" << httpInfo.redirectTime + << ",{\"redirect_count\":" << httpInfo.redirectCount + << ",{\"os_errno\":" << httpInfo.osError + << ",{\"ssl_verifyresult\":" << httpInfo.sslVerifyResult + << ",{\"appconnect_time\":" << httpInfo.appconnectTime + << ",{\"retry_after\":" << httpInfo.uid + << ",{\"proxy_error\":" << httpInfo.proxyError + << ",{\"queue_time\":" << httpInfo.queueTime + << ",{\"curl_code\":"<< httpInfo.curlCode + << ",{\"request_start_time\":" << httpInfo.requestStartTime << "}"; + httpInfoJsonStr = ss.str(); +} + +void NetStackChrReport::SetTcpInfoJsonStr(DataTransTcpInfo tcpInfo, std::string& tcpInfoJsonStr) +{ + std::stringstream ss; + ss << "{\"tcpi_unacked\":" << tcpInfo.unacked + << ",{\"tcpi_last_data_sent\":" << tcpInfo.lastDataSent + << ",{\"tcpi_last_ack_sent\":" << tcpInfo.lastAckSent + << ",{\"tcpi_last_data_recv\":" << tcpInfo.lastDataRecv + << ",{\"tcpi_last_ack_recv\":" << tcpInfo.lastAckRecv + << ",{\"tcpi_rtt\":" << tcpInfo.rtt + << ",{\"tcpi_rttvar\":" << tcpInfo.rttvar + << ",{\"tcpi_retransmits\":" << tcpInfo.retransmits + << ",{\"tcpi_total_retrans\":" << tcpInfo.totalRetrans + << ",{\"src_ip\":\"" << tcpInfo.srcIp + << "\",{\"dst_ip\":\"" << tcpInfo.dstIp + << "\",{\"src_port\":" << tcpInfo.srcPort + << ",{\"dst_port\":" << tcpInfo.dstPort << "}"; + tcpInfoJsonStr = ss.str(); +} \ No newline at end of file