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, errno(%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 DFXLOG_ERROR("setsockopt(%d) SO_RCVTIMEO error, errno(%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 DFXLOG_ERROR("setsockopt(%d) SO_SNDTIMEO error, errno(%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 DFXLOG_ERROR("%s :: strncpy failed, err = %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 DFXLOG_ERROR("%s :: connect failed, errno = %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
GetServerSocket(int & sockfd,const char * name)85 static 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 DFXLOG_ERROR("%s :: Failed to create socket, errno(%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 DFXLOG_ERROR("%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 DFXLOG_ERROR("%s :: Failed to set socket option, errno(%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 DFXLOG_ERROR("%s :: Failed to bind socket, errno(%d)", __func__, errno);
115 return false;
116 }
117
118 return true;
119 }
120
StartListen(int & sockfd,const char * name,const int listenCnt)121 bool 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 DFXLOG_WARN("%s :: Failed to get socket fd by cfg", __func__);
129 if (GetServerSocket(sockfd, name) == false) {
130 DFXLOG_ERROR("%s :: Failed to get socket fd by path", __func__);
131 return false;
132 }
133 }
134
135 if (listen(sockfd, listenCnt) < 0) {
136 DFXLOG_ERROR("%s :: Failed to listen socket, errno(%d)", __func__, errno);
137 close(sockfd);
138 sockfd = -1;
139 return false;
140 }
141
142 DFXLOG_INFO("%s :: success to listen socket", __func__);
143 return true;
144 }
145
RecvMsgFromSocket(int sockfd,unsigned char * data,size_t & len)146 static 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 DFXLOG_ERROR("%s :: Failed to recv message, errno(%d)\n", __func__, errno);
170 break;
171 }
172
173 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh);
174 if (cmsg == nullptr) {
175 DFXLOG_ERROR("%s :: Invalid message\n", __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 DFXLOG_ERROR("%s :: memcpy error\n", __func__);
182 break;
183 }
184
185 ret = true;
186 } while (false);
187 return ret;
188 }
189
RecvMsgCredFromSocket(int sockfd,struct ucred * pucred)190 bool 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 DFXLOG_ERROR("%s :: Failed to recv message, errno(%d)\n", __func__, errno);
223 break;
224 }
225
226 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh);
227 if (cmsg == nullptr) {
228 DFXLOG_ERROR("%s :: Invalid message\n", __func__);
229 break;
230 }
231
232 if (memcpy_s(pucred, sizeof(struct ucred), CMSG_DATA(cmsg), sizeof(struct ucred)) != 0) {
233 DFXLOG_ERROR("%s :: memcpy error\n", __func__);
234 break;
235 }
236
237 ret = true;
238 } while (false);
239 return ret;
240 }
241
SendMsgIovToSocket(int sockfd,void * iovBase,const int iovLen)242 bool 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 DFXLOG_ERROR("%s :: Failed to send message, errno(%d).", __func__, errno);
264 return false;
265 }
266 return true;
267 }
268
SendMsgCtlToSocket(int sockfd,const void * cmsg,const int cmsgLen)269 static 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 DFXLOG_ERROR("%s :: memcpy error\n", __func__);
298 }
299
300 if (OHOS_TEMP_FAILURE_RETRY(sendmsg(sockfd, &msgh, 0)) < 0) {
301 DFXLOG_ERROR("%s :: Failed to send message, errno(%d)", __func__, errno);
302 return false;
303 }
304 return true;
305 }
306
SendFileDescriptorToSocket(int sockfd,int fd)307 bool SendFileDescriptorToSocket(int sockfd, int fd)
308 {
309 return SendMsgCtlToSocket(sockfd, reinterpret_cast<void *>(&fd), sizeof(fd));
310 }
311
ReadFileDescriptorFromSocket(int sockfd)312 int ReadFileDescriptorFromSocket(int sockfd)
313 {
314 size_t len = sizeof(int);
315 unsigned char data[len + 1];
316 if (!RecvMsgFromSocket(sockfd, data, len)) {
317 DFXLOG_ERROR("%s :: Failed to recv message", __func__);
318 return -1;
319 }
320
321 if (len != sizeof(int)) {
322 DFXLOG_ERROR("%s :: data is null or len is %zu", __func__, len);
323 return -1;
324 }
325 int fd = *(reinterpret_cast<int *>(data));
326 DFXLOG_DEBUG("%s :: fd: %d", __func__, fd);
327 return fd;
328 }