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