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
16#include "faultloggerd_socket.h"
17
18#include <cstddef>
19#include <cstdio>
20#include <securec.h>
21#include <string>
22#include <unistd.h>
23
24#include <sys/socket.h>
25#include <sys/stat.h>
26#include <sys/time.h>
27#include <sys/un.h>
28
29#include "dfx_define.h"
30#include "dfx_log.h"
31#include "init_socket.h"
32
33bool StartConnect(int& sockfd, const char* path, const int timeout)
34{
35    bool ret = false;
36    if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
37        DFXLOGE("%{public}s :: Failed to socket, errno(%{public}d)", __func__, errno);
38        return ret;
39    }
40
41    do {
42        if (timeout > 0) {
43            struct timeval timev = {
44                timeout,
45                0
46            };
47            void* pTimev = &timev;
48            if (OHOS_TEMP_FAILURE_RETRY(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, \
49                static_cast<const char*>(pTimev), sizeof(timev))) != 0) {
50                    DFXLOGE("setsockopt(%{public}d) SO_RCVTIMEO error, errno(%{public}d).", sockfd, errno);
51            }
52            if (OHOS_TEMP_FAILURE_RETRY(setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, \
53                static_cast<const char*>(pTimev), sizeof(timev))) != 0) {
54                    DFXLOGE("setsockopt(%{public}d) SO_SNDTIMEO error, errno(%{public}d).", sockfd, errno);
55            }
56        }
57
58        std::string fullPath = std::string(FAULTLOGGERD_SOCK_BASE_PATH) + std::string(path);
59        struct sockaddr_un server;
60        (void)memset_s(&server, sizeof(server), 0, sizeof(server));
61        server.sun_family = AF_LOCAL;
62        errno_t err = strncpy_s(server.sun_path, sizeof(server.sun_path), fullPath.c_str(),
63            sizeof(server.sun_path) - 1);
64        if (err != EOK) {
65            DFXLOGE("%{public}s :: strncpy failed, err = %{public}d.", __func__, (int)err);
66            break;
67        }
68
69        int len = static_cast<int>(offsetof(struct sockaddr_un, sun_path) + strlen(server.sun_path) + 1);
70        int connected = OHOS_TEMP_FAILURE_RETRY(connect(sockfd, reinterpret_cast<struct sockaddr *>(&server), len));
71        if (connected < 0) {
72            DFXLOGE("%{public}s :: connect failed, errno = %{public}d.", __func__, errno);
73            break;
74        }
75
76        ret = true;
77    } while (false);
78
79    if (!ret) {
80        close(sockfd);
81    }
82    return ret;
83}
84
85static bool GetServerSocket(int& sockfd, const char* name)
86{
87    sockfd = OHOS_TEMP_FAILURE_RETRY(socket(AF_LOCAL, SOCK_STREAM, 0));
88    if (sockfd < 0) {
89        DFXLOGE("%{public}s :: Failed to create socket, errno(%{public}d)", __func__, errno);
90        return false;
91    }
92
93    std::string path = std::string(FAULTLOGGERD_SOCK_BASE_PATH) + std::string(name);
94    struct sockaddr_un server;
95    (void)memset_s(&server, sizeof(server), 0, sizeof(server));
96    server.sun_family = AF_LOCAL;
97    if (strncpy_s(server.sun_path, sizeof(server.sun_path), path.c_str(), sizeof(server.sun_path) - 1) != 0) {
98        DFXLOGE("%{public}s :: strncpy failed.", __func__);
99        return false;
100    }
101
102    chmod(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IWOTH);
103    unlink(path.c_str());
104
105    int optval = 1;
106    int ret = OHOS_TEMP_FAILURE_RETRY(setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)));
107    if (ret < 0) {
108        DFXLOGE("%{public}s :: Failed to set socket option, errno(%{public}d)", __func__, errno);
109        return false;
110    }
111
112    if (bind(sockfd, reinterpret_cast<struct sockaddr *>(&server),
113        offsetof(struct sockaddr_un, sun_path) + strlen(server.sun_path)) < 0) {
114        DFXLOGE("%{public}s :: Failed to bind socket, errno(%{public}d)", __func__, errno);
115        return false;
116    }
117
118    return true;
119}
120
121bool StartListen(int& sockfd, const char* name, const int listenCnt)
122{
123    if (name == nullptr) {
124        return false;
125    }
126    sockfd = GetControlSocket(name);
127    if (sockfd < 0) {
128        DFXLOGW("%{public}s :: Failed to get socket fd by cfg", __func__);
129        if (GetServerSocket(sockfd, name) == false) {
130            DFXLOGE("%{public}s :: Failed to get socket fd by path", __func__);
131            return false;
132        }
133    }
134
135    if (listen(sockfd, listenCnt) < 0) {
136        DFXLOGE("%{public}s :: Failed to listen socket, errno(%{public}d)", __func__, errno);
137        close(sockfd);
138        sockfd = -1;
139        return false;
140    }
141
142    DFXLOGI("%{public}s :: success to listen socket", __func__);
143    return true;
144}
145
146static bool RecvMsgFromSocket(int sockfd, unsigned char* data, size_t& len)
147{
148    bool ret = false;
149    if ((sockfd < 0) || (data == nullptr)) {
150        return ret;
151    }
152
153    do {
154        struct msghdr msgh;
155        (void)memset_s(&msgh, sizeof(msgh), 0, sizeof(msgh));
156        char msgBuffer[SOCKET_BUFFER_SIZE] = { 0 };
157        struct iovec iov = {
158            .iov_base = msgBuffer,
159            .iov_len = sizeof(msgBuffer)
160        };
161        msgh.msg_iov = &iov;
162        msgh.msg_iovlen = 1;
163
164        char ctlBuffer[SOCKET_BUFFER_SIZE] = { 0 };
165        msgh.msg_control = ctlBuffer;
166        msgh.msg_controllen = sizeof(ctlBuffer);
167
168        if (OHOS_TEMP_FAILURE_RETRY(recvmsg(sockfd, &msgh, 0)) < 0) {
169            DFXLOGE("%{public}s :: Failed to recv message, errno(%{public}d)", __func__, errno);
170            break;
171        }
172
173        struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh);
174        if (cmsg == nullptr) {
175            DFXLOGE("%{public}s :: Invalid message", __func__);
176            break;
177        }
178
179        len = cmsg->cmsg_len - sizeof(struct cmsghdr);
180        if (memcpy_s(data, len, CMSG_DATA(cmsg), len) != 0) {
181            DFXLOGE("%{public}s :: memcpy error", __func__);
182            break;
183        }
184
185        ret = true;
186    } while (false);
187    return ret;
188}
189
190bool RecvMsgCredFromSocket(int sockfd, struct ucred* pucred)
191{
192    bool ret = false;
193    if ((sockfd < 0) || (pucred == nullptr)) {
194        return ret;
195    }
196
197    do {
198        struct msghdr msgh;
199        (void)memset_s(&msgh, sizeof(msgh), 0, sizeof(msgh));
200        union {
201            char buf[CMSG_SPACE(sizeof(struct ucred))];
202
203            /* Space large enough to hold a 'ucred' structure */
204            struct cmsghdr align;
205        } controlMsg;
206
207        msgh.msg_name = nullptr;
208        msgh.msg_namelen = 0;
209
210        int data;
211        struct iovec iov = {
212            .iov_base = &data,
213            .iov_len = sizeof(data)
214        };
215        msgh.msg_iov = &iov;
216        msgh.msg_iovlen = 1;
217
218        msgh.msg_control = controlMsg.buf;
219        msgh.msg_controllen = sizeof(controlMsg.buf);
220
221        if (OHOS_TEMP_FAILURE_RETRY(recvmsg(sockfd, &msgh, 0)) < 0) {
222            DFXLOGE("%{public}s :: Failed to recv message, errno(%{public}d)", __func__, errno);
223            break;
224        }
225
226        struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh);
227        if (cmsg == nullptr) {
228            DFXLOGE("%{public}s :: Invalid message", __func__);
229            break;
230        }
231
232        if (memcpy_s(pucred, sizeof(struct ucred), CMSG_DATA(cmsg), sizeof(struct ucred)) != 0) {
233            DFXLOGE("%{public}s :: memcpy error", __func__);
234            break;
235        }
236
237        ret = true;
238    } while (false);
239    return ret;
240}
241
242bool SendMsgIovToSocket(int sockfd, void *iovBase, const int iovLen)
243{
244    if ((sockfd < 0) || (iovBase == nullptr) || (iovLen == 0)) {
245        return false;
246    }
247
248    struct msghdr msgh;
249    (void)memset_s(&msgh, sizeof(msgh), 0, sizeof(msgh));
250    msgh.msg_name = nullptr;
251    msgh.msg_namelen = 0;
252
253    struct iovec iov;
254    iov.iov_base = iovBase;
255    iov.iov_len = iovLen;
256    msgh.msg_iov = &iov;
257    msgh.msg_iovlen = 1;
258
259    msgh.msg_control = nullptr;
260    msgh.msg_controllen = 0;
261
262    if (OHOS_TEMP_FAILURE_RETRY(sendmsg(sockfd, &msgh, 0)) < 0) {
263        DFXLOGE("%{public}s :: Failed to send message, errno(%{public}d).", __func__, errno);
264        return false;
265    }
266    return true;
267}
268
269static bool SendMsgCtlToSocket(int sockfd, const void *cmsg, const int cmsgLen)
270{
271    if ((sockfd < 0) || (cmsg == nullptr) || (cmsgLen == 0)) {
272        return false;
273    }
274
275    struct msghdr msgh;
276    (void)memset_s(&msgh, sizeof(msgh), 0, sizeof(msgh));
277    char iovBase[] = "";
278    struct iovec iov = {
279        .iov_base = reinterpret_cast<void *>(iovBase),
280        .iov_len = 1
281    };
282    msgh.msg_iov = &iov;
283    msgh.msg_iovlen = 1;
284
285    int controlBufLen = CMSG_SPACE(static_cast<unsigned int>(cmsgLen));
286    char controlBuf[controlBufLen];
287    msgh.msg_control = controlBuf;
288    msgh.msg_controllen = sizeof(controlBuf);
289
290    struct cmsghdr *cmsgh = CMSG_FIRSTHDR(&msgh);
291    if (cmsgh != nullptr) {
292        cmsgh->cmsg_level = SOL_SOCKET;
293        cmsgh->cmsg_type = SCM_RIGHTS;
294        cmsgh->cmsg_len = CMSG_LEN(cmsgLen);
295    }
296    if (memcpy_s(CMSG_DATA(cmsgh), cmsgLen, cmsg, cmsgLen) != 0) {
297        DFXLOGE("%{public}s :: memcpy error", __func__);
298    }
299
300    if (OHOS_TEMP_FAILURE_RETRY(sendmsg(sockfd, &msgh, 0)) < 0) {
301        DFXLOGE("%{public}s :: Failed to send message, errno(%{public}d)", __func__, errno);
302        return false;
303    }
304    return true;
305}
306
307bool SendFileDescriptorToSocket(int sockfd, int fd)
308{
309    return SendMsgCtlToSocket(sockfd, reinterpret_cast<void *>(&fd), sizeof(fd));
310}
311
312int ReadFileDescriptorFromSocket(int sockfd)
313{
314    size_t len = sizeof(int);
315    unsigned char data[len + 1];
316    if (!RecvMsgFromSocket(sockfd, data, len)) {
317        DFXLOGE("%{public}s :: Failed to recv message", __func__);
318        return -1;
319    }
320
321    if (len != sizeof(int)) {
322        DFXLOGE("%{public}s :: data is null or len is %{public}zu", __func__, len);
323        return -1;
324    }
325    int fd = *(reinterpret_cast<int *>(data));
326    DFXLOGD("%{public}s :: fd: %{public}d", __func__, fd);
327    return fd;
328}