• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <unistd.h>
16 #include <arpa/inet.h>
17 #include <netinet/tcp.h>
18 #include <netinet/in.h>
19 #include "netstack_chr_client.h"
20 #include "netstack_common_utils.h"
21 #include "netstack_log.h"
22 #include "i_netstack_chr_client.h"
23 
24 namespace OHOS::NetStack::ChrClient {
25 
26 static constexpr const long HTTP_REQUEST_SUCCESS = 200;
27 static constexpr const int HTTP_FILE_TRANSFER_SIZE_THRESHOLD = 100000;
28 static constexpr const int HTTP_FILE_TRANSFER_TIME_THRESHOLD = 500000;
29 
GetInstance()30 NetStackChrClient &NetStackChrClient::GetInstance()
31 {
32     static NetStackChrClient instance;
33     return instance;
34 }
35 
GetAddrFromSock(int sockfd,std::string & srcIp,std::string & dstIp,uint16_t & srcPort,uint16_t & dstPort)36 int NetStackChrClient::GetAddrFromSock(
37     int sockfd, std::string &srcIp, std::string &dstIp, uint16_t &srcPort, uint16_t &dstPort)
38 {
39     sockaddr_storage localss{};
40     sockaddr_storage peerss{};
41     socklen_t addrLen = 0;
42 
43     // Get local addr
44     addrLen = sizeof(localss);
45     (void)getsockname(sockfd, reinterpret_cast<sockaddr *>(&localss), &addrLen);
46 
47     // Get peer addr
48     addrLen = sizeof(peerss);
49    (void)getpeername(sockfd, reinterpret_cast<sockaddr *>(&peerss), &addrLen);
50 
51     char buf[INET6_ADDRSTRLEN] = {0};
52     if (localss.ss_family == AF_INET && peerss.ss_family == AF_INET) {
53         auto *l4 = reinterpret_cast<sockaddr_in *>(&localss);
54         auto *p4 = reinterpret_cast<sockaddr_in *>(&peerss);
55         if (inet_ntop(AF_INET, &l4->sin_addr, buf, sizeof(buf)) != nullptr) {
56             srcIp = buf;
57             srcPort = ntohs(l4->sin_port);
58         }
59         if (inet_ntop(AF_INET, &p4->sin_addr, buf, sizeof(buf)) != nullptr) {
60             dstIp = buf;
61             dstPort = ntohs(p4->sin_port);
62         }
63     } else if (localss.ss_family == AF_INET6 && peerss.ss_family == AF_INET6) {
64         auto *l6 = reinterpret_cast<sockaddr_in6 *>(&localss);
65         auto *p6 = reinterpret_cast<sockaddr_in6 *>(&peerss);
66         if (inet_ntop(AF_INET6, &l6->sin6_addr, buf, sizeof(buf)) != nullptr) {
67             srcIp = buf;
68             srcPort = ntohs(l6->sin6_port);
69         }
70         if (inet_ntop(AF_INET6, &p6->sin6_addr, buf, sizeof(buf)) != nullptr) {
71             dstIp = buf;
72             dstPort = ntohs(p6->sin6_port);
73         }
74     } else {
75         return -1;
76     }
77 
78     return 0;
79 }
80 
GetTcpInfoFromSock(const curl_socket_t sockfd,DataTransTcpInfo & httpTcpInfo)81 int NetStackChrClient::GetTcpInfoFromSock(const curl_socket_t sockfd, DataTransTcpInfo &httpTcpInfo)
82 {
83     if (sockfd <= 0) {
84         return -1;
85     }
86     struct tcp_info tcpInfo = {};
87     socklen_t infoLen = sizeof(tcpInfo);
88 
89     if (getsockopt(sockfd, IPPROTO_TCP, TCP_INFO, &tcpInfo, &infoLen) < 0) {
90         return -1;
91     }
92 
93     httpTcpInfo.unacked = tcpInfo.tcpi_unacked;
94     httpTcpInfo.lastDataSent = tcpInfo.tcpi_last_data_sent;
95     httpTcpInfo.lastAckSent = tcpInfo.tcpi_last_ack_sent;
96     httpTcpInfo.lastDataRecv = tcpInfo.tcpi_last_data_recv;
97     httpTcpInfo.lastAckRecv = tcpInfo.tcpi_last_ack_recv;
98     httpTcpInfo.rtt = tcpInfo.tcpi_rtt;
99     httpTcpInfo.rttvar = tcpInfo.tcpi_rttvar;
100     httpTcpInfo.totalRetrans = tcpInfo.tcpi_total_retrans;
101     httpTcpInfo.retransmits = tcpInfo.tcpi_retransmits;
102 
103     if (GetAddrFromSock(sockfd, httpTcpInfo.srcIp, httpTcpInfo.dstIp, httpTcpInfo.srcPort, httpTcpInfo.dstPort) == 0) {
104         httpTcpInfo.srcIp = CommonUtils::AnonymizeIp(httpTcpInfo.srcIp);
105         httpTcpInfo.dstIp = CommonUtils::AnonymizeIp(httpTcpInfo.dstIp);
106     }
107 
108     return 0;
109 }
110 
111 template <typename DataType>
GetNumericAttributeFromCurl(CURL * handle,CURLINFO info)112 DataType NetStackChrClient::GetNumericAttributeFromCurl(CURL *handle, CURLINFO info)
113 {
114     DataType number = 0;
115     CURLcode res = curl_easy_getinfo(handle, info, &number);
116     if (res != CURLE_OK) {
117         return -1;
118     }
119     return number;
120 }
121 
GetStringAttributeFromCurl(CURL * handle,CURLINFO info)122 std::string NetStackChrClient::GetStringAttributeFromCurl(CURL *handle, CURLINFO info)
123 {
124     char *result = nullptr;
125     CURLcode res = curl_easy_getinfo(handle, info, &result);
126     if (res != CURLE_OK || result == nullptr) {
127         return std::string();
128     }
129     return std::string(result);
130 }
131 
GetRequestStartTime(curl_off_t totalTime)132 long NetStackChrClient::GetRequestStartTime(curl_off_t totalTime)
133 {
134     auto now = std::chrono::system_clock::now();
135     long msCount = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
136     return msCount;
137 }
138 
GetHttpInfoFromCurl(CURL * handle,DataTransHttpInfo & httpInfo)139 void NetStackChrClient::GetHttpInfoFromCurl(CURL *handle, DataTransHttpInfo &httpInfo)
140 {
141     (void)curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &httpInfo.responseCode);
142     httpInfo.nameLookUpTime = GetNumericAttributeFromCurl<curl_off_t>(handle, CURLINFO_NAMELOOKUP_TIME_T);
143     httpInfo.connectTime = GetNumericAttributeFromCurl<curl_off_t>(handle, CURLINFO_CONNECT_TIME_T);
144     httpInfo.preTransferTime = GetNumericAttributeFromCurl<curl_off_t>(handle, CURLINFO_PRETRANSFER_TIME_T);
145     httpInfo.startTransferTime = GetNumericAttributeFromCurl<curl_off_t>(handle, CURLINFO_STARTTRANSFER_TIME_T);
146     httpInfo.totalTime = GetNumericAttributeFromCurl<curl_off_t>(handle, CURLINFO_TOTAL_TIME_T);
147     httpInfo.redirectTime = GetNumericAttributeFromCurl<curl_off_t>(handle, CURLINFO_REDIRECT_TIME_T);
148     httpInfo.appconnectTime = GetNumericAttributeFromCurl<curl_off_t>(handle, CURLINFO_APPCONNECT_TIME_T);
149     httpInfo.queueTime = GetNumericAttributeFromCurl<curl_off_t>(handle, CURLINFO_QUEUE_TIME_T);
150     httpInfo.retryAfter = GetNumericAttributeFromCurl<curl_off_t>(handle, CURLINFO_RETRY_AFTER);
151     httpInfo.requestStartTime = GetRequestStartTime(httpInfo.totalTime);
152 
153     httpInfo.sizeUpload = GetNumericAttributeFromCurl<curl_off_t>(handle, CURLINFO_SIZE_UPLOAD_T);
154     httpInfo.sizeDownload = GetNumericAttributeFromCurl<curl_off_t>(handle, CURLINFO_SIZE_DOWNLOAD_T);
155     httpInfo.speedDownload = GetNumericAttributeFromCurl<curl_off_t>(handle, CURLINFO_SPEED_DOWNLOAD_T);
156     httpInfo.speedUpload = GetNumericAttributeFromCurl<curl_off_t>(handle, CURLINFO_SPEED_UPLOAD_T);
157 
158     httpInfo.redirectCount = GetNumericAttributeFromCurl<long>(handle, CURLINFO_REDIRECT_COUNT);
159     httpInfo.osError = GetNumericAttributeFromCurl<long>(handle, CURLINFO_OS_ERRNO);
160     httpInfo.sslVerifyResult = GetNumericAttributeFromCurl<long>(handle, CURLINFO_PROXY_SSL_VERIFYRESULT);
161     httpInfo.proxyError = GetNumericAttributeFromCurl<long>(handle, CURLINFO_PROXY_ERROR);
162 
163     httpInfo.effectiveMethod = GetStringAttributeFromCurl(handle, CURLINFO_EFFECTIVE_METHOD);
164     httpInfo.contentType = GetStringAttributeFromCurl(handle, CURLINFO_CONTENT_TYPE);
165 }
166 
ShouldReportHttpAbnormalEvent(const DataTransHttpInfo & httpInfo)167 int NetStackChrClient::ShouldReportHttpAbnormalEvent(const DataTransHttpInfo &httpInfo)
168 {
169     if (httpInfo.curlCode != 0 || httpInfo.responseCode != HTTP_REQUEST_SUCCESS ||
170         httpInfo.osError != 0 || httpInfo.proxyError != 0) {
171         return 0;
172     }
173     if ((httpInfo.sizeUpload + httpInfo.sizeDownload <= HTTP_FILE_TRANSFER_SIZE_THRESHOLD) &&
174         httpInfo.totalTime > HTTP_FILE_TRANSFER_TIME_THRESHOLD) {
175         return 0;
176     }
177 
178     return -1;
179 }
180 
GetDfxInfoFromCurlHandleAndReport(CURL * handle,int32_t curlCode)181 void NetStackChrClient::GetDfxInfoFromCurlHandleAndReport(CURL *handle, int32_t curlCode)
182 {
183     if (handle == NULL) {
184         return;
185     }
186 
187     DataTransChrStats dataTransChrStats{};
188     dataTransChrStats.httpInfo.uid = static_cast<int>(getuid());
189     dataTransChrStats.httpInfo.curlCode = curlCode;
190     if (CommonUtils::GetBundleName().has_value()) {
191         dataTransChrStats.processName = CommonUtils::GetBundleName().value();
192     }
193 
194     GetHttpInfoFromCurl(handle, dataTransChrStats.httpInfo);
195     if (ShouldReportHttpAbnormalEvent(dataTransChrStats.httpInfo) != 0) {
196         return;
197     }
198 
199     curl_off_t sockfd = 0;
200     curl_easy_getinfo(handle, CURLINFO_ACTIVESOCKET, &sockfd);
201 
202     if (GetTcpInfoFromSock(sockfd, dataTransChrStats.tcpInfo) != 0) {
203         NETSTACK_LOGD("Chr client get tcp info from socket failed, sockfd: %{public}" PRId64, sockfd);
204     }
205 
206     int ret = netstackChrReport_.ReportCommonEvent(dataTransChrStats);
207     if (ret > 0) {
208         NETSTACK_LOGI("Send to CHR failed, error code %{public}d", ret);
209     }
210 }
211 
212 }  // namespace OHOS::NetStack::ChrClient