1/*
2 * Copyright (c) 2021-2023 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 "faultloggerd_client.h"
16
17#include <climits>
18#include <cstdint>
19#include <cstdio>
20#include <cstdlib>
21#include <securec.h>
22#include <unistd.h>
23
24#include <sys/socket.h>
25#include <sys/syscall.h>
26#include <sys/un.h>
27#include <sys/stat.h>
28
29#include "dfx_cutil.h"
30#include "dfx_define.h"
31#include "dfx_log.h"
32#include "dfx_util.h"
33#include "faultloggerd_socket.h"
34
35static const int32_t SOCKET_TIMEOUT = 5;
36
37static std::string GetSocketConnectionName()
38{
39    char content[NAME_BUF_LEN];
40    GetProcessName(content, sizeof(content));
41    if (std::string(content).find("processdump") != std::string::npos) {
42        return std::string(SERVER_CRASH_SOCKET_NAME);
43    }
44    return std::string(SERVER_SOCKET_NAME);
45}
46
47int32_t RequestFileDescriptor(int32_t type)
48{
49    struct FaultLoggerdRequest request;
50    (void)memset_s(&request, sizeof(request), 0, sizeof(request));
51    request.type = type;
52    request.pid = getpid();
53    request.tid = gettid();
54    request.uid = getuid();
55    request.time = OHOS::HiviewDFX::GetTimeMilliSeconds();
56    return RequestFileDescriptorEx(&request);
57}
58
59int32_t RequestLogFileDescriptor(struct FaultLoggerdRequest *request)
60{
61    if (request == nullptr) {
62        DFXLOGE("[%{public}d]: nullptr request", __LINE__);
63        return -1;
64    }
65    request->clientType = (int32_t)FaultLoggerClientType::LOG_FILE_DES_CLIENT;
66    return RequestFileDescriptorEx(request);
67}
68
69int32_t RequestFileDescriptorEx(const struct FaultLoggerdRequest *request)
70{
71    if (request == nullptr) {
72        DFXLOGE("[%{public}d]: nullptr request", __LINE__);
73        return -1;
74    }
75
76    int sockfd;
77    std::string name = GetSocketConnectionName();
78    if (!StartConnect(sockfd, name.c_str(), SOCKET_TIMEOUT)) {
79        DFXLOGE("[%{public}d]: StartConnect(%{public}d) failed", __LINE__, sockfd);
80        return -1;
81    }
82
83    OHOS_TEMP_FAILURE_RETRY(write(sockfd, request, sizeof(struct FaultLoggerdRequest)));
84    int fd = ReadFileDescriptorFromSocket(sockfd);
85    DFXLOGD("RequestFileDescriptorEx(%{public}d).", fd);
86    close(sockfd);
87    return fd;
88}
89
90static bool CheckReadResp(int sockfd)
91{
92    char ControlBuffer[SOCKET_BUFFER_SIZE] = {0};
93    ssize_t nread = OHOS_TEMP_FAILURE_RETRY(read(sockfd, ControlBuffer, sizeof(ControlBuffer) - 1));
94    if (nread != static_cast<ssize_t>(strlen(FAULTLOGGER_DAEMON_RESP))) {
95        DFXLOGE("nread: %{public}zd.", nread);
96        return false;
97    }
98    return true;
99}
100
101static int32_t RequestFileDescriptorByCheck(const struct FaultLoggerdRequest *request)
102{
103    int32_t fd = -1;
104    if (request == nullptr) {
105        DFXLOGE("[%{public}d]: nullptr request", __LINE__);
106        return -1;
107    }
108
109    int sockfd = -1;
110    do {
111        std::string name = GetSocketConnectionName();
112        if (!StartConnect(sockfd, name.c_str(), SOCKET_TIMEOUT)) {
113            DFXLOGE("[%{public}d]: StartConnect(%{public}d) failed", __LINE__, sockfd);
114            break;
115        }
116
117        OHOS_TEMP_FAILURE_RETRY(write(sockfd, request, sizeof(struct FaultLoggerdRequest)));
118
119        if (!CheckReadResp(sockfd)) {
120            break;
121        }
122
123        int data = 12345;
124        if (!SendMsgIovToSocket(sockfd, reinterpret_cast<void *>(&data), sizeof(data))) {
125            DFXLOGE("%{public}s :: Failed to sendmsg.", __func__);
126            break;
127        }
128
129        fd = ReadFileDescriptorFromSocket(sockfd);
130        DFXLOGD("RequestFileDescriptorByCheck(%{public}d).", fd);
131    } while (false);
132    close(sockfd);
133    return fd;
134}
135
136static int SendUidToServer(int sockfd)
137{
138    int mRsp = (int)FaultLoggerCheckPermissionResp::CHECK_PERMISSION_REJECT;
139
140    int data = 12345;
141    if (!SendMsgIovToSocket(sockfd, reinterpret_cast<void *>(&data), sizeof(data))) {
142        DFXLOGE("%{public}s :: Failed to sendmsg.", __func__);
143        return mRsp;
144    }
145
146    char recvbuf[SOCKET_BUFFER_SIZE] = {'\0'};
147    ssize_t count = OHOS_TEMP_FAILURE_RETRY(recv(sockfd, recvbuf, sizeof(recvbuf), 0));
148    if (count < 0) {
149        DFXLOGE("%{public}s :: Failed to recv.", __func__);
150        return mRsp;
151    }
152
153    mRsp = atoi(recvbuf);
154    return mRsp;
155}
156
157bool CheckConnectStatus()
158{
159    int sockfd = -1;
160    std::string name = GetSocketConnectionName();
161    if (StartConnect(sockfd, name.c_str(), SOCKET_TIMEOUT)) {
162        close(sockfd);
163        return true;
164    }
165    return false;
166}
167
168static int SendRequestToServer(const FaultLoggerdRequest &request)
169{
170    int sockfd = -1;
171    int resRsp = (int)FaultLoggerCheckPermissionResp::CHECK_PERMISSION_REJECT;
172    do {
173        std::string name = GetSocketConnectionName();
174        if (request.clientType == FaultLoggerClientType::SDK_DUMP_CLIENT) {
175            name = std::string(SERVER_SDKDUMP_SOCKET_NAME);
176        }
177
178        if (!StartConnect(sockfd, name.c_str(), SOCKET_TIMEOUT)) {
179            DFXLOGE("[%{public}d]: StartConnect(%{public}d) failed", __LINE__, sockfd);
180            break;
181        }
182        if (OHOS_TEMP_FAILURE_RETRY(write(sockfd, &request,
183            sizeof(struct FaultLoggerdRequest))) != static_cast<long>(sizeof(request))) {
184            DFXLOGE("write failed.");
185            break;
186        }
187
188        if (!CheckReadResp(sockfd)) {
189            break;
190        }
191        resRsp = SendUidToServer(sockfd);
192    } while (false);
193
194    close(sockfd);
195    DFXLOGI("SendRequestToServer :: resRsp(%{public}d).", resRsp);
196    return resRsp;
197}
198
199bool RequestCheckPermission(int32_t pid)
200{
201    DFXLOGI("RequestCheckPermission :: %{public}d.", pid);
202    if (pid <= 0) {
203        return false;
204    }
205
206    struct FaultLoggerdRequest request;
207    (void)memset_s(&request, sizeof(request), 0, sizeof(request));
208
209    request.pid = pid;
210    request.clientType = (int32_t)FaultLoggerClientType::PERMISSION_CLIENT;
211
212    bool ret = false;
213    if (SendRequestToServer(request) == (int)FaultLoggerCheckPermissionResp::CHECK_PERMISSION_PASS) {
214        ret = true;
215    }
216    return ret;
217}
218
219int RequestSdkDump(int32_t pid, int32_t tid, int timeout)
220{
221    return RequestSdkDumpJson(pid, tid, false, timeout);
222}
223
224int RequestSdkDumpJson(int32_t pid, int32_t tid, bool isJson, int timeout)
225{
226    DFXLOGI("RequestSdkDumpJson :: pid(%{public}d), tid(%{public}d).", pid, tid);
227    if (pid <= 0 || tid < 0) {
228        return -1;
229    }
230
231    struct FaultLoggerdRequest request;
232    (void)memset_s(&request, sizeof(request), 0, sizeof(request));
233    request.isJson = isJson;
234    request.sigCode = DUMP_TYPE_REMOTE;
235    request.pid = pid;
236    request.tid = tid;
237    request.callerPid = getpid();
238    request.callerTid = gettid();
239    request.clientType = (int32_t)FaultLoggerClientType::SDK_DUMP_CLIENT;
240    request.time = OHOS::HiviewDFX::GetTimeMilliSeconds();
241    request.endTime = GetAbsTimeMilliSeconds() + static_cast<uint64_t>(timeout);
242
243    return SendRequestToServer(request);
244}
245
246int RequestPrintTHilog(const char *msg, int length)
247{
248    if (length >= LINE_BUF_SIZE) {
249        return -1;
250    }
251
252    struct FaultLoggerdRequest request;
253    (void)memset_s(&request, sizeof(request), 0, sizeof(request));
254    request.clientType = (int32_t)FaultLoggerClientType::PRINT_T_HILOG_CLIENT;
255    request.pid = getpid();
256    request.uid = getuid();
257    int sockfd = -1;
258    do {
259        std::string name = GetSocketConnectionName();
260        if (!StartConnect(sockfd, name.c_str(), SOCKET_TIMEOUT)) {
261            DFXLOGE("[%{public}d]: StartConnect(%{public}d) failed", __LINE__, sockfd);
262            break;
263        }
264
265        if (OHOS_TEMP_FAILURE_RETRY(write(sockfd, &request,
266            sizeof(struct FaultLoggerdRequest))) != static_cast<long>(sizeof(request))) {
267            break;
268        }
269
270        if (!CheckReadResp(sockfd)) {
271            break;
272        }
273
274        int nwrite = OHOS_TEMP_FAILURE_RETRY(write(sockfd, msg, strlen(msg)));
275        if (nwrite != static_cast<long>(strlen(msg))) {
276            DFXLOGE("nwrite: %{public}d.", nwrite);
277            break;
278        }
279        close(sockfd);
280        return 0;
281    } while (false);
282    close(sockfd);
283    return -1;
284}
285
286int32_t RequestPipeFd(int32_t pid, int32_t pipeType)
287{
288    if (pipeType < static_cast<int32_t>(FaultLoggerPipeType::PIPE_FD_READ_BUF) ||
289        pipeType > static_cast<int32_t>(FaultLoggerPipeType::PIPE_FD_DELETE)) {
290        DFXLOGE("%{public}s :: pipeType(%{public}d) failed.", __func__, pipeType);
291        return -1;
292    }
293    struct FaultLoggerdRequest request;
294    (void)memset_s(&request, sizeof(request), 0, sizeof(struct FaultLoggerdRequest));
295
296    if ((pipeType == static_cast<int32_t>(FaultLoggerPipeType::PIPE_FD_JSON_READ_BUF)) ||
297        (pipeType == static_cast<int32_t>(FaultLoggerPipeType::PIPE_FD_JSON_READ_RES))) {
298        request.isJson = true;
299    } else {
300        request.isJson = false;
301    }
302    request.pipeType = pipeType;
303    request.pid = pid;
304    request.callerPid = getpid();
305    request.callerTid = gettid();
306    request.clientType = (int32_t)FaultLoggerClientType::PIPE_FD_CLIENT;
307    if ((pipeType == static_cast<int32_t>(FaultLoggerPipeType::PIPE_FD_READ_BUF)) ||
308        (pipeType == static_cast<int32_t>(FaultLoggerPipeType::PIPE_FD_READ_RES)) ||
309        (pipeType == static_cast<int32_t>(FaultLoggerPipeType::PIPE_FD_JSON_READ_BUF)) ||
310        (pipeType == static_cast<int32_t>(FaultLoggerPipeType::PIPE_FD_JSON_READ_RES))) {
311        return RequestFileDescriptorByCheck(&request);
312    }
313    return RequestFileDescriptorEx(&request);
314}
315
316int32_t RequestDelPipeFd(int32_t pid)
317{
318    struct FaultLoggerdRequest request;
319    (void)memset_s(&request, sizeof(request), 0, sizeof(struct FaultLoggerdRequest));
320    request.pipeType = FaultLoggerPipeType::PIPE_FD_DELETE;
321    request.pid = pid;
322    request.clientType = (int32_t)FaultLoggerClientType::PIPE_FD_CLIENT;
323
324    int sockfd;
325    std::string name = GetSocketConnectionName();
326    if (!StartConnect(sockfd, name.c_str(), SOCKET_TIMEOUT)) {
327        DFXLOGE("[%{public}d]: StartConnect(%{public}d) failed", __LINE__, sockfd);
328        return -1;
329    }
330
331    OHOS_TEMP_FAILURE_RETRY(write(sockfd, &request, sizeof(struct FaultLoggerdRequest)));
332    close(sockfd);
333    return 0;
334}
335
336int ReportDumpStats(const struct FaultLoggerdStatsRequest *request)
337{
338    int sockfd = -1;
339    std::string name = GetSocketConnectionName();
340    if (!StartConnect(sockfd, name.c_str(), SOCKET_TIMEOUT)) {
341        DFXLOGE("[%{public}d]: StartConnect(%{public}d) failed", __LINE__, sockfd);
342        return -1;
343    }
344
345    if (OHOS_TEMP_FAILURE_RETRY(write(sockfd, request,
346        sizeof(struct FaultLoggerdStatsRequest))) != static_cast<long int>(sizeof(struct FaultLoggerdStatsRequest))) {
347        DFXLOGE("ReportDumpCatcherStats: failed to write stats.");
348        close(sockfd);
349        return -1;
350    }
351    close(sockfd);
352    return 0;
353}
354