1800b99b8Sopenharmony_ci/*
2800b99b8Sopenharmony_ci * Copyright (c) 2021-2023 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 "faultloggerd_socket.h"
17800b99b8Sopenharmony_ci
18800b99b8Sopenharmony_ci#include <cstddef>
19800b99b8Sopenharmony_ci#include <cstdio>
20800b99b8Sopenharmony_ci#include <securec.h>
21800b99b8Sopenharmony_ci#include <string>
22800b99b8Sopenharmony_ci#include <unistd.h>
23800b99b8Sopenharmony_ci
24800b99b8Sopenharmony_ci#include <sys/socket.h>
25800b99b8Sopenharmony_ci#include <sys/stat.h>
26800b99b8Sopenharmony_ci#include <sys/time.h>
27800b99b8Sopenharmony_ci#include <sys/un.h>
28800b99b8Sopenharmony_ci
29800b99b8Sopenharmony_ci#include "dfx_define.h"
30800b99b8Sopenharmony_ci#include "dfx_log.h"
31800b99b8Sopenharmony_ci#include "init_socket.h"
32800b99b8Sopenharmony_ci
33800b99b8Sopenharmony_cibool StartConnect(int& sockfd, const char* path, const int timeout)
34800b99b8Sopenharmony_ci{
35800b99b8Sopenharmony_ci    bool ret = false;
36800b99b8Sopenharmony_ci    if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
37800b99b8Sopenharmony_ci        DFXLOGE("%{public}s :: Failed to socket, errno(%{public}d)", __func__, errno);
38800b99b8Sopenharmony_ci        return ret;
39800b99b8Sopenharmony_ci    }
40800b99b8Sopenharmony_ci
41800b99b8Sopenharmony_ci    do {
42800b99b8Sopenharmony_ci        if (timeout > 0) {
43800b99b8Sopenharmony_ci            struct timeval timev = {
44800b99b8Sopenharmony_ci                timeout,
45800b99b8Sopenharmony_ci                0
46800b99b8Sopenharmony_ci            };
47800b99b8Sopenharmony_ci            void* pTimev = &timev;
48800b99b8Sopenharmony_ci            if (OHOS_TEMP_FAILURE_RETRY(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, \
49800b99b8Sopenharmony_ci                static_cast<const char*>(pTimev), sizeof(timev))) != 0) {
50800b99b8Sopenharmony_ci                    DFXLOGE("setsockopt(%{public}d) SO_RCVTIMEO error, errno(%{public}d).", sockfd, errno);
51800b99b8Sopenharmony_ci            }
52800b99b8Sopenharmony_ci            if (OHOS_TEMP_FAILURE_RETRY(setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, \
53800b99b8Sopenharmony_ci                static_cast<const char*>(pTimev), sizeof(timev))) != 0) {
54800b99b8Sopenharmony_ci                    DFXLOGE("setsockopt(%{public}d) SO_SNDTIMEO error, errno(%{public}d).", sockfd, errno);
55800b99b8Sopenharmony_ci            }
56800b99b8Sopenharmony_ci        }
57800b99b8Sopenharmony_ci
58800b99b8Sopenharmony_ci        std::string fullPath = std::string(FAULTLOGGERD_SOCK_BASE_PATH) + std::string(path);
59800b99b8Sopenharmony_ci        struct sockaddr_un server;
60800b99b8Sopenharmony_ci        (void)memset_s(&server, sizeof(server), 0, sizeof(server));
61800b99b8Sopenharmony_ci        server.sun_family = AF_LOCAL;
62800b99b8Sopenharmony_ci        errno_t err = strncpy_s(server.sun_path, sizeof(server.sun_path), fullPath.c_str(),
63800b99b8Sopenharmony_ci            sizeof(server.sun_path) - 1);
64800b99b8Sopenharmony_ci        if (err != EOK) {
65800b99b8Sopenharmony_ci            DFXLOGE("%{public}s :: strncpy failed, err = %{public}d.", __func__, (int)err);
66800b99b8Sopenharmony_ci            break;
67800b99b8Sopenharmony_ci        }
68800b99b8Sopenharmony_ci
69800b99b8Sopenharmony_ci        int len = static_cast<int>(offsetof(struct sockaddr_un, sun_path) + strlen(server.sun_path) + 1);
70800b99b8Sopenharmony_ci        int connected = OHOS_TEMP_FAILURE_RETRY(connect(sockfd, reinterpret_cast<struct sockaddr *>(&server), len));
71800b99b8Sopenharmony_ci        if (connected < 0) {
72800b99b8Sopenharmony_ci            DFXLOGE("%{public}s :: connect failed, errno = %{public}d.", __func__, errno);
73800b99b8Sopenharmony_ci            break;
74800b99b8Sopenharmony_ci        }
75800b99b8Sopenharmony_ci
76800b99b8Sopenharmony_ci        ret = true;
77800b99b8Sopenharmony_ci    } while (false);
78800b99b8Sopenharmony_ci
79800b99b8Sopenharmony_ci    if (!ret) {
80800b99b8Sopenharmony_ci        close(sockfd);
81800b99b8Sopenharmony_ci    }
82800b99b8Sopenharmony_ci    return ret;
83800b99b8Sopenharmony_ci}
84800b99b8Sopenharmony_ci
85800b99b8Sopenharmony_cistatic bool GetServerSocket(int& sockfd, const char* name)
86800b99b8Sopenharmony_ci{
87800b99b8Sopenharmony_ci    sockfd = OHOS_TEMP_FAILURE_RETRY(socket(AF_LOCAL, SOCK_STREAM, 0));
88800b99b8Sopenharmony_ci    if (sockfd < 0) {
89800b99b8Sopenharmony_ci        DFXLOGE("%{public}s :: Failed to create socket, errno(%{public}d)", __func__, errno);
90800b99b8Sopenharmony_ci        return false;
91800b99b8Sopenharmony_ci    }
92800b99b8Sopenharmony_ci
93800b99b8Sopenharmony_ci    std::string path = std::string(FAULTLOGGERD_SOCK_BASE_PATH) + std::string(name);
94800b99b8Sopenharmony_ci    struct sockaddr_un server;
95800b99b8Sopenharmony_ci    (void)memset_s(&server, sizeof(server), 0, sizeof(server));
96800b99b8Sopenharmony_ci    server.sun_family = AF_LOCAL;
97800b99b8Sopenharmony_ci    if (strncpy_s(server.sun_path, sizeof(server.sun_path), path.c_str(), sizeof(server.sun_path) - 1) != 0) {
98800b99b8Sopenharmony_ci        DFXLOGE("%{public}s :: strncpy failed.", __func__);
99800b99b8Sopenharmony_ci        return false;
100800b99b8Sopenharmony_ci    }
101800b99b8Sopenharmony_ci
102800b99b8Sopenharmony_ci    chmod(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IWOTH);
103800b99b8Sopenharmony_ci    unlink(path.c_str());
104800b99b8Sopenharmony_ci
105800b99b8Sopenharmony_ci    int optval = 1;
106800b99b8Sopenharmony_ci    int ret = OHOS_TEMP_FAILURE_RETRY(setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)));
107800b99b8Sopenharmony_ci    if (ret < 0) {
108800b99b8Sopenharmony_ci        DFXLOGE("%{public}s :: Failed to set socket option, errno(%{public}d)", __func__, errno);
109800b99b8Sopenharmony_ci        return false;
110800b99b8Sopenharmony_ci    }
111800b99b8Sopenharmony_ci
112800b99b8Sopenharmony_ci    if (bind(sockfd, reinterpret_cast<struct sockaddr *>(&server),
113800b99b8Sopenharmony_ci        offsetof(struct sockaddr_un, sun_path) + strlen(server.sun_path)) < 0) {
114800b99b8Sopenharmony_ci        DFXLOGE("%{public}s :: Failed to bind socket, errno(%{public}d)", __func__, errno);
115800b99b8Sopenharmony_ci        return false;
116800b99b8Sopenharmony_ci    }
117800b99b8Sopenharmony_ci
118800b99b8Sopenharmony_ci    return true;
119800b99b8Sopenharmony_ci}
120800b99b8Sopenharmony_ci
121800b99b8Sopenharmony_cibool StartListen(int& sockfd, const char* name, const int listenCnt)
122800b99b8Sopenharmony_ci{
123800b99b8Sopenharmony_ci    if (name == nullptr) {
124800b99b8Sopenharmony_ci        return false;
125800b99b8Sopenharmony_ci    }
126800b99b8Sopenharmony_ci    sockfd = GetControlSocket(name);
127800b99b8Sopenharmony_ci    if (sockfd < 0) {
128800b99b8Sopenharmony_ci        DFXLOGW("%{public}s :: Failed to get socket fd by cfg", __func__);
129800b99b8Sopenharmony_ci        if (GetServerSocket(sockfd, name) == false) {
130800b99b8Sopenharmony_ci            DFXLOGE("%{public}s :: Failed to get socket fd by path", __func__);
131800b99b8Sopenharmony_ci            return false;
132800b99b8Sopenharmony_ci        }
133800b99b8Sopenharmony_ci    }
134800b99b8Sopenharmony_ci
135800b99b8Sopenharmony_ci    if (listen(sockfd, listenCnt) < 0) {
136800b99b8Sopenharmony_ci        DFXLOGE("%{public}s :: Failed to listen socket, errno(%{public}d)", __func__, errno);
137800b99b8Sopenharmony_ci        close(sockfd);
138800b99b8Sopenharmony_ci        sockfd = -1;
139800b99b8Sopenharmony_ci        return false;
140800b99b8Sopenharmony_ci    }
141800b99b8Sopenharmony_ci
142800b99b8Sopenharmony_ci    DFXLOGI("%{public}s :: success to listen socket", __func__);
143800b99b8Sopenharmony_ci    return true;
144800b99b8Sopenharmony_ci}
145800b99b8Sopenharmony_ci
146800b99b8Sopenharmony_cistatic bool RecvMsgFromSocket(int sockfd, unsigned char* data, size_t& len)
147800b99b8Sopenharmony_ci{
148800b99b8Sopenharmony_ci    bool ret = false;
149800b99b8Sopenharmony_ci    if ((sockfd < 0) || (data == nullptr)) {
150800b99b8Sopenharmony_ci        return ret;
151800b99b8Sopenharmony_ci    }
152800b99b8Sopenharmony_ci
153800b99b8Sopenharmony_ci    do {
154800b99b8Sopenharmony_ci        struct msghdr msgh;
155800b99b8Sopenharmony_ci        (void)memset_s(&msgh, sizeof(msgh), 0, sizeof(msgh));
156800b99b8Sopenharmony_ci        char msgBuffer[SOCKET_BUFFER_SIZE] = { 0 };
157800b99b8Sopenharmony_ci        struct iovec iov = {
158800b99b8Sopenharmony_ci            .iov_base = msgBuffer,
159800b99b8Sopenharmony_ci            .iov_len = sizeof(msgBuffer)
160800b99b8Sopenharmony_ci        };
161800b99b8Sopenharmony_ci        msgh.msg_iov = &iov;
162800b99b8Sopenharmony_ci        msgh.msg_iovlen = 1;
163800b99b8Sopenharmony_ci
164800b99b8Sopenharmony_ci        char ctlBuffer[SOCKET_BUFFER_SIZE] = { 0 };
165800b99b8Sopenharmony_ci        msgh.msg_control = ctlBuffer;
166800b99b8Sopenharmony_ci        msgh.msg_controllen = sizeof(ctlBuffer);
167800b99b8Sopenharmony_ci
168800b99b8Sopenharmony_ci        if (OHOS_TEMP_FAILURE_RETRY(recvmsg(sockfd, &msgh, 0)) < 0) {
169800b99b8Sopenharmony_ci            DFXLOGE("%{public}s :: Failed to recv message, errno(%{public}d)", __func__, errno);
170800b99b8Sopenharmony_ci            break;
171800b99b8Sopenharmony_ci        }
172800b99b8Sopenharmony_ci
173800b99b8Sopenharmony_ci        struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh);
174800b99b8Sopenharmony_ci        if (cmsg == nullptr) {
175800b99b8Sopenharmony_ci            DFXLOGE("%{public}s :: Invalid message", __func__);
176800b99b8Sopenharmony_ci            break;
177800b99b8Sopenharmony_ci        }
178800b99b8Sopenharmony_ci
179800b99b8Sopenharmony_ci        len = cmsg->cmsg_len - sizeof(struct cmsghdr);
180800b99b8Sopenharmony_ci        if (memcpy_s(data, len, CMSG_DATA(cmsg), len) != 0) {
181800b99b8Sopenharmony_ci            DFXLOGE("%{public}s :: memcpy error", __func__);
182800b99b8Sopenharmony_ci            break;
183800b99b8Sopenharmony_ci        }
184800b99b8Sopenharmony_ci
185800b99b8Sopenharmony_ci        ret = true;
186800b99b8Sopenharmony_ci    } while (false);
187800b99b8Sopenharmony_ci    return ret;
188800b99b8Sopenharmony_ci}
189800b99b8Sopenharmony_ci
190800b99b8Sopenharmony_cibool RecvMsgCredFromSocket(int sockfd, struct ucred* pucred)
191800b99b8Sopenharmony_ci{
192800b99b8Sopenharmony_ci    bool ret = false;
193800b99b8Sopenharmony_ci    if ((sockfd < 0) || (pucred == nullptr)) {
194800b99b8Sopenharmony_ci        return ret;
195800b99b8Sopenharmony_ci    }
196800b99b8Sopenharmony_ci
197800b99b8Sopenharmony_ci    do {
198800b99b8Sopenharmony_ci        struct msghdr msgh;
199800b99b8Sopenharmony_ci        (void)memset_s(&msgh, sizeof(msgh), 0, sizeof(msgh));
200800b99b8Sopenharmony_ci        union {
201800b99b8Sopenharmony_ci            char buf[CMSG_SPACE(sizeof(struct ucred))];
202800b99b8Sopenharmony_ci
203800b99b8Sopenharmony_ci            /* Space large enough to hold a 'ucred' structure */
204800b99b8Sopenharmony_ci            struct cmsghdr align;
205800b99b8Sopenharmony_ci        } controlMsg;
206800b99b8Sopenharmony_ci
207800b99b8Sopenharmony_ci        msgh.msg_name = nullptr;
208800b99b8Sopenharmony_ci        msgh.msg_namelen = 0;
209800b99b8Sopenharmony_ci
210800b99b8Sopenharmony_ci        int data;
211800b99b8Sopenharmony_ci        struct iovec iov = {
212800b99b8Sopenharmony_ci            .iov_base = &data,
213800b99b8Sopenharmony_ci            .iov_len = sizeof(data)
214800b99b8Sopenharmony_ci        };
215800b99b8Sopenharmony_ci        msgh.msg_iov = &iov;
216800b99b8Sopenharmony_ci        msgh.msg_iovlen = 1;
217800b99b8Sopenharmony_ci
218800b99b8Sopenharmony_ci        msgh.msg_control = controlMsg.buf;
219800b99b8Sopenharmony_ci        msgh.msg_controllen = sizeof(controlMsg.buf);
220800b99b8Sopenharmony_ci
221800b99b8Sopenharmony_ci        if (OHOS_TEMP_FAILURE_RETRY(recvmsg(sockfd, &msgh, 0)) < 0) {
222800b99b8Sopenharmony_ci            DFXLOGE("%{public}s :: Failed to recv message, errno(%{public}d)", __func__, errno);
223800b99b8Sopenharmony_ci            break;
224800b99b8Sopenharmony_ci        }
225800b99b8Sopenharmony_ci
226800b99b8Sopenharmony_ci        struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh);
227800b99b8Sopenharmony_ci        if (cmsg == nullptr) {
228800b99b8Sopenharmony_ci            DFXLOGE("%{public}s :: Invalid message", __func__);
229800b99b8Sopenharmony_ci            break;
230800b99b8Sopenharmony_ci        }
231800b99b8Sopenharmony_ci
232800b99b8Sopenharmony_ci        if (memcpy_s(pucred, sizeof(struct ucred), CMSG_DATA(cmsg), sizeof(struct ucred)) != 0) {
233800b99b8Sopenharmony_ci            DFXLOGE("%{public}s :: memcpy error", __func__);
234800b99b8Sopenharmony_ci            break;
235800b99b8Sopenharmony_ci        }
236800b99b8Sopenharmony_ci
237800b99b8Sopenharmony_ci        ret = true;
238800b99b8Sopenharmony_ci    } while (false);
239800b99b8Sopenharmony_ci    return ret;
240800b99b8Sopenharmony_ci}
241800b99b8Sopenharmony_ci
242800b99b8Sopenharmony_cibool SendMsgIovToSocket(int sockfd, void *iovBase, const int iovLen)
243800b99b8Sopenharmony_ci{
244800b99b8Sopenharmony_ci    if ((sockfd < 0) || (iovBase == nullptr) || (iovLen == 0)) {
245800b99b8Sopenharmony_ci        return false;
246800b99b8Sopenharmony_ci    }
247800b99b8Sopenharmony_ci
248800b99b8Sopenharmony_ci    struct msghdr msgh;
249800b99b8Sopenharmony_ci    (void)memset_s(&msgh, sizeof(msgh), 0, sizeof(msgh));
250800b99b8Sopenharmony_ci    msgh.msg_name = nullptr;
251800b99b8Sopenharmony_ci    msgh.msg_namelen = 0;
252800b99b8Sopenharmony_ci
253800b99b8Sopenharmony_ci    struct iovec iov;
254800b99b8Sopenharmony_ci    iov.iov_base = iovBase;
255800b99b8Sopenharmony_ci    iov.iov_len = iovLen;
256800b99b8Sopenharmony_ci    msgh.msg_iov = &iov;
257800b99b8Sopenharmony_ci    msgh.msg_iovlen = 1;
258800b99b8Sopenharmony_ci
259800b99b8Sopenharmony_ci    msgh.msg_control = nullptr;
260800b99b8Sopenharmony_ci    msgh.msg_controllen = 0;
261800b99b8Sopenharmony_ci
262800b99b8Sopenharmony_ci    if (OHOS_TEMP_FAILURE_RETRY(sendmsg(sockfd, &msgh, 0)) < 0) {
263800b99b8Sopenharmony_ci        DFXLOGE("%{public}s :: Failed to send message, errno(%{public}d).", __func__, errno);
264800b99b8Sopenharmony_ci        return false;
265800b99b8Sopenharmony_ci    }
266800b99b8Sopenharmony_ci    return true;
267800b99b8Sopenharmony_ci}
268800b99b8Sopenharmony_ci
269800b99b8Sopenharmony_cistatic bool SendMsgCtlToSocket(int sockfd, const void *cmsg, const int cmsgLen)
270800b99b8Sopenharmony_ci{
271800b99b8Sopenharmony_ci    if ((sockfd < 0) || (cmsg == nullptr) || (cmsgLen == 0)) {
272800b99b8Sopenharmony_ci        return false;
273800b99b8Sopenharmony_ci    }
274800b99b8Sopenharmony_ci
275800b99b8Sopenharmony_ci    struct msghdr msgh;
276800b99b8Sopenharmony_ci    (void)memset_s(&msgh, sizeof(msgh), 0, sizeof(msgh));
277800b99b8Sopenharmony_ci    char iovBase[] = "";
278800b99b8Sopenharmony_ci    struct iovec iov = {
279800b99b8Sopenharmony_ci        .iov_base = reinterpret_cast<void *>(iovBase),
280800b99b8Sopenharmony_ci        .iov_len = 1
281800b99b8Sopenharmony_ci    };
282800b99b8Sopenharmony_ci    msgh.msg_iov = &iov;
283800b99b8Sopenharmony_ci    msgh.msg_iovlen = 1;
284800b99b8Sopenharmony_ci
285800b99b8Sopenharmony_ci    int controlBufLen = CMSG_SPACE(static_cast<unsigned int>(cmsgLen));
286800b99b8Sopenharmony_ci    char controlBuf[controlBufLen];
287800b99b8Sopenharmony_ci    msgh.msg_control = controlBuf;
288800b99b8Sopenharmony_ci    msgh.msg_controllen = sizeof(controlBuf);
289800b99b8Sopenharmony_ci
290800b99b8Sopenharmony_ci    struct cmsghdr *cmsgh = CMSG_FIRSTHDR(&msgh);
291800b99b8Sopenharmony_ci    if (cmsgh != nullptr) {
292800b99b8Sopenharmony_ci        cmsgh->cmsg_level = SOL_SOCKET;
293800b99b8Sopenharmony_ci        cmsgh->cmsg_type = SCM_RIGHTS;
294800b99b8Sopenharmony_ci        cmsgh->cmsg_len = CMSG_LEN(cmsgLen);
295800b99b8Sopenharmony_ci    }
296800b99b8Sopenharmony_ci    if (memcpy_s(CMSG_DATA(cmsgh), cmsgLen, cmsg, cmsgLen) != 0) {
297800b99b8Sopenharmony_ci        DFXLOGE("%{public}s :: memcpy error", __func__);
298800b99b8Sopenharmony_ci    }
299800b99b8Sopenharmony_ci
300800b99b8Sopenharmony_ci    if (OHOS_TEMP_FAILURE_RETRY(sendmsg(sockfd, &msgh, 0)) < 0) {
301800b99b8Sopenharmony_ci        DFXLOGE("%{public}s :: Failed to send message, errno(%{public}d)", __func__, errno);
302800b99b8Sopenharmony_ci        return false;
303800b99b8Sopenharmony_ci    }
304800b99b8Sopenharmony_ci    return true;
305800b99b8Sopenharmony_ci}
306800b99b8Sopenharmony_ci
307800b99b8Sopenharmony_cibool SendFileDescriptorToSocket(int sockfd, int fd)
308800b99b8Sopenharmony_ci{
309800b99b8Sopenharmony_ci    return SendMsgCtlToSocket(sockfd, reinterpret_cast<void *>(&fd), sizeof(fd));
310800b99b8Sopenharmony_ci}
311800b99b8Sopenharmony_ci
312800b99b8Sopenharmony_ciint ReadFileDescriptorFromSocket(int sockfd)
313800b99b8Sopenharmony_ci{
314800b99b8Sopenharmony_ci    size_t len = sizeof(int);
315800b99b8Sopenharmony_ci    unsigned char data[len + 1];
316800b99b8Sopenharmony_ci    if (!RecvMsgFromSocket(sockfd, data, len)) {
317800b99b8Sopenharmony_ci        DFXLOGE("%{public}s :: Failed to recv message", __func__);
318800b99b8Sopenharmony_ci        return -1;
319800b99b8Sopenharmony_ci    }
320800b99b8Sopenharmony_ci
321800b99b8Sopenharmony_ci    if (len != sizeof(int)) {
322800b99b8Sopenharmony_ci        DFXLOGE("%{public}s :: data is null or len is %{public}zu", __func__, len);
323800b99b8Sopenharmony_ci        return -1;
324800b99b8Sopenharmony_ci    }
325800b99b8Sopenharmony_ci    int fd = *(reinterpret_cast<int *>(data));
326800b99b8Sopenharmony_ci    DFXLOGD("%{public}s :: fd: %{public}d", __func__, fd);
327800b99b8Sopenharmony_ci    return fd;
328800b99b8Sopenharmony_ci}