diff --git a/bundle.json b/bundle.json index b361336800b02358fd834505f26918fbed2c50bd..e5147f5a67204bf2f402a96461aa8ed89c2f1d70 100644 --- a/bundle.json +++ b/bundle.json @@ -56,7 +56,8 @@ "libwebsockets", "node", "jsoncpp", - "netmanager_enhanced" + "netmanager_enhanced", + "common_event_service" ] }, "build": { diff --git a/frameworks/js/napi/http/BUILD.gn b/frameworks/js/napi/http/BUILD.gn index 81fa9f8ffa665a5c2cdfcb4b82395e7cd7fea493..257dee2586e0148a554be15b7a0b07bf4855226c 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 = [] @@ -161,6 +164,8 @@ ohos_shared_library("http") { external_deps += [ "netmanager_base:netsys_client" ] defines = [ "HAS_NETMANAGER_BASE=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", ] 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 8d4215801c2104aa7c634645d0981e9940464270..76916bbc43895f69f51314393e44f0aaf370161c 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" @@ -549,6 +550,9 @@ void HttpExec::HandleCurlData(CURLMsg *msg) NETSTACK_LOGD("priority = %{public}d", context->options.GetPriority()); context->SetExecOK(GetCurlDataFromHandle(handle, context, msg->msg, msg->data.result)); CacheCurlPerformanceTiming(handle, context); +#if HAS_NETMANAGER_BASE + ChrClient::NetStackChrClient::GetInstance().GetDfxInfoFromCurlHandleAndReport(handle, msg->data.result); +#endif if (context->IsExecOK()) { CacheProxy proxy(context->options); proxy.WriteResponseToCache(context->response); diff --git a/frameworks/native/http/http_client/http_client_task.cpp b/frameworks/native/http/http_client/http_client_task.cpp index f113f34dbcf61feaca75e97776585fe4d660a42e..abdfd31e6c03b62dfd278a362e0a7f3f949a24a5 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,6 +734,9 @@ void HttpClientTask::ProcessResponse(CURLMsg *msg) response_.SetResponseTime(HttpTime::GetNowTimeGMT()); DumpHttpPerformance(); +#if HAS_NETMANAGER_BASE + ChrClient::NetStackChrClient::GetInstance().GetDfxInfoFromCurlHandleAndReport(curlHandle_, code); +#endif if (CURLE_ABORTED_BY_CALLBACK == code) { (void)ProcessResponseCode(); diff --git a/interfaces/innerkits/http_client/BUILD.gn b/interfaces/innerkits/http_client/BUILD.gn index 9e209c686f501fea94910e417fd537eac9a9b4b0..b2fa2fc2e823ec7452e5ec398dc8079a89e0b35c 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 = [] @@ -61,6 +62,7 @@ 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/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/test/unittest/http/BUILD.gn b/test/unittest/http/BUILD.gn index ecf3f050a5fa65ca843dd4858de37354dda93574..1fd029d916a4e929200db04b36377e0e50188266 100644 --- a/test/unittest/http/BUILD.gn +++ b/test/unittest/http/BUILD.gn @@ -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,7 @@ 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/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/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..03ce178ea2bcc9acaf3be3d9396ecb3c70a55e87 --- /dev/null +++ b/utils/netstack_chr_client/include/i_netstack_chr_client.h @@ -0,0 +1,127 @@ +/* + * 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 DataTransTcpInfo { + uint8_t retransmits; + uint32_t unacked; + + uint32_t lastDataSent; + uint32_t lastAckSent; + uint32_t lastDataRecv; + uint32_t lastAckRecv; + + uint32_t rtt; + uint32_t rttvar; + uint32_t totalRetrans; + + std::string srcIp; + std::string dstIp; + uint16_t srcPort; + uint16_t dstPort; +} DataTransTcpInfo; + +typedef struct DataTransHttpInfo { + long curlCode; + int responseCode; + + curl_off_t totalTime; + curl_off_t nameLookUpTime; + curl_off_t connectTime; + curl_off_t appconnectTime; + curl_off_t preTransferTime; + curl_off_t startTransferTime; + curl_off_t queueTime; + curl_off_t retryAfter; + + curl_off_t sizeUpload; + curl_off_t sizeDownload; + curl_off_t speedDownload; + curl_off_t speedUpload; + std::string effectiveMethod; + std::string contentType; + + curl_off_t redirectTime; + long redirectCount; + + int proxyError; + long osError; + long sslVerifyResult; +} DataTransHttpInfo; + +typedef struct DataTransChrStats { + int uid; + int sockfd; + DataTransHttpInfo httpInfo; + DataTransTcpInfo tcpInfo; +} DataTransChrStats; + +constexpr int REPORT_CHR_RESULT_SUCCESS = 0; +constexpr int REPORT_CHR_RESULT_TIME_LIMIT_ERROR = 1; +constexpr int REPORT_CHR_RESULT_SET_DATA_FAIL = 2; +constexpr int REPORT_CHR_RESULT_REPORT_FAIL = 3; + +constexpr char UID_KEY[] = "uid"; +constexpr char SOCKFD_KEY[] = "sockfd"; + +constexpr char HTTP_INFO_KEY[] = "http_info"; +constexpr char CURL_CODE_KEY[] = "curl_code"; +constexpr char RESPONSE_CODE_KEY[] = "response_code"; +constexpr char TOTAL_TIME_KEY[] = "total_time"; +constexpr char NAMELOOKUP_TIME_KEY[] = "namelookup_time"; +constexpr char CONNECT_TIME_KEY[] = "connect_time"; +constexpr char APPCONNECT_TIME_KEY[] = "appconnect_time"; +constexpr char PRETRANSFER_TIME_KEY[] = "pretransfer_time"; +constexpr char STARTTRANSFER_TIME_KEY[] = "starttransfer_time"; +constexpr char QUEUE_TIME_KEY[] = "queue_time"; +constexpr char RETRY_AFTER_KEY[] = "retry_after"; +constexpr char SIZE_UPLOAD_KEY[] = "size_upload"; +constexpr char SIZE_DOWNLOAD_KEY[] = "size_download"; +constexpr char SPEED_DOWNLOAD_KEY[] = "speed_download"; +constexpr char SPEED_UPLOAD_KEY[] = "speed_upload"; +constexpr char EFFECTIVE_METHOD_KEY[] = "effective_method"; +constexpr char CONTENT_TYPE_KEY[] = "content_type"; +constexpr char REDIRECT_TIME_KEY[] = "redirect_time"; +constexpr char REDIRECT_COUNT_KEY[] = "redirect_count"; +constexpr char PROXY_ERROR_KEY[] = "proxy_error"; +constexpr char OS_ERRNO_KEY[] = "os_errno"; +constexpr char SSL_VERIFYRESULT_KEY[] = "ssl_verifyresult"; + +constexpr char TCP_INFO_KEY[] = "tcp_info"; +constexpr char TCPI_RETRANSMITS_KEY[] = "tcpi_retransmits"; +constexpr char TCPI_UNACKED_KEY[] = "tcpi_unacked"; +constexpr char TCPI_LAST_DATA_SENT_KEY[] = "tcpi_last_data_sent"; +constexpr char TCPI_LAST_ACK_SENT_KEY[] = "tcpi_last_ack_sent"; +constexpr char TCPI_LAST_DATA_RECV_KEY[] = "tcpi_last_data_recv"; +constexpr char TCPI_LAST_ACK_RECV_KEY[] = "tcpi_last_ack_recv"; +constexpr char TCPI_RTT_KEY[] = "tcpi_rtt"; +constexpr char TCPI_RTTVAR_KEY[] = "tcpi_rttvar"; +constexpr char TCPI_TOTAL_RETRANS_KEY[] = "tcpi_total_retrans"; +constexpr char SRC_IP_KEY[] = "src_ip"; +constexpr char DST_IP_KEY[] = "dst_ip"; +constexpr char SRC_PORT_KEY[] = "src_port"; +constexpr char DST_PORT_KEY[] = "dst_port"; + +} // 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..ea908ef7f41c8440642d7a2697c23355081f2bc3 --- /dev/null +++ b/utils/netstack_chr_client/include/netstack_chr_client.h @@ -0,0 +1,52 @@ +/* + * 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 + +#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 bool GetAddrFromSock( + int sockfd, std::string &srcIp, std::string &dstIp, uint16_t &srcPort, uint16_t &dstPort); + static bool 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 bool 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..6e8990455d872e4d84679f62dfee69cd27b23efd --- /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 +#include +#include "i_netstack_chr_client.h" +#include "want.h" + +namespace OHOS::NatStack::ChrClient { + +class NetstackChrReport { +public: + NetstackChrReport(); + ~NetstackChrReport(); + + int ReportCommonEvent(DataTransChrStats chrStats); +private: + std::chrono::system_clock::time_point lastReceivedTime_; + std::mutex agentMutex_; + + int ConvertWantParam(AAFwk::Want& want, DataTransChrStats chrStats); + std::string ConvertHttpInfoToJsonStr(DataTransChrStats chrStats); + std::string ConvertTcpInfoToJsonStr(DataTransChrStats chrStats); +}; + +} // 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..25f75b1f78ed2e9aaaf6c6b0eff4b5ea4a4bf894 --- /dev/null +++ b/utils/netstack_chr_client/src/netstack_chr_client.cpp @@ -0,0 +1,216 @@ +/* + * 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 + +#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; +} + +bool 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); + if (getsockname(sockfd, reinterpret_cast(&localss), &addrLen) < 0) { + return false; + } + + // Get peer addr + addrLen = sizeof(peerss); + if (getsockname(sockfd, reinterpret_cast(&peerss), &addrLen) < 0) { + return false; + } + + char buf[INET6_ADDRSTRLEN]; + 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) { + return false; + } + srcIp = buf; + srcPort = ntohs(l4->sin_port); + + if (inet_ntop(AF_INET, &p4->sin_addr, buf, sizeof(buf)) == nullptr) { + return false; + } + + 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) { + return false; + } + srcIp = buf; + srcPort = ntohs(l6->sin6_port); + if (inet_ntop(AF_INET6, &p6->sin6_addr, buf, sizeof(buf)) == nullptr) { + return false; + } + dstIp = buf; + dstPort = ntohs(p6->sin6_port); + } else { + return false; + } + + return true; +} + +bool NetStackChrClient::GetTcpInfoFromSock(const curl_socket_t sockfd, DataTransTcpInfo &httpTcpInfo) +{ + if (sockfd <= 0) { + return false; + } + struct tcp_info tcpInfo = {}; + socklen_t infoLen = sizeof(tcpInfo); + + if (getsockopt(sockfd, IPPROTO_TCP, TCP_INFO, &tcpInfo, &infoLen) < 0) { + return false; + } + + 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)) { + httpTcpInfo.srcIp = CommonUtils::AnonymizeIp(httpTcpInfo.srcIp); + httpTcpInfo.dstIp = CommonUtils::AnonymizeIp(httpTcpInfo.dstIp); + } + + return true; +} + +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); +} + +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.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); +} + +bool NetStackChrClient::shouldReportHttpAbnormalEvent(const DataTransHttpInfo &httpInfo) +{ + if (httpInfo.curlCode != 0 || httpInfo.responseCode != HTTP_REQUEST_SUCCESS) { + return true; + } + if ((httpInfo.sizeDownload + httpInfo.sizeDownload <= HTTP_FILE_TRANSFER_SIZE_THRESHOLD) && + httpInfo.totalTime > HTTP_FILE_TRANSFER_TIME_THRESHOLD) { + return true; + } + + return false; +} + +void NetStackChrClient::GetDfxInfoFromCurlHandleAndReport(CURL *handle, int32_t curlCode) +{ + if (handle == NULL) { + return; + } + + DataTransChrStats dataTransChrStats{}; + dataTransChrStats.uid = static_cast(getuid()); + dataTransChrStats.httpInfo.curlCode = curlCode; + + GetHttpInfoFromCurl(handle, dataTransChrStats.httpInfo); + if (!shouldReportHttpAbnormalEvent(dataTransChrStats.httpInfo)) { + return; + } + + curl_off_t sockfd = 0; + curl_easy_getinfo(handle, CURLINFO_ACTIVESOCKET, &sockfd); + dataTransChrStats.sockfd = sockfd; + + if (!GetTcpInfoFromSock(sockfd, dataTransChrStats.tcpInfo)) { + NETSTACK_LOGD("Chr client get tcp info from socket failed, sockfd: %{public}d", dataTransChrStats.sockfd); + } + + int ret = netstackChrReport.ReportCommonEvent(dataTransChrStats); + if (ret > 0) { + NETSTACK_LOGE("Send to CHR failed."); + } +} + +} // 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..fe0efd85a11710102a86a107ab442845e3a83ef5 --- /dev/null +++ b/utils/netstack_chr_client/src/netstack_chr_report.cpp @@ -0,0 +1,121 @@ +/* + * 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 +#include "netstack_chr_client.h" +#include "netstack_log.h" +#include "common_event_manager.h" +#include "want.h" + +namespace OHOS::NetStack::ChrClient { + +constexpr char REPORT_HTTP_EVENT_NAME[] = "custom.event.CHR_REPORT_HTTP"; +constexpr int REPORT_TIME_LIMIT_MINUTE = 5; + +NetstackChrReport::NetstackChrReport() +{} + +NetstackChrReport::~NetstackChrReport() +{} + +int NetstackChrReport::ReportCommonEvent(DataTransChrStats chrStats) +{ + std::lock_guard lock(agentMutex_); + auto currentTime = std::chrono::system_clock::now(); + auto timeDifference = std::chrono::duration_cast(currentTime - lastReceivedTime_); + if (timeDifference.count() < REPORT_TIME_LIMIT_MINUTE) { + NETSTACK_LOGE("From last report %{public}ld minutes, ignore this report.", timeDifference.count()); + return REPORT_CHR_RESULT_TIME_LIMIT_ERROR; + } + AAFwk::Want want; + want.SetAction(REPORT_HTTP_EVENT_NAME); + if (!ConvertWantParam(want, chrStats)) { + return REPORT_CHR_RESULT_SET_DATA_FAIL; + } + + EventFwk::CommonEventData common_event_data; + common_event_data.SetWant(want); + EventFwk::CommonEventPublishInfo publish_info; + if (!EventFwk::CommonEventManager::PublishCommonEvent(common_event_data, publish_info)) { + NETSTACK_LOGE("Report to CHR failed."); + return REPORT_CHR_RESULT_REPORT_FAIL; + } + lastReceivedTime_ = currentTime; + NETSTACK_LOGI("Report to CHR success."); + return REPORT_CHR_RESULT_SUCCESS; +} + +int NetstackChrReport::ConvertWantParam(AAFwk::Want& want, DataTransChrStats chrStats) +{ + std::string httpInfoJsonStr = ConvertHttpInfoToJsonStr(chrStats); + std::string tcpInfoJsonStr = ConvertTcpInfoToJsonStr(chrStats); + if (httpInfoJsonStr == "" or tcpInfoJsonStr == "") { + return -1; + } + want.SetParam(UID_KEY, chrStats.uid); + want.SetParam(SOCKFD_KEY, chrStats.sockfd); + want.SetParam(HTTP_INFO_KEY, httpInfoJsonStr); + want.SetParam(TCP_INFO_KEY, tcpInfoJsonStr); + return 0; +} + +std::string NetstackChrReport::ConvertHttpInfoToJsonStr(DataTransChrStats chrStats) +{ + AAFwk::Want want; + want.SetParam(CURL_CODE_KEY, static_cast(chrStats.httpInfo.curlCode)); + want.SetParam(RESPONSE_CODE_KEY, static_cast(chrStats.httpInfo.responseCode)); + want.SetParam(TOTAL_TIME_KEY, static_cast(chrStats.httpInfo.totalTime)); + want.SetParam(NAMELOOKUP_TIME_KEY, static_cast(chrStats.httpInfo.nameLookUpTime)); + want.SetParam(CONNECT_TIME_KEY, static_cast(chrStats.httpInfo.connectTime)); + want.SetParam(APPCONNECT_TIME_KEY, static_cast(chrStats.httpInfo.appconnectTime)); + want.SetParam(PRETRANSFER_TIME_KEY, static_cast(chrStats.httpInfo.preTransferTime)); + want.SetParam(STARTTRANSFER_TIME_KEY, static_cast(chrStats.httpInfo.startTransferTime)); + want.SetParam(QUEUE_TIME_KEY, static_cast(chrStats.httpInfo.queueTime)); + want.SetParam(RETRY_AFTER_KEY, static_cast(chrStats.httpInfo.retryAfter)); + want.SetParam(SIZE_UPLOAD_KEY, static_cast(chrStats.httpInfo.sizeUpload)); + want.SetParam(SIZE_DOWNLOAD_KEY, static_cast(chrStats.httpInfo.sizeDownload)); + want.SetParam(SPEED_DOWNLOAD_KEY, static_cast(chrStats.httpInfo.speedDownload)); + want.SetParam(SPEED_UPLOAD_KEY, static_cast(chrStats.httpInfo.speedUpload)); + want.SetParam(EFFECTIVE_METHOD_KEY, std::string(chrStats.httpInfo.effectiveMethod)); + want.SetParam(CONTENT_TYPE_KEY, std::string(chrStats.httpInfo.contentType)); + want.SetParam(REDIRECT_TIME_KEY, static_cast(chrStats.httpInfo.redirectTime)); + want.SetParam(REDIRECT_COUNT_KEY, static_cast(chrStats.httpInfo.redirectCount)); + want.SetParam(PROXY_ERROR_KEY, static_cast(chrStats.httpInfo.proxyError)); + want.SetParam(OS_ERRNO_KEY, static_cast(chrStats.httpInfo.osError)); + want.SetParam(SSL_VERIFYRESULT_KEY, static_cast(chrStats.httpInfo.sslVerifyResult)); + std::string paramStr = want.ToString(); + return paramStr; +} + +std::string NetstackChrReport::ConvertTcpInfoToJsonStr(DataTransChrStats chrStats) +{ + AAFwk::Want want; + want.SetParam(TCPI_RETRANSMITS_KEY, static_cast(chrStats.tcpInfo.tcpi_retransmits)); + want.SetParam(TCPI_UNACKED_KEY, static_cast(chrStats.tcpInfo.tcpi_unacked)); + want.SetParam(TCPI_LAST_DATA_SENT_KEY, static_cast(chrStats.tcpInfo.lastDataSent)); + want.SetParam(TCPI_LAST_ACK_SENT_KEY, static_cast(chrStats.tcpInfo.lastAckSent)); + want.SetParam(TCPI_LAST_DATA_RECV_KEY, static_cast(chrStats.tcpInfo.lastDataRecv)); + want.SetParam(TCPI_LAST_ACK_RECV_KEY, static_cast(chrStats.tcpInfo.lastAckRecv)); + want.SetParam(TCPI_RTT_KEY, static_cast(chrStats.tcpInfo.rtt)); + want.SetParam(TCPI_RTTVAR_KEY, static_cast(chrStats.tcpInfo.rttvar)); + want.SetParam(TCPI_TOTAL_RETRANS_KEY, static_cast(chrStats.tcpInfo.totalRetrans)); + want.SetParam(SRC_IP_KEY, std::string(chrStats.tcpInfo.srcIp)); + want.SetParam(DST_IP_KEY, std::string(chrStats.tcpInfo.dstIp)); + want.SetParam(SRC_PORT_KEY, static_cast(chrStats.tcpInfo.srcPort)); + want.SetParam(DST_PORT_KEY, static_cast(chrStats.tcpInfo.dstPort)); + std::string paramStr = want.ToString(); + return paramStr; +} +} \ No newline at end of file