1800b99b8Sopenharmony_ci/*
2800b99b8Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License.
5800b99b8Sopenharmony_ci * You may obtain a copy of the License at
6800b99b8Sopenharmony_ci *
7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8800b99b8Sopenharmony_ci *
9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and
13800b99b8Sopenharmony_ci * limitations under the License.
14800b99b8Sopenharmony_ci */
15800b99b8Sopenharmony_ci
16800b99b8Sopenharmony_ci#include "dfx_signalhandler_exception.h"
17800b99b8Sopenharmony_ci
18800b99b8Sopenharmony_ci#include <stdio.h>
19800b99b8Sopenharmony_ci#include <sys/syscall.h>
20800b99b8Sopenharmony_ci#include <sys/socket.h>
21800b99b8Sopenharmony_ci#include <sys/time.h>
22800b99b8Sopenharmony_ci#include <sys/un.h>
23800b99b8Sopenharmony_ci#include <unistd.h>
24800b99b8Sopenharmony_ci
25800b99b8Sopenharmony_ci#include "dfx_define.h"
26800b99b8Sopenharmony_ci#include "dfx_exception.h"
27800b99b8Sopenharmony_ci#include "dfx_socket_request.h"
28800b99b8Sopenharmony_ci#include "errno.h"
29800b99b8Sopenharmony_ci#include "string.h"
30800b99b8Sopenharmony_ci
31800b99b8Sopenharmony_ci#ifndef DFX_SIGNAL_LIBC
32800b99b8Sopenharmony_ci#include "dfx_log.h"
33800b99b8Sopenharmony_ci#else
34800b99b8Sopenharmony_ci#include "musl_log.h"
35800b99b8Sopenharmony_ci#endif
36800b99b8Sopenharmony_ci
37800b99b8Sopenharmony_ci#ifdef LOG_DOMAIN
38800b99b8Sopenharmony_ci#undef LOG_DOMAIN
39800b99b8Sopenharmony_ci#define LOG_DOMAIN 0xD002D11
40800b99b8Sopenharmony_ci#endif
41800b99b8Sopenharmony_ci
42800b99b8Sopenharmony_ci#ifdef LOG_TAG
43800b99b8Sopenharmony_ci#undef LOG_TAG
44800b99b8Sopenharmony_ci#define LOG_TAG "DfxSignalHandlerException"
45800b99b8Sopenharmony_ci#endif
46800b99b8Sopenharmony_ci
47800b99b8Sopenharmony_cistatic const int TIME_OUT = 2;       /* seconds */
48800b99b8Sopenharmony_cistatic const char FAULTLOGGERD_SOCKET_NAME[] = "/dev/unix/socket/faultloggerd.server";
49800b99b8Sopenharmony_ci
50800b99b8Sopenharmony_cistatic int ConnectSocket(const char* path, const int timeout)
51800b99b8Sopenharmony_ci{
52800b99b8Sopenharmony_ci    int fd = -1;
53800b99b8Sopenharmony_ci    if ((fd = syscall(SYS_socket, AF_LOCAL, SOCK_STREAM, 0)) < 0) {
54800b99b8Sopenharmony_ci        DFXLOGE("Failed to create a socket, errno(%{public}d).", errno);
55800b99b8Sopenharmony_ci        return -1;
56800b99b8Sopenharmony_ci    }
57800b99b8Sopenharmony_ci
58800b99b8Sopenharmony_ci    do {
59800b99b8Sopenharmony_ci        if (timeout > 0) {
60800b99b8Sopenharmony_ci            struct timeval timev = {
61800b99b8Sopenharmony_ci                timeout,
62800b99b8Sopenharmony_ci                0
63800b99b8Sopenharmony_ci            };
64800b99b8Sopenharmony_ci            void* pTimev = &timev;
65800b99b8Sopenharmony_ci            if (OHOS_TEMP_FAILURE_RETRY(syscall(SYS_setsockopt, fd, SOL_SOCKET, SO_RCVTIMEO,
66800b99b8Sopenharmony_ci                (const void*)(pTimev), sizeof(timev))) != 0) {
67800b99b8Sopenharmony_ci                DFXLOGE("setsockopt SO_RCVTIMEO error, errno(%{public}d).", errno);
68800b99b8Sopenharmony_ci                syscall(SYS_close, fd);
69800b99b8Sopenharmony_ci                fd = -1;
70800b99b8Sopenharmony_ci                break;
71800b99b8Sopenharmony_ci            }
72800b99b8Sopenharmony_ci        }
73800b99b8Sopenharmony_ci        struct sockaddr_un server;
74800b99b8Sopenharmony_ci        (void)memset(&server, 0, sizeof(server));
75800b99b8Sopenharmony_ci        server.sun_family = AF_LOCAL;
76800b99b8Sopenharmony_ci        (void)strncpy(server.sun_path, path, sizeof(server.sun_path) - 1);
77800b99b8Sopenharmony_ci        int len = sizeof(server.sun_family) + strlen(server.sun_path);
78800b99b8Sopenharmony_ci        int connected = OHOS_TEMP_FAILURE_RETRY(connect(fd, (struct sockaddr*)(&server), len));
79800b99b8Sopenharmony_ci        if (connected < 0) {
80800b99b8Sopenharmony_ci            DFXLOGE("Failed to connect to faultloggerd socket, errno = %{public}d.", errno);
81800b99b8Sopenharmony_ci            syscall(SYS_close, fd);
82800b99b8Sopenharmony_ci            fd = -1;
83800b99b8Sopenharmony_ci            break;
84800b99b8Sopenharmony_ci        }
85800b99b8Sopenharmony_ci    } while (false);
86800b99b8Sopenharmony_ci    return fd;
87800b99b8Sopenharmony_ci}
88800b99b8Sopenharmony_ci
89800b99b8Sopenharmony_cistatic bool CheckReadResp(int fd)
90800b99b8Sopenharmony_ci{
91800b99b8Sopenharmony_ci    char controlBuffer[MAX_FUNC_NAME_LEN] = {0};
92800b99b8Sopenharmony_ci    ssize_t nread = OHOS_TEMP_FAILURE_RETRY(read(fd, controlBuffer, sizeof(controlBuffer) - 1));
93800b99b8Sopenharmony_ci    if (nread != (ssize_t)(strlen(FAULTLOGGER_DAEMON_RESP))) {
94800b99b8Sopenharmony_ci        DFXLOGE("Failed to read expected length, nread: %{public}zd, errno(%{public}d).", nread, errno);
95800b99b8Sopenharmony_ci        return false;
96800b99b8Sopenharmony_ci    }
97800b99b8Sopenharmony_ci    return true;
98800b99b8Sopenharmony_ci}
99800b99b8Sopenharmony_ci
100800b99b8Sopenharmony_ciint ReportException(struct CrashDumpException exception)
101800b99b8Sopenharmony_ci{
102800b99b8Sopenharmony_ci    struct FaultLoggerdRequest request;
103800b99b8Sopenharmony_ci    (void)memset(&request, 0, sizeof(struct FaultLoggerdRequest));
104800b99b8Sopenharmony_ci    request.clientType = (int32_t)REPORT_EXCEPTION_CLIENT;
105800b99b8Sopenharmony_ci    request.pid = exception.pid;
106800b99b8Sopenharmony_ci    request.uid = (uint32_t)(exception.uid);
107800b99b8Sopenharmony_ci    int ret = -1;
108800b99b8Sopenharmony_ci    int fd = ConnectSocket(FAULTLOGGERD_SOCKET_NAME, TIME_OUT); // connect timeout
109800b99b8Sopenharmony_ci    if (fd == -1) {
110800b99b8Sopenharmony_ci        DFXLOGE("Failed to connect socket.");
111800b99b8Sopenharmony_ci        return ret;
112800b99b8Sopenharmony_ci    }
113800b99b8Sopenharmony_ci    do {
114800b99b8Sopenharmony_ci        if (OHOS_TEMP_FAILURE_RETRY(write(fd, &request, sizeof(request))) != (long)sizeof(request)) {
115800b99b8Sopenharmony_ci            DFXLOGE("Failed to write request message to socket, errno(%{public}d).", errno);
116800b99b8Sopenharmony_ci            break;
117800b99b8Sopenharmony_ci        }
118800b99b8Sopenharmony_ci
119800b99b8Sopenharmony_ci        if (!CheckReadResp(fd)) {
120800b99b8Sopenharmony_ci            DFXLOGE("Failed to receive socket responces.");
121800b99b8Sopenharmony_ci            break;
122800b99b8Sopenharmony_ci        }
123800b99b8Sopenharmony_ci
124800b99b8Sopenharmony_ci        if (OHOS_TEMP_FAILURE_RETRY(write(fd, &exception,
125800b99b8Sopenharmony_ci            sizeof(exception))) != (long)sizeof(exception)) {
126800b99b8Sopenharmony_ci            DFXLOGE("Failed to write exception message to socket, errno(%{public}d).", errno);
127800b99b8Sopenharmony_ci            break;
128800b99b8Sopenharmony_ci        }
129800b99b8Sopenharmony_ci
130800b99b8Sopenharmony_ci        ret = 0;
131800b99b8Sopenharmony_ci    } while (false);
132800b99b8Sopenharmony_ci    syscall(SYS_close, fd);
133800b99b8Sopenharmony_ci    return ret;
134800b99b8Sopenharmony_ci}
135